Skip to content

Instantly share code, notes, and snippets.

@adnelson
Created December 16, 2015 19:12
Show Gist options
  • Save adnelson/e36090bffc5301133559 to your computer and use it in GitHub Desktop.
Save adnelson/e36090bffc5301133559 to your computer and use it in GitHub Desktop.

Building nix with a repo over SSH

It's pretty simple to use a repo to aid the building of nix packages. You need:

  • Two machines, let's call them Builder and Repo.
  • Each machine has nix installed. Let's say that Repo has a nix installation owned by the user nix-repo, and Builder has one owned by nix-builder.
  • nix-builder is able to SSH into Repo as nix-repo.

Once you have this, to build a package on Builder using Repo:

Builder$ nix-build <thing_to_build> --option ssh-substituter-hosts nix-repo@Repo

Once a build is finished, it's likely that there will be one or more new objects that Builder built, that weren't on Repo. To upload these objects from Builder to Repo, we need to know what their paths are. nix-build prints to stdout the paths that were built, which we can store in a text file (this second build will complete instantly, so don't worry; of course, if you're reading ahead you could just run this the first time):

Builder$ nix-build <thing_to_build> --option ssh-substituter-hosts nix-repo@Repo > store_paths.txt

Then we use nix-copy-closure to upload them back to the repo:

Builder$ cat store_paths.txt | xargs nix-copy-closure --to nix-repo@Repo

(Note that it might be desirable to add extra options to nix-copy-closure; see the manual for details).

At this point the paths will exist on Repo, and be available to future builds and other build machines as well.

So let's show a quick example. Let's assume Builder has only nix installed and nothing else. Let's assume it has a nix expression for foo living in foo.nix, and that foo has not been built on the Builder or the Repo.

Builder$ nix-build foo.nix --option ssh-substituter-hosts nix-repo@Repo --dry-run

The --dry-run option will tell nix not to actually do the build, but to show what actions would be performed. It should say something along the lines of

these derivations will be built:
  /nix/store/<some long hash>-foo.drv

It's saying that the derivations will be built, and not fetched. This means they will be built from scratch. So let's do the actual build, and put it in store_paths.txt:

Builder$ nix-build foo.nix --option ssh-substituter-hosts nix-repo@Repo > store_paths.txt

We can cat store_paths.txt and verify that it contains the path in the nix store. Now we upload that to the repo:

Builder$ cat store_paths.txt | xargs nix-copy-closure --to nix-repo@Repo

At this point, we can SSH into the repo and verify that the paths are found there:

Repo$ ls /nix/store | grep foo
/nix/store/<some long hash>-foo

Going back to the builder machine, let's delete the thing that we built. We have to delete the result symlink that was created by the nix-build or it won't let us:

Builder$ rm result
Builder$ nix-store --delete /nix/store/<some long hash>-foo

Now let's try building foo again:

Builder$ nix-build foo.nix --option ssh-substituter-hosts nix-repo@Repo --dry-run

This time, it will be slightly different:

these paths will be fetched:
  /nix/store/<some long hash>-foo

Now it's pulling down from the repo, so it doesn't need to build! Yay. We can confirm this by doing a build:

Builder$ nix-build foo.nix --option ssh-substituter-hosts nix-repo@Repo

And see that it's fetching the path instead of building:

fetching path '/nix/store/<some long hash>-foo'

And there we go, the repo is working.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment