127 lines
		
	
	
		
			3.3 KiB
		
	
	
	
		
			Bash
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			127 lines
		
	
	
		
			3.3 KiB
		
	
	
	
		
			Bash
		
	
	
		
			Executable File
		
	
	
	
	
#!/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
 |