#!/usr/bin/env bash set -euo pipefail usage() { echo "Usage: $0 --payload-dir DIR --entrypoint FILE [--output FILE]" echo " $0 -p DIR -e FILE [-o FILE]" exit 1 } # 📥 Default values HEADER="sfx_header.sh" PAYLOAD_DIR="" ENTRYPOINT="" OUTPUT="sfx.run" # 📋 Process arguments while [[ $# -gt 0 ]]; do case "$1" in --payload-dir|-p) PAYLOAD_DIR="$2" shift 2 ;; --entrypoint|-e) ENTRYPOINT="$2" shift 2 ;; --output|-o) OUTPUT="$2" shift 2 ;; *) echo "❌ Unknown option: $1" >&2 usage ;; esac done # ✅ Validation [[ -z "$PAYLOAD_DIR" || -z "$ENTRYPOINT" ]] && usage [[ ! -d "$PAYLOAD_DIR" ]] && { echo "❌ Payload directory not found: $PAYLOAD_DIR" >&2; exit 1; } [[ ! -f "$PAYLOAD_DIR/$ENTRYPOINT" ]] && { echo "❌ Entrypoint not found in payload: $ENTRYPOINT" >&2; exit 1; } # 🧊 Temporary directory BUILD_TMP="$(mktemp -d "${TMPDIR:-/tmp}/sfxbuild.XXXXXX")" PAYLOAD_ARCHIVE="$BUILD_TMP/payload.tar.zst" HEADER_TMP="$BUILD_TMP/sfx_header.final" cleanup() { rm -rf "$BUILD_TMP" } trap cleanup EXIT echo "📦 Creating payload (→ $PAYLOAD_ARCHIVE)..." tar -cf - -C "$PAYLOAD_DIR" . | tee >(wc -c > "$BUILD_TMP/raw_size") | zstd -19 -T0 -o "$PAYLOAD_ARCHIVE" RAW_SIZE=$(numfmt --to=iec < "$BUILD_TMP/raw_size") # 🧭 Find marker ARCHIVE_LINE=$(grep -n '^__ARCHIVE_BEGIN__$' "$HEADER" | cut -d: -f1) [[ ! "$ARCHIVE_LINE" =~ ^[0-9]+$ ]] && { echo "❌ Error: Marker __ARCHIVE_BEGIN__ not found!" >&2 exit 1 } echo "🧮 Archive starts from line $ARCHIVE_LINE" # 🛠️ Replace placeholders sed "s|__ARCHIVE_LINE__|$ARCHIVE_LINE|" "$HEADER" | \ sed "s|__ENTRYPOINT__|$ENTRYPOINT|" | \ sed '/^__ARCHIVE_BEGIN__$/d' > "$HEADER_TMP" # 🔗 Combine cat "$HEADER_TMP" "$PAYLOAD_ARCHIVE" > "$OUTPUT" chmod +x "$OUTPUT" # 📊 Output FINAL_SIZE=$(du -h "$OUTPUT" | cut -f1) echo "✅ Done: $OUTPUT" echo " 📁 Original size: $RAW_SIZE" echo " 📦 Output file: $FINAL_SIZE"