Merge pull request #220413 from NixOS/home-assistant

home-assistant: 2023.3.2 -> 2023.3.3
This commit is contained in:
Martin Weinelt 2023-03-10 19:55:20 +00:00 committed by GitHub
commit 3a9aec4691
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 289 additions and 60 deletions

View file

@ -11,7 +11,7 @@
buildPythonPackage rec {
pname = "roombapy";
version = "1.6.5";
version = "1.6.6";
format = "pyproject";
disabled = pythonOlder "3.7";
@ -20,7 +20,7 @@ buildPythonPackage rec {
owner = "pschmitt";
repo = "roombapy";
rev = version;
sha256 = "sha256-Xjeh29U+FCzI5n/i5s6wC0B88Ktmb8pnNDdOzCiKWi4=";
hash = "sha256-dfeMd/THlj2HQYcLPmeC3AWP3vR/6+8BFU1QtSu5xg4=";
};
nativeBuildInputs = [

View file

@ -2,7 +2,7 @@
# Do not edit!
{
version = "2023.3.2";
version = "2023.3.3";
components = {
"3_day_blinds" = ps: with ps; [
];

View file

@ -263,7 +263,7 @@ let
extraBuildInputs = extraPackages python.pkgs;
# Don't forget to run parse-requirements.py after updating
hassVersion = "2023.3.2";
hassVersion = "2023.3.3";
in python.pkgs.buildPythonApplication rec {
pname = "homeassistant";
@ -279,7 +279,7 @@ in python.pkgs.buildPythonApplication rec {
# Primary source is the pypi sdist, because it contains translations
src = fetchPypi {
inherit pname version;
hash = "sha256-I6NSVoMS3xbUqh/7BxJj/Evkk7+g3N0dZVJjEbr2pCs=";
hash = "sha256-AJJ0w66a8D3kiLHhnoFmnGRWyDJ4OCebwwKTGdprGa0=";
};
# Secondary source is git for tests
@ -287,7 +287,7 @@ in python.pkgs.buildPythonApplication rec {
owner = "home-assistant";
repo = "core";
rev = "refs/tags/${version}";
hash = "sha256-Qd++/73c9VDNe4AMdiDIVJXxh4qFx2x4HDkY1An2VjE=";
hash = "sha256-KTmMA8P0MhYAiwp073Q3s60budFKHrsBnAJSqYC7zis=";
};
nativeBuildInputs = with python3.pkgs; [
@ -442,6 +442,7 @@ in python.pkgs.buildPythonApplication rec {
python
supportedComponentsWithTests;
pythonPath = python3.pkgs.makePythonPath (componentBuildInputs ++ extraBuildInputs);
frontend = python.pkgs.home-assistant-frontend;
intents = python.pkgs.home-assistant-intents;
tests = {
nixos = nixosTests.home-assistant;

View file

@ -4,7 +4,7 @@ buildPythonPackage rec {
# the frontend version corresponding to a specific home-assistant version can be found here
# https://github.com/home-assistant/home-assistant/blob/master/homeassistant/components/frontend/manifest.json
pname = "home-assistant-frontend";
version = "20230306.0";
version = "20230309.0";
format = "wheel";
src = fetchPypi {
@ -12,7 +12,7 @@ buildPythonPackage rec {
pname = "home_assistant_frontend";
dist = "py3";
python = "py3";
hash = "sha256-E/e1XyhwFiNMLz7+o99eG9sW2ZCCfPFnkBcu3BpCbxQ=";
hash = "sha256-gHc93xKIm0LDQrkTtlMdLv/N2smfYz5lQ6uLV+Cqj+s=";
};
# there is nothing to strip in this package

View file

@ -1,5 +1,5 @@
#! /usr/bin/env nix-shell
#! nix-shell -i python3 -p "python3.withPackages (ps: with ps; [ mypy attrs packaging rich ])
#! nix-shell -i python3 -p "python3.withPackages (ps: with ps; [ attrs packaging rich ])" -p nodePackages.pyright ruff isort"
#
# This script downloads Home Assistant's source tarball.
# Inside the homeassistant/components directory, each integration has an associated manifest.json,
@ -25,8 +25,9 @@ import tarfile
import tempfile
from functools import reduce
from io import BytesIO
from typing import Dict, Optional, Set, Any
from typing import Any, Dict, List, Optional, Set
from urllib.request import urlopen
from packaging import version as Version
from rich.console import Console
from rich.table import Table
@ -45,17 +46,21 @@ PKG_PREFERENCES = {
}
def run_mypy() -> None:
cmd = ["mypy", "--ignore-missing-imports", __file__]
def run_sync(cmd: List[str]) -> None:
print(f"$ {' '.join(cmd)}")
subprocess.run(cmd, check=True)
process = subprocess.run(cmd)
if process.returncode != 0:
sys.exit(1)
def get_version():
def get_version() -> str:
with open(os.path.dirname(sys.argv[0]) + "/default.nix") as f:
# A version consists of digits, dots, and possibly a "b" (for beta)
m = re.search('hassVersion = "([\\d\\.b]+)";', f.read())
return m.group(1)
if match := re.search('hassVersion = "([\\d\\.b]+)";', f.read()):
return match.group(1)
raise RuntimeError("hassVersion not in default.nix")
def parse_components(version: str = "master"):
@ -74,7 +79,7 @@ def parse_components(version: str = "master"):
components_with_tests.append(entry.name)
sys.path.append(core_path)
from script.hassfest.model import Integration
from script.hassfest.model import Integration # type: ignore
integrations = Integration.load_dir(
pathlib.Path(
os.path.join(core_path, "homeassistant/components")
@ -270,5 +275,7 @@ def main() -> None:
if __name__ == "__main__":
run_mypy()
run_sync(["pyright", __file__])
run_sync(["ruff", "--ignore=E501", __file__])
run_sync(["isort", __file__])
main()

View file

@ -0,0 +1,263 @@
#!/usr/bin/env nix-shell
#!nix-shell -I nixpkgs=channel:nixpkgs-unstable -i python3 -p "python3.withPackages (ps: with ps; [ aiohttp packaging ])" -p git nurl nodePackages.pyright ruff isort
import asyncio
import json
import os
import re
import sys
from subprocess import check_output, run
from typing import Dict, Final, List, Optional, Union
import aiohttp
from aiohttp import ClientSession
from packaging.version import Version
ROOT: Final = check_output([
"git",
"rev-parse",
"--show-toplevel",
]).decode().strip()
def run_sync(cmd: List[str]) -> None:
print(f"$ {' '.join(cmd)}")
process = run(cmd)
if process.returncode != 0:
sys.exit(1)
async def check_async(cmd: List[str]) -> str:
print(f"$ {' '.join(cmd)}")
process = await asyncio.create_subprocess_exec(
*cmd,
stdout=asyncio.subprocess.PIPE,
stderr=asyncio.subprocess.PIPE
)
stdout, stderr = await process.communicate()
if process.returncode != 0:
error = stderr.decode()
raise RuntimeError(f"{cmd[0]} failed: {error}")
return stdout.decode().strip()
async def run_async(cmd: List[str]):
print(f"$ {' '.join(cmd)}")
process = await asyncio.create_subprocess_exec(
*cmd,
stdout=asyncio.subprocess.PIPE,
stderr=asyncio.subprocess.PIPE,
)
stdout, stderr = await process.communicate()
print(stdout.decode())
if process.returncode != 0:
error = stderr.decode()
raise RuntimeError(f"{cmd[0]} failed: {error}")
class File:
def __init__(self, path: str):
self.path = os.path.join(ROOT, path)
def __enter__(self):
with open(self.path, "r") as handle:
self.text = handle.read()
return self
def get_exact_match(self, attr: str, value: str):
matches = re.findall(
rf'{re.escape(attr)}\s+=\s+\"?{re.escape(value)}\"?',
self.text
)
n = len(matches)
if n > 1:
raise ValueError(f"multiple occurrences found for {attr}={value}")
elif n == 1:
return matches.pop()
else:
raise ValueError(f"no occurrence found for {attr}={value}")
def substitute(self, attr: str, old_value: str, new_value: str) -> None:
old_line = self.get_exact_match(attr, old_value)
new_line = old_line.replace(old_value, new_value)
self.text = self.text.replace(old_line, new_line)
print(f"Substitute `{attr}` value `{old_value}` with `{new_value}`")
def __exit__(self, exc_type, exc_val, exc_tb):
with open(self.path, "w") as handle:
handle.write(self.text)
class Nurl:
@classmethod
async def prefetch(cls, url: str, version: str, *extra_args: str) -> str:
cmd = [
"nurl",
"--hash",
url,
version,
]
cmd.extend(extra_args)
return await check_async(cmd)
class Nix:
base_cmd: Final = [
"nix",
"--show-trace",
"--extra-experimental-features", "nix-command"
]
@classmethod
async def _run(cls, args: List[str]) -> Optional[str]:
return await check_async(cls.base_cmd + args)
@classmethod
async def eval(cls, expr: str) -> Union[List, Dict, int, float, str, bool]:
response = await cls._run([
"eval",
"-f", f"{ROOT}/default.nix",
"--json",
expr
])
if response is None:
raise RuntimeError("Nix eval expression returned no response")
try:
return json.loads(response)
except (TypeError, ValueError):
raise RuntimeError("Nix eval response could not be parsed from JSON")
@classmethod
async def hash_to_sri(cls, algorithm: str, value: str) -> Optional[str]:
return await cls._run([
"hash",
"to-sri",
"--type", algorithm,
value
])
class HomeAssistant:
def __init__(self, session: ClientSession):
self._session = session
async def get_latest_core_version(
self,
owner: str = "home-assistant",
repo: str = "core"
) -> str:
async with self._session.get(
f"https://api.github.com/repos/{owner}/{repo}/releases/latest"
) as response:
document = await response.json()
try:
return str(document.get("name"))
except KeyError:
raise RuntimeError("No tag name in response document")
async def get_latest_frontend_version(
self,
core_version: str
) -> str:
async with self._session.get(
f"https://raw.githubusercontent.com/home-assistant/core/{core_version}/homeassistant/components/frontend/manifest.json"
) as response:
document = await response.json(content_type="text/plain")
requirements = [
requirement
for requirement in document.get("requirements", [])
if requirement.startswith("home-assistant-frontend==")
]
if len(requirements) > 1:
raise RuntimeError(
"Found more than one version specifier for the frontend package"
)
elif len(requirements) == 1:
requirement = requirements.pop()
_, version = requirement.split("==", maxsplit=1)
return str(version)
else:
raise RuntimeError(
"Found no version specifier for frontend package"
)
async def update_core(self, old_version: str, new_version: str) -> None:
old_sdist_hash = str(await Nix.eval("home-assistant.src.outputHash"))
new_sdist_hash = await Nurl.prefetch("https://pypi.org/project/homeassistant/", new_version)
print(f"sdist: {old_sdist_hash} -> {new_sdist_hash}")
old_git_hash = str(await Nix.eval("home-assistant.gitSrc.outputHash"))
new_git_hash = await Nurl.prefetch("https://github.com/home-assistant/core/", new_version)
print(f"git: {old_git_hash} -> {new_git_hash}")
with File("pkgs/servers/home-assistant/default.nix") as file:
file.substitute("hassVersion", old_version, new_version)
file.substitute("hash", old_sdist_hash, new_sdist_hash)
file.substitute("hash", old_git_hash, new_git_hash)
async def update_frontend(self, old_version: str, new_version: str) -> None:
old_hash = str(await Nix.eval("home-assistant.frontend.src.outputHash"))
new_hash = await Nurl.prefetch(
"https://pypi.org/project/home_assistant_frontend/",
new_version,
"-A", "format", "wheel",
"-A", "dist", "py3",
"-A", "python", "py3"
)
print(f"frontend: {old_hash} -> {new_hash}")
with File("pkgs/servers/home-assistant/frontend.nix") as file:
file.substitute("version", old_version, new_version)
file.substitute("hash", old_hash, new_hash)
async def update_components(self):
await run_async([
f"{ROOT}/pkgs/servers/home-assistant/parse-requirements.py"
])
async def main():
headers = {}
if token := os.environ.get("GITHUB_TOKEN", None):
headers.update({"GITHUB_TOKEN": token})
async with aiohttp.ClientSession(headers=headers) as client:
hass = HomeAssistant(client)
core_current = str(await Nix.eval("home-assistant.version"))
core_latest = await hass.get_latest_core_version()
if Version(core_latest) > Version(core_current):
print(f"New Home Assistant version {core_latest} is available")
await hass.update_core(str(core_current), str(core_latest))
frontend_current = str(await Nix.eval("home-assistant.frontend.version"))
frontend_latest = await hass.get_latest_frontend_version(str(core_latest))
if Version(frontend_latest) > Version(frontend_current):
await hass.update_frontend(str(frontend_current), str(frontend_latest))
await hass.update_components()
else:
print(f"Home Assistant {core_current} is still the latest version.")
# wait for async client sessions to close
# https://docs.aiohttp.org/en/stable/client_advanced.html#graceful-shutdown
await asyncio.sleep(0)
if __name__ == "__main__":
run_sync(["pyright", __file__])
run_sync(["ruff", "--ignore=E501", __file__])
run_sync(["isort", __file__])
asyncio.run(main())

View file

@ -1,42 +0,0 @@
#!/usr/bin/env nix-shell
#!nix-shell -p nix -p jq -p curl -p bash -p git -p nix-update -i bash
set -eux
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
cd "$DIR"
CURRENT_VERSION=$(nix-instantiate ../../.. --eval --strict -A home-assistant.version | tr -d '"')
TARGET_VERSION=$(curl https://api.github.com/repos/home-assistant/core/releases/latest | jq -r '.name')
MANIFEST=$(curl https://raw.githubusercontent.com/home-assistant/core/${TARGET_VERSION}/homeassistant/components/frontend/manifest.json)
FRONTEND_VERSION=$(echo $MANIFEST | jq -r '.requirements[] | select(startswith("home-assistant-frontend")) | sub(".*==(?<vers>.*)"; .vers)')
if [[ "$CURRENT_VERSION" == "$TARGET_VERSION" ]]; then
echo "home-assistant is up-to-date: ${CURRENT_VERSION}"
exit 0
fi
sed -i -e "s/version =.*/version = \"${TARGET_VERSION}\";/" \
component-packages.nix
sed -i -e "s/hassVersion =.*/hassVersion = \"${TARGET_VERSION}\";/" \
default.nix
(
# update the frontend before running parse-requirements, so it doesn't get shown as outdated
cd ../../..
nix-update --version "$FRONTEND_VERSION" home-assistant.python.pkgs.home-assistant-frontend
)
./parse-requirements.py
read
(
cd ../../..
nix-update --version "$TARGET_VERSION" --build home-assistant
)
#git add ./component-packages.nix ./default.nix ./frontend.nix
#git commit -m "home-assistant: ${CURRENT_VERSION} -> ${TARGET_VERSION}"