{ lib, callPackage, }: # Turn a directory tree containing package files suitable for `callPackages` # into a matching nested attribute set of derivations # # For example, if the following files existed relative to the starting # directory: # # ```nix # # ./writeFoo.nix # { writeText }: # # { file }: # # writeText file "foo" # ``` # # ```nix # # ./bar/baz.nix # { writeFoo }: # # writeFoo { file = "example.txt"; } # ``` # # Then `pkgs.bar.baz` will be the same thing as # `pkgs.writeText "example.text" "foo"`. # # Tweaked from @Gabriella439's code. directory: let supported = basename: type: lib.hasSuffix ".nix" basename || type == "directory"; loop = dir: let toKeyVal = basename: type: let path = dir + "/${basename}"; in { name = builtins.replaceStrings [".nix"] [""] basename; value = if type == "regular" then callPackage path {} else if type == "directory" then let default = path + "/default.nix"; in if builtins.pathExists default then callPackage default {} else loop path else abort '' packagesFromDirectory: Unsupported file type File type: ${type} Path: ${path} ''; }; in builtins.listToAttrs (lib.mapAttrsToList toKeyVal (lib.filterAttrs supported (builtins.readDir dir))); in loop (./. + "/${directory}")