#!/bin/bash # # stage-usb-share.sh - Put everything Build-PxeUsb.ps1 needs into a folder # on a share, so a Windows PC can build the installer USB from it. # # Usage: # scripts/stage-usb-share.sh [--iso FILE] [--payload-root DIR] [DEST] # # DEST defaults to ~/pxe-images/pxe-usb (the [pxe-images] Samba share; on # the work PC: \\\pxe-images\pxe-usb, usually Z:\pxe-usb). It gets: # - the repo as committed (git archive HEAD: uncommitted edits are NOT # staged, so the stick matches a commit); # - the payload folders (offline-packages, pip-wheels, boot-files, # boot-tools, enrollment, bios-staging, drivers-staging, site-content) # as hard links, so they cost no extra disk space; # - the Ubuntu ISO offline-packages/ was built for (hard link); # - STAGED.txt: commit, date, sizes. # Then on the work PC: copy the folder to a local disk (C:\pxe-usb) and # double-click Build-PxeUsb.cmd (KB: docs/kb/How_To_Deploy_PXE_Server_New_Site.html). # # The new copy is built beside the old one and swapped in when complete. # Run capture-site-content.sh --apply first so site-content/ is current. set -euo pipefail REPO_ROOT="$(cd "$(dirname "$0")"/.. && pwd)" PAYLOAD_ROOT="$REPO_ROOT" ISO="" DEST="" while [ $# -gt 0 ]; do case "$1" in --iso) ISO="${2:?}"; shift 2 ;; --payload-root) PAYLOAD_ROOT="$(cd "${2:?}" && pwd)"; shift 2 ;; -h|--help) sed -n '2,/^$/p' "$0" | sed 's/^# \{0,1\}//'; exit 0 ;; -*) echo "unknown option $1" >&2; exit 2 ;; *) DEST="$1"; shift ;; esac done DEST="${DEST:-$HOME/pxe-images/pxe-usb}" mkdir -p "$(dirname "$DEST")" DEST="$(cd "$(dirname "$DEST")" && pwd)/$(basename "$DEST")" # Only ever replace a folder this script made (it is swapped and deleted). if [ -e "$DEST" ] && [ ! -f "$DEST/STAGED.txt" ]; then echo "ERROR: $DEST exists and was not made by this script (no STAGED.txt); refusing to replace it" >&2 exit 1 fi # The ISO the offline set was resolved for (BUILD-INFO names it). if [ -z "$ISO" ]; then name=$(sed -n 's/.*--iso \([^ ]*\.iso\).*/\1/p' "$PAYLOAD_ROOT/offline-packages/BUILD-INFO.txt" 2>/dev/null | head -1) name=$(basename "${name:-}") for d in "$PAYLOAD_ROOT" "$PAYLOAD_ROOT/iso" "${PXETEST_CACHE:-$HOME/.cache/pxetest}"; do [ -n "$name" ] && [ -f "$d/$name" ] && { ISO="$d/$name"; break; } done [ -n "$ISO" ] || { echo "ERROR: give --iso FILE (the offline set was built for ${name:-an unknown ISO})" >&2; exit 1; } fi [ -f "$ISO" ] || { echo "ERROR: ISO not found: $ISO" >&2; exit 1; } same_fs() { [ "$(stat -c %d "$1")" = "$(stat -c %d "$2")" ]; } NEW="$DEST.new.$$" OLD="$DEST.old.$$" cleanup() { [ -d "$NEW" ] && rm -rf -- "$NEW"; return 0; } trap cleanup EXIT mkdir -p "$NEW" cd "$REPO_ROOT" COMMIT=$(git rev-parse --short HEAD) if ! git diff --quiet HEAD -- autoinstall playbook scripts webapp; then echo "NOTE: uncommitted changes in autoinstall/playbook/scripts/webapp are NOT staged (HEAD $COMMIT is)." fi echo "Repo $COMMIT -> $NEW" git archive HEAD | tar -x -C "$NEW" link_or_copy() { # SRC DST if same_fs "$1" "$(dirname "$2")"; then cp -al "$1" "$2"; else cp -a "$1" "$2"; fi } for d in offline-packages pip-wheels boot-files boot-tools enrollment bios-staging drivers-staging site-content; do src="$PAYLOAD_ROOT/$d" [ -d "$src" ] || { echo " $d: not in $PAYLOAD_ROOT (skipped)"; continue; } # git archive brings the tracked bits of boot-files/ and boot-tools/; the # payload folder replaces them whole. rm -rf -- "${NEW:?}/$d" link_or_copy "$src" "$NEW/$d" printf ' %-17s %s\n' "$d" "$(du -sh "$NEW/$d" | cut -f1)" done link_or_copy "$ISO" "$NEW/$(basename "$ISO")" echo " ISO $(basename "$ISO")" { echo "Staged by scripts/stage-usb-share.sh $(date -Is)" echo "Commit: $(git log -1 --format='%h %s')" echo "ISO: $(basename "$ISO")" echo "Payload root: $PAYLOAD_ROOT" echo echo "On the Windows PC:" echo " 1. Copy this whole folder to a local disk, e.g. C:\\pxe-usb" echo " 2. Double-click C:\\pxe-usb\\Build-PxeUsb.cmd (asks for admin, lists USB disks)" echo " Instructions: docs\\kb\\How_To_Deploy_PXE_Server_New_Site.html" } >"$NEW/STAGED.txt" if [ -e "$DEST" ]; then mv -- "$DEST" "$OLD"; fi mv -- "$NEW" "$DEST" [ -e "$OLD" ] && rm -rf -- "$OLD" trap - EXIT echo "Staged: $DEST ($(du -sh "$DEST" | cut -f1) apparent, hard-linked payload)"