diff --git a/fauxmo.nix b/fauxmo.nix new file mode 100644 index 0000000..ce772b8 --- /dev/null +++ b/fauxmo.nix @@ -0,0 +1,18 @@ +{ + lib, + python3Packages, +}: let + inherit (python3Packages) buildPythonPackage setuptools-scm; +in + buildPythonPackage { + pname = "fauxmo"; + version = + builtins.head + (lib.findFirst (v: v != null) null + (builtins.map + (builtins.match "^__version__ = \"(.*)\"") + (lib.splitString "\n" (builtins.readFile ./src/fauxmo/__init__.py)))); + src = lib.cleanSource ./.; + format = "pyproject"; + propagatedBuildInputs = [setuptools-scm]; + } diff --git a/flake.nix b/flake.nix index f0827a5..448fe27 100644 --- a/flake.nix +++ b/flake.nix @@ -8,63 +8,88 @@ nixpkgs, }: let inherit (nixpkgs) lib; - pname = "fauxmo"; systems = ["aarch64-darwin" "x86_64-linux" "aarch64-linux"]; systemGen = attrs: builtins.foldl' (acc: system: lib.recursiveUpdate acc (attrs { inherit system; - pkgs = import nixpkgs {inherit system;}; + pkgs = import nixpkgs { + inherit system; + overlays = [self.outputs.overlays.default]; + }; })) {} systems; in - systemGen ({ + { + overlays.default = _: prev: rec { + python3 = let + packageOverrides = _: _: { + inherit (self.outputs.packages.${prev.system}) fauxmo; + }; + in + prev.python3.override { + inherit packageOverrides; + self = python3; + }; + }; + + # pythonPackagesExtensions = + # prev.pythonPackagesExtensions + # ++ [ + # ( + # _: _: { + # inherit (self.outputs.packages.${prev.system}) fauxmo; + # } + # ) + # ]; + # }; + } + // systemGen ({ pkgs, system, }: { formatter.${system} = pkgs.alejandra; packages.${system} = { - default = self.packages.${system}.${pname}; - ${pname} = pkgs.python311.withPackages (ps: + default = self.outputs.packages.${system}.pythonWithFauxmo; + pythonWithFauxmo = pkgs.python3.withPackages (ps: with ps; [ + self.outputs.packages.${system}.fauxmo uvloop - (buildPythonPackage { - inherit pname; - version = builtins.head (lib.findFirst (v: v != null) null (builtins.map (builtins.match "^__version__ = \"(.*)\"") (lib.splitString "\n" (builtins.readFile ./src/fauxmo/__init__.py)))); - src = ./.; - format = "pyproject"; - propagatedBuildInputs = [setuptools]; - }) ]); + fauxmo = pkgs.callPackage ./fauxmo.nix {}; + }; + + nixosModules = { + default = self.outputs.nixosModules.fauxmo; + fauxmo = import ./module.nix; }; apps.${system}.default = { type = "app"; - program = "${self.packages.${system}.${pname}}/bin/python -m ${pname}.cli"; + program = "${self.packages.${system}.default}/bin/python -m fauxmo.cli"; }; - devShells.${system}.default = let - py = pkgs.python311; - in - pkgs.mkShell { - # Provides GCC for building brotli - LD_LIBRARY_PATH = pkgs.lib.makeLibraryPath [pkgs.stdenv.cc.cc]; + devShells.${system}.default = pkgs.mkShell { + # Provides GCC for building brotli + LD_LIBRARY_PATH = pkgs.lib.makeLibraryPath [pkgs.stdenv.cc.cc]; + + venvDir = ".venv"; + postVenvCreation = '' + unset SOURCE_DATE_EPOCH + pip install -e .[dev,test] + ''; + postShellHook = '' + export SSL_CERT_FILE=$NIX_SSL_CERT_FILE; + ''; + buildInputs = with pkgs; [ + python38 + python39 + python310 + python311 + python311.pkgs.venvShellHook + ]; + }; - venvDir = ".venv"; - postVenvCreation = '' - unset SOURCE_DATE_EPOCH - pip install -e .[dev,test] - ''; - postShellHook = '' - export SSL_CERT_FILE=$NIX_SSL_CERT_FILE; - ''; - buildInputs = with pkgs; [ - py - py.pkgs.venvShellHook - python38 - python39 - python310 - ]; - }; + checks.${system}.integration = import ./integration_test.nix {inherit pkgs;}; }); } diff --git a/module.nix b/module.nix new file mode 100644 index 0000000..d11943a --- /dev/null +++ b/module.nix @@ -0,0 +1,86 @@ +{ + pkgs, + config, + lib, + ... +}: let + service_name = "fauxmo"; + cfg = config.services.${service_name}; +in + with lib; { + options.services.${service_name} = { + enable = mkEnableOption service_name; + user = mkOption { + type = types.str; + description = "User that fauxmo will run as"; + default = "fauxmo"; + }; + configFile = mkOption { + type = types.str; + description = "Path to config.json"; + }; + verbosity = mkOption { + type = types.enum [0 1 2 3]; + default = 0; + }; + + openFirewall = mkOption { + type = types.bool; + default = false; + description = lib.mdDoc "Whether to open TCP ports in the firewall"; + }; + tcpPortRange = mkOption { + description = "TCP range to open for fauxmo"; + type = with types; + submodule { + options = { + from = mkOption { + type = int; + }; + to = mkOption { + type = int; + }; + }; + }; + }; + }; + + config = mkIf cfg.enable { + networking.firewall = mkIf cfg.openFirewall { + allowedUDPPorts = [ + 1900 + ]; + allowedTCPPortRanges = [ + { + inherit (cfg.tcpPortRange) to from; + } + ]; + }; + systemd.services.${service_name} = let + pythonWithFauxmo = + pkgs.python3.withPackages + (ps: + with ps; [ + fauxmo + uvloop + ]); + after = ["network-online.target"]; + in { + description = service_name; + inherit after; + requires = after; + script = let + verbosity = + if cfg.verbosity == 0 + then "" + else "-" + lib.concatStrings (builtins.genList (_: "v") cfg.verbosity); + in ''${pythonWithFauxmo}/bin/python -m fauxmo.cli ${verbosity} -c "${cfg.configFile}"''; + serviceConfig = { + User = cfg.user; + Restart = "on-failure"; + RestartSec = 30; + }; + wantedBy = ["multi-user.target"]; + }; + }; + }