diff options
Diffstat (limited to 'maintainers/scripts/rebuild-amount.sh')
-rwxr-xr-x | maintainers/scripts/rebuild-amount.sh | 133 |
1 files changed, 133 insertions, 0 deletions
diff --git a/maintainers/scripts/rebuild-amount.sh b/maintainers/scripts/rebuild-amount.sh new file mode 100755 index 00000000000..bedd352db5f --- /dev/null +++ b/maintainers/scripts/rebuild-amount.sh @@ -0,0 +1,133 @@ +#!/usr/bin/env bash +set -e + +# --print: avoid dependency on environment +optPrint= +if [ "$1" == "--print" ]; then + optPrint=true + shift +fi + +if [ "$#" != 1 ] && [ "$#" != 2 ]; then + cat <<EOF + Usage: $0 [--print] from-commit-spec [to-commit-spec] + You need to be in a git-controlled nixpkgs tree. + The current state of the tree will be used if the second commit is missing. + + Examples: + effect of latest commit: + $ $0 HEAD^ + $ $0 --print HEAD^ + effect of the whole patch series for 'staging' branch: + $ $0 origin/staging staging +EOF + exit 1 +fi + +# A slightly hacky way to get the config. +parallel="$(echo 'config.rebuild-amount.parallel or false' | nix-repl . 2>/dev/null \ + | grep -v '^\(nix-repl.*\)\?$' | tail -n 1 || true)" + +echo "Estimating rebuild amount by counting changed Hydra jobs (parallel=${parallel:-unset})." + +toRemove=() + +cleanup() { + rm -rf "${toRemove[@]}" +} +trap cleanup EXIT SIGINT SIGQUIT ERR + +MKTEMP='mktemp --tmpdir nix-rebuild-amount-XXXXXXXX' + +nixexpr() { + cat <<EONIX + let + lib = import $1/lib; + hydraJobs = import $1/pkgs/top-level/release.nix + # Compromise: accuracy vs. resources needed for evaluation. + { supportedSystems = cfg.systems or [ "x86_64-linux" "x86_64-darwin" ]; }; + cfg = (import $1 {}).config.rebuild-amount or {}; + + recurseIntoAttrs = attrs: attrs // { recurseForDerivations = true; }; + + # hydraJobs leaves recurseForDerivations as empty attrmaps; + # that would break nix-env and we also need to recurse everywhere. + tweak = lib.mapAttrs + (name: val: + if name == "recurseForDerivations" then true + else if lib.isAttrs val && val.type or null != "derivation" + then recurseIntoAttrs (tweak val) + else val + ); + + # Some of these contain explicit references to platform(s) we want to avoid; + # some even (transitively) depend on ~/.nixpkgs/config.nix (!) + blacklist = [ + "tarball" "metrics" "manual" + "darwin-tested" "unstable" "stdenvBootstrapTools" + "moduleSystem" "lib-tests" # these just confuse the output + ]; + + in + tweak (builtins.removeAttrs hydraJobs blacklist) +EONIX +} + +# Output packages in tree $2 that weren't in $1. +# Changing the output hash or name is taken as a change. +# Extra nix-env parameters can be in $3 +newPkgs() { + # We use files instead of pipes, as running multiple nix-env processes + # could eat too much memory for a standard 4GiB machine. + local -a list + for i in 1 2; do + local l="$($MKTEMP)" + list[$i]="$l" + toRemove+=("$l") + + local expr="$($MKTEMP)" + toRemove+=("$expr") + nixexpr "${!i}" > "$expr" + + nix-env -f "$expr" -qaP --no-name --out-path --show-trace $3 \ + | sort > "${list[$i]}" & + + if [ "$parallel" != "true" ]; then + wait + fi + done + + wait + comm -13 "${list[@]}" +} + +# Prepare nixpkgs trees. +declare -a tree +for i in 1 2; do + if [ -n "${!i}" ]; then # use the given commit + dir="$($MKTEMP -d)" + tree[$i]="$dir" + toRemove+=("$dir") + + git clone --shared --no-checkout --quiet . "${tree[$i]}" + (cd "${tree[$i]}" && git checkout --quiet "${!i}") + else #use the current tree + tree[$i]="$(pwd)" + fi +done + +newlist="$($MKTEMP)" +toRemove+=("$newlist") +# Notes: +# - the evaluation is done on x86_64-linux, like on Hydra. +# - using $newlist file so that newPkgs() isn't in a sub-shell (because of toRemove) +newPkgs "${tree[1]}" "${tree[2]}" '--argstr system "x86_64-linux"' > "$newlist" + +# Hacky: keep only the last word of each attribute path and sort. +sed -n 's/\([^. ]*\.\)*\([^. ]*\) .*$/\2/p' < "$newlist" \ + | sort | uniq -c + +if [ -n "$optPrint" ]; then + echo + cat "$newlist" +fi |