flake-parts icon indicating copy to clipboard operation
flake-parts copied to clipboard

No access to flake inputs within a perSystem module

Open DavHau opened this issue 3 years ago • 4 comments

Similar to https://github.com/hercules-ci/flake-parts/issues/81.

Trying to add inputs to the perSystem args, triggers this error:

error: `inputs` (without `'`) is not a `perSystem` module argument, but a
       module argument of the top level config.

       The following is an example usage of `inputs`. Note that its binding
       is in the `top` parameter list, which is declared by the top level module
       rather than the `perSystem` module.

         top@{ config, lib, inputs, ... }: {
           perSystem = { config, inputs', ... }: {
             # in scope here:
             #  - inputs
             #  - inputs'
             #  - config (of perSystem)
             #  - top.config (note the `top@` pattern)
           };
         }

The statements about the scope only hold true as long as all code is defined inside a single flake.nix file. The lexical scope breaks as soon as the code is split into modules.

For example given the following flake.nix:

{
  inputs = {
    flake-parts.url = "github:hercules-ci/flake-parts";
    poetry2nix.url = "poetry2nix";
  };

  outputs = inputs@{ flake-parts, ... }:
    flake-parts.lib.mkFlake { inherit inputs; } {
      systems = [
        "x86_64-linux"
      ];
      perSystem = { config, pkgs, ... }: {
        imports = [./my-package.nix];
      };
    };
}

and my-package.nix:

# flake-parts module for the tesh package
{config, pkgs, inputs, self, ...}: let
  poetry2nix = import inputs.poetry2nix {inherit pkgs;};
in {
  packages.tesh = poetry2nix.mkPythonPplication {
    projectDir = self;
  };
}

This breaks because inputs is not allowed as a function argument. This means it is not possible to access some inputs lib or similar things inside a perSystem module.

DavHau avatar Jan 06 '23 08:01 DavHau

The idea behind this restriction is to make sure that all flake-parts modules are in one, compatible form. This convention avoids weird errors that would arise when importing a perSystem-level module into the top level or vice versa.

  • https://github.com/NixOS/nixpkgs/pull/197547 would help, but only in cases where the module has its "class" set; usually not by the author, but possibly by flake-parts itself, via flake.flakeModules or similar.

The statements about the scope only hold true as long as all code is defined inside a single flake.nix file. The lexical scope breaks as soon as the code is split into modules.

This should work if you define the module as a top-level module. The top-level module provides the lexical scope with these variables, as suggested in the error message.

roberth avatar Jan 06 '23 11:01 roberth

This decision could be reverted when we have

  • [ ] error messages for bad imports: https://github.com/NixOS/nixpkgs/pull/197547
  • [ ] deferredModule options that tag modules with their class

roberth avatar Mar 31 '23 09:03 roberth

I think the top-level module should always be a flake module, then it can define nested nixosModules/flakeModules. For example:

  • https://github.com/Preemo-Inc/nix-ml-ops/blob/main/nixos-modules/nix-ld.nix
  • https://github.com/Preemo-Inc/nix-ml-ops/blob/main/flake-modules/options-document.nix

When defining a nested flakeModules, the top level inputs are from the flake that defines the module, and the nested inputs are from the flake that use the module.

Atry avatar Nov 16 '23 21:11 Atry

I just had the same issue, I wanted to access my util flake from a perSystem module. A workaround is adding this to the imports where the module gets imported:

({...}: {
  _module.args.origInputs = inputs;
})

I could then just use origInputs.<flake>

TECHNOFAB11 avatar Jan 26 '24 16:01 TECHNOFAB11