diff options
author | Vincent Ambo <mail@tazj.in> | 2022-05-02T10·32+0200 |
---|---|---|
committer | tazjin <tazjin@tvl.su> | 2022-05-02T23·34+0000 |
commit | 0ce396bdab902be626a9055e991551ce6120551e (patch) | |
tree | bf834c0bf9bff9886942e2e39d4690df5e704478 | |
parent | 419dd2a7aa4523bf89f1ff2d4e876f6b85a3bacb (diff) |
feat(nix/lazy-deps): Add function to generate lazy binary dispatcher r/3996
There is a reoccuring problem in readTree-type repositories that use nix-shell, where evaluation of the full set of dependencies that should be made available to users takes a noticeable amount of time, slowing down operations when `direnv` is involved. In depot, we have so far fixed this by maintaining a manual `//bin` directory which contains a set of symlinks to a central dispatch script that can dispatch to various tools in depot lazily. This script can instead be generated ad-hoc by Nix (pretty fast if we can make assumptions like `git` and `nix-build` existing on user's machines already) and added to $PATH. The function introduced in this commit implements the logic for that. The structure of the script is based on the existing `//bin/__dispatch`. This does not yet switch depot's envrc to use this new method of installing dependencies lazily. Change-Id: I92efcd9bb6aa51aa2709ad910a464e9dac97ee89 Reviewed-on: https://cl.tvl.fyi/c/depot/+/5512 Tested-by: BuildkiteCI Reviewed-by: ezemtsov <eugene.zemtsov@gmail.com>
Diffstat (limited to '')
-rw-r--r-- | nix/lazy-deps/default.nix | 75 |
1 files changed, 75 insertions, 0 deletions
diff --git a/nix/lazy-deps/default.nix b/nix/lazy-deps/default.nix new file mode 100644 index 000000000000..3cce48d8a53e --- /dev/null +++ b/nix/lazy-deps/default.nix @@ -0,0 +1,75 @@ +# Helper function to synthesize a directory of "lazy-built" binaries +# that can be added to $PATH inside of a repository. +# +# Using this, a Nix shell environment in some repository can contain +# several slow-to-build commands without blowing up evaluation and +# build time whenever the shell is loaded. +# +# Note that the generated script is deliberately impure to speed up +# evaluation, and expects both `git` and `nix-build` to exist in the +# user's $PATH. If required, this can be done in the shell +# configuration invoking this function. +{ pkgs, ... }: + +let + inherit (builtins) attrNames attrValues mapAttrs; + inherit (pkgs.lib) concatStringsSep; + + # Create the case statement for a command invocations, optionally + # overriding the `TARGET_TOOL` variable. + invoke = name: { attr, cmd ? null }: '' + ${name}) + attr="${attr}" + ${if cmd != null then "TARGET_TOOL=\"${cmd}\"\n;;" else ";;"} + ''; + + # Create command to symlink to the dispatch script for each tool. + link = name: "ln -s $target $out/bin/${name}"; + + invocations = tools: concatStringsSep "\n" (attrValues (mapAttrs invoke tools)); +in + +# Attribute set of tools that should be lazily-added to the $PATH. + + # The name of each attribute is used as the command name (on $PATH). + # It must contain the keys 'attr' (containing the Nix attribute path + # to the tool's derivation from the top-level), and may optionally + # contain the key 'cmd' to override the name of the binary inside the + # derivation. +tools: + +pkgs.writeTextFile { + name = "lazy-dispatch"; + executable = true; + destination = "/bin/__dispatch"; + + text = '' + #!${pkgs.runtimeShell} + set -ue + + if ! type git>/dev/null || ! type nix-build>/dev/null; then + echo "The 'git' and 'nix-build' commands must be available." >&2 + exit 127 + fi + + readonly REPO_ROOT=$(git rev-parse --show-toplevel) + TARGET_TOOL=$(basename "$0") + + case "''${TARGET_TOOL}" in + ${invocations tools} + *) + echo "''${TARGET_TOOL} is currently not installed in this repository." >&2 + exit 127 + ;; + esac + + result=$(nix-build --no-out-link --attr "''${attr}" "''${REPO_ROOT}") + PATH="''${result}/bin:$PATH" + exec "''${TARGET_TOOL}" "''${@}" + ''; + + checkPhase = '' + ${pkgs.stdenv.shellDryRun} "$target" + ${concatStringsSep "\n" (map link (attrNames tools))} + ''; +} |