diff options
| author | Karel Kočí <cynerd@email.cz> | 2022-08-09 09:20:02 +0200 | 
|---|---|---|
| committer | Karel Kočí <cynerd@email.cz> | 2022-08-09 09:20:02 +0200 | 
| commit | 33356ec9bc1a1571491894c6edef73df181f9ac9 (patch) | |
| tree | 567833c1243b403538b460c63a660a851e6eec5b | |
| parent | 3649c233b73d03370779a8f58c6613a412979e8b (diff) | |
| download | nixos-personal-33356ec9bc1a1571491894c6edef73df181f9ac9.tar.gz nixos-personal-33356ec9bc1a1571491894c6edef73df181f9ac9.tar.bz2 nixos-personal-33356ec9bc1a1571491894c6edef73df181f9ac9.zip | |
Add local.sh script to update local machine
Yes there is nixos-rebuild but this turns out to be for me much more
handy when updating and testing system.
| -rw-r--r-- | .gitignore | 1 | ||||
| -rw-r--r-- | common.sh | 157 | ||||
| -rwxr-xr-x | devices.sh | 125 | ||||
| -rwxr-xr-x | local.sh | 58 | 
4 files changed, 221 insertions, 120 deletions
| @@ -1 +1,2 @@  result* +.result-* diff --git a/common.sh b/common.sh new file mode 100644 index 0000000..995a57e --- /dev/null +++ b/common.sh @@ -0,0 +1,157 @@ +# Common Bash functions for helper scripts in this repository +set -eu + +## Logging ##################################################################### +_print() { +	local color="\e[$1m" +	local clrcolor="\e[0m" +	shift +	if [ ! -t 1 ]; then +		color="" +		clrcolor="" +	fi +	printf "${color}%s${clrcolor}\n" "$*" >&2 +} + +stage() { +	_print '1;32' "$@" +} + +info() { +	_print '1;35' "$@" +} + +error() { +	_print '1;31' "$@" +} +warning() { +	_print '1;33' "$@" +} + +## SSH access helper ########################################################### + +# Convert hostname to the SSH destination +sshdest() { +	awk -F- 'NF > 1 { print $2"."$1; exit } { print $1 }' <<<"$1" +} + +_ssh() { +	local device="$1" +	shift +	if [ "$device" != "$(hostname)" ]; then +		local -a args +		[ "$1" = "sudo" ] && \ +			args+=('-t') # Crude detection for terminal need +		ssh "${args[@]}" "$(sshdest "$device")" -- "$@" +	else +		"$@" +	fi +} + +## Evalutions and queries ###################################################### + +# The path where build result is linked to +result() { +	echo ".result-$1" +} + +# Get system of the device +device_system() { +	nix eval --raw ".#nixosConfigurations.$1.config.nixpkgs.system" +} + +# Validates if link is valid. +build_validate() { +	local device="$1" +	[ -L "$(result "$device")" ] && [ -e "$(result "$device")" ] +} + +## Build NixOS system ########################################################## +# $1: device name +# All other arguments are passed to the nix build command +build() { +	local device="$1" +	shift + +	local toplevel=".config.system.build.toplevel" +	if [ "$(device_system "$device")" = "armv7l-linux" ]; then +		toplevel=".config.system.build.cross.x86_64-linux${toplevel}" +	fi + +	stage "Building system for device: $device" +	nix build \ +		-o "$(result "${device}")" \ +		--keep-going \ +		"$@" \ +		"${0%/*}#nixosConfigurations.${device}${toplevel}" +} + +## Copy NixOS system ########################################################### +# $1: device name +copy() { +	local device="$1" +	if ! build_validate "$device"; then +		warning "System for device '$device' seems to be not build." >&2 +		return 1 +	fi +	local store +	store="$(readlink -f "$(result "$device")")" + +	local freespace required; +	freespace="$(_ssh "$device" df -B 1 /nix | awk 'NR == 2 { print $4 }')" +	required="$(nix path-info -S "$store" | awk '{ print $2 }')" +	info "Free space on device: $(numfmt --to=iec "$freespace")" +	info "Required space: $(numfmt --to=iec "$required")" +	if [ "$required" -ge "$freespace" ]; then +		error "There is not enough space to copy clousure to: $device" >&2 +		return 1 +	fi + +	stage "Copy closure to: $device" +	nix copy -s --to "ssh://$(sshdest "$device")" "$store" +} + +## Switch Nix encironment ###################################################### +# $1: switch operation to be performed +# $2: device name +# TODO possibly really query if switch is or is not required +setenv() { +	local switchop="$1" +	local device="$2" +	if ! build_validate "$device"; then +		warning "System '$device' seems to be not build." >&2 +		return 1 +	fi +	local store +	store="$(readlink -f "$(result "$device")")" + +	stage "${switchop^} system: $device" +	local cursystem +	cursystem="$(_ssh "$device" readlink -f /nix/var/nix/profiles/system)" +	if [ "$cursystem" != "$store" ]; then +		info "-----------------------------------------------------------------" +		_ssh "$device" \ +			nix store diff-closures "$cursystem" "$store" +		info "-----------------------------------------------------------------" +		# TODO we should call here switch-to-configuration as well to use single +		# sudo session and remove one prompt. +		_ssh "$device" \ +			sudo sh -c \ +				'nix-env --profile /nix/var/nix/profiles/system --set "$store" && /nix/var/nix/profiles/system/bin/switch-to-configuration "$1"' \ +					"$switchop" +	else +		warning "The latest system might have been already set." +	fi +} + +boot() { +	setenv boot "$1" +} + +switch() { +	setenv switch "$1" +} + +switch_test() { +	setenv test "$1" +} @@ -1,5 +1,5 @@  #!/usr/bin/env bash -set -eu +source "${0%/*}/common.sh"  declare -a devices  ################################################################################  ## aarch64 @@ -24,134 +24,18 @@ valid_device() {  	return 1  } -device_system() { -	nix eval --raw ".#nixosConfigurations.$1.config.nixpkgs.system" -} - -sshdev() { -	echo "$1" | awk -F- 'NF > 1 { print $2"."$1; exit } { print $1 }' -} - - -build() { -	local system="$1" -	echo "Building $system" -	local -a args -	local toplevel=".config.system.build.toplevel" -	args+=("--keep-going") -	if [ "$(device_system "$1")" = "armv7l-linux" ]; then -		toplevel=".config.system.build.cross.x86_64-linux${toplevel}" -	fi -	nix build \ -		-o "result-${system}" \ -		"${args[@]}" \ -		"${0%/*}#nixosConfigurations.${system}${toplevel}" -} - -build_validate() { -	local system="$1" -	[ -L "result-$system" ] && [ -e "result-$system" ] -} - -copy() { -	local system="$1" -	if ! build_validate "$system"; then -		echo "System '$system' seems to be not build." >&2 -		return 1 -	fi -	local store="$(readlink -f "result-$system")" -	local host="$(sshdev "$system")" - -	local freespace="$(ssh "$host" -- df -B 1 /nix | awk 'NR == 2 { print $4 }')" -	local required="$(nix path-info -S "$store" | awk '{ print $2 }')" -	echo "Free space on device: $(numfmt --to=iec "$freespace")" -	echo "Required space: $(numfmt --to=iec "$required")" -	if [ "$required" -ge "$freespace" ]; then -		echo "There is not enough space to copy clousure to: $system" >&2 -		return 1 -	fi - -	echo "Copy closure to: $system" -	nix copy -s --to "ssh://$host" "$store" -} - -setenv() { -	local system="$1" -	if ! build_validate "$system"; then -		echo "System '$system' seems to be not build." >&2 -		return 1 -	fi -	local store="$(readlink -f "result-$system")" -	local host="$(sshdev "$system")" - -	echo "Update system: $system" -	if [ "$(ssh "$host" -- readlink -f /nix/var/nix/profiles/system)" != "$store" ]; then -		ssh -t "$host" -- \ -			sudo nix-env --profile /nix/var/nix/profiles/system --set "$store" -	fi -} - -boot() { -	local system="$1" -	setenv "$system" || return 1 - -	local store="$(readlink -f "result-$system")" -	local host="$(sshdev "$system")" - -	echo "Setting boot system: $system" -	ssh -t "$host" -- \ -		sudo /nix/var/nix/profiles/system/bin/switch-to-configuration boot -} - -is_current() { -	ssh "$1" -- \ -		'[ "$(readlink -f /run/current-system)" != "$(readlink -f /nix/var/nix/profiles/system)" ]' -} - -switch() { -	local system="$1" -	setenv "$system" || return 1 - -	local store="$(readlink -f "result-$system")" -	local host="$(sshdev "$system")" - -	if is_current "$host"; then -		echo "Switching: $system" -		ssh -t "$host" -- \ -			sudo /nix/var/nix/profiles/system/bin/switch-to-configuration switch -	else -		echo "This system is already running: $system" -	fi -} - -switch_test() { -	local system="$1" -	setenv "$system" || return 1 - -	local store="$(readlink -f "result-$system")" -	local host="$(sshdev "$system")" - -	if is_current "$host"; then -		echo "Testing: $system" -		ssh -t "$host" -- \ -			sudo /nix/var/nix/profiles/system/bin/switch-to-configuration test -	else -		echo "This system is already running: $system" -	fi -} -  for_devices() {  	for device in "${selected_devices[@]}"; do  		for op in "$@"; do  			if ! "$op" "$device"; then -				echo "Operation '$op' failed for: $device" >&2 +				error "Operation '$op' failed for: $device" >&2  				break  			fi  		done  	done  } - +################################################################################  operation="${1:-}"  [ $# -gt 0 ] && shift @@ -159,7 +43,7 @@ declare -a selected_devices  if [ $# -gt 0 ]; then  	for device in "$@"; do  		if ! valid_device "$device"; then -			echo "No such device: $device" >&2 +			error "No such device: $device" >&2  			exit 2  		fi  		selected_devices+=("$device") @@ -168,6 +52,7 @@ else  	selected_devices=("${devices[@]}")  fi +  case "$operation" in  	help|h)  		cat <<-EOF diff --git a/local.sh b/local.sh new file mode 100755 index 0000000..37985c3 --- /dev/null +++ b/local.sh @@ -0,0 +1,58 @@ +#!/usr/bin/env bash +source "${0%/*}/common.sh" + +operations() { +	for op in "$@"; do +		if ! "$op" "$(hostname)"; then +			error "Operation '$op' failed" >&2 +			break +		fi +	done +} + +################################################################################ +operation="${1:-}" +if [ $# -gt 1 ]; then +	echo "Invalid argument: $2" >&2 +	exit 2 +fi + +case "$operation" in +	help|h) +		cat <<-EOF +		Usage $0 operation [device]... +		Local system builder and updater for remote devices. + +		Operations: +		  build: build device system +		  boot: set built system to be boot default on the device +		  switch: switch to the built system on the target device +		  test: test the built system on the target device +		EOF +		;; +	build|b) +		operations build +		;; +	boot) +		operations boot +		;; +	switch|s) +		operations switch +		;; +	test|t) +		operations switch_test +		;; +	build-switch|bs|"") +		operations build switch +		;; +	build-test|bt) +		operations build switch_test +		;; +	build-boot|bb) +		operations build boot +		;; +	default) +		echo "Unknown operation: $operation" >&2 +		exit 2 +		;; +esac | 
