From 1f44a81b36d17d7d8bdcae245d1713b7a874aa14 Mon Sep 17 00:00:00 2001 From: Daniel Vicory Date: Mon, 3 Mar 2025 02:31:13 -0800 Subject: [PATCH] Support engine override, support overriding some env, and improve macOS compatibility With the latest Docker on Homebrew, build no longer works. It seems an engine override is a nice addition, in case you prefer to not select docker as the default choice. Additionally, to allow forks to be more maintainable, allow the docker tag, repository, ZBM, and EFI to be changed through env. These are exposed through env since most users should not customize these. Use the latest released ZBM as the default. Improve macOS compatibility by using GNU versions for du and stat. inject (stat), and iso (du) are fixed by checking for GNU versions. Signed-off-by: Daniel Vicory --- Dockerfile | 1 - zquickinit.sh | 108 ++++++++++++++++++++++++++++++++++++++------------ 2 files changed, 82 insertions(+), 27 deletions(-) diff --git a/Dockerfile b/Dockerfile index 588026c..67c8e0c 100644 --- a/Dockerfile +++ b/Dockerfile @@ -10,7 +10,6 @@ # Use the official Void Linux container FROM ghcr.io/void-linux/void-glibc-full -LABEL org.opencontainers.image.source=https://github.com/midzelis/zquickinit ARG XBPS_REPOS="https://repo-fastly.voidlinux.org/current https://repo-fastly.voidlinux.org/current/nonfree" diff --git a/zquickinit.sh b/zquickinit.sh index bf048e7..2865414 100755 --- a/zquickinit.sh +++ b/zquickinit.sh @@ -27,12 +27,24 @@ SRC_ROOT=${DIR} ZBM_ROOT=${SRC_ROOT}/../zfsbootmenu RECIPES_ROOT=${RECIPES_ROOT:-${SRC_ROOT}/recipes} -RECIPE_BUILDER="ghcr.io/midzelis/zquickinit" -ZQUICKEFI_URL="https://github.com/midzelis/zquickinit/releases/latest" -# if empty, use latest release tag -ZBM_TAG= +RECIPE_BUILDER="${RECIPE_BUILDER:-ghcr.io/midzelis/zquickinit}" +ZQUICKINIT_REPO="${ZQUICKINIT_REPO:-https://github.com/midzelis/zquickinit}" +ZQUICKEFI_URL="${ZQUICKEFI_URL:-${ZQUICKINIT_REPO}/releases/latest}" + +# provide default stable, latest ZBM_TAG if not specified +ZBM_TAG="${ZBM_TAG:-v3.0.1}" +# if empty, then unset to get latest release +if [[ -z "$ZBM_TAG" ]]; then + ZBM_TAG="" +fi + # if specified, takes precedence over ZBM_TAG -ZBM_COMMIT_HASH=db78c980f40937f3b4de8d85e7430f6553a39972 +ZBM_COMMIT_HASH="${ZBM_COMMIT_HASH:-}" +# if ZBM_COMMIT_HASH is specified, unset ZBM_TAG +if [[ -n "$ZBM_COMMIT_HASH" ]]; then + ZBM_TAG="" +fi + INPUT=/input OUTPUT=/output ADD_LOADER= @@ -40,8 +52,10 @@ MKINIT_VERBOSE= KERNEL_BOOT= ENGINE= OBJCOPY= +DU= FIND= YG= +STAT= NOASK=0 DEBUG=0 ENTER=0 @@ -101,10 +115,10 @@ check() { fi fi if [[ $1 == docker || $1 == podman ]]; then - if command -v docker &>/dev/null; then + if [ -z "$ENGINE" ] && command -v docker &>/dev/null; then ENGINE=docker return 0 - elif command -v podman &>/dev/null; then + elif [ -z "$ENGINE" ] && command -v podman &>/dev/null; then ENGINE=podman return 0 fi @@ -142,17 +156,6 @@ check() { OBJCOPY=objcopy fi fi - if ! command -v "$1" &>/dev/null; then - echo "$1 not found. usually part of the $2 package" - if [[ $1 == "gum" && -f "/etc/debian_version" ]]; then - echo "To install, try:" - echo 'sudo mkdir -p /etc/apt/keyrings' - echo 'curl -fsSL https://repo.charm.sh/apt/gpg.key | sudo gpg --dearmor -o /etc/apt/keyrings/charm.gpg' - echo 'echo "deb [signed-by=/etc/apt/keyrings/charm.gpg] https://repo.charm.sh/apt/ * *" | sudo tee /etc/apt/sources.list.d/charm.list' - echo 'sudo apt update && sudo apt install gum' - fi - exit 1 - fi if [[ $1 == find ]] && [[ -z "${FIND}" ]]; then if command -v gfind &>/dev/null; then FIND="gfind" @@ -168,6 +171,47 @@ check() { exit 1 fi fi + if [[ $1 == du ]] && [[ -z "${DU}" ]]; then + if command -v gdu &>/dev/null; then + DU="gdu" + else + DU="du" + fi + if [[ ! "$(${DU} --version 2>&1 | head -n1)" == *GNU* ]]; then + echo "du must be GNU flavored. Update or install coreutils package. " + if [[ "$OSTYPE" == "darwin"* ]]; then + echo "On MacOS, use brew to install coreutils" + echo "Note: brew uses /usr/local/bin on Intel, and /opt/homebrew/bin on Apple" + fi + exit 1 + fi + fi + if [[ $1 == stat ]] && [[ -z "${STAT}" ]]; then + if command -v gstat &>/dev/null; then + STAT="gstat" + else + STAT="stat" + fi + if [[ ! "$(${STAT} --version 2>&1 | head -n2)" =~ (GNU|BusyBox) ]]; then + echo "stat must be GNU or BusyBox flavored. Update or install coreutils package." + if [[ "$OSTYPE" == "darwin"* ]]; then + echo "On MacOS, use brew to install coreutils" + echo "Note: brew uses /usr/local/bin on Intel, and /opt/homebrew/bin on Apple" + fi + exit 1 + fi + fi + if ! command -v "$1" &>/dev/null; then + echo "$1 not found. usually part of the $2 package" + if [[ $1 == "gum" && -f "/etc/debian_version" ]]; then + echo "To install, try:" + echo 'sudo mkdir -p /etc/apt/keyrings' + echo 'curl -fsSL https://repo.charm.sh/apt/gpg.key | sudo gpg --dearmor -o /etc/apt/keyrings/charm.gpg' + echo 'echo "deb [signed-by=/etc/apt/keyrings/charm.gpg] https://repo.charm.sh/apt/ * *" | sudo tee /etc/apt/sources.list.d/charm.list' + echo 'sudo apt update && sudo apt install gum' + fi + exit 1 + fi } # This will build the main ZquickInit Builder OCI image @@ -197,6 +241,7 @@ builder() { echo cmd=("$ENGINE" build . -t "$RECIPE_BUILDER" + --label org.opencontainers.image.source="${ZQUICKINIT_REPO}" --build-arg KERNELS=linux6.6 --build-arg "PACKAGES=${packages[*]}" --build-arg ZBM_COMMIT_HASH="${ZBM_COMMIT_HASH}" @@ -225,6 +270,7 @@ tailscale() { make_zquick_initramfs() { check gum gum check mkinitcpio mkinitcpio + check stat stat gum style --bold --border double --align center \ --width 50 --margin "1 2" --padding "0 2" "Welcome to ZQuickInit make initramfs" @@ -234,13 +280,13 @@ make_zquick_initramfs() { local hash echo "Downloading zquickinit" rm -rf "${INPUT}" - git clone --quiet --depth 1 https://github.com/midzelis/zquickinit.git "${INPUT}" + git clone --quiet --depth 1 "${ZQUICKINIT_REPO}" "${INPUT}" hash=$(cat /etc/zquickinit-commit-hash || echo '') if [[ -n "${hash}" ]]; then (cd "${INPUT}" && git fetch --depth 1 origin "$hash" && git checkout FETCH_HEAD) fi fi - [[ -x /etc/zquickinit-commit-hash ]] && (cd "${INPUT}" && git config --global --add safe.directory "${INPUT}" && /etc/zquickinit-commit-hash && git rev-parse HEAD >/etc/zquickinit-commit-hash && echo "ZQuickInit (https://github.com/midzelis/zquickinit) commit hash: $(git rev-parse --short HEAD) ($(git rev-parse HEAD))") + [[ -x /etc/zquickinit-commit-hash ]] && (cd "${INPUT}" && git config --global --add safe.directory "${INPUT}" && /etc/zquickinit-commit-hash && git rev-parse HEAD >/etc/zquickinit-commit-hash && echo "ZQuickInit (${ZQUICKINIT_REPO}) commit hash: $(git rev-parse --short HEAD) ($(git rev-parse HEAD))") if [[ ! -f "${ZBM}/bin/generate-zbm" ]]; then echo "Downloading latest zfsbootmenu" @@ -576,9 +622,9 @@ make_zquick_initramfs() { ) chmod o+rw -R "${OUTPUT}"/* chmod g+rw -R "${OUTPUT}"/* - env LC_ALL=en_US.UTF-8 printf "Kernel size: \t\t%'.0f bytes\n" "$(stat -c '%s' "${OUTPUT}/zquickinit-$build_time.vmlinuz-$kernel")" - env LC_ALL=en_US.UTF-8 printf "initramfs size: \t%'.0f bytes\n" "$(stat -c '%s' "$output_img")" - env LC_ALL=en_US.UTF-8 printf "EFI size: \t\t%'.0f bytes\n" "$(stat -c '%s' "$output_uki")" + env LC_ALL=en_US.UTF-8 printf "Kernel size: \t\t%'.0f bytes\n" "$(${STAT} -c '%s' "${OUTPUT}/zquickinit-$build_time.vmlinuz-$kernel")" + env LC_ALL=en_US.UTF-8 printf "initramfs size: \t%'.0f bytes\n" "$(${STAT} -c '%s' "$output_img")" + env LC_ALL=en_US.UTF-8 printf "EFI size: \t\t%'.0f bytes\n" "$(${STAT} -c '%s' "$output_uki")" find "${OUTPUT}" -name 'zquickinit*.img' | sort -r | tail -n +4 | xargs -r rm find "${OUTPUT}" -name 'zquickinit*.efi' | sort -r | tail -n +4 | xargs -r rm find "${OUTPUT}" -name 'zquickinit*.vmlinuz-*' | sort -r | tail -n +4 | xargs -r rm @@ -631,7 +677,7 @@ getefi() { echo "No image found, finding latest release..." local version='' download='' version=$(curl --silent -qI "${ZQUICKEFI_URL}" | awk -F '/' '/^location/ {print substr($NF, 1, length($NF)-1)}') - download="https://github.com/midzelis/zquickinit/releases/download/$version/zquickinit.efi" + download="${ZQUICKINIT_REPO}/releases/download/$version/zquickinit.efi" source="${tmp}/zquickinit-${version}.efi" echo "Downloading from ${download} to ${source}..." curl -o "$source" --progress-bar -L "${download}" @@ -736,6 +782,7 @@ inject() { check bsdtar "libarchive-tools" check objcopy binutils check truncate coreutils + check stat coreutils check find findutils echo "Secrets were injected, appending '_injected' to name" @@ -753,7 +800,7 @@ inject() { # To append an additional initrd segment, the new archive must aligned to a # 4-byte boundary: https://unix.stackexchange.com/a/737219 - initrd_size=$(stat -c '%s' "${initrd}") + initrd_size=$(${STAT} -c '%s' "${initrd}") initrd_size=$(((initrd_size + 3) / 4 * 4)) truncate -s "${initrd_size}" "${initrd}" @@ -829,6 +876,7 @@ iso() { check xorriso xorriso check truncate coreutils check find findutils + check du coreutils local target=${1:-zquickinit.iso} local source=${2:-} @@ -844,7 +892,7 @@ iso() { local isoroot="${tmp}/iso" mkdir -p "${isoroot}" local size - read -ra size <<<"$(du --apparent-size --block-size=1M "$source")" + read -ra size <<<"$(${DU} --apparent-size --block-size=1M "$source")" local padded=$((size[0] + 12)) local part_img="${tmp}/efs_partition.img" rm -rf "${part_img}" @@ -878,6 +926,7 @@ playground() { check truncate coreutils check qemu-system-x86_64 qemu check find findutils + check nproc coreutils # shellcheck disable=SC2155 local tmp=$(tmpdir) @@ -1101,6 +1150,12 @@ if [[ $(type -t "$command") == function ]]; then shift fi ;; + --engine) + if [[ -n ${2:-} ]]; then + ENGINE=$2 + shift + fi + ;; --no-container) NOCONTAINER=1 ;; @@ -1188,6 +1243,7 @@ else echo " --no-container Do not use containers to build initramfs" echo " --release Do not add QEMU debug, or any secrets" echo " --secrets Use this folder for secrets." + echo " --engine Override automatic detection to use specific engine." echo " -d,--debug Advanced: Turn on tracing" echo " -e,--enter Advanced: Do not build an image. Execute bash and" echo " enter the builder image."