about summary refs log tree commit diff
path: root/nixpkgs/maintainers/scripts/rebuild-amount.sh
diff options
context:
space:
mode:
Diffstat (limited to 'nixpkgs/maintainers/scripts/rebuild-amount.sh')
-rwxr-xr-xnixpkgs/maintainers/scripts/rebuild-amount.sh127
1 files changed, 127 insertions, 0 deletions
diff --git a/nixpkgs/maintainers/scripts/rebuild-amount.sh b/nixpkgs/maintainers/scripts/rebuild-amount.sh
new file mode 100755
index 000000000000..1a54cada8af6
--- /dev/null
+++ b/nixpkgs/maintainers/scripts/rebuild-amount.sh
@@ -0,0 +1,127 @@
+#!/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] commit-spec [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.
+	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."
+
+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
+