166 lines
4.1 KiB
Plaintext
Executable File
166 lines
4.1 KiB
Plaintext
Executable File
#!/usr/bin/env nix-shell
|
|
#!nix-shell -i bash -p findutils -p git -p nix-update
|
|
|
|
# each update job has to do an entire nix eval, which can be memory intensive; be careful when tuning this
|
|
PARALLELISM=8
|
|
SELF_PATH=$PWD/$0
|
|
|
|
usage() {
|
|
echo "update: update rev/hash for one or more packages"
|
|
echo "usage: update [options] [attr-path]"
|
|
echo ""
|
|
echo "options:"
|
|
echo "- --dry-run"
|
|
echo "- --verbose"
|
|
echo "- -j <n> (default: $PARALLELISM)"
|
|
echo ""
|
|
echo "examples:"
|
|
echo "- update nixpkgs: update only the nixpkgs input"
|
|
echo "- update sane: update every package under the 'sane' attribute"
|
|
echo "- update: update everything i know how to update"
|
|
exit 1
|
|
}
|
|
|
|
warn() {
|
|
echo "$@"
|
|
}
|
|
info() {
|
|
echo "$@"
|
|
}
|
|
debug() {
|
|
if [ -n "$verbose" ]; then
|
|
echo "$@"
|
|
fi
|
|
}
|
|
|
|
hasEffect() {
|
|
if [ -n "$dryRun" ]; then
|
|
echo "dry-run: skip $@"
|
|
else
|
|
eval "$@"
|
|
fi
|
|
}
|
|
|
|
REPO_ROOT=
|
|
repo_root() {
|
|
if [ -z "$REPO_ROOT" ]; then
|
|
REPO_ROOT=$(git -C "$(dirname SELF_PATH)" rev-parse --show-toplevel)
|
|
fi
|
|
echo "$REPO_ROOT"
|
|
}
|
|
|
|
# usage: getPkgs outVar prefix
|
|
getPkgs() {
|
|
local -n attrsArr="$1"
|
|
local attrPrefix="$2"
|
|
if [ -z "$attrPrefix" ]; then
|
|
attrPrefix=sane
|
|
fi
|
|
|
|
# # nix-env doesn't seem to build anything when evaluating queries,
|
|
# # but since i use Import From Derivation along paths which i also want to query,
|
|
# # then i need to ensure those derivations are available for import.
|
|
# debug "creating requisite .drv store paths"
|
|
# nix-instantiate -A nix "$(repo_root)"
|
|
# nix-instantiate -A nixpkgs-bootstrap.master "$(repo_root)"
|
|
debug "querying packages to update as part of '$attrPrefix'"
|
|
local attrs=$(nix eval --raw -f "$(repo_root)" 'updateTargets."'"$attrPrefix"'"' --apply 'builtins.concatStringsSep " "' "${nixFlags[@]}")
|
|
debug "got: $attrs"
|
|
attrsArr+=($attrs)
|
|
}
|
|
|
|
updateOnePkg() {
|
|
local attrPath="$1"
|
|
|
|
local updateScript=$(nix eval --raw -f "$(repo_root)" 'updateScripts."'"$attrPath"'"' "${nixFlags[@]}")
|
|
if [ -z "$updateScript" ]; then
|
|
warn "don't know how to update '$attrPath'"
|
|
return
|
|
fi
|
|
|
|
# make sure everything needed to invoke the update script exists in-store
|
|
local context=$(nix eval --raw -f "$(repo_root)" 'updateScripts."'"$attrPath"'"' --apply 's: builtins.concatStringsSep " " (builtins.attrNames (builtins.getContext s))' "${nixFlags[@]}")
|
|
for c in $context; do
|
|
debug "realizing updateScript requisite: $context"
|
|
nix-store --realize "$c" "${nixFlags[@]}" || true
|
|
done
|
|
|
|
local workingDir="$(repo_root)/.working/update/$attrPath"
|
|
rm -rf "$workingDir"
|
|
mkdir -p "$workingDir"
|
|
|
|
info "updating: '$attrPath'"
|
|
info "working out of $workingDir"
|
|
debug "$updateScript"
|
|
|
|
# update scripts often write artifacts (e.g. `git-commits.txt`) to the working directory,
|
|
# so change to a unique directory before running the update script to avoid interfering with any other
|
|
# update scripts that might be running simultaneously.
|
|
pushd "$workingDir"
|
|
"$updateScript" > >(tee update.log) 2> >(tee update.stderr >&2)
|
|
popd
|
|
}
|
|
|
|
updatePkgsInParallel() {
|
|
debug "updating packages in parallel using xargs"
|
|
debug "- $@"
|
|
debug "- xargs -n 1 -P $PARALLELISM $0 ${scriptFlags[*]}"
|
|
echo "$@" | xargs -n 1 -P "$PARALLELISM" "$0" "${scriptFlags[@]}"
|
|
}
|
|
|
|
scriptFlags=()
|
|
nixFlags=()
|
|
dryRun=
|
|
toplevelsToUpdate=()
|
|
verbose=
|
|
parseArgs() {
|
|
while [ "$#" -ne 0 ]; do
|
|
local arg=$1
|
|
shift
|
|
case "$arg" in
|
|
(--help)
|
|
usage
|
|
;;
|
|
(--dry-run)
|
|
scriptFlags+=(--dry-run)
|
|
dryRun=1
|
|
;;
|
|
(--verbose)
|
|
scriptFlags+=(--verbose)
|
|
verbose=1
|
|
;;
|
|
(-j)
|
|
PARALLELISM=$1
|
|
shift
|
|
;;
|
|
(--*)
|
|
nixFlags+=("$arg")
|
|
;;
|
|
(*)
|
|
toplevelsToUpdate+=("$arg")
|
|
;;
|
|
esac
|
|
done
|
|
if [ "${#toplevelsToUpdate[@]}" -eq 0 ]; then
|
|
toplevelsToUpdate=(sane)
|
|
fi
|
|
}
|
|
|
|
parseArgs "$@"
|
|
pkgsToUpdate=()
|
|
for t in "${toplevelsToUpdate[@]}"; do
|
|
getPkgs pkgsToUpdate "$t"
|
|
done
|
|
|
|
case "${#pkgsToUpdate[@]}" in
|
|
(0)
|
|
echo "nothing to do"
|
|
;;
|
|
(1)
|
|
hasEffect updateOnePkg "${pkgsToUpdate[0]}"
|
|
;;
|
|
(*)
|
|
hasEffect updatePkgsInParallel "${pkgsToUpdate[@]}"
|
|
;;
|
|
esac
|