Unverified Commit c38f9ee1 authored by Robert Hensing's avatar Robert Hensing Committed by GitHub
Browse files

Merge pull request #324789 from NixOS/devShellTools-env

`devShellTools`: add environment functions
parents 055ee1d5 1a70c803
Loading
Loading
Loading
Loading
+46 −0
Original line number Diff line number Diff line
@@ -27,3 +27,49 @@ devShellTools.valueToString (builtins.toFile "foo" "bar")
devShellTools.valueToString false
=> ""
```

:::

## `devShellTools.unstructuredDerivationInputEnv` {#sec-devShellTools-unstructuredDerivationInputEnv}

Convert a set of derivation attributes (as would be passed to [`derivation`]) to a set of environment variables that can be used in a shell script.
This function does not support `__structuredAttrs`, but does support `passAsFile`.

:::{.example}
## `unstructuredDerivationInputEnv` usage example

```nix
devShellTools.unstructuredDerivationInputEnv {
  drvAttrs = {
    name = "foo";
    buildInputs = [ hello figlet ];
    builder = bash;
    args = [ "-c" "${./builder.sh}" ];
  };
}
=> {
  name = "foo";
  buildInputs = "/nix/store/...-hello /nix/store/...-figlet";
  builder = "/nix/store/...-bash";
}
```

Note that `args` is not included, because Nix does not added it to the builder process environment.

:::

## `devShellTools.derivationOutputEnv` {#sec-devShellTools-derivationOutputEnv}

Takes the relevant parts of a derivation and returns a set of environment variables, that would be present in the derivation.

:::{.example}
## `derivationOutputEnv` usage example

```nix
let
  pkg = hello;
