MyNixOS website logo
Description

Convert a tree of files into fixed-output derivations.

nix-freeze-tree walks a directory tree and generates a tree of Nix expressions that recreate the tree from fixed-output derivations, one derivation per file in the source tree. See README.md to get started.

nix-freeze-tree

builds.sr.ht status AGPLv3

nix-freeze-tree is a utility that walks a directory tree, and writes out 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 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 profile install sourcehut:~jack/nix-freeze-tree. If you're not using flakes, you can instead try 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 flake defines a function lib.${system}.freeze, which can be used to freeze the output of an existing derivation. You can use it like this:

{
  inputs = {
    flake-utils.url = "github:numtide/flake-utils";
    nix-freeze-tree = "git+https://git.sr.ht/~jack/nix-freeze-tree"
  };

  outputs = inputs@{ ... }:
    inputs.flake-utils.lib.eachDefaultSystem (system:
      {
        defaultPackage = (import nix-freeze-tree { }).lib.${system}.freeze
          some-derivation-to-be-frozen;
      }
    );
}

The freeze function corresponding to builtins.currentSystem is also exposed in default.nix, so you can use it with Nix code that looks a bit like:

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 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 symlinkJoining 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

Metadata

Version

0.1.1.0

Platforms (75)

    Darwin
    FreeBSD
    Genode
    GHCJS
    Linux
    MMIXware
    NetBSD
    none
    OpenBSD
    Redox
    Solaris
    WASI
    Windows
Show all
  • aarch64-darwin
  • aarch64-genode
  • aarch64-linux
  • aarch64-netbsd
  • aarch64-none
  • aarch64_be-none
  • arm-none
  • armv5tel-linux
  • armv6l-linux
  • armv6l-netbsd
  • armv6l-none
  • armv7a-darwin
  • armv7a-linux
  • armv7a-netbsd
  • armv7l-linux
  • armv7l-netbsd
  • avr-none
  • i686-cygwin
  • i686-darwin
  • i686-freebsd
  • i686-genode
  • i686-linux
  • i686-netbsd
  • i686-none
  • i686-openbsd
  • i686-windows
  • javascript-ghcjs
  • loongarch64-linux
  • m68k-linux
  • m68k-netbsd
  • m68k-none
  • microblaze-linux
  • microblaze-none
  • microblazeel-linux
  • microblazeel-none
  • mips-linux
  • mips-none
  • mips64-linux
  • mips64-none
  • mips64el-linux
  • mipsel-linux
  • mipsel-netbsd
  • mmix-mmixware
  • msp430-none
  • or1k-none
  • powerpc-netbsd
  • powerpc-none
  • powerpc64-linux
  • powerpc64le-linux
  • powerpcle-none
  • riscv32-linux
  • riscv32-netbsd
  • riscv32-none
  • riscv64-linux
  • riscv64-netbsd
  • riscv64-none
  • rx-none
  • s390-linux
  • s390-none
  • s390x-linux
  • s390x-none
  • vc4-none
  • wasm32-wasi
  • wasm64-wasi
  • x86_64-cygwin
  • x86_64-darwin
  • x86_64-freebsd
  • x86_64-genode
  • x86_64-linux
  • x86_64-netbsd
  • x86_64-none
  • x86_64-openbsd
  • x86_64-redox
  • x86_64-solaris
  • x86_64-windows