symlinkJoin: ability to strip prefix from tree (#345127)
This commit is contained in:
@@ -3,7 +3,11 @@
|
||||
let
|
||||
inherit (lib)
|
||||
optionalAttrs
|
||||
optionalString
|
||||
hasPrefix
|
||||
warn
|
||||
map
|
||||
isList
|
||||
;
|
||||
in
|
||||
|
||||
@@ -468,6 +472,29 @@ rec {
|
||||
...
|
||||
|
||||
|
||||
To create a directory structure from a specific subdirectory of input `paths` instead of their full trees,
|
||||
you can either append the subdirectory path to each input path, or use the `stripPrefix` argument to
|
||||
remove the common prefix during linking.
|
||||
|
||||
Example:
|
||||
|
||||
|
||||
# create symlinks of tmpfiles.d rules from multiple packages
|
||||
symlinkJoin { name = "tmpfiles.d"; paths = [ pkgs.lvm2 pkgs.nix ]; stripPrefix = "/lib/tmpfiles.d"; }
|
||||
|
||||
|
||||
This creates a derivation with a directory structure like the following:
|
||||
|
||||
|
||||
/nix/store/m5s775yicb763hfa133jwml5hwmwzv14-tmpfiles.d
|
||||
|-- lvm2.conf -> /nix/store/k6js0l5f0zpvrhay49579fj939j77p2w-lvm2-2.03.29/lib/tmpfiles.d/lvm2.conf
|
||||
`-- nix-daemon.conf -> /nix/store/z4v2s3s3y79fmabhps5hakb3c5dwaj5a-nix-1.33.7/lib/tmpfiles.d/nix-daemon.conf
|
||||
|
||||
|
||||
By default, packages that don't contain the specified subdirectory are silently skipped.
|
||||
Set `failOnMissing = true` to make the build fail if any input package is missing the subdirectory
|
||||
(this is the default behavior when not using stripPrefix).
|
||||
|
||||
symlinkJoin and linkFarm are similar functions, but they output
|
||||
derivations with different structure.
|
||||
|
||||
@@ -490,15 +517,29 @@ rec {
|
||||
"symlinkJoin requires either a `name` OR `pname` and `version`";
|
||||
"${args_.pname}-${args_.version}"
|
||||
, paths
|
||||
, stripPrefix ? ""
|
||||
, preferLocalBuild ? true
|
||||
, allowSubstitutes ? false
|
||||
, postBuild ? ""
|
||||
, failOnMissing ? stripPrefix == ""
|
||||
, ...
|
||||
}:
|
||||
assert lib.assertMsg (stripPrefix != "" -> (hasPrefix "/" stripPrefix && stripPrefix != "/")) ''
|
||||
stripPrefix must be either an empty string (disable stripping behavior), or relative path prefixed with /.
|
||||
|
||||
Ensure that the path starts with / and specifies path to the subdirectory.
|
||||
'';
|
||||
|
||||
let
|
||||
args = removeAttrs args_ [ "name" "postBuild" ]
|
||||
mapPaths = f: paths: map (path:
|
||||
if path == null then null
|
||||
else if isList path then mapPaths f path
|
||||
else f path
|
||||
) paths;
|
||||
args = removeAttrs args_ [ "name" "postBuild" "stripPrefix" "paths" "failOnMissing" ]
|
||||
// {
|
||||
inherit preferLocalBuild allowSubstitutes;
|
||||
paths = mapPaths (path: "${path}${stripPrefix}") paths;
|
||||
passAsFile = [ "paths" ];
|
||||
}; # pass the defaults
|
||||
in
|
||||
@@ -506,7 +547,7 @@ rec {
|
||||
''
|
||||
mkdir -p $out
|
||||
for i in $(cat $pathsPath); do
|
||||
${lndir}/bin/lndir -silent $i $out
|
||||
${optionalString (!failOnMissing) "if test -d $i; then "}${lndir}/bin/lndir -silent $i $out${optionalString (!failOnMissing) "; fi"}
|
||||
done
|
||||
${postBuild}
|
||||
'';
|
||||
|
||||
@@ -19,6 +19,7 @@ in
|
||||
recurseIntoAttrs {
|
||||
concat = callPackage ./concat-test.nix {};
|
||||
linkFarm = callPackage ./link-farm.nix {};
|
||||
symlinkJoin = recurseIntoAttrs (callPackage ./symlink-join.nix {});
|
||||
overriding = callPackage ../test-overriding.nix {};
|
||||
inherit references;
|
||||
writeCBin = callPackage ./writeCBin.nix {};
|
||||
|
||||
136
pkgs/build-support/trivial-builders/test/symlink-join.nix
Normal file
136
pkgs/build-support/trivial-builders/test/symlink-join.nix
Normal file
@@ -0,0 +1,136 @@
|
||||
{
|
||||
symlinkJoin,
|
||||
writeTextFile,
|
||||
runCommand,
|
||||
testers,
|
||||
}:
|
||||
|
||||
let
|
||||
inherit (testers) testEqualContents testBuildFailure;
|
||||
|
||||
foo = writeTextFile {
|
||||
name = "foo";
|
||||
text = "foo";
|
||||
destination = "/etc/test.d/foo";
|
||||
};
|
||||
|
||||
bar = writeTextFile {
|
||||
name = "bar";
|
||||
text = "bar";
|
||||
destination = "/etc/test.d/bar";
|
||||
};
|
||||
|
||||
baz = writeTextFile {
|
||||
name = "baz";
|
||||
text = "baz";
|
||||
destination = "/var/lib/arbitrary/baz";
|
||||
};
|
||||
|
||||
qux = writeTextFile {
|
||||
name = "qux";
|
||||
text = "qux";
|
||||
};
|
||||
|
||||
emulatedSymlinkJoinFooBarStrip = runCommand "symlinkJoin-strip-foo-bar" { } ''
|
||||
mkdir $out
|
||||
ln -s ${foo}/etc/test.d/foo $out/
|
||||
ln -s ${bar}/etc/test.d/bar $out/
|
||||
'';
|
||||
in
|
||||
{
|
||||
symlinkJoin = testEqualContents {
|
||||
assertion = "symlinkJoin";
|
||||
actual = symlinkJoin {
|
||||
name = "symlinkJoin";
|
||||
paths = [
|
||||
foo
|
||||
bar
|
||||
baz
|
||||
];
|
||||
};
|
||||
expected = runCommand "symlinkJoin-foo-bar-baz" { } ''
|
||||
mkdir -p $out/{var/lib/arbitrary,etc/test.d}
|
||||
ln -s {${foo},${bar}}/etc/test.d/* $out/etc/test.d
|
||||
ln -s ${baz}/var/lib/arbitrary/baz $out/var/lib/arbitrary/
|
||||
'';
|
||||
};
|
||||
|
||||
symlinkJoin-strip-paths = testEqualContents {
|
||||
assertion = "symlinkJoin-strip-paths";
|
||||
actual = symlinkJoin {
|
||||
name = "symlinkJoinPrefix";
|
||||
paths = [
|
||||
foo
|
||||
bar
|
||||
];
|
||||
stripPrefix = "/etc/test.d";
|
||||
};
|
||||
expected = emulatedSymlinkJoinFooBarStrip;
|
||||
};
|
||||
|
||||
symlinkJoin-strip-paths-skip-missing = testEqualContents {
|
||||
assertion = "symlinkJoin-strip-paths-skip-missing";
|
||||
actual = symlinkJoin {
|
||||
name = "symlinkJoinPrefix";
|
||||
paths = [
|
||||
foo
|
||||
bar
|
||||
baz
|
||||
];
|
||||
stripPrefix = "/etc/test.d";
|
||||
};
|
||||
expected = emulatedSymlinkJoinFooBarStrip;
|
||||
};
|
||||
|
||||
symlinkJoin-strip-paths-skip-not-directories = testEqualContents {
|
||||
assertion = "symlinkJoin-strip-paths-skip-not-directories";
|
||||
actual = symlinkJoin {
|
||||
name = "symlinkJoinPrefix";
|
||||
paths = [
|
||||
foo
|
||||
bar
|
||||
qux
|
||||
];
|
||||
stripPrefix = "/etc/test.d";
|
||||
};
|
||||
expected = emulatedSymlinkJoinFooBarStrip;
|
||||
};
|
||||
|
||||
symlinkJoin-fails-on-missing =
|
||||
runCommand "symlinkJoin-fails-on-missing"
|
||||
{
|
||||
failed = testBuildFailure (symlinkJoin {
|
||||
name = "symlinkJoin-fail";
|
||||
paths = [
|
||||
foo
|
||||
bar
|
||||
baz
|
||||
];
|
||||
stripPrefix = "/etc/test.d";
|
||||
failOnMissing = true;
|
||||
});
|
||||
}
|
||||
''
|
||||
grep -e "-baz/etc/test.d: No such file or directory" $failed/testBuildFailure.log
|
||||
touch $out
|
||||
'';
|
||||
|
||||
symlinkJoin-fails-on-file =
|
||||
runCommand "symlinkJoin-fails-on-file"
|
||||
{
|
||||
failed = testBuildFailure (symlinkJoin {
|
||||
name = "symlinkJoin-fail";
|
||||
paths = [
|
||||
foo
|
||||
bar
|
||||
qux
|
||||
];
|
||||
stripPrefix = "/etc/test.d";
|
||||
failOnMissing = true;
|
||||
});
|
||||
}
|
||||
''
|
||||
grep -e "-qux/etc/test.d: Not a directory" $failed/testBuildFailure.log
|
||||
touch $out
|
||||
'';
|
||||
}
|
||||
Reference in New Issue
Block a user