in
devShellTools.derivationOutputEnv { outputList = pkg.outputs; outputMap = pkg; }
```

:::
+1 −0
Original line number Diff line number Diff line
@@ -264,6 +264,7 @@ in {
  docker-rootless = handleTestOn ["aarch64-linux" "x86_64-linux"] ./docker-rootless.nix {};
  docker-registry = handleTest ./docker-registry.nix {};
  docker-tools = handleTestOn ["x86_64-linux"] ./docker-tools.nix {};
  docker-tools-nix-shell = runTest ./docker-tools-nix-shell.nix;
  docker-tools-cross = handleTestOn ["x86_64-linux" "aarch64-linux"] ./docker-tools-cross.nix {};
  docker-tools-overlay = handleTestOn ["x86_64-linux"] ./docker-tools-overlay.nix {};
  documize = handleTest ./documize.nix {};
+95 −0
Original line number Diff line number Diff line
# nix-build -A nixosTests.docker-tools-nix-shell
{ config, lib, ... }:
let
  inherit (config.node.pkgs.dockerTools) examples;
in
{
  name = "docker-tools-nix-shell";
  meta = with lib.maintainers; {
    maintainers = [
      infinisil
      roberth
    ];
  };

  nodes = {
    docker =
      { ... }:
      {
        virtualisation = {
          diskSize = 3072;
          docker.enable = true;
        };
      };
  };

  testScript = ''
    docker.wait_for_unit("sockets.target")

    with subtest("buildImageWithNixDB: Has a nix database"):
        docker.succeed(
            "docker load --input='${examples.nix}'",
            "docker run --rm ${examples.nix.imageName} nix-store -q --references /bin/bash"
        )

    with subtest("buildNixShellImage: Can build a basic derivation"):
        docker.succeed(
            "${examples.nix-shell-basic} | docker load",
            "docker run --rm nix-shell-basic bash -c 'buildDerivation && $out/bin/hello' | grep '^Hello, world!$'"
        )

    with subtest("buildNixShellImage: Runs the shell hook"):
        docker.succeed(
            "${examples.nix-shell-hook} | docker load",
            "docker run --rm -it nix-shell-hook | grep 'This is the shell hook!'"
        )

    with subtest("buildNixShellImage: Sources stdenv, making build inputs available"):
        docker.succeed(
            "${examples.nix-shell-inputs} | docker load",
            "docker run --rm -it nix-shell-inputs | grep 'Hello, world!'"
        )

    with subtest("buildNixShellImage: passAsFile works"):
        docker.succeed(
            "${examples.nix-shell-pass-as-file} | docker load",
            "docker run --rm -it nix-shell-pass-as-file | grep 'this is a string'"
        )

    with subtest("buildNixShellImage: run argument works"):
        docker.succeed(
            "${examples.nix-shell-run} | docker load",
            "docker run --rm -it nix-shell-run | grep 'This shell is not interactive'"
        )

    with subtest("buildNixShellImage: command argument works"):
        docker.succeed(
            "${examples.nix-shell-command} | docker load",
            "docker run --rm -it nix-shell-command | grep 'This shell is interactive'"
        )

    with subtest("buildNixShellImage: home directory is writable by default"):
        docker.succeed(
            "${examples.nix-shell-writable-home} | docker load",
            "docker run --rm -it nix-shell-writable-home"
        )

    with subtest("buildNixShellImage: home directory can be made non-existent"):
        docker.succeed(
            "${examples.nix-shell-nonexistent-home} | docker load",
            "docker run --rm -it nix-shell-nonexistent-home"
        )

    with subtest("buildNixShellImage: can build derivations"):
        docker.succeed(
            "${examples.nix-shell-build-derivation} | docker load",
            "docker run --rm -it nix-shell-build-derivation"
        )

    with subtest("streamLayeredImage: with nix db"):
        docker.succeed(
            "${examples.nix-layered} | docker load",
            "docker run --rm ${examples.nix-layered.imageName} nix-store -q --references /bin/bash"
        )
  '';
}
+1 −67
Original line number Diff line number Diff line
@@ -60,7 +60,7 @@ let
    };

  nonRootTestImage =
    pkgs.dockerTools.streamLayeredImage rec {
    pkgs.dockerTools.streamLayeredImage {
      name = "non-root-test";
      tag = "latest";
      uid = 1000;
@@ -567,66 +567,6 @@ in {
        docker.succeed("docker run --rm image-with-certs:latest test -r /etc/pki/tls/certs/ca-bundle.crt")
        docker.succeed("docker image rm image-with-certs:latest")

    with subtest("buildImageWithNixDB: Has a nix database"):
        docker.succeed(
            "docker load --input='${examples.nix}'",
            "docker run --rm ${examples.nix.imageName} nix-store -q --references /bin/bash"
        )

    with subtest("buildNixShellImage: Can build a basic derivation"):
        docker.succeed(
            "${examples.nix-shell-basic} | docker load",
            "docker run --rm nix-shell-basic bash -c 'buildDerivation && $out/bin/hello' | grep '^Hello, world!$'"
        )

    with subtest("buildNixShellImage: Runs the shell hook"):
        docker.succeed(
            "${examples.nix-shell-hook} | docker load",
            "docker run --rm -it nix-shell-hook | grep 'This is the shell hook!'"
        )

    with subtest("buildNixShellImage: Sources stdenv, making build inputs available"):
        docker.succeed(
            "${examples.nix-shell-inputs} | docker load",
            "docker run --rm -it nix-shell-inputs | grep 'Hello, world!'"
        )

    with subtest("buildNixShellImage: passAsFile works"):
        docker.succeed(
            "${examples.nix-shell-pass-as-file} | docker load",
            "docker run --rm -it nix-shell-pass-as-file | grep 'this is a string'"
        )

    with subtest("buildNixShellImage: run argument works"):
        docker.succeed(
            "${examples.nix-shell-run} | docker load",
            "docker run --rm -it nix-shell-run | grep 'This shell is not interactive'"
        )

    with subtest("buildNixShellImage: command argument works"):
        docker.succeed(
            "${examples.nix-shell-command} | docker load",
            "docker run --rm -it nix-shell-command | grep 'This shell is interactive'"
        )

    with subtest("buildNixShellImage: home directory is writable by default"):
        docker.succeed(
            "${examples.nix-shell-writable-home} | docker load",
            "docker run --rm -it nix-shell-writable-home"
        )

    with subtest("buildNixShellImage: home directory can be made non-existent"):
        docker.succeed(
            "${examples.nix-shell-nonexistent-home} | docker load",
            "docker run --rm -it nix-shell-nonexistent-home"
        )

    with subtest("buildNixShellImage: can build derivations"):
        docker.succeed(
            "${examples.nix-shell-build-derivation} | docker load",
            "docker run --rm -it nix-shell-build-derivation"
        )

    with subtest("streamLayeredImage: chown is persistent in fakeRootCommands"):
        docker.succeed(
            "${chownTestImage} | docker load",
@@ -638,11 +578,5 @@ in {
            "${nonRootTestImage} | docker load",
            "docker run --rm ${chownTestImage.imageName} | diff /dev/stdin <(echo 12345:12345)"
        )

    with subtest("streamLayeredImage: with nix db"):
        docker.succeed(
            "${examples.nix-layered} | docker load",
            "docker run --rm ${examples.nix-layered.imageName} nix-store -q --references /bin/bash"
        )
  '';
})
+50 −1
Original line number Diff line number Diff line
{ lib }:
{
  lib,
  writeTextFile,
}:
let
  inherit (builtins) typeOf;
in
rec {
  # Docs: doc/build-helpers/dev-shell-tools.chapter.md
  # Tests: ./tests/default.nix
  # 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
@@ -13,4 +18,48 @@ rec {
    if typeOf value == "path" then "${value}"
    else if typeOf value == "list" then toString (map valueToString value)
    else toString value;


  # Docs: doc/build-helpers/dev-shell-tools.chapter.md
  # Tests: ./tests/default.nix
  # https://github.com/NixOS/nix/blob/2.8.0/src/libstore/build/local-derivation-goal.cc#L992-L1004
  unstructuredDerivationInputEnv = { drvAttrs }:
    # FIXME: this should be `normalAttrs // passAsFileAttrs`
    lib.mapAttrs'
      (name: value:
        let str = valueToString value;
        in if lib.elem name (drvAttrs.passAsFile or [])
        then
          let
            nameHash =
              if builtins?convertHash
              then builtins.convertHash {
                hash = "sha256:" + builtins.hashString "sha256" name;
                toHashFormat = "nix32";
              }
              else
                builtins.hashString "sha256" name;
            basename = ".attr-${nameHash}";
          in
            lib.nameValuePair "${name}Path" "${
              writeTextFile {
                name = "shell-passAsFile-${name}";
                text = str;
                destination = "/${basename}";
              }
            }/${basename}"
        else lib.nameValuePair name str
      )
      (removeAttrs drvAttrs [
        # TODO: there may be more of these
        "args"
      ]);

  # Docs: doc/build-helpers/dev-shell-tools.chapter.md
  # Tests: ./tests/default.nix
  derivationOutputEnv = { outputList, outputMap }:
    # 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 outputList (output: builtins.unsafeDiscardStringContext outputMap.${output}.outPath);

}
Loading