= Content-addressed derivations and the Zilch build scheduler :page-pagination: next Zilch implements its own content-addressed derivations, along with a subset of the Nix build scheduler. This brings a few important features with it, such as derivation fallbacks and post-build hooks. It also means that content-addressed derivations can be experimented with inside Zilch without worrying about changes to Nix breaking it, and without enabling any `experimental-features`. == Content-addressed derivations Currently, the content-addressed derivation format used by Zilch closely matches that of Nix, with a few subtleties. content-addressed derivations are never written to the Nix store, as that would require Nix support them. If a Zilch CA derivation is built, it is translated to an input-addressed derivation and built. Each output of this derivation is then queried and the NAR hash is used to copy the output path to its final, content-addressed, destination.footnote:[This means self-references aren't supported; though as these are not correctly handled in Nix either this problem has been punted for now.] These store paths are then used to substitute the placeholder in the generated derivation for any derivation that depends on it. The output of these content-addressed derivations has the Deriver set properly, so it's possible to use the Nix CLI to quickly query the (input-addressed equivalent) derivation used to build them, using a shell script: [source,bash] ---- nix derivation show "$(nix path-info --json /nix/store/mjs27ix6ig2bkbi3s3sm470vrv4lf7ic-hello | jq -r '.[].deriver') ---- == Build hooks By implementing the content-addressed derivation logic itself, Zilch is able to provide a few features Nix is unable to: Build hooks. When a content-addressed derivation fails to build, it is possible to swap out the derivation, and instead build a different derivation. This is done using xref:generated:zilch.magic.adoc#store-path-register-fallback[`store-path-register-fallback`], which takes a thunk that is evaluated when the build fails, and returns a new derivation to build. [source,scheme] ---- (define fails-to-build (cdar (store-path-for-ca-drv "hello" "x86_64-linux" '("/bin/sh" "-c" "echo i fail to build") '() '("out"))) ;; # (define fallback (cdar (store-path-for-ca-drv "hello" "x86_64-linux" '("/bin/sh" "-c" "echo hi > $out") '() '("out"))) ;; # (store-path-register-fallback fails-to-build (lambda () fallback)) ;; # (store-path-realised fails-to-build) ;> [..building "/nix/store/qmx86vqz7pl191vwpcc8zrpnh98rils8-hello.drv"] ;> [0/1 builds, 1 running] ;> i fail to build ;> ;> Error: daemon logger received error: (error "Error" 0 "builder for '\x1b[35;1m/nix/store/qmx86vqz7pl191vwpcc8zrpnh98r...") ;> [..building "/nix/store/76w21n1f03fs5kw8fnffphx7qrqffw6r-hello.drv"] ;> [0/1 builds, 1 running] ;; "/nix/store/a5izqk5bgpxcrrnrm1m8n1fvyq2jlc52-hello" ---- The post-build hook works similarly, but calls the callback with an `alist` of output name to output store path: [source,scheme] ---- (define example (cdar (store-path-for-ca-drv "hello" "x86_64-linux" '("/bin/sh" "-c" "echo hi > $out") '() '("out"))) ;; # (store-path-register-post-build example (lambda (vals) (write vals) (newline))) ;; # (store-path-realised example) ;> (("out" . "/nix/store/a5izqk5bgpxcrrnrm1m8n1fvyq2jlc52-hello")) ;; "/nix/store/a5izqk5bgpxcrrnrm1m8n1fvyq2jlc52-hello" ----