diff options
Diffstat (limited to 'pkgs/build-support')
-rw-r--r-- | pkgs/build-support/appimage/default.nix | 8 | ||||
-rw-r--r-- | pkgs/build-support/docker/default.nix | 187 | ||||
-rw-r--r-- | pkgs/build-support/docker/examples.nix | 116 | ||||
-rw-r--r-- | pkgs/build-support/fake-nss/default.nix | 6 | ||||
-rw-r--r-- | pkgs/build-support/node/build-npm-package/default.nix | 4 | ||||
-rw-r--r-- | pkgs/build-support/node/build-npm-package/hooks/npm-install-hook.sh | 2 | ||||
-rw-r--r-- | pkgs/build-support/node/fetch-npm-deps/default.nix | 8 | ||||
-rw-r--r-- | pkgs/build-support/node/fetch-npm-deps/src/main.rs | 2 |
8 files changed, 321 insertions, 12 deletions
diff --git a/pkgs/build-support/appimage/default.nix b/pkgs/build-support/appimage/default.nix index 6d4dbfbe421b0..b974b8f68712c 100644 --- a/pkgs/build-support/appimage/default.nix +++ b/pkgs/build-support/appimage/default.nix @@ -61,6 +61,14 @@ rec { (args // { inherit name extraPkgs; src = extract { inherit name src; }; + + # passthru src to make nix-update work + # hack to keep the origin position (unsafeGetAttrPos) + passthru = lib.pipe args [ + lib.attrNames + (lib.remove "src") + (removeAttrs args) + ] // args.passthru or { }; }); defaultFhsEnvArgs = { diff --git a/pkgs/build-support/docker/default.nix b/pkgs/build-support/docker/default.nix index 6b07865928e62..c6ab4589aefac 100644 --- a/pkgs/build-support/docker/default.nix +++ b/pkgs/build-support/docker/default.nix @@ -30,6 +30,7 @@ , vmTools , writeReferencesToFile , writeScript +, writeShellScriptBin , writeText , writeTextDir , writePython3 @@ -78,7 +79,7 @@ let in rec { examples = callPackage ./examples.nix { - inherit buildImage buildLayeredImage fakeNss pullImage shadowSetup buildImageWithNixDb; + inherit buildImage buildLayeredImage fakeNss pullImage shadowSetup buildImageWithNixDb streamNixShellImage; }; tests = { @@ -1034,4 +1035,188 @@ rec { ''; in result; + + # This function streams a docker image that behaves like a nix-shell for a derivation + streamNixShellImage = + { # The derivation whose environment this docker image should be based on + drv + , # Image Name + name ? drv.name + "-env" + , # Image tag, the Nix's output hash will be used if null + tag ? null + , # User id to run the container as. Defaults to 1000, because many + # binaries don't like to be run as root + uid ? 1000 + , # Group id to run the container as, see also uid + gid ? 1000 + , # The home directory of the user + homeDirectory ? "/build" + , # The path to the bash binary to use as the shell. See `NIX_BUILD_SHELL` in `man nix-shell` + shell ? bashInteractive + "/bin/bash" + , # Run this command in the environment of the derivation, in an interactive shell. See `--command` in `man nix-shell` + command ? null + , # Same as `command`, but runs the command in a non-interactive shell instead. See `--run` in `man nix-shell` + run ? null + }: + assert lib.assertMsg (! (drv.drvAttrs.__structuredAttrs or false)) + "streamNixShellImage: Does not work with the derivation ${drv.name} because it uses __structuredAttrs"; + assert lib.assertMsg (command == null || run == null) + "streamNixShellImage: Can't specify both command and run"; + let + + # A binary that calls the command to build the derivation + builder = writeShellScriptBin "buildDerivation" '' + exec ${lib.escapeShellArg (stringValue drv.drvAttrs.builder)} ${lib.escapeShellArgs (map stringValue drv.drvAttrs.args)} + ''; + + staticPath = "${dirOf shell}:${lib.makeBinPath [ builder ]}"; + + # https://github.com/NixOS/nix/blob/2.8.0/src/nix-build/nix-build.cc#L493-L526 + rcfile = writeText "nix-shell-rc" '' + unset PATH + dontAddDisableDepTrack=1 + # TODO: https://github.com/NixOS/nix/blob/2.8.0/src/nix-build/nix-build.cc#L506 + [ -e $stdenv/setup ] && source $stdenv/setup + PATH=${staticPath}:"$PATH" + SHELL=${lib.escapeShellArg shell} + BASH=${lib.escapeShellArg shell} + set +e + [ -n "$PS1" -a -z "$NIX_SHELL_PRESERVE_PROMPT" ] && PS1='\n\[\033[1;32m\][nix-shell:\w]\$\[\033[0m\] ' + if [ "$(type -t runHook)" = function ]; then + runHook shellHook + fi + unset NIX_ENFORCE_PURITY + shopt -u nullglob + shopt -s execfail + ${optionalString (command != null || run != null) '' + ${optionalString (command != null) command} + ${optionalString (run != null) run} + exit + ''} + ''; + + # https://github.com/NixOS/nix/blob/2.8.0/src/libstore/globals.hh#L464-L465 + sandboxBuildDir = "/build"; + + # This function closely mirrors what this Nix code does: + # https://github.com/NixOS/nix/blob/2.8.0/src/libexpr/primops.cc#L1102 + # https://github.com/NixOS/nix/blob/2.8.0/src/libexpr/eval.cc#L1981-L2036 + stringValue = value: + # We can't just use `toString` on all derivation attributes because that + # would not put path literals in the closure. So we explicitly copy + # those into the store here + if builtins.typeOf value == "path" then "${value}" + else if builtins.typeOf value == "list" then toString (map stringValue value) + else toString value; + + # https://github.com/NixOS/nix/blob/2.8.0/src/libstore/build/local-derivation-goal.cc#L992-L1004 + drvEnv = lib.mapAttrs' (name: value: + let str = stringValue value; + in if lib.elem name (drv.drvAttrs.passAsFile or []) + then lib.nameValuePair "${name}Path" (writeText "pass-as-text-${name}" str) + else lib.nameValuePair name str + ) drv.drvAttrs // + # A mapping from output name to the nix store path where they should end up + # https://github.com/NixOS/nix/blob/2.8.0/src/libexpr/primops.cc#L1253 + lib.genAttrs drv.outputs (output: builtins.unsafeDiscardStringContext drv.${output}.outPath); + + # Environment variables set in the image + envVars = { + + # Root certificates for internet access + SSL_CERT_FILE = "${cacert}/etc/ssl/certs/ca-bundle.crt"; + + # https://github.com/NixOS/nix/blob/2.8.0/src/libstore/build/local-derivation-goal.cc#L1027-L1030 + # PATH = "/path-not-set"; + # Allows calling bash and `buildDerivation` as the Cmd + PATH = staticPath; + + # https://github.com/NixOS/nix/blob/2.8.0/src/libstore/build/local-derivation-goal.cc#L1032-L1038 + HOME = homeDirectory; + + # https://github.com/NixOS/nix/blob/2.8.0/src/libstore/build/local-derivation-goal.cc#L1040-L1044 + NIX_STORE = storeDir; + + # https://github.com/NixOS/nix/blob/2.8.0/src/libstore/build/local-derivation-goal.cc#L1046-L1047 + # TODO: Make configurable? + NIX_BUILD_CORES = "1"; + + } // drvEnv // { + + # https://github.com/NixOS/nix/blob/2.8.0/src/libstore/build/local-derivation-goal.cc#L1008-L1010 + NIX_BUILD_TOP = sandboxBuildDir; + + # https://github.com/NixOS/nix/blob/2.8.0/src/libstore/build/local-derivation-goal.cc#L1012-L1013 + TMPDIR = sandboxBuildDir; + TEMPDIR = sandboxBuildDir; + TMP = sandboxBuildDir; + TEMP = sandboxBuildDir; + + # https://github.com/NixOS/nix/blob/2.8.0/src/libstore/build/local-derivation-goal.cc#L1015-L1019 + PWD = sandboxBuildDir; + + # https://github.com/NixOS/nix/blob/2.8.0/src/libstore/build/local-derivation-goal.cc#L1071-L1074 + # We don't set it here because the output here isn't handled in any special way + # NIX_LOG_FD = "2"; + + # https://github.com/NixOS/nix/blob/2.8.0/src/libstore/build/local-derivation-goal.cc#L1076-L1077 + TERM = "xterm-256color"; + }; + + + in streamLayeredImage { + inherit name tag; + contents = [ + binSh + usrBinEnv + (fakeNss.override { + # Allows programs to look up the build user's home directory + # https://github.com/NixOS/nix/blob/ffe155abd36366a870482625543f9bf924a58281/src/libstore/build/local-derivation-goal.cc#L906-L910 + # Slightly differs however: We use the passed-in homeDirectory instead of sandboxBuildDir. + # We're doing this because it's arguably a bug in Nix that sandboxBuildDir is used here: https://github.com/NixOS/nix/issues/6379 + extraPasswdLines = [ + "nixbld:x:${toString uid}:${toString gid}:Build user:${homeDirectory}:/noshell" + ]; + extraGroupLines = [ + "nixbld:!:${toString gid}:" + ]; + }) + ]; + + fakeRootCommands = '' + # Effectively a single-user installation of Nix, giving the user full + # control over the Nix store. Needed for building the derivation this + # shell is for, but also in case one wants to use Nix inside the + # image + mkdir -p ./nix/{store,var/nix} ./etc/nix + chown -R ${toString uid}:${toString gid} ./nix ./etc/nix + + # Gives the user control over the build directory + mkdir -p .${sandboxBuildDir} + chown -R ${toString uid}:${toString gid} .${sandboxBuildDir} + ''; + + # Run this image as the given uid/gid + config.User = "${toString uid}:${toString gid}"; + config.Cmd = + # https://github.com/NixOS/nix/blob/2.8.0/src/nix-build/nix-build.cc#L185-L186 + # https://github.com/NixOS/nix/blob/2.8.0/src/nix-build/nix-build.cc#L534-L536 + if run == null + then [ shell "--rcfile" rcfile ] + else [ shell rcfile ]; + config.WorkingDir = sandboxBuildDir; + config.Env = lib.mapAttrsToList (name: value: "${name}=${value}") envVars; + }; + + # Wrapper around streamNixShellImage to build an image from the result + buildNixShellImage = { drv, ... }@args: + let + stream = streamNixShellImage args; + in + runCommand "${drv.name}-env.tar.gz" + { + inherit (stream) imageName; + passthru = { inherit (stream) imageTag; }; + nativeBuildInputs = [ pigz ]; + } "${stream} | pigz -nT > $out"; } diff --git a/pkgs/build-support/docker/examples.nix b/pkgs/build-support/docker/examples.nix index 1e9f07045e370..802b2f79f0fc5 100644 --- a/pkgs/build-support/docker/examples.nix +++ b/pkgs/build-support/docker/examples.nix @@ -7,7 +7,7 @@ # $ nix-build '<nixpkgs>' -A dockerTools.examples.redis # $ docker load < result -{ pkgs, buildImage, buildLayeredImage, fakeNss, pullImage, shadowSetup, buildImageWithNixDb, pkgsCross }: +{ pkgs, buildImage, buildLayeredImage, fakeNss, pullImage, shadowSetup, buildImageWithNixDb, pkgsCross, streamNixShellImage }: let nixosLib = import ../../../nixos/lib { @@ -715,4 +715,118 @@ rec { config = { }; }; + + nix-shell-basic = streamNixShellImage { + name = "nix-shell-basic"; + tag = "latest"; + drv = pkgs.hello; + }; + + nix-shell-hook = streamNixShellImage { + name = "nix-shell-hook"; + tag = "latest"; + drv = pkgs.mkShell { + shellHook = '' + echo "This is the shell hook!" + exit + ''; + }; + }; + + nix-shell-inputs = streamNixShellImage { + name = "nix-shell-inputs"; + tag = "latest"; + drv = pkgs.mkShell { + nativeBuildInputs = [ + pkgs.hello + ]; + }; + command = '' + hello + ''; + }; + + nix-shell-pass-as-file = streamNixShellImage { + name = "nix-shell-pass-as-file"; + tag = "latest"; + drv = pkgs.mkShell { + str = "this is a string"; + passAsFile = [ "str" ]; + }; + command = '' + cat "$strPath" + ''; + }; + + nix-shell-run = streamNixShellImage { + name = "nix-shell-run"; + tag = "latest"; + drv = pkgs.mkShell {}; + run = '' + case "$-" in + *i*) echo This shell is interactive ;; + *) echo This shell is not interactive ;; + esac + ''; + }; + + nix-shell-command = streamNixShellImage { + name = "nix-shell-command"; + tag = "latest"; + drv = pkgs.mkShell {}; + command = '' + case "$-" in + *i*) echo This shell is interactive ;; + *) echo This shell is not interactive ;; + esac + ''; + }; + + nix-shell-writable-home = streamNixShellImage { + name = "nix-shell-writable-home"; + tag = "latest"; + drv = pkgs.mkShell {}; + run = '' + if [[ "$HOME" != "$(eval "echo ~$(whoami)")" ]]; then + echo "\$HOME ($HOME) is not the same as ~\$(whoami) ($(eval "echo ~$(whoami)"))" + exit 1 + fi + + if ! touch $HOME/test-file; then + echo "home directory is not writable" + exit 1 + fi + echo "home directory is writable" + ''; + }; + + nix-shell-nonexistent-home = streamNixShellImage { + name = "nix-shell-nonexistent-home"; + tag = "latest"; + drv = pkgs.mkShell {}; + homeDirectory = "/homeless-shelter"; + run = '' + if [[ "$HOME" != "$(eval "echo ~$(whoami)")" ]]; then + echo "\$HOME ($HOME) is not the same as ~\$(whoami) ($(eval "echo ~$(whoami)"))" + exit 1 + fi + + if -e $HOME; then + echo "home directory exists" + exit 1 + fi + echo "home directory doesn't exist" + ''; + }; + + nix-shell-build-derivation = streamNixShellImage { + name = "nix-shell-build-derivation"; + tag = "latest"; + drv = pkgs.hello; + run = '' + buildDerivation + $out/bin/hello + ''; + }; + } diff --git a/pkgs/build-support/fake-nss/default.nix b/pkgs/build-support/fake-nss/default.nix index 9e0b60133e00f..7d85ec5fc0a5f 100644 --- a/pkgs/build-support/fake-nss/default.nix +++ b/pkgs/build-support/fake-nss/default.nix @@ -2,17 +2,17 @@ # Useful when packaging binaries that insist on using nss to look up # username/groups (like nginx). # /bin/sh is fine to not exist, and provided by another shim. -{ symlinkJoin, writeTextDir, runCommand }: +{ lib, symlinkJoin, writeTextDir, runCommand, extraPasswdLines ? [], extraGroupLines ? [] }: symlinkJoin { name = "fake-nss"; paths = [ (writeTextDir "etc/passwd" '' root:x:0:0:root user:/var/empty:/bin/sh - nobody:x:65534:65534:nobody:/var/empty:/bin/sh + ${lib.concatStrings (map (line: line + "\n") extraPasswdLines)}nobody:x:65534:65534:nobody:/var/empty:/bin/sh '') (writeTextDir "etc/group" '' root:x:0: - nobody:x:65534: + ${lib.concatStrings (map (line: line + "\n") extraGroupLines)}nobody:x:65534: '') (writeTextDir "etc/nsswitch.conf" '' hosts: files dns diff --git a/pkgs/build-support/node/build-npm-package/default.nix b/pkgs/build-support/node/build-npm-package/default.nix index 5ab86996e56b2..26cc678c571e7 100644 --- a/pkgs/build-support/node/build-npm-package/default.nix +++ b/pkgs/build-support/node/build-npm-package/default.nix @@ -4,7 +4,9 @@ , src ? null , srcs ? null , sourceRoot ? null +, prePatch ? "" , patches ? [ ] +, postPatch ? "" , nativeBuildInputs ? [ ] , buildInputs ? [ ] # The output hash of the dependencies for this project. @@ -30,7 +32,7 @@ let npmDeps = fetchNpmDeps { - inherit src srcs sourceRoot patches; + inherit src srcs sourceRoot prePatch patches postPatch; name = "${name}-npm-deps"; hash = npmDepsHash; }; diff --git a/pkgs/build-support/node/build-npm-package/hooks/npm-install-hook.sh b/pkgs/build-support/node/build-npm-package/hooks/npm-install-hook.sh index c3983e2895681..59ea2da993d87 100644 --- a/pkgs/build-support/node/build-npm-package/hooks/npm-install-hook.sh +++ b/pkgs/build-support/node/build-npm-package/hooks/npm-install-hook.sh @@ -27,7 +27,7 @@ npmInstallHook() { local -r nodeModulesPath="$packageOut/node_modules" if [ ! -d "$nodeModulesPath" ]; then - npm prune --omit dev $npmInstallFlags "${npmInstallFlagsArray[@]}" $npmFlags "${npmFlagsArray[@]}" + npm prune --omit dev --no-save $npmInstallFlags "${npmInstallFlagsArray[@]}" $npmFlags "${npmFlagsArray[@]}" find node_modules -maxdepth 1 -type d -empty -delete cp -r node_modules "$nodeModulesPath" diff --git a/pkgs/build-support/node/fetch-npm-deps/default.nix b/pkgs/build-support/node/fetch-npm-deps/default.nix index 7d5ea7cbfbe8f..7d6277df987f3 100644 --- a/pkgs/build-support/node/fetch-npm-deps/default.nix +++ b/pkgs/build-support/node/fetch-npm-deps/default.nix @@ -84,7 +84,7 @@ hash = "sha256-X9mCwPqV5yP0S2GonNvpYnLSLJMd/SUIked+hMRxDpA="; }; - hash = "sha256-5Mg7KDJLMM5e/7BCHGinGAnBRft2ySQzvKW06p3u/0o="; + hash = "sha256-tEdElWJ+KBTxBobzXBpPopQSwK2usGW/it1+yfbVzBw="; }; linkDependencies = makeTest { @@ -107,7 +107,7 @@ hash = "sha256-1fGNxYJi1I4cXK/jinNG+Y6tPEOhP3QAqWOBEQttS9E="; }; - hash = "sha256-8xF8F74nHwL9KPN2QLsxnfvsk0rNCKOZniYJQCD5u/I="; + hash = "sha256-+KA8/orSBJ4EhuSyQO8IKSxsN/FAsYU3lOzq+awuxNQ="; }; }; @@ -140,14 +140,14 @@ buildPhase = '' runHook preBuild - if [[ ! -f package-lock.json ]]; then + if [[ ! -e package-lock.json ]]; then echo echo "ERROR: The package-lock.json file does not exist!" echo echo "package-lock.json is required to make sure that npmDepsHash doesn't change" echo "when packages are updated on npm." echo - echo "Hint: You can use the patches attribute to add a package-lock.json manually to the build." + echo "Hint: You can copy a vendored package-lock.json file via postPatch." echo exit 1 diff --git a/pkgs/build-support/node/fetch-npm-deps/src/main.rs b/pkgs/build-support/node/fetch-npm-deps/src/main.rs index cf9651d42d649..3d2204071a66a 100644 --- a/pkgs/build-support/node/fetch-npm-deps/src/main.rs +++ b/pkgs/build-support/node/fetch-npm-deps/src/main.rs @@ -421,7 +421,7 @@ fn main() -> anyhow::Result<()> { data = Command::new("tar") .args([ "--sort=name", - "--mtime=0", + "--mtime=@0", "--owner=0", "--group=0", "--numeric-owner", |