lib.packagesFromDirectoryRecursive: init
Co-authored-by: Gabriella Gonzalez <GenuineGabriella@gmail.com>
This commit is contained in:
parent
7cb7b7f98d
commit
090b929b8a
14 changed files with 205 additions and 1 deletions
|
@ -120,7 +120,8 @@ let
|
|||
inherit (self.meta) addMetaAttrs dontDistribute setName updateName
|
||||
appendToName mapDerivationAttrset setPrio lowPrio lowPrioSet hiPrio
|
||||
hiPrioSet getLicenseFromSpdxId getExe getExe';
|
||||
inherit (self.filesystem) pathType pathIsDirectory pathIsRegularFile;
|
||||
inherit (self.filesystem) pathType pathIsDirectory pathIsRegularFile
|
||||
packagesFromDirectoryRecursive;
|
||||
inherit (self.sources) cleanSourceFilter
|
||||
cleanSource sourceByRegex sourceFilesBySuffices
|
||||
commitIdFromGitRepo cleanSourceWith pathHasContext
|
||||
|
|
|
@ -9,11 +9,22 @@ let
|
|||
inherit (builtins)
|
||||
readDir
|
||||
pathExists
|
||||
toString
|
||||
;
|
||||
|
||||
inherit (lib.attrsets)
|
||||
mapAttrs'
|
||||
filterAttrs
|
||||
;
|
||||
|
||||
inherit (lib.filesystem)
|
||||
pathType
|
||||
;
|
||||
|
||||
inherit (lib.strings)
|
||||
hasSuffix
|
||||
removeSuffix
|
||||
;
|
||||
in
|
||||
|
||||
{
|
||||
|
@ -154,4 +165,147 @@ in
|
|||
dir + "/${name}"
|
||||
) (builtins.readDir dir));
|
||||
|
||||
/*
|
||||
Transform a directory tree containing package files suitable for
|
||||
`callPackage` into a matching nested attribute set of derivations.
|
||||
|
||||
For a directory tree like this:
|
||||
|
||||
```
|
||||
my-packages
|
||||
├── a.nix
|
||||
├── b.nix
|
||||
├── c
|
||||
│ ├── my-extra-feature.patch
|
||||
│ ├── package.nix
|
||||
│ └── support-definitions.nix
|
||||
└── my-namespace
|
||||
├── d.nix
|
||||
├── e.nix
|
||||
└── f
|
||||
└── package.nix
|
||||
```
|
||||
|
||||
`packagesFromDirectoryRecursive` will produce an attribute set like this:
|
||||
|
||||
```nix
|
||||
# packagesFromDirectoryRecursive {
|
||||
# callPackage = pkgs.callPackage;
|
||||
# directory = ./my-packages;
|
||||
# }
|
||||
{
|
||||
a = pkgs.callPackage ./my-packages/a.nix { };
|
||||
b = pkgs.callPackage ./my-packages/b.nix { };
|
||||
c = pkgs.callPackage ./my-packages/c/package.nix { };
|
||||
my-namespace = {
|
||||
d = pkgs.callPackage ./my-packages/my-namespace/d.nix { };
|
||||
e = pkgs.callPackage ./my-packages/my-namespace/e.nix { };
|
||||
f = pkgs.callPackage ./my-packages/my-namespace/f/package.nix { };
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
In particular:
|
||||
- If the input directory contains a `package.nix` file, then
|
||||
`callPackage <directory>/package.nix { }` is returned.
|
||||
- Otherwise, the input directory's contents are listed and transformed into
|
||||
an attribute set.
|
||||
- If a file name has the `.nix` extension, it is turned into attribute
|
||||
where:
|
||||
- The attribute name is the file name without the `.nix` extension
|
||||
- The attribute value is `callPackage <file path> { }`
|
||||
- Other files are ignored.
|
||||
- Directories are turned into an attribute where:
|
||||
- The attribute name is the name of the directory
|
||||
- The attribute value is the result of calling
|
||||
`packagesFromDirectoryRecursive { ... }` on the directory.
|
||||
|
||||
As a result, directories with no `.nix` files (including empty
|
||||
directories) will be transformed into empty attribute sets.
|
||||
|
||||
Example:
|
||||
packagesFromDirectoryRecursive {
|
||||
inherit (pkgs) callPackage;
|
||||
directory = ./my-packages;
|
||||
}
|
||||
=> { ... }
|
||||
|
||||
lib.makeScope pkgs.newScope (
|
||||
self: packagesFromDirectoryRecursive {
|
||||
callPackage = self.callPackage;
|
||||
directory = ./my-packages;
|
||||
}
|
||||
)
|
||||
=> { ... }
|
||||
|
||||
Type:
|
||||
packagesFromDirectoryRecursive :: AttrSet -> AttrSet
|
||||
*/
|
||||
packagesFromDirectoryRecursive =
|
||||
# Options.
|
||||
{
|
||||
/*
|
||||
`pkgs.callPackage`
|
||||
|
||||
Type:
|
||||
Path -> AttrSet -> a
|
||||
*/
|
||||
callPackage,
|
||||
/*
|
||||
The directory to read package files from
|
||||
|
||||
Type:
|
||||
Path
|
||||
*/
|
||||
directory,
|
||||
...
|
||||
}:
|
||||
let
|
||||
# Determine if a directory entry from `readDir` indicates a package or
|
||||
# directory of packages.
|
||||
directoryEntryIsPackage = basename: type:
|
||||
type == "directory" || hasSuffix ".nix" basename;
|
||||
|
||||
# List directory entries that indicate packages in the given `path`.
|
||||
packageDirectoryEntries = path:
|
||||
filterAttrs directoryEntryIsPackage (readDir path);
|
||||
|
||||
# Transform a directory entry (a `basename` and `type` pair) into a
|
||||
# package.
|
||||
directoryEntryToAttrPair = subdirectory: basename: type:
|
||||
let
|
||||
path = subdirectory + "/${basename}";
|
||||
in
|
||||
if type == "regular"
|
||||
then
|
||||
{
|
||||
name = removeSuffix ".nix" basename;
|
||||
value = callPackage path { };
|
||||
}
|
||||
else
|
||||
if type == "directory"
|
||||
then
|
||||
{
|
||||
name = basename;
|
||||
value = packagesFromDirectory path;
|
||||
}
|
||||
else
|
||||
throw
|
||||
''
|
||||
lib.filesystem.packagesFromDirectoryRecursive: Unsupported file type ${type} at path ${toString subdirectory}
|
||||
'';
|
||||
|
||||
# Transform a directory into a package (if there's a `package.nix`) or
|
||||
# set of packages (otherwise).
|
||||
packagesFromDirectory = path:
|
||||
let
|
||||
defaultPackagePath = path + "/package.nix";
|
||||
in
|
||||
if pathExists defaultPackagePath
|
||||
then callPackage defaultPackagePath { }
|
||||
else mapAttrs'
|
||||
(directoryEntryToAttrPair path)
|
||||
(packageDirectoryEntries path);
|
||||
in
|
||||
packagesFromDirectory directory;
|
||||
}
|
||||
|
|
|
@ -1988,4 +1988,37 @@ runTests {
|
|||
expr = meta.platformMatch { } "x86_64-linux";
|
||||
expected = false;
|
||||
};
|
||||
|
||||
testPackagesFromDirectoryRecursive = {
|
||||
expr = packagesFromDirectoryRecursive {
|
||||
callPackage = path: overrides: import path overrides;
|
||||
directory = ./packages-from-directory;
|
||||
};
|
||||
expected = {
|
||||
a = "a";
|
||||
b = "b";
|
||||
# Note: Other files/directories in `./test-data/c/` are ignored and can be
|
||||
# used by `package.nix`.
|
||||
c = "c";
|
||||
my-namespace = {
|
||||
d = "d";
|
||||
e = "e";
|
||||
f = "f";
|
||||
my-sub-namespace = {
|
||||
g = "g";
|
||||
h = "h";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
# Check that `packagesFromDirectoryRecursive` can process a directory with a
|
||||
# top-level `package.nix` file into a single package.
|
||||
testPackagesFromDirectoryRecursiveTopLevelPackageNix = {
|
||||
expr = packagesFromDirectoryRecursive {
|
||||
callPackage = path: overrides: import path overrides;
|
||||
directory = ./packages-from-directory/c;
|
||||
};
|
||||
expected = "c";
|
||||
};
|
||||
}
|
||||
|
|
2
lib/tests/packages-from-directory/a.nix
Normal file
2
lib/tests/packages-from-directory/a.nix
Normal file
|
@ -0,0 +1,2 @@
|
|||
{ }:
|
||||
"a"
|
2
lib/tests/packages-from-directory/b.nix
Normal file
2
lib/tests/packages-from-directory/b.nix
Normal file
|
@ -0,0 +1,2 @@
|
|||
{ }:
|
||||
"b"
|
2
lib/tests/packages-from-directory/c/package.nix
Normal file
2
lib/tests/packages-from-directory/c/package.nix
Normal file
|
@ -0,0 +1,2 @@
|
|||
{ }:
|
||||
"c"
|
2
lib/tests/packages-from-directory/my-namespace/d.nix
Normal file
2
lib/tests/packages-from-directory/my-namespace/d.nix
Normal file
|
@ -0,0 +1,2 @@
|
|||
{ }:
|
||||
"d"
|
2
lib/tests/packages-from-directory/my-namespace/e.nix
Normal file
2
lib/tests/packages-from-directory/my-namespace/e.nix
Normal file
|
@ -0,0 +1,2 @@
|
|||
{ }:
|
||||
"e"
|
|
@ -0,0 +1,2 @@
|
|||
{ }:
|
||||
"f"
|
|
@ -0,0 +1,2 @@
|
|||
{ }:
|
||||
"g"
|
|
@ -0,0 +1,2 @@
|
|||
{ }:
|
||||
"h"
|
Loading…
Reference in a new issue