Nix copy doesn't copy everything?

I’m trying to use nix copy to copy a development environment to disk so that I can take with me to a computer that doesn’t have Internet access.

According to the docs, and Moving stuff around with Nix it should be fairly straightforward, but it doesn’t work.

I have a complete reproduction of the issue at GitHub - a-h/nix-devshell-problem that uses a Docker container with the network disabled.

The first step is to export the required parts of the local store.

# Copy the packages (there's only 1).
nix copy --to file://$PWD/export .#packages.x86_64-linux.default
nix copy --derivation --to file://$PWD/export .#packages.x86_64-linux.default
# Copy the devshell.
nix copy --to file://$PWD/export .#devShells.x86_64-linux.default
nix copy --derivation --to file://$PWD/export .#devShells.x86_64-linux.default
# According to this post, the inputDerivation is needed to run the devshell.
# https://discourse.nixos.org/t/how-to-get-nix-store-path-of-nix-develop-shell/38846/2?u=a-h
nix copy --to file://$PWD/export .#devShells.x86_64-linux.default.inputDerivation
# Copy the flake inputs to the store.
nix flake archive --to file://$PWD/export

Then, I can mount the export into a Docker container for testing.

The Docker container is very simple, it’s stock Ubuntu with Nix installed via the Determinate systems Nix installer.

FROM ubuntu:latest
RUN apt update -y
RUN apt install curl -y
RUN curl --proto '=https' --tlsv1.2 -sSf -L https://install.determinate.systems/nix | sh -s -- install linux \
  --extra-conf "filter-syscalls = false" \
  --init none \
  --no-confirm
ENV PATH="${PATH}:/nix/var/nix/profiles/default/bin"

I can then run the container with the export and flake code mounted:

docker run --entrypoint=/bin/bash \
  --mount type=bind,source="$(pwd)",target=/code \
  --workdir=/code --network=none \
  -it --rm --platform linux/amd64 \
  nix-devshell-problem:latest

Inside the container, I can then import the export.

root@d369f4b7260a:/code# nix copy --no-check-sigs --all --from file://$PWD/export/
warning: you don't have Internet access; disabling some network-dependent features

This chugs away, and imports everything, but when I run nix develop it attempts to connect to the Internet, even though it should have everything it needs already.

root@d369f4b7260a:/code# nix develop
warning: you don't have Internet access; disabling some network-dependent features
warning: Git tree '/code' is dirty
error: builder for '/nix/store/5jrd75v747s76s16zxk59384xfcjqn58-bash-5.2.tar.gz.drv' failed with exit code 1;
       last 4 log lines:
       > error:
       >        … writing file '/nix/store/v28dv6l0qk3j382kp40bksa1v6h7dx9p-bash-5.2.tar.gz'
       >
       >        error: unable to download 'https://ftpmirror.gnu.org/bash/bash-5.2.tar.gz': Couldn't resolve host name (6)
       For full logs, run 'nix log /nix/store/5jrd75v747s76s16zxk59384xfcjqn58-bash-5.2.tar.gz.drv'.
error: 1 dependencies of derivation '/nix/store/hdpsnzp3vajlzbi6dmrbnkb6mhfc8axz-bash-5.2-p15.drv' failed to build
error: 1 dependencies of derivation '/nix/store/hpkl2vyxiwf7rwvjh9lpij7swp7igilx-bash-5.2-p15.drv' failed to build
error: 1 dependencies of derivation '/nix/store/kgag4vbp9csw1mqbig4r2dd1l2fri70s-bash-5.2-p15.drv' failed to build
error: 1 dependencies of derivation '/nix/store/lp1y9zymyyrn2hc5l8sycffd0048ls4z-bash-5.2-p15.drv' failed to build
error: 1 dependencies of derivation '/nix/store/dm7bl6lprdslgkcspsws8jk999b02a5q-bash-5.2.tar.gz.drv' failed to build
error (ignored): error: 1 dependencies of derivation '/nix/store/xjvqa1vlyfzay8z8nzkbzm5rl478l0fy-bash-interactive-5.2-p15.drv' failed to build

I’ve noticed that if I copy the whole store from my current store into the container, it works, but I think that’s just through luck more than judgement, and it takes a long time.

Am I doing something wrong or have I found a bug?

1 Like

From the nix develop docs, I got a clue:

Nix determines the build environment by building a modified version of the derivation installable that just records the environment initialised by stdenv and exits.

So, nix develop attempts to use the nipkgs set from the flake input to find bashInteractive. If the nixpkgs source code for the flake is not found in the store, or a built store path of bashInteractive is not found, nix develop will attempt to build bashInteractive.

To prevent this, you can nix copy the correct bashInteractive to your machine.

export NIXPKGS_COMMIT=`nix flake metadata --json | jq -r '.locks.nodes.nixpkgs | "\(.locked.type):\(.locked.owner)/\(.locked.repo)/\(.locked.rev)"'`
nix copy --to file://$PWD/export "$NIXPKGS_COMMIT#legacyPackages.x86_64-linux.bashInteractive"

I think this is a bug. nix copy of a devShell should include bashInteractive, since without it, it doesn’t work, so you couldn’t really say it’s copying the closure.

1 Like

The commands required were a bit more involved, since you have to realise the first-level inputs of the things you want to build and transfer those too, plus the source code etc.

I’ve worked this into GitHub - a-h/flakegap: Take a Flake and package it for deployment across an airgap. so that you can run a single command to export a flake to a .tar.gz file.

5 Likes

Nice job. It would be really nice if this feature or similar was provided directly by the nix cli. Did you already file a feature request in the nix bug tracker?

No, I haven’t done that.

I do think it would be good for the Nix CLI to include the feature, perhaps as nix flake export that did the same sort of thing, and also if nix copy was a bit smarter - I think it might be common to expect that copying the devShell also gives you everything you need to make changes to, and rebuild the software.

If you could nix flake import the tar.gz into a binary cache or store, that would be excellent too.

If you want to put together a proposal of how that would look as an RFC (I think there’s a process for Nix CLI changes), go for it.

The best outcome would be that I can archive flakegap because it’s a supported operation.

without having looked in great detail, this seems like it should have a fair degree of overlap with nix bundle, just focused on bundling the devshell rather than the program.