#!/usr/bin/env nix-shell #!nix-shell -i bash -p nettools SELF=$(hostname) usage() { echo "deploy: deploy a nix config to a remote machine, possibly activating it" echo "" echo "usage: deploy [options] [host] [host2 ...]" echo "options:" echo "- --copy: only build + copy files, nothing more" echo "- --switch (default)" echo "- --test: switch to the new configuration, but do not make it bootable" echo "- --dry-run: show what would be done without actually doing it" echo "- --pre: alias for --action copy --variant all all" echo "- --reboot: reboot the target machine after deploying (if deployed with no errors)" echo "- --reboot-force: reboot the target machine after deploying (even on error)" echo "- --variant light|min|''|all (default: '')" echo "- --wireguard always|never|opportunistic: deploy over wireguard" echo "- --ip
: deploy to the specific IP address" echo "- --deriv /nix/store/...: prebuilt store path to deploy instead of (re-)building the default target" echo "" echo "common idioms:" echo "- deploy all: deploy all hosts, sequentially" echo "- deploy --pre: build and copy all hosts" echo "- deploy desko lappy: build and deploy just those hosts" echo "- deploy: deploy the local host" exit 1 } info() { echo "[deploy]" "$@" } action=switch hosts=() ip= defaultHost="$SELF" variants=() defaultVariant= # by default, don't ship builds to servo. i'd guess this can be overriden by passing --builders servo nixArgs=(--builders "") doReboot= doRebootForce= dryRun= wireguard=opportunistic storePath= addHost() { if [ "$1" = all ]; then # order matters: hosts+=(moby lappy desko servo crappy) else hosts+=("$1") fi } addVariant() { if [ "$1" = all ]; then variants+=("-min" "-light" "" "-min-next" "-light-next" "-next") elif [ -n "$1" ]; then variants+=("-$1") else # "full" variant variants+=("") fi } parseArgs() { while [ "$#" -ne 0 ]; do local arg=$1 shift case "$arg" in (--copy|--switch|--test) action=${arg/--/} ;; (--deriv) storePath="$1" shift ;; (--dry-run) dryRun=1 ;; (--help) usage ;; (--ip) ip="$1" shift ;; (--pre) action=copy defaultVariant=all defaultHost=all ;; (--reboot) doReboot=1 ;; (--reboot-force) doReboot=1 doRebootForce=1 ;; (--variant) addVariant "$1" shift ;; (--wireguard) wireguard="$1" shift ;; (all|crappy|desko|lappy|moby|servo) addHost "$arg" ;; (*) nixArgs+=("$arg") ;; esac done if [ "${#hosts[@]}" -eq 0 ] && [ -n "$defaultHost" ]; then addHost "$defaultHost" fi if [ "${#variants[@]}" -eq 0 ]; then addVariant "$defaultVariant" fi } destructive() { if [ -z "$dryRun" ]; then if [ -n "$ECHO_CMD" ]; then echo "$@" fi "$@" else echo "dry-run: $@" fi } # return "$1" or "$1-hn", based on if wireguard was requested or not resolveHost() { if [ -n "$ip" ]; then echo "$ip" else case "$wireguard-$1" in (opportunistic-moby) echo "$1-hn" ;; (opportunistic-*) echo "$1" ;; (never-*) echo "$1" ;; (always-*) echo "$1-hn" ;; (*) echo "$1-hn" ;; esac fi } runOnTarget() { local host="$1" shift # run the command ($@) on the machine we're deploying to. # if that's a remote machine, then do it via ssh, else local shell. if [ -n "$host" ] && [ "$host" != "$SELF" ]; then info "running on remote ($host):" "$@" ssh "$host" "$@" else info "running locally ($SELF):" "$@" "$@" fi } # deployOneHost $host $variant deployOneHost() { local host="$1" local variant="$2" local myStorePath="$storePath" if [ -z "$myStorePath" ]; then # `nix-build -A foo` evals and then realizes foo, but it never unloads the memory used to eval foo. # my exprs are heavyweight, we need that memory for building, so do the evals separately from the realizations: info "evaluating $host$variant..." local drvPath=$(nix eval --raw -f . "hosts.$host$variant.toplevel.drvPath") info "building $host$variant ($drvPath)" myStorePath=$(destructive nix-store --realize "$drvPath" "${nixArgs[@]}") if [ -z "$myStorePath" ]; then return 1 fi info "built $host$variant -> $myStorePath" fi # mimic `nixos-rebuild --target-host`, in effect: # - nix-copy-closure ... # - nix-env --set ... # - switch-to-configuration