#!/usr/bin/env nix-shell #!nix-shell -i bash -p findutils -p nix-update NIX_FILES_TOP=/home/colin/nixos 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 "" 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 } # 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 "$NIX_FILES_TOP" nix-instantiate -A nixpkgs "$NIX_FILES_TOP" debug "querying packages to update as part of '$attrPrefix'" local attrs=$(nix eval --raw -f "$NIX_FILES_TOP" 'updateTargets."'"$attrPrefix"'"' --apply 'builtins.concatStringsSep " "') debug "got: $attrs" attrsArr+=($attrs) } updateOnePkg() { local attrPath="$1" local updateScript=$(nix eval --raw -f "$NIX_FILES_TOP" 'updateScripts."'"$attrPath"'"') 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 "$NIX_FILES_TOP" 'updateScripts."'"$attrPath"'"' --apply 's: builtins.concatStringsSep " " (builtins.attrNames (builtins.getContext s))') for c in $context; do debug "realizing updateScript requisite: $context" nix-store --realize "$c" || true done info "updating: '$attrPath'" debug "$updateScript" "$updateScript" } updatePkgsInParallel() { debug "updating packages in parallel using xargs" debug "- $@" debug "- xargs -n 1 -P 4 $0 ${scriptFlags[*]}" echo "$@" | xargs -n 1 -P 4 "$0" "${scriptFlags[@]}" } scriptFlags=() 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 ;; (*) 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