diff --git a/nixos/tests/docker-tools.nix b/nixos/tests/docker-tools.nix index c48e5b07976..ad734a71f01 100644 --- a/nixos/tests/docker-tools.nix +++ b/nixos/tests/docker-tools.nix @@ -178,5 +178,12 @@ import ./make-test-python.nix ({ pkgs, ... }: { # This check may be loosened to allow an *empty* store rather than *no* store. docker.succeed("docker run --rm no-store-paths ls /") docker.fail("docker run --rm no-store-paths ls /nix/store") + + with subtest("Ensure buildLayeredImage does not change store path contents."): + docker.succeed( + "docker load --input='${pkgs.dockerTools.examples.filesInStore}'", + "docker run --rm file-in-store nix-store --verify --check-contents", + "docker run --rm file-in-store |& grep 'some data'", + ) ''; }) diff --git a/pkgs/build-support/docker/examples.nix b/pkgs/build-support/docker/examples.nix index b040d830b31..068daa8df72 100644 --- a/pkgs/build-support/docker/examples.nix +++ b/pkgs/build-support/docker/examples.nix @@ -335,4 +335,23 @@ rec { }; }; + # 19. Support files in the store on buildLayeredImage + # See: https://github.com/NixOS/nixpkgs/pull/91084#issuecomment-653496223 + filesInStore = pkgs.dockerTools.buildLayeredImageWithNixDb { + name = "file-in-store"; + tag = "latest"; + contents = [ + pkgs.coreutils + pkgs.nix + (pkgs.writeScriptBin "myscript" '' + #!${pkgs.runtimeShell} + cat ${pkgs.writeText "somefile" "some data"} + '') + ]; + config = { + Cmd = [ "myscript" ]; + # For some reason 'nix-store --verify' requires this environment variable + Env = [ "USER=root" ]; + }; + }; } diff --git a/pkgs/build-support/docker/stream_layered_image.py b/pkgs/build-support/docker/stream_layered_image.py index 4348513338d..9a13878a783 100644 --- a/pkgs/build-support/docker/stream_layered_image.py +++ b/pkgs/build-support/docker/stream_layered_image.py @@ -39,6 +39,7 @@ import json import hashlib import pathlib import tarfile +import itertools import threading from datetime import datetime from collections import namedtuple @@ -87,16 +88,16 @@ def archive_paths_to(obj, paths, mtime, add_nix, filter=None): tar.addfile(apply_filters(dir("/nix/store"))) for path in paths: - ti = tar.gettarinfo(os.path.join("/", path)) - tar.addfile(apply_filters(append_root(ti))) - - for filename in pathlib.Path(path).rglob("*"): + path = pathlib.Path(path) + files = itertools.chain([path], path.rglob("*")) + for filename in sorted(files): ti = append_root(tar.gettarinfo(filename)) # copy hardlinks as regular files if ti.islnk(): ti.type = tarfile.REGTYPE ti.linkname = "" + ti.size = filename.stat().st_size ti = apply_filters(ti) if ti.isfile():