symlinkJoin
pkgs.symlinkJoin
Docs pulled from | This Revision | 10 minutes ago
TODO: Deduplicate this documentation. More docs in doc/build-helpers/trivial-build-helpers.chapter.md See https://nixos.org/manual/nixpkgs/unstable/#trivial-builder-symlinkJoin
Create a forest of symlinks to the files in paths
.
This creates a single derivation that replicates the directory structure of all the input paths.
BEWARE: it may not "work right" when the passed paths contain symlinks to directories.
Examples
symlinkJoin
usage example
# adds symlinks of hello to current build.
symlinkJoin { name = "myhello"; paths = [ pkgs.hello ]; }
# adds symlinks of hello and stack to current build and prints "links added"
symlinkJoin { name = "myexample"; paths = [ pkgs.hello pkgs.stack ]; postBuild = "echo links added"; }
This creates a derivation with a directory structure like the following:
/nix/store/sglsr5g079a5235hy29da3mq3hv8sjmm-myexample
|-- bin
| |-- hello -> /nix/store/qy93dp4a3rqyn2mz63fbxjg228hffwyw-hello-2.10/bin/hello
| `-- stack -> /nix/store/6lzdpxshx78281vy056lbk553ijsdr44-stack-2.1.3.1/bin/stack
`-- share
|-- bash-completion
| `-- completions
| `-- stack -> /nix/store/6lzdpxshx78281vy056lbk553ijsdr44-stack-2.1.3.1/share/bash-completion/completions/stack
|-- fish
| `-- vendor_completions.d
| `-- stack.fish -> /nix/store/6lzdpxshx78281vy056lbk553ijsdr44-stack-2.1.3.1/share/fish/vendor_completions.d/stack.fish
...
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.
# 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.
symlinkJoin is used to create a derivation with a familiar directory
structure (top-level bin/, share/, etc), but with all actual files being symlinks to
the files in the input derivations.
symlinkJoin is used many places in nixpkgs to create a single derivation
that appears to contain binaries, libraries, documentation, etc from
multiple input derivations.
linkFarm is instead used to create a simple derivation with symlinks to
other derivations. A derivation created with linkFarm is often used in CI
as a easy way to build multiple derivations at once.
Noogle detected
Implementation
The following is the current implementation of this function.
symlinkJoin =
args_@{
name ?
assert lib.assertMsg (
args_ ? pname && args_ ? version
) "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
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
${optionalString (!failOnMissing) "if test -d $i; then "}${lndir}/bin/lndir -silent $i $out${
optionalString (!failOnMissing) "; fi"
}
done
${postBuild}
'';