Created
June 6, 2025 11:14
-
-
Save dzogrim/33a62d4e0b1fefc4ce8265c69f1ed3c2 to your computer and use it in GitHub Desktop.
Safely deploy latest nixos image to USB stick after build for hardware tests
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env bash | |
# SPDX-License-Identifier: MIT | |
# after-builder.sh β Safely deploy latest sebos image to USB stick after build for hardware tests | |
# Author: SΓ©bastien L. | |
# Description: | |
# This script installs the latest sebos_*.raw image from ./result/full to a USB stick mounted under /run/media/<user>/DATA. | |
# It writes metadata, computes hash, verifies it, and cleanly ejects the device. | |
# Dry-run by default, requires "APPLY" to take action. | |
set -euo pipefail | |
# Customize here | |
REPO_NAME="sebos" | |
USB_MOUNTPOINT_LABELS=(DATA RESCUE1102) | |
USER_NAME=$(logname) | |
EXPECTED_DIR="$HOME/Documents/Workspaces/${REPO_NAME}" | |
MOUNT_BASE="/run/media/$USER_NAME" | |
DRY_RUN=true | |
[[ "${1:-}" == "APPLY" ]] && DRY_RUN=false | |
# Used later | |
MOUNTPOINT="" | |
DEST_RAW="" | |
DEST_TXT="" | |
DEST_SHA="" | |
SKIP_COPY=0 | |
errors=0 | |
###################################### | |
# 1. Environment checks | |
###################################### | |
# Check current directory | |
if [[ "$(pwd)" != "$EXPECTED_DIR" ]]; then | |
echo "β Wrong working directory: $(pwd)" | |
echo "π Expected: $EXPECTED_DIR" | |
((errors++)) | |
else | |
echo "β Working directory OK" | |
fi | |
# Locate mountpoint by label | |
for label in "${USB_MOUNTPOINT_LABELS[@]}"; do | |
if [[ -d "$MOUNT_BASE/$label" ]]; then | |
MOUNTPOINT="$MOUNT_BASE/$label" | |
echo "β USB stick mounted at: $MOUNTPOINT" | |
break | |
fi | |
done | |
if [[ -z "$MOUNTPOINT" ]]; then | |
echo "β USB stick not found under: ${USB_MOUNTPOINT_LABELS[*]}" | |
((errors++)) | |
fi | |
# Find .raw file | |
RAW_FILE=$(find ./result/full/ -maxdepth 1 -name "${REPO_NAME}_*.raw" -print -quit) | |
if [[ -z "${RAW_FILE:-}" ]]; then | |
echo "β No .raw file found in ./result/full/" | |
((errors++)) | |
else | |
echo "β .raw file detected: $RAW_FILE" | |
fi | |
# Abort if error(s) | |
if ((errors > 0)); then | |
echo | |
echo "β $errors error(s) found, aborting." | |
exit 1 | |
fi | |
###################################### | |
# 2. Set derived variables | |
###################################### | |
VERSION=$(basename "$RAW_FILE" | sed -E "s/^${REPO_NAME}_(.+)\.raw$/\1/") | |
DEST_RAW="$MOUNTPOINT/image.raw" | |
DEST_TXT="$MOUNTPOINT/image.raw.txt" | |
DEST_SHA="$MOUNTPOINT/image.raw.sha256" | |
echo | |
echo "π Detected version: $VERSION" | |
###################################### | |
# 3. Check for existing image | |
###################################### | |
if [ -f "$DEST_RAW" ]; then | |
echo "β οΈ Warning: $DEST_RAW already exists." | |
if [ -f "$DEST_TXT" ]; then | |
echo "βΉοΈ Existing metadata:" | |
echo "----------------------------------" | |
cat "$DEST_TXT" | |
echo "----------------------------------" | |
else | |
echo "βΉοΈ No metadata file found." | |
fi | |
if $DRY_RUN; then | |
echo "π‘ Dry-run: would check and maybe replace existing image." | |
else | |
echo "π Comparing source and destination hashes..." | |
RAW_HASH=$(sha256sum "$RAW_FILE" | awk '{print $1}') | |
DEST_HASH="" | |
if [ -f "$DEST_SHA" ]; then | |
DEST_HASH=$(awk '{print $1}' "$DEST_SHA") | |
fi | |
if [[ "$RAW_HASH" == "$DEST_HASH" ]]; then | |
echo "β File already up-to-date on USB, skipping copy." | |
SKIP_COPY=1 | |
else | |
echo -n "β Do you want to delete and replace the existing image? [y/N] " | |
read -r confirm | |
if [[ "$confirm" != "y" && "$confirm" != "Y" ]]; then | |
echo "β Aborted by user." | |
exit 10 | |
fi | |
echo "ποΈ Removing old image and metadata..." | |
rm -f "$DEST_RAW" "$DEST_TXT" "$DEST_SHA" | |
fi | |
fi | |
fi | |
echo | |
###################################### | |
# 4. Perform operations | |
###################################### | |
if $DRY_RUN; then | |
echo "π‘ Dry-run mode: planned actions:" | |
if [[ "$SKIP_COPY" == 0 ]]; then | |
echo "β Copy $RAW_FILE to $DEST_RAW" | |
echo "β Write version info to $DEST_TXT" | |
echo "β Compute SHA256 and write to $DEST_SHA" | |
echo "β Verify SHA256 after copy" | |
fi | |
echo "β Eject USB key (labels: ${USB_MOUNTPOINT_LABELS[*]})" | |
else | |
echo "π APPLY mode: executing actions..." | |
if [[ "$SKIP_COPY" == 0 ]]; then | |
echo "π€ Copying image to USB..." | |
cp "$RAW_FILE" "$DEST_RAW" | |
echo "π Writing version info..." | |
echo "Version $VERSION $(date)" > "$DEST_TXT" | |
echo "π Computing SHA256..." | |
HASH=$(sha256sum "$DEST_RAW" | awk '{print $1}') | |
echo "$HASH image.raw" > "$DEST_SHA" | |
echo "π Verifying SHA256..." | |
VERIFY_HASH=$(sha256sum "$DEST_RAW" | awk '{print $1}') | |
if [[ "$HASH" != "$VERIFY_HASH" ]]; then | |
echo "β Hash mismatch after copy! Aborting." | |
exit 2 | |
fi | |
echo "β Copy and verification successful." | |
fi | |
echo "βοΈ Ejecting USB device..." | |
DISK=$(lsblk -no PKNAME "$DEST_RAW" 2>/dev/null || true) | |
for label in "${USB_MOUNTPOINT_LABELS[@]}"; do | |
if [ -e "/dev/disk/by-label/$label" ]; then | |
echo "π Unmounting /dev/disk/by-label/$label..." | |
udisksctl unmount -b "/dev/disk/by-label/$label" || true | |
fi | |
done | |
if [ -n "$DISK" ]; then | |
echo "π Powering off /dev/$DISK..." | |
udisksctl power-off -b "/dev/$DISK" || true | |
fi | |
echo "β Done." | |
fi |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment