compile.sh 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212
  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. # Temporary directory for building
  10. WORK_DIR=$(mktemp -d)
  11. trap "rm -rf $WORK_DIR" EXIT
  12. echo "Compiling USM installer..."
  13. echo " Version: $VERSION"
  14. echo " Output: $OUTPUT_FILE"
  15. echo " USM Source: $USM_SOURCE_DIR"
  16. # Step 1: Clone external repositories
  17. echo "Cloning external repositories..."
  18. SOURCES_DIR="$WORK_DIR/sources"
  19. mkdir -p "$SOURCES_DIR"
  20. # Clone Invercargill
  21. if [[ ! -d "$SOURCES_DIR/Invercargill" ]]; then
  22. echo " Cloning Invercargill..."
  23. git clone --depth 1 https://fabrica.unitatem.net/Tilo15/Invercargill.git "$SOURCES_DIR/Invercargill" 2>/dev/null || {
  24. echo "Warning: Could not clone Invercargill, will try without --depth 1"
  25. git clone https://fabrica.unitatem.net/Tilo15/Invercargill.git "$SOURCES_DIR/Invercargill" 2>/dev/null || {
  26. echo "Error: Could not clone Invercargill repository"
  27. exit 1
  28. }
  29. }
  30. fi
  31. # Clone Invercargill-Json
  32. if [[ ! -d "$SOURCES_DIR/Invercargill-Json" ]]; then
  33. echo " Cloning Invercargill-Json..."
  34. git clone --depth 1 https://git.sr.ht/~tilo15/Invercargill-Json "$SOURCES_DIR/Invercargill-Json" 2>/dev/null || {
  35. echo "Warning: Could not clone Invercargill-Json, will try without --depth 1"
  36. git clone https://git.sr.ht/~tilo15/Invercargill-Json "$SOURCES_DIR/Invercargill-Json" 2>/dev/null || {
  37. echo "Error: Could not clone Invercargill-Json repository"
  38. exit 1
  39. }
  40. }
  41. fi
  42. # Copy USM source
  43. echo "Copying USM source..."
  44. mkdir -p "$SOURCES_DIR/usm"
  45. cp -r "$USM_SOURCE_DIR" "$SOURCES_DIR/usm/src"
  46. cp "$USM_SOURCE_DIR/../MANIFEST.usm" "$SOURCES_DIR/usm/" 2>/dev/null || true
  47. cp "$USM_SOURCE_DIR/../usm.config" "$SOURCES_DIR/usm/" 2>/dev/null || true
  48. # Step 2: Create the combined script header
  49. echo "Building combined script..."
  50. HEADER_FILE="$WORK_DIR/header.sh"
  51. cat > "$HEADER_FILE" << SCRIPT_HEADER
  52. #!/bin/bash
  53. # USM Installer - self-contained installation script
  54. # This script was automatically generated. Do not edit.
  55. # Version: $VERSION
  56. # Generated: $(date -u +"%Y-%m-%d %H:%M:%S UTC")
  57. set -e
  58. SCRIPT_HEADER
  59. # Step 3: Combine all shell scripts
  60. # We need to rename the PM functions to avoid conflicts
  61. COMBINED_FILE="$WORK_DIR/combined.sh"
  62. # Function to process a bash script (minify and adapt)
  63. process_script() {
  64. local file="$1"
  65. local section="$2"
  66. echo "# === $section ==="
  67. # For PM files, we need to prefix the functions
  68. case "$section" in
  69. "Package Manager APT")
  70. # Rename functions with apt_ prefix
  71. sed -e 's/^pm_is_installed()/pm_apt_is_installed()/' \
  72. -e 's/^pm_get_package_name()/pm_apt_get_package_name()/' \
  73. -e 's/^pm_update()/pm_apt_update()/' \
  74. -e 's/^pm_install()/pm_apt_install()/' \
  75. -e 's/^get_missing_deps()/get_missing_deps_apt()/' \
  76. "$file"
  77. ;;
  78. "Package Manager DNF")
  79. # Rename functions with dnf_ prefix
  80. sed -e 's/^pm_is_installed()/pm_dnf_is_installed()/' \
  81. -e 's/^pm_get_package_name()/pm_dnf_get_package_name()/' \
  82. -e 's/^pm_update()/pm_dnf_update()/' \
  83. -e 's/^pm_install()/pm_dnf_install()/' \
  84. -e 's/^get_missing_deps()/get_missing_deps_dnf()/' \
  85. "$file"
  86. ;;
  87. *)
  88. cat "$file"
  89. ;;
  90. esac
  91. }
  92. # Create the dispatcher functions
  93. DISPATCHER_FILE="$WORK_DIR/dispatcher.sh"
  94. cat > "$DISPATCHER_FILE" << 'DISPATCHER'
  95. # === Package Manager Dispatcher ===
  96. # These functions dispatch to the appropriate PM implementation
  97. pm_is_installed() {
  98. case "$PM_TYPE" in
  99. apt) pm_apt_is_installed "$@" ;;
  100. dnf) pm_dnf_is_installed "$@" ;;
  101. esac
  102. }
  103. pm_get_package_name() {
  104. case "$PM_TYPE" in
  105. apt) pm_apt_get_package_name "$@" ;;
  106. dnf) pm_dnf_get_package_name "$@" ;;
  107. esac
  108. }
  109. pm_update() {
  110. case "$PM_TYPE" in
  111. apt) pm_apt_update "$@" ;;
  112. dnf) pm_dnf_update "$@" ;;
  113. esac
  114. }
  115. pm_install() {
  116. case "$PM_TYPE" in
  117. apt) pm_apt_install "$@" ;;
  118. dnf) pm_dnf_install "$@" ;;
  119. esac
  120. }
  121. get_missing_deps() {
  122. case "$PM_TYPE" in
  123. apt) get_missing_deps_apt "$@" ;;
  124. dnf) get_missing_deps_dnf "$@" ;;
  125. esac
  126. }
  127. DISPATCHER
  128. # Combine scripts in order - IMPORTANT:
  129. # 1. PM implementations (apt, dnf) come first with prefixed names
  130. # 2. Dispatcher comes next to provide the generic interface
  131. # 3. pm_base.sh uses the generic interface (get_missing_deps, etc.)
  132. # 4. main.sh and others come last
  133. {
  134. process_script "$SCRIPT_DIR/utils.sh" "Utils"
  135. echo ""
  136. process_script "$SCRIPT_DIR/ui.sh" "UI"
  137. echo ""
  138. # PM implementations first (with prefixed function names)
  139. process_script "$SCRIPT_DIR/pm_apt.sh" "Package Manager APT"
  140. echo ""
  141. process_script "$SCRIPT_DIR/pm_dnf.sh" "Package Manager DNF"
  142. echo ""
  143. # Dispatcher provides the generic interface using PM_TYPE
  144. cat "$DISPATCHER_FILE"
  145. echo ""
  146. # Now pm_base.sh can use the generic interface
  147. process_script "$SCRIPT_DIR/pm_base.sh" "Package Manager Base"
  148. echo ""
  149. process_script "$SCRIPT_DIR/build_config.sh" "Build Config"
  150. echo ""
  151. process_script "$SCRIPT_DIR/main.sh" "Main"
  152. echo ""
  153. # Add the main call at the very end
  154. echo "# Run main function"
  155. echo 'main "$@"'
  156. } > "$COMBINED_FILE"
  157. # Replace version placeholder in combined file
  158. sed -i "s/@VERSION@/$VERSION/g" "$COMBINED_FILE"
  159. # Step 4: Create the payload
  160. echo "Creating compressed payload..."
  161. PAYLOAD_FILE="$WORK_DIR/payload.tar.xz"
  162. # Use highest compression for smaller file size
  163. tar -C "$SOURCES_DIR" -cf - . | xz -9 -T0 > "$PAYLOAD_FILE"
  164. # Step 5: Assemble final installer
  165. echo "Assembling final installer..."
  166. {
  167. cat "$HEADER_FILE"
  168. cat "$COMBINED_FILE"
  169. echo ""
  170. echo "__PAYLOAD_START__"
  171. cat "$PAYLOAD_FILE"
  172. } > "$OUTPUT_FILE"
  173. # Make executable
  174. chmod +x "$OUTPUT_FILE"
  175. # Calculate output size
  176. OUTPUT_SIZE=$(du -h "$OUTPUT_FILE" | cut -f1)
  177. echo ""
  178. echo "✓ Installer created successfully!"
  179. echo " Output: $OUTPUT_FILE"
  180. echo " Size: $OUTPUT_SIZE"