diff --git a/doc/build-helpers.md b/doc/build-helpers.md index 06737e166760..010665484cfd 100644 --- a/doc/build-helpers.md +++ b/doc/build-helpers.md @@ -20,6 +20,7 @@ There is no uniform interface for build helpers. build-helpers/fetchers.chapter.md build-helpers/trivial-build-helpers.chapter.md build-helpers/testers.chapter.md +build-helpers/dev-shell-tools.chapter.md build-helpers/special.md build-helpers/images.md hooks/index.md diff --git a/doc/build-helpers/dev-shell-tools.chapter.md b/doc/build-helpers/dev-shell-tools.chapter.md new file mode 100644 index 000000000000..21636df8017b --- /dev/null +++ b/doc/build-helpers/dev-shell-tools.chapter.md @@ -0,0 +1,29 @@ +# Development Shell helpers {#chap-devShellTools} + +The `nix-shell` command has popularized the concept of transient shell environments for development or testing purposes. + +However, `nix-shell` is not the only way to create such environments, and even `nix-shell` itself can indirectly benefit from this library. + +This library provides a set of functions that help create such environments. + +## `devShellTools.valueToString` {#sec-devShellTools-valueToString} + +Converts Nix values to strings in the way the [`derivation` built-in function](https://nix.dev/manual/nix/2.23/language/derivations) does. + +:::{.example} +## `valueToString` usage examples + +```nix +devShellTools.valueToString (builtins.toFile "foo" "bar") +=> "/nix/store/...-foo" +``` + +```nix +devShellTools.valueToString false +=> "" +``` diff --git a/pkgs/build-support/dev-shell-tools/README.md b/pkgs/build-support/dev-shell-tools/README.md new file mode 100644 index 000000000000..d6d9a8c8ad0d --- /dev/null +++ b/pkgs/build-support/dev-shell-tools/README.md @@ -0,0 +1,13 @@ + +# `devShellTools` + +This directory implements the `pkgs.devShellTools` library. + +# Contributing to `devShellTools` + +- Documentation should be contributed to the Nixpkgs manual, not here. + +- Tests are available in the `tests` directory. + You may run them with `nix-build -A tests.devShellTools`. + +- See [../../README.md](../../README.md) for more information on contributing to Nixpkgs. diff --git a/pkgs/build-support/dev-shell-tools/default.nix b/pkgs/build-support/dev-shell-tools/default.nix new file mode 100644 index 000000000000..cd5fa5f5937e --- /dev/null +++ b/pkgs/build-support/dev-shell-tools/default.nix @@ -0,0 +1,16 @@ +{ lib }: +let + inherit (builtins) typeOf; +in +rec { + # 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 + valueToString = 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 typeOf value == "path" then "${value}" + else if typeOf value == "list" then toString (map valueToString value) + else toString value; +} diff --git a/pkgs/build-support/dev-shell-tools/tests/default.nix b/pkgs/build-support/dev-shell-tools/tests/default.nix new file mode 100644 index 000000000000..bfedc04409a9 --- /dev/null +++ b/pkgs/build-support/dev-shell-tools/tests/default.nix @@ -0,0 +1,45 @@ +{ + devShellTools, + emptyFile, + lib, + stdenv, + hello, +}: +let + inherit (lib) escapeShellArg; +in +{ + # nix-build -A tests.devShellTools.valueToString + valueToString = + let inherit (devShellTools) valueToString; in + + stdenv.mkDerivation { + name = "devShellTools-valueToString-built-tests"; + + # Test inputs + inherit emptyFile hello; + one = 1; + boolTrue = true; + boolFalse = false; + foo = "foo"; + list = [ 1 2 3 ]; + pathDefaultNix = ./default.nix; + packages = [ hello emptyFile ]; + # TODO: nested lists + + buildCommand = '' + touch $out + ( set -x + [[ "$one" = ${escapeShellArg (valueToString 1)} ]] + [[ "$boolTrue" = ${escapeShellArg (valueToString true)} ]] + [[ "$boolFalse" = ${escapeShellArg (valueToString false)} ]] + [[ "$foo" = ${escapeShellArg (valueToString "foo")} ]] + [[ "$hello" = ${escapeShellArg (valueToString hello)} ]] + [[ "$list" = ${escapeShellArg (valueToString [ 1 2 3 ])} ]] + [[ "$packages" = ${escapeShellArg (valueToString [ hello emptyFile ])} ]] + [[ "$pathDefaultNix" = ${escapeShellArg (valueToString ./default.nix)} ]] + [[ "$emptyFile" = ${escapeShellArg (valueToString emptyFile)} ]] + ) >log 2>&1 || { cat log; exit 1; } + ''; + }; +} diff --git a/pkgs/build-support/docker/default.nix b/pkgs/build-support/docker/default.nix index 1d1989d27fbb..ea461ccffa07 100644 --- a/pkgs/build-support/docker/default.nix +++ b/pkgs/build-support/docker/default.nix @@ -4,6 +4,7 @@ , callPackage , closureInfo , coreutils +, devShellTools , e2fsprogs , proot , fakeNss @@ -49,6 +50,10 @@ let toList ; + inherit (devShellTools) + valueToString + ; + mkDbExtraCommand = contents: let contentsList = if builtins.isList contents then contents else [ contents ]; @@ -1141,7 +1146,7 @@ rec { # 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)} + exec ${lib.escapeShellArg (valueToString drv.drvAttrs.builder)} ${lib.escapeShellArgs (map valueToString drv.drvAttrs.args)} ''; staticPath = "${dirOf shell}:${lib.makeBinPath [ builder ]}"; @@ -1173,20 +1178,9 @@ rec { # 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; + let str = valueToString 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 diff --git a/pkgs/test/default.nix b/pkgs/test/default.nix index 2b978ff3e1bc..1b7882bcbed3 100644 --- a/pkgs/test/default.nix +++ b/pkgs/test/default.nix @@ -83,6 +83,8 @@ with pkgs; inherit gccTests; }; + devShellTools = callPackage ../build-support/dev-shell-tools/tests { }; + stdenv-inputs = callPackage ./stdenv-inputs { }; stdenv = callPackage ./stdenv { }; diff --git a/pkgs/top-level/all-packages.nix b/pkgs/top-level/all-packages.nix index f4fbdcc4de8b..0ef49f68e439 100644 --- a/pkgs/top-level/all-packages.nix +++ b/pkgs/top-level/all-packages.nix @@ -837,6 +837,8 @@ with pkgs; grsync = callPackage ../applications/misc/grsync { }; + devShellTools = callPackage ../build-support/dev-shell-tools { }; + dockerTools = callPackage ../build-support/docker { writePython3 = buildPackages.writers.writePython3; };