Importing multiple files from one directory, syntax

Good Afternoon,

I’m working on modularising my nixos configuration, but I’m running into some problems when performing my imports. I’d like to do something like this:

{config, pkgs, lib, ...}:
let 
  components = with .../components/general; [
    /base-config.nix
    /graphical.nix
    /networking.nix
    /sound.nix
    /bluetooth.nix
    /printing.nix
  ];
  programs = with .../programs; [
    /core.nix
    /cad.nix
    /devkit.nix
    /gaming.nix
  ];
  users = with .../users; [
    /$user.nix
  ];
in 

{
  imports = components ++ programs ++users;
}

All the file paths are correct, but the with statements are not working with file paths, so I assume I’m doing this the wrong way. Is there a correct way to do this other than typing out the full path for each file manually?

Thanks.

Add a default.nix to the folder an there import your modules.

configuration.nix

{
   imports = [ ./components ./programs ./users ];
}

./components/default.nix

{
  imports = [
    ./base-config.nix
    ./graphical.nix
    ./networking.nix
    ./sound.nix
    ./bluetooth.nix
    ./printing.nix
  ];
}

with keyword exposes an attr, ie:

let 
  programsPaths = { 
     core = ./programs/core.nix; 
     cad  = ./programs/cad.nix;
  };
  programs = with programsPaths; [ core cad ];
in
{
  imports = programs ++ compontens ++ users;
};

Would be easier just add paths without with

You could use let after equals and concat vars

let 
  components = let p = ../components/general; in [
    (p + "/base-config.nix")
    (p + "/graphical.nix")
  ];
in 
{
  imports = components ++ programs ++users;
}

I would prefer default.nix version :blush:

In your example has ... in nix parent dir is ../, current dir is ./.

There is also Haumea. to convert your dir structure in options. But to your case would be too complex.

2 Likes

I’m bumping this old thread as I don’t think that is has an entirely satisfactory solution.

I was looking to have any file I added to my modules folder automatically imported without needing to edit my config or the default.nix in the modules directory. That way I can just add a line to my configs enabling the modules I want on a given system without worrying about if they are imported or not.

My version requires enabling the experimental pipe-operators feature, you could write a longer version that doesn’t need it but its harder to understand and more verbose.

{ config, pkgs, lib, ... }:
let
  b = builtins;                                      # short alias for builtins
  module_files = ../modules/ |>                      # assign the result of the pipe to module_files, & pass ../modules/ to the function on the next line
    b.readDir |>                                     # returns an attribute set, names are files, values their type
    b.attrNames |>                                   # gets the names of the attribute set, the files
    b.filter (f: lib.strings.hasSuffix ".nix" f) |>  # keep only files that end in ".nix"
    b.map (e: ../modules/${e});                      # for each file prepend the path to the directory
in
{
  imports = module_files
}

I’m still not very good at nix lang so I couldn’t figure out how not to have to repeat the path to the modules folder in the first step and the map. Saving it to a variable didn’t seem to work - something about the way paths are handled being different from strings maybe IDK. If someone knows how to have the module path as a variable I’d appreciate it.

1 Like