uboot: (firmwareOdroidC2/C4) don't invoke patch tool, use patches = [] instead
https://github.com/NixOS/nixpkgs/blob/master/pkgs/stdenv/generic/setup.sh#L948 this can do it nicely. Signed-off-by: Anton Arapov <anton@deadbeef.mx>
This commit is contained in:
commit
56de2bcd43
30691 changed files with 3076956 additions and 0 deletions
69
pkgs/servers/home-assistant/appdaemon.nix
Normal file
69
pkgs/servers/home-assistant/appdaemon.nix
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
{ lib
|
||||
, python3
|
||||
, fetchFromGitHub
|
||||
}:
|
||||
|
||||
python3.pkgs.buildPythonApplication rec {
|
||||
pname = "appdaemon";
|
||||
version = "4.0.8";
|
||||
disabled = python3.pythonOlder "3.6";
|
||||
|
||||
src = fetchFromGitHub {
|
||||
owner = "AppDaemon";
|
||||
repo = pname;
|
||||
rev = version;
|
||||
sha256 = "04a4qx0rbx2vpkzpibmwkpy7fawa6dbgqlrllryrl7dchbrf703q";
|
||||
};
|
||||
|
||||
# relax dependencies
|
||||
postPatch = ''
|
||||
substituteInPlace requirements.txt \
|
||||
--replace "deepdiff==5.2.3" "deepdiff" \
|
||||
--replace "pygments==2.8.1" "pygments"
|
||||
sed -i 's/==/>=/' requirements.txt
|
||||
'';
|
||||
|
||||
propagatedBuildInputs = with python3.pkgs; [
|
||||
aiodns
|
||||
aiohttp
|
||||
aiohttp-jinja2
|
||||
astral
|
||||
azure-keyvault-secrets
|
||||
azure-mgmt-compute
|
||||
azure-mgmt-resource
|
||||
azure-mgmt-storage
|
||||
azure-storage-blob
|
||||
bcrypt
|
||||
cchardet
|
||||
deepdiff
|
||||
feedparser
|
||||
iso8601
|
||||
jinja2
|
||||
paho-mqtt
|
||||
pid
|
||||
pygments
|
||||
python-dateutil
|
||||
python-engineio
|
||||
python-socketio
|
||||
pytz
|
||||
pyyaml
|
||||
requests
|
||||
sockjs
|
||||
uvloop
|
||||
voluptuous
|
||||
websocket-client
|
||||
yarl
|
||||
];
|
||||
|
||||
# no tests implemented
|
||||
checkPhase = ''
|
||||
$out/bin/appdaemon -v | grep -q "${version}"
|
||||
'';
|
||||
|
||||
meta = with lib; {
|
||||
description = "Sandboxed Python execution environment for writing automation apps for Home Assistant";
|
||||
homepage = "https://github.com/AppDaemon/appdaemon";
|
||||
license = licenses.mit;
|
||||
maintainers = teams.home-assistant.members;
|
||||
};
|
||||
}
|
||||
67
pkgs/servers/home-assistant/cli.nix
Normal file
67
pkgs/servers/home-assistant/cli.nix
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
{ lib
|
||||
, python3
|
||||
}:
|
||||
|
||||
let
|
||||
python = python3.override {
|
||||
packageOverrides = self: super: {
|
||||
click = super.click.overrideAttrs (oldAttrs: rec {
|
||||
version = "8.0.4";
|
||||
src = oldAttrs.src.override {
|
||||
inherit version;
|
||||
sha256 = "sha256-hFjXsSh8X7EoyQ4jOBz5nc3nS+r2x/9jhM6E1v4JCts=";
|
||||
};
|
||||
});
|
||||
};
|
||||
};
|
||||
in
|
||||
|
||||
python.pkgs.buildPythonApplication rec {
|
||||
pname = "homeassistant-cli";
|
||||
version = "0.9.4";
|
||||
|
||||
src = python3.pkgs.fetchPypi {
|
||||
inherit pname version;
|
||||
sha256 = "03kiyqpp3zf8rg30d12h4fapihh0rqwpv5p8jfxb3iq0chfmjx2f";
|
||||
};
|
||||
|
||||
postPatch = ''
|
||||
# Ignore pinned versions
|
||||
sed -i "s/'\(.*\)\(==\|>=\).*'/'\1'/g" setup.py
|
||||
'';
|
||||
|
||||
propagatedBuildInputs = with python.pkgs; [
|
||||
aiohttp
|
||||
click
|
||||
click-log
|
||||
dateparser
|
||||
jinja2
|
||||
jsonpath-ng
|
||||
netdisco
|
||||
regex
|
||||
requests
|
||||
ruamel-yaml
|
||||
tabulate
|
||||
];
|
||||
|
||||
# Completion needs to be ported to work with click > 8.0
|
||||
# https://github.com/home-assistant-ecosystem/home-assistant-cli/issues/367
|
||||
#postInstall = ''
|
||||
# mkdir -p "$out/share/bash-completion/completions" "$out/share/zsh/site-functions"
|
||||
# $out/bin/hass-cli completion bash > "$out/share/bash-completion/completions/hass-cli"
|
||||
# $out/bin/hass-cli completion zsh > "$out/share/zsh/site-functions/_hass-cli"
|
||||
#'';
|
||||
|
||||
checkInputs = with python.pkgs; [
|
||||
pytestCheckHook
|
||||
requests-mock
|
||||
];
|
||||
|
||||
meta = with lib; {
|
||||
description = "Command-line tool for Home Assistant";
|
||||
homepage = "https://github.com/home-assistant-ecosystem/home-assistant-cli";
|
||||
changelog = "https://github.com/home-assistant-ecosystem/home-assistant-cli/releases/tag/${version}";
|
||||
license = licenses.asl20;
|
||||
maintainers = teams.home-assistant.members;
|
||||
};
|
||||
}
|
||||
3856
pkgs/servers/home-assistant/component-packages.nix
Normal file
3856
pkgs/servers/home-assistant/component-packages.nix
Normal file
File diff suppressed because it is too large
Load diff
341
pkgs/servers/home-assistant/default.nix
Normal file
341
pkgs/servers/home-assistant/default.nix
Normal file
|
|
@ -0,0 +1,341 @@
|
|||
{ stdenv
|
||||
, lib
|
||||
, callPackage
|
||||
, fetchFromGitHub
|
||||
, fetchpatch
|
||||
, python3
|
||||
, substituteAll
|
||||
, ffmpeg
|
||||
, inetutils
|
||||
, nixosTests
|
||||
|
||||
# Look up dependencies of specified components in component-packages.nix
|
||||
, extraComponents ? [ ]
|
||||
|
||||
# Additional packages to add to propagatedBuildInputs
|
||||
, extraPackages ? ps: []
|
||||
|
||||
# Write out info about included extraComponents and extraPackages
|
||||
, writeText
|
||||
|
||||
# Override Python packages using
|
||||
# self: super: { pkg = super.pkg.overridePythonAttrs (oldAttrs: { ... }); }
|
||||
# Applied after defaultOverrides
|
||||
, packageOverrides ? self: super: {}
|
||||
|
||||
# Skip pip install of required packages on startup
|
||||
, skipPip ? true }:
|
||||
|
||||
let
|
||||
defaultOverrides = [
|
||||
# Override the version of some packages pinned in Home Assistant's setup.py and requirements_all.txt
|
||||
(mkOverride "python-slugify" "4.0.1" "sha256-aaUXdm4AwSaOW7/A0BCgqFCN4LGNMK1aH/NX+K5yQnA=")
|
||||
|
||||
# pytest-aiohttp>0.3.0 breaks home-assistant tests
|
||||
(self: super: {
|
||||
pytest-aiohttp = super.pytest-aiohttp.overridePythonAttrs (oldAttrs: rec {
|
||||
version = "0.3.0";
|
||||
src = oldAttrs.src.override {
|
||||
inherit version;
|
||||
hash = "sha256-ySmFQzljeXc3WDhwO2L+9jUoWYvAqdRRY566lfSqpE8=";
|
||||
};
|
||||
propagatedBuildInputs = with python3.pkgs; [ aiohttp pytest ];
|
||||
doCheck = false;
|
||||
patches = [];
|
||||
});
|
||||
aiohomekit = super.aiohomekit.overridePythonAttrs (oldAttrs: {
|
||||
doCheck = false; # requires aiohttp>=1.0.0
|
||||
});
|
||||
gcal-sync = super.gcal-sync.overridePythonAttrs (oldAttrs: {
|
||||
doCheck = false; # requires aiohttp>=1.0.0
|
||||
});
|
||||
hass-nabucasa = super.hass-nabucasa.overridePythonAttrs (oldAttrs: {
|
||||
doCheck = false; # requires aiohttp>=1.0.0
|
||||
});
|
||||
pydeconz = super.pydeconz.overridePythonAttrs (oldAttrs: {
|
||||
doCheck = false; # requires pytest-aiohttp>=1.0.0
|
||||
});
|
||||
pynws = super.pynws.overridePythonAttrs (oldAttrs: {
|
||||
doCheck = false; # requires pytest-aiohttp>=1.0.0
|
||||
});
|
||||
pytomorrowio = super.pytomorrowio.overridePythonAttrs (oldAttrs: {
|
||||
doCheck = false; # requires pytest-aiohttp>=1.0.0
|
||||
});
|
||||
rtsp-to-webrtc = super.rtsp-to-webrtc.overridePythonAttrs (oldAttrs: {
|
||||
doCheck = false; # requires pytest-aiohttp>=1.0.0
|
||||
});
|
||||
snitun = super.snitun.overridePythonAttrs (oldAttrs: {
|
||||
doCheck = false; # requires aiohttp>=1.0.0
|
||||
});
|
||||
zwave-js-server-python = super.zwave-js-server-python.overridePythonAttrs (oldAttrs: {
|
||||
doCheck = false; # requires aiohttp>=1.0.0
|
||||
});
|
||||
})
|
||||
|
||||
# Pinned due to API changes in pyruckus>0.12
|
||||
(self: super: {
|
||||
pyruckus = super.pyruckus.overridePythonAttrs (oldAttrs: rec {
|
||||
version = "0.12";
|
||||
src = fetchFromGitHub {
|
||||
owner = "gabe565";
|
||||
repo = "pyruckus";
|
||||
rev = version;
|
||||
sha256 = "0ykv6r6blbj3fg9fplk9i7xclkv5d93rwvx0fm5s8ms9f2s9ih8z";
|
||||
};
|
||||
});
|
||||
})
|
||||
|
||||
# Pinned due to API changes in 0.1.0
|
||||
(mkOverride "poolsense" "0.0.8" "sha256-17MHrYRmqkH+1QLtgq2d6zaRtqvb9ju9dvPt9gB2xCc=")
|
||||
|
||||
# Pinned due to API changes >0.3.5.3
|
||||
(self: super: {
|
||||
pyatag = super.pyatag.overridePythonAttrs (oldAttrs: rec {
|
||||
version = "0.3.5.3";
|
||||
src = fetchFromGitHub {
|
||||
owner = "MatsNl";
|
||||
repo = "pyatag";
|
||||
rev = version;
|
||||
sha256 = "00ly4injmgrj34p0lyx7cz2crgnfcijmzc0540gf7hpwha0marf6";
|
||||
};
|
||||
});
|
||||
})
|
||||
|
||||
# Pinned due to API changes in 0.4.0
|
||||
(self: super: {
|
||||
vilfo-api-client = super.vilfo-api-client.overridePythonAttrs (oldAttrs: rec {
|
||||
version = "0.3.3";
|
||||
src = fetchFromGitHub {
|
||||
owner = "ManneW";
|
||||
repo = "vilfo-api-client-python";
|
||||
rev = "v${version}";
|
||||
sha256 = "1gy5gpsg99rcm1cc3m30232za00r9i46sp74zpd12p3vzz1wyyqf";
|
||||
};
|
||||
});
|
||||
})
|
||||
|
||||
# Pinned due to API changes ~1.0
|
||||
(self: super: {
|
||||
vultr = super.vultr.overridePythonAttrs (oldAttrs: rec {
|
||||
version = "0.1.2";
|
||||
src = fetchFromGitHub {
|
||||
owner = "spry-group";
|
||||
repo = "python-vultr";
|
||||
rev = "v${version}";
|
||||
sha256 = "1qjvvr2v9gfnwskdl0ayazpcmiyw9zlgnijnhgq9mcri5gq9jw5h";
|
||||
};
|
||||
});
|
||||
})
|
||||
|
||||
# home-assistant-frontend does not exist in python3.pkgs
|
||||
(self: super: {
|
||||
home-assistant-frontend = self.callPackage ./frontend.nix { };
|
||||
})
|
||||
];
|
||||
|
||||
mkOverride = attrName: version: hash:
|
||||
self: super: {
|
||||
${attrName} = super.${attrName}.overridePythonAttrs (oldAttrs: {
|
||||
inherit version;
|
||||
src = oldAttrs.src.override {
|
||||
inherit version hash;
|
||||
};
|
||||
});
|
||||
};
|
||||
|
||||
python = python3.override {
|
||||
# Put packageOverrides at the start so they are applied after defaultOverrides
|
||||
packageOverrides = lib.foldr lib.composeExtensions (self: super: { }) ([ packageOverrides ] ++ defaultOverrides);
|
||||
};
|
||||
|
||||
componentPackages = import ./component-packages.nix;
|
||||
|
||||
availableComponents = builtins.attrNames componentPackages.components;
|
||||
|
||||
inherit (componentPackages) supportedComponentsWithTests;
|
||||
|
||||
getPackages = component: componentPackages.components.${component};
|
||||
|
||||
componentBuildInputs = lib.concatMap (component: getPackages component python.pkgs) extraComponents;
|
||||
|
||||
# Ensure that we are using a consistent package set
|
||||
extraBuildInputs = extraPackages python.pkgs;
|
||||
|
||||
# Create info about included packages and components
|
||||
extraComponentsFile = writeText "home-assistant-components" (lib.concatStringsSep "\n" extraComponents);
|
||||
extraPackagesFile = writeText "home-assistant-packages" (lib.concatMapStringsSep "\n" (pkg: pkg.pname) extraBuildInputs);
|
||||
|
||||
# Don't forget to run parse-requirements.py after updating
|
||||
hassVersion = "2022.6.3";
|
||||
|
||||
in python.pkgs.buildPythonApplication rec {
|
||||
pname = "homeassistant";
|
||||
version = assert (componentPackages.version == hassVersion); hassVersion;
|
||||
format = "pyproject";
|
||||
|
||||
# check REQUIRED_PYTHON_VER in homeassistant/const.py
|
||||
disabled = python.pythonOlder "3.9";
|
||||
|
||||
# don't try and fail to strip 6600+ python files, it takes minutes!
|
||||
dontStrip = true;
|
||||
|
||||
# PyPI tarball is missing tests/ directory
|
||||
src = fetchFromGitHub {
|
||||
owner = "home-assistant";
|
||||
repo = "core";
|
||||
rev = version;
|
||||
hash = "sha256-dYJbYrOwjJ2OO+gYT9UmCam+gNvSycFGUEeHBoGTqSM=";
|
||||
};
|
||||
|
||||
# leave this in, so users don't have to constantly update their downstream patch handling
|
||||
patches = [
|
||||
(substituteAll {
|
||||
src = ./patches/ffmpeg-path.patch;
|
||||
ffmpeg = "${lib.getBin ffmpeg}/bin/ffmpeg";
|
||||
})
|
||||
];
|
||||
|
||||
postPatch = let
|
||||
relaxedConstraints = [
|
||||
"attrs"
|
||||
"awesomeversion"
|
||||
"bcrypt"
|
||||
"httpx"
|
||||
"PyJWT"
|
||||
];
|
||||
in ''
|
||||
sed -r -i \
|
||||
${lib.concatStringsSep "\n" (map (package:
|
||||
''-e 's@${package}[<>=]+.*@${package}@g' \''
|
||||
) relaxedConstraints)}
|
||||
setup.cfg
|
||||
substituteInPlace tests/test_config.py --replace '"/usr"' '"/build/media"'
|
||||
'';
|
||||
|
||||
propagatedBuildInputs = with python.pkgs; [
|
||||
# Only packages required in setup.py
|
||||
aiohttp
|
||||
astral
|
||||
async-timeout
|
||||
atomicwrites
|
||||
attrs
|
||||
awesomeversion
|
||||
bcrypt
|
||||
certifi
|
||||
ciso8601
|
||||
cryptography
|
||||
httpx
|
||||
ifaddr
|
||||
jinja2
|
||||
pip
|
||||
pyjwt
|
||||
python-slugify
|
||||
pytz
|
||||
pyyaml
|
||||
requests
|
||||
ruamel-yaml
|
||||
voluptuous
|
||||
voluptuous-serialize
|
||||
yarl
|
||||
# Not in setup.py, but used in homeassistant/util/package.py
|
||||
setuptools
|
||||
# Not in setup.py, but uncounditionally imported via tests/conftest.py
|
||||
paho-mqtt
|
||||
] ++ componentBuildInputs ++ extraBuildInputs;
|
||||
|
||||
makeWrapperArgs = lib.optional skipPip "--add-flags --skip-pip";
|
||||
|
||||
# upstream only tests on Linux, so do we.
|
||||
doCheck = stdenv.isLinux;
|
||||
|
||||
checkInputs = with python.pkgs; [
|
||||
# test infrastructure (selectively from requirement_test.txt)
|
||||
freezegun
|
||||
pytest-aiohttp
|
||||
pytest-freezegun
|
||||
pytest-mock
|
||||
pytest-rerunfailures
|
||||
pytest-socket
|
||||
pytest-xdist
|
||||
pytestCheckHook
|
||||
requests-mock
|
||||
respx
|
||||
stdlib-list
|
||||
# required by tests/auth/mfa_modules
|
||||
pyotp
|
||||
] ++ lib.concatMap (component: getPackages component python.pkgs) [
|
||||
# some components are needed even if tests in tests/components are disabled
|
||||
"default_config"
|
||||
"hue"
|
||||
];
|
||||
|
||||
pytestFlagsArray = [
|
||||
# assign tests grouped by file to workers
|
||||
"--dist loadfile"
|
||||
# retry racy tests that end in "RuntimeError: Event loop is closed"
|
||||
"--reruns 3"
|
||||
"--only-rerun RuntimeError"
|
||||
# enable full variable printing on error
|
||||
"--showlocals"
|
||||
# helpers/test_system_info.py: AssertionError: assert 'Unknown' == 'Home Assistant Container'
|
||||
"--deselect tests/helpers/test_system_info.py::test_container_installationtype"
|
||||
# tests are located in tests/
|
||||
"tests"
|
||||
];
|
||||
|
||||
disabledTestPaths = [
|
||||
# we neither run nor distribute hassfest
|
||||
"tests/hassfest"
|
||||
# we don't care about code quality
|
||||
"tests/pylint"
|
||||
# don't bulk test all components
|
||||
"tests/components"
|
||||
# pyotp since v2.4.0 complains about the short mock keys, hass pins v2.3.0
|
||||
"tests/auth/mfa_modules/test_notify.py"
|
||||
];
|
||||
|
||||
disabledTests = [
|
||||
# AssertionError: assert 1 == 0
|
||||
"test_merge"
|
||||
# Tests are flaky
|
||||
"test_config_platform_valid"
|
||||
# Test requires pylint>=2.13.0
|
||||
"test_invalid_discovery_info"
|
||||
];
|
||||
|
||||
preCheck = ''
|
||||
export HOME="$TEMPDIR"
|
||||
|
||||
# the tests require the existance of a media dir
|
||||
mkdir /build/media
|
||||
|
||||
# put ping binary into PATH, e.g. for wake_on_lan tests
|
||||
export PATH=${inetutils}/bin:$PATH
|
||||
'';
|
||||
|
||||
postInstall = ''
|
||||
cp -v ${extraComponentsFile} $out/extra_components
|
||||
cp -v ${extraPackagesFile} $out/extra_packages
|
||||
'';
|
||||
|
||||
passthru = {
|
||||
inherit
|
||||
availableComponents
|
||||
extraComponents
|
||||
getPackages
|
||||
python
|
||||
supportedComponentsWithTests;
|
||||
tests = {
|
||||
nixos = nixosTests.home-assistant;
|
||||
components = callPackage ./tests.nix { };
|
||||
};
|
||||
};
|
||||
|
||||
meta = with lib; {
|
||||
homepage = "https://home-assistant.io/";
|
||||
description = "Open source home automation that puts local control and privacy first";
|
||||
license = licenses.asl20;
|
||||
maintainers = teams.home-assistant.members;
|
||||
platforms = platforms.linux;
|
||||
};
|
||||
}
|
||||
30
pkgs/servers/home-assistant/frontend.nix
Normal file
30
pkgs/servers/home-assistant/frontend.nix
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
{ lib, fetchPypi, buildPythonPackage }:
|
||||
|
||||
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 = "20220601.0";
|
||||
format = "wheel";
|
||||
|
||||
src = fetchPypi {
|
||||
inherit version format;
|
||||
pname = "home_assistant_frontend";
|
||||
dist = "py3";
|
||||
python = "py3";
|
||||
sha256 = "sha256-WGRKJq429fIxZQJzVK2xFqXUNrIYbCjr2zTSzpBlakI=";
|
||||
};
|
||||
|
||||
# there is nothing to strip in this package
|
||||
dontStrip = true;
|
||||
|
||||
# no Python tests implemented
|
||||
doCheck = false;
|
||||
|
||||
meta = with lib; {
|
||||
description = "Polymer frontend for Home Assistant";
|
||||
homepage = "https://github.com/home-assistant/home-assistant-polymer";
|
||||
license = licenses.asl20;
|
||||
maintainers = teams.home-assistant.members;
|
||||
};
|
||||
}
|
||||
271
pkgs/servers/home-assistant/parse-requirements.py
Executable file
271
pkgs/servers/home-assistant/parse-requirements.py
Executable file
|
|
@ -0,0 +1,271 @@
|
|||
#! /usr/bin/env nix-shell
|
||||
#! nix-shell -i python3 -p "python3.withPackages (ps: with ps; [ mypy attrs packaging rich ])
|
||||
#
|
||||
# This script downloads Home Assistant's source tarball.
|
||||
# Inside the homeassistant/components directory, each integration has an associated manifest.json,
|
||||
# specifying required packages and other integrations it depends on:
|
||||
#
|
||||
# {
|
||||
# "requirements": [ "package==1.2.3" ],
|
||||
# "dependencies": [ "component" ]
|
||||
# }
|
||||
#
|
||||
# By parsing the files, a dictionary mapping integrations to requirements and dependencies is created.
|
||||
# For all of these requirements and the dependencies' requirements,
|
||||
# nixpkgs' python3Packages are searched for appropriate names.
|
||||
# Then, a Nix attribute set mapping integration name to dependencies is created.
|
||||
|
||||
import json
|
||||
import os
|
||||
import pathlib
|
||||
import re
|
||||
import subprocess
|
||||
import sys
|
||||
import tarfile
|
||||
import tempfile
|
||||
from functools import reduce
|
||||
from io import BytesIO
|
||||
from typing import Dict, Optional, Set, Any
|
||||
from urllib.request import urlopen
|
||||
from packaging import version as Version
|
||||
from rich.console import Console
|
||||
from rich.table import Table
|
||||
|
||||
COMPONENT_PREFIX = "homeassistant.components"
|
||||
PKG_SET = "home-assistant.python.pkgs"
|
||||
|
||||
# If some requirements are matched by multiple or no Python packages, the
|
||||
# following can be used to choose the correct one
|
||||
PKG_PREFERENCES = {
|
||||
"ha-av": "av",
|
||||
"youtube_dl": "youtube-dl-light",
|
||||
"tensorflow": "tensorflow",
|
||||
"fiblary3": "fiblary3-fork", # https://github.com/home-assistant/core/issues/66466
|
||||
}
|
||||
|
||||
|
||||
def run_mypy() -> None:
|
||||
cmd = ["mypy", "--ignore-missing-imports", __file__]
|
||||
print(f"$ {' '.join(cmd)}")
|
||||
subprocess.run(cmd, check=True)
|
||||
|
||||
|
||||
def get_version():
|
||||
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)
|
||||
|
||||
|
||||
def parse_components(version: str = "master"):
|
||||
components = {}
|
||||
components_with_tests = []
|
||||
with tempfile.TemporaryDirectory() as tmp:
|
||||
with urlopen(
|
||||
f"https://github.com/home-assistant/home-assistant/archive/{version}.tar.gz"
|
||||
) as response:
|
||||
tarfile.open(fileobj=BytesIO(response.read())).extractall(tmp)
|
||||
# Use part of a script from the Home Assistant codebase
|
||||
core_path = os.path.join(tmp, f"core-{version}")
|
||||
|
||||
for entry in os.scandir(os.path.join(core_path, "tests/components")):
|
||||
if entry.is_dir():
|
||||
components_with_tests.append(entry.name)
|
||||
|
||||
sys.path.append(core_path)
|
||||
from script.hassfest.model import Integration
|
||||
integrations = Integration.load_dir(
|
||||
pathlib.Path(
|
||||
os.path.join(core_path, "homeassistant/components")
|
||||
)
|
||||
)
|
||||
for domain in sorted(integrations):
|
||||
integration = integrations[domain]
|
||||
if not integration.disabled:
|
||||
components[domain] = integration.manifest
|
||||
|
||||
return components, components_with_tests
|
||||
|
||||
|
||||
# Recursively get the requirements of a component and its dependencies
|
||||
def get_reqs(components: Dict[str, Dict[str, Any]], component: str, processed: Set[str]) -> Set[str]:
|
||||
requirements = set(components[component].get("requirements", []))
|
||||
deps = components[component].get("dependencies", [])
|
||||
deps.extend(components[component].get("after_dependencies", []))
|
||||
processed.add(component)
|
||||
for dependency in deps:
|
||||
if dependency not in processed:
|
||||
requirements.update(get_reqs(components, dependency, processed))
|
||||
return requirements
|
||||
|
||||
|
||||
def repository_root() -> str:
|
||||
return os.path.abspath(sys.argv[0] + "/../../../..")
|
||||
|
||||
|
||||
# For a package attribute and and an extra, check if the package exposes it via passthru.optional-dependencies
|
||||
def has_extra(package: str, extra: str):
|
||||
cmd = [
|
||||
"nix-instantiate",
|
||||
repository_root(),
|
||||
"-A",
|
||||
f"{package}.optional-dependencies.{extra}",
|
||||
]
|
||||
try:
|
||||
subprocess.run(
|
||||
cmd,
|
||||
check=True,
|
||||
stdout=subprocess.DEVNULL,
|
||||
stderr=subprocess.DEVNULL,
|
||||
)
|
||||
except subprocess.CalledProcessError:
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
def dump_packages() -> Dict[str, Dict[str, str]]:
|
||||
# Store a JSON dump of Nixpkgs' python3Packages
|
||||
output = subprocess.check_output(
|
||||
[
|
||||
"nix-env",
|
||||
"-f",
|
||||
repository_root(),
|
||||
"-qa",
|
||||
"-A",
|
||||
PKG_SET,
|
||||
"--arg", "config", "{ allowAliases = false; }",
|
||||
"--json",
|
||||
]
|
||||
)
|
||||
return json.loads(output)
|
||||
|
||||
|
||||
def name_to_attr_path(req: str, packages: Dict[str, Dict[str, str]]) -> Optional[str]:
|
||||
if req in PKG_PREFERENCES:
|
||||
return f"{PKG_SET}.{PKG_PREFERENCES[req]}"
|
||||
attr_paths = []
|
||||
names = [req]
|
||||
# E.g. python-mpd2 is actually called python3.6-mpd2
|
||||
# instead of python-3.6-python-mpd2 inside Nixpkgs
|
||||
if req.startswith("python-") or req.startswith("python_"):
|
||||
names.append(req[len("python-") :])
|
||||
for name in names:
|
||||
# treat "-" and "_" equally
|
||||
name = re.sub("[-_]", "[-_]", name)
|
||||
# python(minor).(major)-(pname)-(version or unstable-date)
|
||||
# we need the version qualifier, or we'll have multiple matches
|
||||
# (e.g. pyserial and pyserial-asyncio when looking for pyserial)
|
||||
pattern = re.compile(f"^python\\d\\.\\d-{name}-(?:\\d|unstable-.*)", re.I)
|
||||
for attr_path, package in packages.items():
|
||||
if pattern.match(package["name"]):
|
||||
attr_paths.append(attr_path)
|
||||
# Let's hope there's only one derivation with a matching name
|
||||
assert len(attr_paths) <= 1, f"{req} matches more than one derivation: {attr_paths}"
|
||||
if attr_paths:
|
||||
return attr_paths[0]
|
||||
else:
|
||||
return None
|
||||
|
||||
|
||||
def get_pkg_version(package: str, packages: Dict[str, Dict[str, str]]) -> Optional[str]:
|
||||
pkg = packages.get(f"{PKG_SET}.{package}", None)
|
||||
if not pkg:
|
||||
return None
|
||||
return pkg["version"]
|
||||
|
||||
|
||||
def main() -> None:
|
||||
packages = dump_packages()
|
||||
version = get_version()
|
||||
print("Generating component-packages.nix for version {}".format(version))
|
||||
components, components_with_tests = parse_components(version=version)
|
||||
build_inputs = {}
|
||||
outdated = {}
|
||||
for component in sorted(components.keys()):
|
||||
attr_paths = []
|
||||
extra_attrs = []
|
||||
missing_reqs = []
|
||||
reqs = sorted(get_reqs(components, component, set()))
|
||||
for req in reqs:
|
||||
# Some requirements are specified by url, e.g. https://example.org/foobar#xyz==1.0.0
|
||||
# Therefore, if there's a "#" in the line, only take the part after it
|
||||
req = req[req.find("#") + 1 :]
|
||||
name, required_version = req.split("==", maxsplit=1)
|
||||
# Split package name and extra requires
|
||||
extras = []
|
||||
if name.endswith("]"):
|
||||
extras = name[name.find("[")+1:name.find("]")].split(",")
|
||||
name = name[:name.find("[")]
|
||||
attr_path = name_to_attr_path(name, packages)
|
||||
if our_version := get_pkg_version(name, packages):
|
||||
if Version.parse(our_version) < Version.parse(required_version):
|
||||
outdated[name] = {
|
||||
'wanted': required_version,
|
||||
'current': our_version
|
||||
}
|
||||
if attr_path is not None:
|
||||
# Add attribute path without "python3Packages." prefix
|
||||
pname = attr_path[len(PKG_SET + "."):]
|
||||
attr_paths.append(pname)
|
||||
for extra in extras:
|
||||
# Check if package advertises extra requirements
|
||||
extra_attr = f"{pname}.optional-dependencies.{extra}"
|
||||
if has_extra(attr_path, extra):
|
||||
extra_attrs.append(extra_attr)
|
||||
else:
|
||||
missing_reqs.append(extra_attr)
|
||||
|
||||
else:
|
||||
missing_reqs.append(name)
|
||||
else:
|
||||
build_inputs[component] = (attr_paths, extra_attrs, missing_reqs)
|
||||
|
||||
with open(os.path.dirname(sys.argv[0]) + "/component-packages.nix", "w") as f:
|
||||
f.write("# Generated by parse-requirements.py\n")
|
||||
f.write("# Do not edit!\n\n")
|
||||
f.write("{\n")
|
||||
f.write(f' version = "{version}";\n')
|
||||
f.write(" components = {\n")
|
||||
for component, deps in build_inputs.items():
|
||||
available, extras, missing = deps
|
||||
f.write(f' "{component}" = ps: with ps; [')
|
||||
if available:
|
||||
f.write("\n " + "\n ".join(available))
|
||||
f.write("\n ]")
|
||||
if extras:
|
||||
f.write("\n ++ " + "\n ++ ".join(extras))
|
||||
f.write(";")
|
||||
if len(missing) > 0:
|
||||
f.write(f" # missing inputs: {' '.join(missing)}")
|
||||
f.write("\n")
|
||||
f.write(" };\n")
|
||||
f.write(" # components listed in tests/components for which all dependencies are packaged\n")
|
||||
f.write(" supportedComponentsWithTests = [\n")
|
||||
for component, deps in build_inputs.items():
|
||||
available, extras, missing = deps
|
||||
if len(missing) == 0 and component in components_with_tests:
|
||||
f.write(f' "{component}"' + "\n")
|
||||
f.write(" ];\n")
|
||||
f.write("}\n")
|
||||
|
||||
supported_components = reduce(lambda n, c: n + (build_inputs[c][2] == []),
|
||||
components.keys(), 0)
|
||||
total_components = len(components)
|
||||
print(f"{supported_components} / {total_components} components supported, "
|
||||
f"i.e. {supported_components / total_components:.2%}")
|
||||
|
||||
if outdated:
|
||||
table = Table(title="Outdated dependencies")
|
||||
table.add_column("Package")
|
||||
table.add_column("Current")
|
||||
table.add_column("Wanted")
|
||||
for package, version in sorted(outdated.items()):
|
||||
table.add_row(package, version['current'], version['wanted'])
|
||||
|
||||
console = Console()
|
||||
console.print(table)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
run_mypy()
|
||||
main()
|
||||
84
pkgs/servers/home-assistant/patches/ffmpeg-path.patch
Normal file
84
pkgs/servers/home-assistant/patches/ffmpeg-path.patch
Normal file
|
|
@ -0,0 +1,84 @@
|
|||
diff --git a/homeassistant/components/ffmpeg/__init__.py b/homeassistant/components/ffmpeg/__init__.py
|
||||
index 74c826f47d..91f359da2a 100644
|
||||
--- a/homeassistant/components/ffmpeg/__init__.py
|
||||
+++ b/homeassistant/components/ffmpeg/__init__.py
|
||||
@@ -40,7 +40,7 @@ CONF_FFMPEG_BIN = "ffmpeg_bin"
|
||||
CONF_EXTRA_ARGUMENTS = "extra_arguments"
|
||||
CONF_OUTPUT = "output"
|
||||
|
||||
-DEFAULT_BINARY = "ffmpeg"
|
||||
+DEFAULT_BINARY = "@ffmpeg@"
|
||||
|
||||
CONFIG_SCHEMA = vol.Schema(
|
||||
{
|
||||
diff --git a/tests/components/ffmpeg/test_init.py b/tests/components/ffmpeg/test_init.py
|
||||
index e1730ffdab..e9cd7934fd 100644
|
||||
--- a/tests/components/ffmpeg/test_init.py
|
||||
+++ b/tests/components/ffmpeg/test_init.py
|
||||
@@ -87,7 +87,7 @@ class TestFFmpegSetup:
|
||||
with assert_setup_component(1):
|
||||
setup_component(self.hass, ffmpeg.DOMAIN, {ffmpeg.DOMAIN: {}})
|
||||
|
||||
- assert self.hass.data[ffmpeg.DATA_FFMPEG].binary == "ffmpeg"
|
||||
+ assert self.hass.data[ffmpeg.DATA_FFMPEG].binary == "@ffmpeg@"
|
||||
|
||||
def test_setup_component_test_service(self):
|
||||
"""Set up ffmpeg component test services."""
|
||||
diff --git a/tests/components/ffmpeg/test_sensor.py b/tests/components/ffmpeg/test_sensor.py
|
||||
index a6c9c1f441..f13091da1a 100644
|
||||
--- a/tests/components/ffmpeg/test_sensor.py
|
||||
+++ b/tests/components/ffmpeg/test_sensor.py
|
||||
@@ -27,7 +27,7 @@ class TestFFmpegNoiseSetup:
|
||||
setup_component(self.hass, "binary_sensor", self.config)
|
||||
self.hass.block_till_done()
|
||||
|
||||
- assert self.hass.data["ffmpeg"].binary == "ffmpeg"
|
||||
+ assert self.hass.data["ffmpeg"].binary == "@ffmpeg@"
|
||||
assert self.hass.states.get("binary_sensor.ffmpeg_noise") is not None
|
||||
|
||||
@patch("haffmpeg.sensor.SensorNoise.open_sensor", return_value=mock_coro())
|
||||
@@ -37,7 +37,7 @@ class TestFFmpegNoiseSetup:
|
||||
setup_component(self.hass, "binary_sensor", self.config)
|
||||
self.hass.block_till_done()
|
||||
|
||||
- assert self.hass.data["ffmpeg"].binary == "ffmpeg"
|
||||
+ assert self.hass.data["ffmpeg"].binary == "@ffmpeg@"
|
||||
assert self.hass.states.get("binary_sensor.ffmpeg_noise") is not None
|
||||
|
||||
self.hass.start()
|
||||
@@ -53,7 +53,7 @@ class TestFFmpegNoiseSetup:
|
||||
setup_component(self.hass, "binary_sensor", self.config)
|
||||
self.hass.block_till_done()
|
||||
|
||||
- assert self.hass.data["ffmpeg"].binary == "ffmpeg"
|
||||
+ assert self.hass.data["ffmpeg"].binary == "@ffmpeg@"
|
||||
assert self.hass.states.get("binary_sensor.ffmpeg_noise") is not None
|
||||
|
||||
self.hass.start()
|
||||
@@ -89,7 +89,7 @@ class TestFFmpegMotionSetup:
|
||||
setup_component(self.hass, "binary_sensor", self.config)
|
||||
self.hass.block_till_done()
|
||||
|
||||
- assert self.hass.data["ffmpeg"].binary == "ffmpeg"
|
||||
+ assert self.hass.data["ffmpeg"].binary == "@ffmpeg@"
|
||||
assert self.hass.states.get("binary_sensor.ffmpeg_motion") is not None
|
||||
|
||||
@patch("haffmpeg.sensor.SensorMotion.open_sensor", return_value=mock_coro())
|
||||
@@ -99,7 +99,7 @@ class TestFFmpegMotionSetup:
|
||||
setup_component(self.hass, "binary_sensor", self.config)
|
||||
self.hass.block_till_done()
|
||||
|
||||
- assert self.hass.data["ffmpeg"].binary == "ffmpeg"
|
||||
+ assert self.hass.data["ffmpeg"].binary == "@ffmpeg@"
|
||||
assert self.hass.states.get("binary_sensor.ffmpeg_motion") is not None
|
||||
|
||||
self.hass.start()
|
||||
@@ -115,7 +115,7 @@ class TestFFmpegMotionSetup:
|
||||
setup_component(self.hass, "binary_sensor", self.config)
|
||||
self.hass.block_till_done()
|
||||
|
||||
- assert self.hass.data["ffmpeg"].binary == "ffmpeg"
|
||||
+ assert self.hass.data["ffmpeg"].binary == "@ffmpeg@"
|
||||
assert self.hass.states.get("binary_sensor.ffmpeg_motion") is not None
|
||||
|
||||
self.hass.start()
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
diff --git a/homeassistant/components/network/__init__.py b/homeassistant/components/network/__init__.py
|
||||
index b3ef88e7ab..b7a8471e1a 100644
|
||||
--- a/homeassistant/components/network/__init__.py
|
||||
+++ b/homeassistant/components/network/__init__.py
|
||||
@@ -30,7 +30,7 @@ async def async_get_source_ip(
|
||||
) -> str:
|
||||
"""Get the source ip for a target ip."""
|
||||
adapters = await async_get_adapters(hass)
|
||||
- all_ipv4s = []
|
||||
+ all_ipv4s = ["127.0.0.1"]
|
||||
for adapter in adapters:
|
||||
if adapter["enabled"] and (ipv4s := adapter["ipv4"]):
|
||||
all_ipv4s.extend([ipv4["address"] for ipv4 in ipv4s])
|
||||
85
pkgs/servers/home-assistant/tests.nix
Normal file
85
pkgs/servers/home-assistant/tests.nix
Normal file
|
|
@ -0,0 +1,85 @@
|
|||
{ lib
|
||||
, home-assistant
|
||||
}:
|
||||
|
||||
let
|
||||
# some components' tests have additional dependencies
|
||||
extraCheckInputs = with home-assistant.python.pkgs; {
|
||||
alexa = [ av ];
|
||||
camera = [ av ];
|
||||
cloud = [ mutagen ];
|
||||
config = [ pydispatcher ];
|
||||
generic = [ av ];
|
||||
google_translate = [ mutagen ];
|
||||
lovelace = [ PyChromecast ];
|
||||
nest = [ av ];
|
||||
onboarding = [ pymetno radios rpi-bad-power ];
|
||||
raspberry_pi = [ rpi-bad-power ];
|
||||
tomorrowio = [ pyclimacell ];
|
||||
version = [ aioaseko ];
|
||||
voicerss = [ mutagen ];
|
||||
yandextts = [ mutagen ];
|
||||
zha = [ pydeconz ];
|
||||
zwave_js = [ homeassistant-pyozw ];
|
||||
};
|
||||
|
||||
extraDisabledTestPaths = {
|
||||
tado = [
|
||||
# tado/test_{climate,water_heater}.py: Tries to connect to my.tado.com
|
||||
"tests/components/tado/test_climate.py"
|
||||
"tests/components/tado/test_water_heater.py"
|
||||
];
|
||||
};
|
||||
|
||||
extraDisabledTests = {
|
||||
roku = [
|
||||
# homeassistant.components.roku.media_player:media_player.py:428 Media type music is not supported with format None (mime: audio/x-matroska)
|
||||
"test_services_play_media_audio"
|
||||
];
|
||||
};
|
||||
|
||||
extraPytestFlagsArray = {
|
||||
asuswrt = [
|
||||
# asuswrt/test_config_flow.py: Sandbox network limitations, fails with unexpected error
|
||||
"--deselect tests/components/asuswrt/test_config_flow.py::test_on_connect_failed"
|
||||
];
|
||||
};
|
||||
in lib.listToAttrs (map (component: lib.nameValuePair component (
|
||||
home-assistant.overridePythonAttrs (old: {
|
||||
pname = "homeassistant-test-${component}";
|
||||
|
||||
dontBuild = true;
|
||||
dontInstall = true;
|
||||
|
||||
checkInputs = old.checkInputs
|
||||
++ home-assistant.getPackages component home-assistant.python.pkgs
|
||||
++ extraCheckInputs.${component} or [ ];
|
||||
|
||||
disabledTests = old.disabledTests ++ extraDisabledTests.${component} or [];
|
||||
disabledTestPaths = old.disabledTestPaths ++ extraDisabledTestPaths.${component} or [ ];
|
||||
|
||||
# components are more often racy than the core
|
||||
dontUsePytestXdist = true;
|
||||
|
||||
pytestFlagsArray = lib.remove "tests" old.pytestFlagsArray
|
||||
++ [ "--numprocesses=4" ]
|
||||
++ extraPytestFlagsArray.${component} or [ ]
|
||||
++ [ "tests/components/${component}" ];
|
||||
|
||||
preCheck = old.preCheck + lib.optionalString (builtins.elem component [ "emulated_hue" "songpal" "system_log" ]) ''
|
||||
patch -p1 < ${./patches/tests-mock-source-ip.patch}
|
||||
'';
|
||||
|
||||
meta = old.meta // {
|
||||
broken = lib.elem component [
|
||||
"bsblan"
|
||||
"dnsip"
|
||||
"efergy"
|
||||
"ssdp"
|
||||
"subaru"
|
||||
];
|
||||
# upstream only tests on Linux, so do we.
|
||||
platforms = lib.platforms.linux;
|
||||
};
|
||||
})
|
||||
)) home-assistant.supportedComponentsWithTests)
|
||||
42
pkgs/servers/home-assistant/update.sh
Executable file
42
pkgs/servers/home-assistant/update.sh
Executable file
|
|
@ -0,0 +1,42 @@
|
|||
#!/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}"
|
||||
Loading…
Add table
Add a link
Reference in a new issue