# `nix-freeze-tree` [![builds.sr.ht status](https://builds.sr.ht/~jack/nix-freeze-tree.svg)](https://builds.sr.ht/~jack/nix-freeze-tree?) [![AGPLv3](https://git.sr.ht/~jack/nix-freeze-tree/blob/master/AGPLv3.png)](https://www.gnu.org/licenses/agpl-3.0.html) `nix-freeze-tree` is a utility that walks a directory tree, and writes out [Nix](https://nixos.org/nix/) expressions which rebuild that tree. The generated expressions have two important properties: 1. Each file in the tree is built by a separate fixed-output derivation, and 2. Directories are built by derivations that symlink their contents recursively. If you are using `nix copy` to ship a derivation between nix stores, copying the derivation built by evaluating the output of `nix-freeze-tree` can reuse existing files in the destination store, as fixed-output derivations can be checked against a hash before copying. I use this to speed up deploys to my personal website. Running `nix-freeze-tree` on the output from [my site generator](https://git.sr.ht/~jack/jackkelly-name) and importing the result means that `nix copy` only uploads new files, instead of copying a single giant derivation containing every image on the site. ## Installation ### Nix If you use Nix, you can install the command into your local environment by running `nix-env -f https://git.sr.ht/~jack/nix-freeze-tree/archive/master.tar.gz -iA command`. ### Cabal If you have GHC installed, you can also build and install the binary by running `cabal v2-install nix-freeze-tree`. You can also run the binary from the build directory with `cabal v2-run nix-freeze-tree -- ARGS`. ## Usage ``` Usage: nix-freeze-tree [--version] [-f|--force] [-v|--verbose] [-o|--out-root OUT_ROOT] [IN_DIR] Write a tree of nix expressions to OUT_ROOT that build a derivation, symlinking every file in IN_DIR as a separate fixed-output derivation. Available options: --version Display version information and exit. -h,--help Show this help text -f,--force If any default.nix exist in the output directory, remove them and generate anyway -v,--verbose Display messages while working. -o,--out-root OUT_ROOT Where to write the nix files (default: IN_DIR) IN_DIR Directory to freeze (default: .) ``` ## Calling from Nix This repository's `default.nix` gives access to a function `freeze`, which can be used to freeze the output of an existing derivation. You can use it with Nix code that looks a bit like: ```nix let # Some nixpkgs from somewhere nixpkgs = ...; # Whether you get it from a channel, a local checkout, # builtins.fetchTarball or builtins.fetchgit is up to you nix-freeze-tree-repo = builtins.fetchTarball { ... }; # Derivation to freeze drv = mkDerivation { ... }; # Evaluate default.nix from nix-freeze-tree-repo and hold onto the # freeze function freeze = (import nix-freeze-tree-repo { inherit nixpkgs; }).freeze; in freeze drv ``` ## FAQ Q: Why didn't you use [`symlinkJoin`](https://nixos.org/nixpkgs/manual/#chap-trivial-builders) to tie all the subtrees together? A: I had the program mostly working before I remembered that `symlinkJoin` existed. I thought about making each file's derivation contain the directories leading up to it and then `symlinkJoin`ing them all together, but decided against it for three reasons: 1. You can easily build subtrees using the Nix expressions generated by `nix-freeze-tree`; 2. Building the output of `nix-freeze-tree` will correctly create empty directories present in the input; and 3. Files are hashed based on their content alone, not their position in the tree-to-be-frozen (reducing duplication). ## Other Resources * Questions should go to the [nix-freeze-tree-discuss](https://lists.sr.ht/~jack/nix-freeze-tree-discuss) mailing list. * Bug reports should go to the [bug tracker](https://todo.sr.ht/~jack/nix-freeze-tree).