compile.sh 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210
  1. #!/bin/bash
  2. # compile.sh - Compile installer sources into a single distributable script
  3. # This script is run during the build process to create the final installer
  4. set -e
  5. SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
  6. OUTPUT_FILE="${1:-install-usm.sh}"
  7. VERSION="${2:-0.1.0}"
  8. USM_SOURCE_DIR="${3:-$SCRIPT_DIR/../src}"
  9. INVERCARGILL_TAG="v1.0.1" # e.g. "v1.0.0"; empty = default branch
  10. INVERCARGILL_JSON_TAG="v0.1.1" # e.g. "v0.1.1"; empty = default branch
  11. USM_TAG="" # empty = use local source directory
  12. # Temporary directory for building
  13. WORK_DIR=$(mktemp -d)
  14. trap "rm -rf $WORK_DIR" EXIT
  15. echo "Compiling USM installer..."
  16. echo " Version: $VERSION"
  17. echo " Output: $OUTPUT_FILE"
  18. if [[ -n "$USM_TAG" ]]; then
  19. echo " USM Source: usm.git at tag \"$USM_TAG\""
  20. else
  21. echo " USM Source: $USM_SOURCE_DIR"
  22. fi
  23. # Step 1: Clone external repositories
  24. echo "Cloning external repositories..."
  25. SOURCES_DIR="$WORK_DIR/sources"
  26. mkdir -p "$SOURCES_DIR"
  27. # Clone Invercargill
  28. INVERCARGILL_BRANCH_ARGS=()
  29. if [[ -n "$INVERCARGILL_TAG" ]]; then
  30. INVERCARGILL_BRANCH_ARGS+=(--branch "$INVERCARGILL_TAG")
  31. fi
  32. if [[ ! -d "$SOURCES_DIR/Invercargill" ]]; then
  33. echo " Cloning Invercargill..."
  34. git clone --depth 1 "${INVERCARGILL_BRANCH_ARGS[@]}" https://fabrica.unitatem.net/Tilo15/Invercargill.git "$SOURCES_DIR/Invercargill" 2>/dev/null || {
  35. echo "Warning: Could not clone Invercargill, will try without --depth 1"
  36. git clone "${INVERCARGILL_BRANCH_ARGS[@]}" https://fabrica.unitatem.net/Tilo15/Invercargill.git "$SOURCES_DIR/Invercargill" 2>/dev/null || {
  37. echo "Error: Could not clone Invercargill repository"
  38. exit 1
  39. }
  40. }
  41. fi
  42. # Clone Invercargill-Json
  43. INVERCARGILL_JSON_BRANCH_ARGS=()
  44. if [[ -n "$INVERCARGILL_JSON_TAG" ]]; then
  45. INVERCARGILL_JSON_BRANCH_ARGS+=(--branch "$INVERCARGILL_JSON_TAG")
  46. fi
  47. if [[ ! -d "$SOURCES_DIR/Invercargill-Json" ]]; then
  48. echo " Cloning Invercargill-Json..."
  49. git clone --depth 1 "${INVERCARGILL_JSON_BRANCH_ARGS[@]}" https://fabrica.unitatem.net/Tilo15/Invercargill-Json.git "$SOURCES_DIR/Invercargill-Json" 2>/dev/null || {
  50. echo "Warning: Could not clone Invercargill-Json, will try without --depth 1"
  51. git clone "${INVERCARGILL_JSON_BRANCH_ARGS[@]}" https://fabrica.unitatem.net/Tilo15/Invercargill-Json.git "$SOURCES_DIR/Invercargill-Json" 2>/dev/null || {
  52. echo "Error: Could not clone Invercargill-Json repository"
  53. exit 1
  54. }
  55. }
  56. fi
  57. # Clone USM at a tag instead of using the local source tree; the copy steps
  58. # below read everything through USM_SOURCE_DIR, so pointing it at the clone's
  59. # src/ picks up the tagged MANIFEST.usm, usm.config and spm/ helpers as well
  60. if [[ -n "$USM_TAG" ]]; then
  61. echo " Cloning USM at tag \"$USM_TAG\"..."
  62. USM_CLONE_DIR="$WORK_DIR/usm-clone"
  63. git clone --depth 1 --branch "$USM_TAG" https://fabrica.unitatem.net/Tilo15/usm.git "$USM_CLONE_DIR" 2>/dev/null || {
  64. echo "Warning: Could not clone USM at tag \"$USM_TAG\", will try without --depth 1"
  65. git clone --branch "$USM_TAG" https://fabrica.unitatem.net/Tilo15/usm.git "$USM_CLONE_DIR" 2>/dev/null || {
  66. echo "Error: Could not clone USM repository at tag \"$USM_TAG\""
  67. exit 1
  68. }
  69. }
  70. USM_SOURCE_DIR="$USM_CLONE_DIR/src"
  71. fi
  72. # Copy USM source (USM's meson.build is in src/, not project root)
  73. echo "Copying USM source..."
  74. mkdir -p "$SOURCES_DIR/usm"
  75. # USM_SOURCE_DIR points to the src/ directory which contains meson.build
  76. # Copy the entire src directory contents to usm/
  77. cp -r "$USM_SOURCE_DIR"/* "$SOURCES_DIR/usm/" 2>/dev/null || true
  78. # Copy additional root level files for reference
  79. cp "$USM_SOURCE_DIR/../MANIFEST.usm" "$SOURCES_DIR/usm/" 2>/dev/null || true
  80. cp "$USM_SOURCE_DIR/../usm.config" "$SOURCES_DIR/usm/" 2>/dev/null || true
  81. # The SPM helpers live in spm/ at the project root, outside src/, but
  82. # src/meson.build configures them via '../spm/<spm>/usm-spm-<spm>' — the
  83. # payload must therefore carry spm/ as a SIBLING of usm/ so the relative
  84. # inputs resolve inside the extracted tree
  85. echo "Copying USM SPM helpers..."
  86. mkdir -p "$SOURCES_DIR/spm"
  87. cp -r "$USM_SOURCE_DIR/../spm"/* "$SOURCES_DIR/spm/" 2>/dev/null || {
  88. echo "Error: Could not copy the spm/ directory from next to $USM_SOURCE_DIR"
  89. exit 1
  90. }
  91. # Step 2: Create the combined script header
  92. echo "Building combined script..."
  93. HEADER_FILE="$WORK_DIR/header.sh"
  94. cat > "$HEADER_FILE" << SCRIPT_HEADER
  95. #!/bin/bash
  96. # USM Installer - self-contained installation script
  97. # This script was automatically generated. Do not edit.
  98. # Version: $VERSION
  99. # Generated: $(date -u +"%Y-%m-%d %H:%M:%S UTC")
  100. set -e
  101. SCRIPT_HEADER
  102. # Step 3: Auto-detect package manager implementations
  103. PM_IMPLEMENTATIONS=()
  104. for pm_file in "$SCRIPT_DIR"/pm_*.sh; do
  105. if [[ -f "$pm_file" ]]; then
  106. # Extract PM name from filename (pm_apt.sh -> apt)
  107. pm_name=$(basename "$pm_file" .sh | sed 's/^pm_//')
  108. # Skip pm_base.sh - it's the interface, not an implementation
  109. if [[ "$pm_name" != "base" ]]; then
  110. PM_IMPLEMENTATIONS+=("$pm_name")
  111. fi
  112. fi
  113. done
  114. echo " Detected package managers: ${PM_IMPLEMENTATIONS[*]}"
  115. # Step 4: Combine all shell scripts
  116. COMBINED_FILE="$WORK_DIR/combined.sh"
  117. # Build the PM implementations array initialization
  118. PM_ARRAY_FILE="$WORK_DIR/pm_array.sh"
  119. cat > "$PM_ARRAY_FILE" << PM_ARRAY
  120. # Auto-detected package manager implementations
  121. PM_IMPLEMENTATIONS=(${PM_IMPLEMENTATIONS[*]})
  122. PM_ARRAY
  123. # Function to process a script file
  124. process_script() {
  125. local file="$1"
  126. local section="$2"
  127. echo "# === $section ==="
  128. cat "$file"
  129. }
  130. # Combine scripts in order
  131. {
  132. process_script "$SCRIPT_DIR/utils.sh" "Utils"
  133. echo ""
  134. process_script "$SCRIPT_DIR/ui.sh" "UI"
  135. echo ""
  136. # Include PM implementations first
  137. for pm_name in "${PM_IMPLEMENTATIONS[@]}"; do
  138. process_script "$SCRIPT_DIR/pm_${pm_name}.sh" "Package Manager ${pm_name}"
  139. echo ""
  140. done
  141. # Include PM array initialization
  142. cat "$PM_ARRAY_FILE"
  143. echo ""
  144. # Include pm_base which uses the array
  145. process_script "$SCRIPT_DIR/pm_base.sh" "Package Manager Base"
  146. echo ""
  147. process_script "$SCRIPT_DIR/build_config.sh" "Build Config"
  148. echo ""
  149. process_script "$SCRIPT_DIR/main.sh" "Main"
  150. echo ""
  151. # Add the main call at the very end
  152. echo "# Run main function"
  153. echo 'main "$@"'
  154. echo ""
  155. echo "# Exit before payload"
  156. echo "exit 0"
  157. } > "$COMBINED_FILE"
  158. # Replace version placeholder in combined file
  159. sed -i "s/@VERSION@/$VERSION/g" "$COMBINED_FILE"
  160. # Step 5: Create the payload
  161. echo "Creating compressed payload..."
  162. PAYLOAD_FILE="$WORK_DIR/payload.tar.xz"
  163. # Use highest compression for smaller file size
  164. tar -C "$SOURCES_DIR" -cf - . | xz -9 -T0 > "$PAYLOAD_FILE"
  165. # Step 6: Assemble final installer
  166. echo "Assembling final installer..."
  167. {
  168. cat "$HEADER_FILE"
  169. cat "$COMBINED_FILE"
  170. echo ""
  171. echo "__PAYLOAD_START__"
  172. cat "$PAYLOAD_FILE"
  173. } > "$OUTPUT_FILE"
  174. # Make executable
  175. chmod +x "$OUTPUT_FILE"
  176. # Calculate output size
  177. OUTPUT_SIZE=$(du -h "$OUTPUT_FILE" | cut -f1)
  178. echo ""
  179. echo "✓ Installer created successfully!"
  180. echo " Output: $OUTPUT_FILE"
  181. echo " Size: $OUTPUT_SIZE"