-
-
Notifications
You must be signed in to change notification settings - Fork 18.2k
symlinkJoin: ability to strip prefix from tree #345127
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -3,7 +3,11 @@ | |
| let | ||
| inherit (lib) | ||
| optionalAttrs | ||
| optionalString | ||
| hasPrefix | ||
| warn | ||
| map | ||
| isList | ||
| ; | ||
| in | ||
|
|
||
|
|
@@ -462,6 +466,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. | ||
|
|
||
|
|
@@ -484,23 +511,37 @@ rec { | |
| "symlinkJoin requires either a `name` OR `pname` and `version`"; | ||
| "${args_.pname}-${args_.version}" | ||
| , paths | ||
| , stripPrefix ? "" | ||
| , preferLocalBuild ? true | ||
| , allowSubstitutes ? false | ||
| , postBuild ? "" | ||
| , failOnMissing ? stripPrefix == "" | ||
CertainLach marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| , ... | ||
| }: | ||
| 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 | ||
| runCommand name args | ||
| '' | ||
| 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} | ||
| ''; | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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 | ||
| ''; | ||
| } |
Uh oh!
There was an error while loading. Please reload this page.