Unverified Commit 01616e53 authored by Martin Weinelt's avatar Martin Weinelt
Browse files

buildHomeAssistantComponent: migrate from pname to owner/domain

Also make the attribute name to match the domain name.

This is more in line with the home-assistant custom component ecosystem
and allows additional validation between the derivation and the manifest.

Also, at a later time, this will enable us to check for domain conflicts
at eval time.
parent 8c87a98c
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -43,7 +43,7 @@ in {

      # test loading custom components
      customComponents = with pkgs.home-assistant-custom-components; [
        prometheus-sensor
        prometheus_sensor
      ];

      # test loading lovelace modules
+26 −12
Original line number Diff line number Diff line
#!/usr/bin/env python3

import json
import importlib_metadata
import os
import sys

import importlib_metadata
from packaging.requirements import Requirement


def error(msg: str) -> None:
    print(f"  - {msg}", file=sys.stderr)
    return False


def check_requirement(req: str):
    # https://packaging.pypa.io/en/stable/requirements.html
    requirement = Requirement(req)
    try:
        version = importlib_metadata.distribution(requirement.name).version
    except importlib_metadata.PackageNotFoundError:
        print(f"  - Dependency {requirement.name} is missing", file=sys.stderr)
        return False
        return error(f"{requirement.name}{requirement.specifier} not present")

    # https://packaging.pypa.io/en/stable/specifiers.html
    if not version in requirement.specifier:
        print(
            f"  - {requirement.name}{requirement.specifier} expected, but got {version}",
            file=sys.stderr,
    if version not in requirement.specifier:
        return error(
            f"{requirement.name}{requirement.specifier} expected, but got {version}"
        )
        return False

    return True

@@ -30,12 +33,23 @@ def check_requirement(req: str):
def check_manifest(manifest_file: str):
    with open(manifest_file) as fd:
        manifest = json.load(fd)
    if "requirements" in manifest:

    ok = True

    derivation_domain = os.environ.get("domain")
    manifest_domain = manifest["domain"]
    if derivation_domain != manifest_domain:
        ok = False
        error(
            f"Derivation attribute domain ({derivation_domain}) must match manifest domain ({manifest_domain})"
        )

    if "requirements" in manifest:
        for requirement in manifest["requirements"]:
            ok &= check_requirement(requirement)

    if not ok:
            print("Manifest requirements are not met", file=sys.stderr)
        error("Manifest check failed.")
        sys.exit(1)


+3 −1
Original line number Diff line number Diff line
@@ -3,7 +3,8 @@
, makeSetupHook
}:

{ pname
{ owner
, domain
, version
, format ? "other"
, ...
@@ -17,6 +18,7 @@ let
in
home-assistant.python.pkgs.buildPythonPackage (
  {
    pname = "${owner}/${domain}";
    inherit format;

    installPhase = ''
+23 −7
Original line number Diff line number Diff line
@@ -25,7 +25,7 @@ versions into the Python environment.
}:

buildHomeAssistantComponent {
  # pname, version
  # owner, domain, version

  src = fetchFromGithub {
    # owner, repo, rev, hash
@@ -40,18 +40,34 @@ buildHomeAssistantComponent {
  }
}

## Package name normalization
## Package attribute

Apply the same normalization rules as defined for python packages in
[PEP503](https://peps.python.org/pep-0503/#normalized-names).
The name should be lowercased and dots, underlines or multiple
dashes should all be replaced by a single dash.
The attribute name must reflect the domain as seen in the
`manifest.json`, which in turn will match the python module name below
in the `custom_components/` directory.

**Example:**

The project [mweinelt/ha-prometheus-sensor](https://github.com/mweinelt/ha-prometheus-sensor/blob/1.0.0/custom_components/prometheus_sensor/manifest.json#L2)
would receive the attribute name `"prometheus_sensor"`, because both
domain in the `manifest.json` as well as the module name are
`prometheus_sensor`.

## Package name

The `pname` attribute is a composition of both `owner` and `domain`.

Don't set `pname`, set `owner and `domain` instead.

Exposing the `domain` attribute separately allows checking for
conflicting components at eval time.

## Manifest check

The `buildHomeAssistantComponent` builder uses a hook to check whether
the dependencies specified in the `manifest.json` are present and
inside the specified version range.
inside the specified version range. It also makes sure derivation
and manifest agree about the domain name.

There shouldn't be a need to disable this hook, but you can set
`dontCheckManifest` to `true` in the derivation to achieve that.
+1 −1
Original line number Diff line number Diff line
@@ -2,5 +2,5 @@
}:

{
  prometheus-sensor = callPackage ./prometheus-sensor {};
  prometheus_sensor = callPackage ./prometheus_sensor {};
}
Loading