home-assistant: allow requirements parser to deal with extras
This commit is contained in:
parent
612a4ba51f
commit
ce697cdfa8
1 changed files with 47 additions and 9 deletions
|
@ -98,13 +98,37 @@ def get_reqs(components: Dict[str, Dict[str, Any]], component: str, processed: S
|
||||||
return requirements
|
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.extras-require
|
||||||
|
def has_extra(package: str, extra: str):
|
||||||
|
cmd = [
|
||||||
|
"nix-instantiate",
|
||||||
|
repository_root(),
|
||||||
|
"-A",
|
||||||
|
f"{package}.extras-require.{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]]:
|
def dump_packages() -> Dict[str, Dict[str, str]]:
|
||||||
# Store a JSON dump of Nixpkgs' python3Packages
|
# Store a JSON dump of Nixpkgs' python3Packages
|
||||||
output = subprocess.check_output(
|
output = subprocess.check_output(
|
||||||
[
|
[
|
||||||
"nix-env",
|
"nix-env",
|
||||||
"-f",
|
"-f",
|
||||||
os.path.dirname(sys.argv[0]) + "/../../..",
|
repository_root(),
|
||||||
"-qa",
|
"-qa",
|
||||||
"-A",
|
"-A",
|
||||||
PKG_SET,
|
PKG_SET,
|
||||||
|
@ -158,6 +182,7 @@ def main() -> None:
|
||||||
outdated = {}
|
outdated = {}
|
||||||
for component in sorted(components.keys()):
|
for component in sorted(components.keys()):
|
||||||
attr_paths = []
|
attr_paths = []
|
||||||
|
extra_attrs = []
|
||||||
missing_reqs = []
|
missing_reqs = []
|
||||||
reqs = sorted(get_reqs(components, component, set()))
|
reqs = sorted(get_reqs(components, component, set()))
|
||||||
for req in reqs:
|
for req in reqs:
|
||||||
|
@ -165,9 +190,10 @@ def main() -> None:
|
||||||
# Therefore, if there's a "#" in the line, only take the part after it
|
# Therefore, if there's a "#" in the line, only take the part after it
|
||||||
req = req[req.find("#") + 1 :]
|
req = req[req.find("#") + 1 :]
|
||||||
name, required_version = req.split("==", maxsplit=1)
|
name, required_version = req.split("==", maxsplit=1)
|
||||||
# Remove extra_require from name, e.g. samsungctl instead of
|
# Split package name and extra requires
|
||||||
# samsungctl[websocket]
|
extras = []
|
||||||
if name.endswith("]"):
|
if name.endswith("]"):
|
||||||
|
extras = name[name.find("[")+1:name.find("]")].split(",")
|
||||||
name = name[:name.find("[")]
|
name = name[:name.find("[")]
|
||||||
attr_path = name_to_attr_path(name, packages)
|
attr_path = name_to_attr_path(name, packages)
|
||||||
if our_version := get_pkg_version(name, packages):
|
if our_version := get_pkg_version(name, packages):
|
||||||
|
@ -178,11 +204,20 @@ def main() -> None:
|
||||||
}
|
}
|
||||||
if attr_path is not None:
|
if attr_path is not None:
|
||||||
# Add attribute path without "python3Packages." prefix
|
# Add attribute path without "python3Packages." prefix
|
||||||
attr_paths.append(attr_path[len(PKG_SET + ".") :])
|
pname = attr_path[len(PKG_SET + "."):]
|
||||||
|
attr_paths.append(pname)
|
||||||
|
for extra in extras:
|
||||||
|
# Check if package advertises extra requirements
|
||||||
|
extra_attr = f"{pname}.extras-require.{extra}"
|
||||||
|
if has_extra(attr_path, extra):
|
||||||
|
extra_attrs.append(extra_attr)
|
||||||
|
else:
|
||||||
|
missing_reqs.append(extra_attr)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
missing_reqs.append(name)
|
missing_reqs.append(name)
|
||||||
else:
|
else:
|
||||||
build_inputs[component] = (attr_paths, missing_reqs)
|
build_inputs[component] = (attr_paths, extra_attrs, missing_reqs)
|
||||||
|
|
||||||
with open(os.path.dirname(sys.argv[0]) + "/component-packages.nix", "w") as f:
|
with open(os.path.dirname(sys.argv[0]) + "/component-packages.nix", "w") as f:
|
||||||
f.write("# Generated by parse-requirements.py\n")
|
f.write("# Generated by parse-requirements.py\n")
|
||||||
|
@ -191,11 +226,14 @@ def main() -> None:
|
||||||
f.write(f' version = "{version}";\n')
|
f.write(f' version = "{version}";\n')
|
||||||
f.write(" components = {\n")
|
f.write(" components = {\n")
|
||||||
for component, deps in build_inputs.items():
|
for component, deps in build_inputs.items():
|
||||||
available, missing = deps
|
available, extras, missing = deps
|
||||||
f.write(f' "{component}" = ps: with ps; [')
|
f.write(f' "{component}" = ps: with ps; [')
|
||||||
if available:
|
if available:
|
||||||
f.write(" " + " ".join(available))
|
f.write("\n " + "\n ".join(available))
|
||||||
f.write(" ];")
|
f.write("\n ]")
|
||||||
|
if extras:
|
||||||
|
f.write("\n ++ " + "\n ++ ".join(extras))
|
||||||
|
f.write(";")
|
||||||
if len(missing) > 0:
|
if len(missing) > 0:
|
||||||
f.write(f" # missing inputs: {' '.join(missing)}")
|
f.write(f" # missing inputs: {' '.join(missing)}")
|
||||||
f.write("\n")
|
f.write("\n")
|
||||||
|
@ -203,7 +241,7 @@ def main() -> None:
|
||||||
f.write(" # components listed in tests/components for which all dependencies are packaged\n")
|
f.write(" # components listed in tests/components for which all dependencies are packaged\n")
|
||||||
f.write(" supportedComponentsWithTests = [\n")
|
f.write(" supportedComponentsWithTests = [\n")
|
||||||
for component, deps in build_inputs.items():
|
for component, deps in build_inputs.items():
|
||||||
available, missing = deps
|
available, extras, missing = deps
|
||||||
if len(missing) == 0 and component in components_with_tests:
|
if len(missing) == 0 and component in components_with_tests:
|
||||||
f.write(f' "{component}"' + "\n")
|
f.write(f' "{component}"' + "\n")
|
||||||
f.write(" ];\n")
|
f.write(" ];\n")
|
||||||
|
|
Loading…
Reference in a new issue