feat: add script for creating self-extracting archives
- Introduces a script to build self-extracting archives with validation - Includes payload compression, placeholder replacement, and output creation - Adds a header script to extract and execute the embedded entrypoint
This commit is contained in:
78
build_sfx.sh
Executable file
78
build_sfx.sh
Executable file
@@ -0,0 +1,78 @@
|
|||||||
|
#!/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"
|
19
sfx_header.sh
Normal file
19
sfx_header.sh
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
TMPDIR="$(mktemp -d "${TMPDIR:-/tmp}/sfx.XXXXXX")"
|
||||||
|
ARCHIVE_LINE=__ARCHIVE_LINE__
|
||||||
|
|
||||||
|
cleanup() {
|
||||||
|
rm -rf "$TMPDIR"
|
||||||
|
}
|
||||||
|
trap cleanup EXIT
|
||||||
|
|
||||||
|
tail -n +$ARCHIVE_LINE "$0" | unzstd | tar -xf - -C "$TMPDIR"
|
||||||
|
|
||||||
|
ENTRYPOINT="$TMPDIR/__ENTRYPOINT__"
|
||||||
|
chmod +x "$ENTRYPOINT"
|
||||||
|
"$ENTRYPOINT" "$@"
|
||||||
|
exit_code=$?
|
||||||
|
exit $exit_code
|
||||||
|
__ARCHIVE_BEGIN__
|
Reference in New Issue
Block a user