diff --git a/ioc/modules/common.nix b/ioc/modules/common.nix index a863e2a3..d98303da 100644 --- a/ioc/modules/common.nix +++ b/ioc/modules/common.nix @@ -27,7 +27,7 @@ with lib; { ~ The actual build of this distribution. ''; default = {}; - type = types.attrs; + type = with types; attrsOf package; }; epnix.pkgs = mkOption { diff --git a/ioc/modules/outputs.nix b/ioc/modules/outputs.nix index 34865ca6..41f56887 100644 --- a/ioc/modules/outputs.nix +++ b/ioc/modules/outputs.nix @@ -3,6 +3,7 @@ lib, pkgs, epnix, + epnixFunEval, ... }: with lib; let @@ -19,25 +20,42 @@ with lib; let toUpper ]; in { - options.epnix.buildConfig = { - attrs = mkOption { - description = "Extra attributes to pass to the derivation"; - type = types.attrs; - default = {}; - }; + options.epnix = { + buildConfig = { + attrs = mkOption { + description = "Extra attributes to pass to the derivation"; + type = types.attrs; + default = {}; + }; + + src = mkOption { + description = '' + The source code for the top. - src = mkOption { - description = '' - The source code for the top. + Defaults to the directory containing the `flake.nix` file. + ''; + type = types.path; + }; + }; - Defaults to the directory containing the `flake.nix` file. - ''; - type = types.path; + generatedOverlay = mkOption { + description = "A generated overlay which has your package inside `pkgs.epnix.support`."; + type = with types; functionTo (functionTo attrs); }; }; config.epnix.buildConfig.src = mkDefault config.epnix.inputs.self; + config.epnix.generatedOverlay = final: prev: let + newEval = final.callPackage epnixFunEval final; + in { + epnix = prev.epnix.extend (_final: prev: { + support = prev.support.extend (_final: _prev: { + "${config.epnix.meta.name}" = newEval.config.epnix.outputs.build; + }); + }); + }; + config.epnix.outputs.build = pkgs.mkEpicsPackage ({ pname = "epnix-${config.epnix.meta.name}"; inherit (config.epnix.meta) version; diff --git a/lib/default.nix b/lib/default.nix index 1edfd521..38ed4520 100644 --- a/lib/default.nix +++ b/lib/default.nix @@ -7,71 +7,13 @@ with lib; let self = { documentation = import ./documentation.nix args; + evaluation = import ./evaluation.nix args; formats = import ./formats.nix args; licenses = import ./licenses.nix args; maintainers = import ./maintainers/maintainer-list.nix; testing = import ./testing.nix; - evalEpnixModules = { - nixpkgsConfig, - epnixConfig, - }: let - nixpkgsConfigWithDefaults = - { - crossSystem = null; - config = {}; - } - // nixpkgsConfig; - eval = evalModules { - modules = [ - ({config, ...}: { - config._module.args = let - # Configure the available packages with e.g. cross compilation - # and overlays - finalPkgs = import inputs.nixpkgs { - inherit (nixpkgsConfigWithDefaults) system crossSystem config; - inherit (config.nixpkgs) overlays; - }; - in { - # See: https://github.com/NixOS/nixpkgs/pull/190358 - pkgs = finalPkgs.__splicedPackages; - - # Used when we want to apply the same config in checks - inherit epnixConfig; - }; - }) - - epnixConfig - inputs.self.nixosModules.ioc - - # nixpkgs and assertions are separate, in case we want to include - # this module in a NixOS configuration, where `nixpkgs` and - # `assertions` options are already defined - ../ioc/modules/nixpkgs.nix - ../ioc/modules/assertions.nix - ]; - }; - - # From Robotnix - # From nixpkgs/nixos/modules/system/activation/top-level.nix - failedAssertions = map (x: x.message) (lib.filter (x: !x.assertion) eval.config.assertions); - - config = - if failedAssertions != [] - then throw "\nFailed assertions:\n${lib.concatStringsSep "\n" (map (x: "- ${x}") failedAssertions)}" - else lib.showWarnings eval.config.warnings eval.config; - in { - inherit (eval) options; - inherit config; - - inherit (config.epnix) outputs; - }; - - mkEpnixBuild = cfg: - (self.evalEpnixModules cfg).config.epnix.outputs.build; - - mkEpnixDevShell = cfg: - (self.evalEpnixModules cfg).config.epnix.outputs.devShell; + inherit (self.evaluation) evalEpnixModules mkEpnixBuild mkEpnixDevShell; # Like lib.getName, but also supports paths getName = thing: diff --git a/lib/evaluation.nix b/lib/evaluation.nix new file mode 100644 index 00000000..8e9cc6dd --- /dev/null +++ b/lib/evaluation.nix @@ -0,0 +1,95 @@ +{ + inputs, + lib, + ... +}: let + evalEpnixModules' = { + epnixConfig, + epnixFunEval, + pkgs, + }: let + eval = lib.evalModules { + modules = [ + ({config, ...}: { + config._module.args = { + pkgs = pkgs config; + + # Used when we want to apply the same config in checks + inherit epnixConfig; + inherit epnixFunEval; + }; + }) + + epnixConfig + inputs.self.nixosModules.ioc + + # nixpkgs and assertions are separate, in case we want to include + # this module in a NixOS configuration, where `nixpkgs` and + # `assertions` options are already defined + ../ioc/modules/nixpkgs.nix + ../ioc/modules/assertions.nix + ]; + }; + + # From Robotnix + # From nixpkgs/nixos/modules/system/activation/top-level.nix + failedAssertions = map (x: x.message) (lib.filter (x: !x.assertion) eval.config.assertions); + + config = + if failedAssertions != [] + then throw "\nFailed assertions:\n${lib.concatStringsSep "\n" (map (x: "- ${x}") failedAssertions)}" + else lib.showWarnings eval.config.warnings eval.config; + in { + inherit (eval) options; + inherit config; + + inherit (config.epnix) outputs generatedOverlay; + }; + + self = { + evalEpnixModules = { + nixpkgsConfig, + epnixConfig, + }: let + nixpkgsConfigWithDefaults = + { + crossSystem = null; + config = {}; + } + // nixpkgsConfig; + + pkgs = config: + (import inputs.nixpkgs { + inherit (nixpkgsConfigWithDefaults) system crossSystem config; + inherit (config.nixpkgs) overlays; + }) + # See: https://github.com/NixOS/nixpkgs/pull/190358 + .__splicedPackages; + + # As a function, + # so that we can import the package without fixing the dependencies. + # + # This is needed because, + # if this package is an EPICS support module, + # it needs to *not* depend on a specific version of epics-base. + # + # It needs to use the same version of epics-base + # that is going to be used by the final IOC. + epnixFunEval = pkgs: + evalEpnixModules' { + inherit epnixConfig epnixFunEval; + pkgs = config: pkgs; + }; + + fixedEval = evalEpnixModules' {inherit epnixConfig epnixFunEval pkgs;}; + in + fixedEval; + + mkEpnixBuild = cfg: + (self.evalEpnixModules cfg).config.epnix.outputs.build; + + mkEpnixDevShell = cfg: + (self.evalEpnixModules cfg).config.epnix.outputs.devShell; + }; +in + self diff --git a/templates/top/flake.nix b/templates/top/flake.nix index a1cb68d4..3be88393 100644 --- a/templates/top/flake.nix +++ b/templates/top/flake.nix @@ -4,6 +4,14 @@ inputs.flake-utils.url = "github:numtide/flake-utils"; inputs.epnix.url = "github:epics-extensions/epnix"; + # If you have a support module as a separate EPNix repository, + # add it as an input here: + # --- + #inputs.mySupportModule = { + # url = "git+ssh://git@my-server.org/me/exampleApp.git"; + # inputs.epnix.follows = "epnix"; + #}; + # If you have an "App" as a separate repository, # add it as an input here: # --- @@ -18,10 +26,15 @@ epnix, ... } @ inputs: let - myEpnixDistribution = {pkgs, ...}: { + myEpnixConfig = {pkgs, ...}: { # Set your EPNix options here # --- + # If you have a support module as a separate EPNix repository, + # uncomment this line to make the package available: + # --- + #overlays = [inputs.mySupportModule.overlays.default]; + epnix = { inherit inputs; @@ -33,9 +46,9 @@ # --- #epics-base.releaseBranch = "3"; # Defaults to "7" - # Add one of the supported modules here: + # Add your support modules here: # --- - #support.modules = with pkgs.epnix.support; [ StreamDevice ]; + #support.modules = with pkgs.epnix.support; [ StreamDevice mySupportModule ]; # If you have an "App" as a separate repository, # add it here: @@ -69,7 +82,7 @@ # environment can be built on your machine. flake-utils.lib.eachSystem ["x86_64-linux"] (system: with epnix.lib; let - result = evalEpnixModules { + epnixDistribution = evalEpnixModules { nixpkgsConfig = { # This specifies the build architecture inherit system; @@ -81,17 +94,23 @@ # --- #crossSystem = epnix.inputs.nixpkgs.lib.systems.examples.armv7l-hf-multiplatform; }; - epnixConfig = myEpnixDistribution; + epnixConfig = myEpnixConfig; }; in { packages = - result.outputs + epnixDistribution.outputs // { default = self.packages.${system}.build; }; + inherit epnixDistribution; + devShells.default = self.packages.${system}.devShell; - checks = result.config.epnix.checks.derivations; - }); + checks = epnixDistribution.config.epnix.checks.derivations; + }) + // { + overlays.default = final: prev: + self.epnixDistribution.x86_64-linux.generatedOverlay final prev; + }; }