summary refs log tree commit diff
diff options
context:
space:
mode:
authorMartin Weinelt <hexa@darmstadt.ccc.de>2022-02-01 03:10:31 +0100
committerMartin Weinelt <hexa@darmstadt.ccc.de>2023-11-10 22:00:36 +0100
commitf30192ae6ffb25cf74cfcfbc5beae3fa9b386bf4 (patch)
treed6d7568a0178d3e65793794abd52b40710f8fc99
parent047b9665f24c14e5dd0136a011e9d61afd582657 (diff)
downloadnixpkgs-f30192ae6ffb25cf74cfcfbc5beae3fa9b386bf4.tar
nixpkgs-f30192ae6ffb25cf74cfcfbc5beae3fa9b386bf4.tar.gz
nixpkgs-f30192ae6ffb25cf74cfcfbc5beae3fa9b386bf4.tar.bz2
nixpkgs-f30192ae6ffb25cf74cfcfbc5beae3fa9b386bf4.tar.lz
nixpkgs-f30192ae6ffb25cf74cfcfbc5beae3fa9b386bf4.tar.xz
nixpkgs-f30192ae6ffb25cf74cfcfbc5beae3fa9b386bf4.tar.zst
nixpkgs-f30192ae6ffb25cf74cfcfbc5beae3fa9b386bf4.zip
nixos/home-assistant: add customComponents support
Allows passing custom component packages, that get installed into
home-assistant's state directory.
Python depedencies, that are propagated from the custom component
get passed into `extraPackages`, so they are available to
home-assistant at runtime.

This is implemented in a way, that allows coexistence with custom
components not managed through the NixOS module.
-rw-r--r--nixos/modules/services/home-automation/home-assistant.nix40
-rw-r--r--pkgs/servers/home-assistant/custom-components/README.md57
2 files changed, 95 insertions, 2 deletions
diff --git a/nixos/modules/services/home-automation/home-assistant.nix b/nixos/modules/services/home-automation/home-assistant.nix
index dc5eb840121..54fd3e17292 100644
--- a/nixos/modules/services/home-automation/home-assistant.nix
+++ b/nixos/modules/services/home-automation/home-assistant.nix
@@ -63,7 +63,9 @@ let
     # Respect overrides that already exist in the passed package and
     # concat it with values passed via the module.
     extraComponents = oldArgs.extraComponents or [] ++ extraComponents;
-    extraPackages = ps: (oldArgs.extraPackages or (_: []) ps) ++ (cfg.extraPackages ps);
+    extraPackages = ps: (oldArgs.extraPackages or (_: []) ps)
+      ++ (cfg.extraPackages ps)
+      ++ (lib.concatMap (component: component.propagatedBuildInputs or []) cfg.customComponents);
   }));
 
   # Create a directory that holds all lovelace modules
@@ -152,6 +154,21 @@ in {
       '';
     };
 
+    customComponents = mkOption {
+      type = types.listOf types.package;
+      default = [];
+      example = literalExpression ''
+        with pkgs.home-assistant-custom-components; [
+          prometheus-sensor
+        ];
+      '';
+      description = lib.mdDoc ''
+        List of custom component packages to install.
+
+        Available components can be found below `pkgs.home-assistant-custom-components`.
+      '';
+    };
+
     customLovelaceModules = mkOption {
       type = types.listOf types.package;
       default = [];
@@ -449,10 +466,29 @@ in {
         '' else ''
           rm -f "${cfg.configDir}/www/nixos-lovelace-modules"
         '';
+        copyCustomComponents = ''
+          mkdir -p "${cfg.configDir}/custom_components"
+
+          # remove components symlinked in from below the /nix/store
+          components="$(find "${cfg.configDir}/custom_components" -maxdepth 1 -type l)"
+          for component in "$components"; do
+            if [[ "$(readlink "$component")" =~ ^${escapeShellArg builtins.storeDir} ]]; then
+              rm "$component"
+            fi
+          done
+
+          # recreate symlinks for desired components
+          declare -a components=(${escapeShellArgs cfg.customComponents})
+          for component in "''${components[@]}"; do
+            path="$(dirname $(find "$component" -name "manifest.json"))"
+            ln -fns "$path" "${cfg.configDir}/custom_components/"
+          done
+        '';
       in
         (optionalString (cfg.config != null) copyConfig) +
         (optionalString (cfg.lovelaceConfig != null) copyLovelaceConfig) +
-        copyCustomLovelaceModules
+        copyCustomLovelaceModules +
+        copyCustomComponents
       ;
       environment.PYTHONPATH = package.pythonPath;
       serviceConfig = let
diff --git a/pkgs/servers/home-assistant/custom-components/README.md b/pkgs/servers/home-assistant/custom-components/README.md
new file mode 100644
index 00000000000..a7244b25c17
--- /dev/null
+++ b/pkgs/servers/home-assistant/custom-components/README.md
@@ -0,0 +1,57 @@
+# Packaging guidelines
+
+## buildHomeAssistantComponent
+
+Custom components should be packaged using the
+ `buildHomeAssistantComponent` function, that is provided at top-level.
+It builds upon `buildPythonPackage` but uses a custom install and check
+phase.
+
+Python runtime dependencies can be directly consumed as unqualified
+function arguments. Pass them into `propagatedBuildInputs`, for them to
+be available to Home Assistant.
+
+Out-of-tree components need to use python packages from
+`home-assistant.python.pkgs` as to not introduce conflicting package
+versions into the Python environment.
+
+
+**Example Boilerplate:**
+
+```nix
+{ lib
+, buildHomeAssistantcomponent
+, fetchFromGitHub
+}:
+
+buildHomeAssistantComponent {
+  # pname, version
+
+  src = fetchFromGithub {
+    # owner, repo, rev, hash
+  };
+
+  propagatedBuildInputs = [
+    # python requirements, as specified in manifest.json
+  ];
+
+  meta = with lib; {
+    # changelog, description, homepage, license, maintainers
+  }
+}
+
+## Package name normalization
+
+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.
+
+## 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.
+
+There shouldn't be a need to disable this hook, but you can set
+`dontCheckManifest` to `true` in the derivation to achieve that.