| @@ -6,6 +6,7 @@ REPO="${EXECUTOR_REPO:-RhysSullivan/executor}" · 5 unmodified lines |
| 6 | INSTALL_DIR="${EXECUTOR_INSTALL_DIR:-$HOME/.executor/bin}" | 6 | INSTALL_DIR="${EXECUTOR_INSTALL_DIR:-$HOME/.executor/bin}" |
| 7 | WEB_INSTALL_DIR="${EXECUTOR_WEB_INSTALL_DIR:-$HOME/.executor/runtime/web}" | 7 | WEB_INSTALL_DIR="${EXECUTOR_WEB_INSTALL_DIR:-$HOME/.executor/runtime/web}" |
| 8 | RUNTIME_DIR="${EXECUTOR_RUNTIME_DIR:-$HOME/.executor/runtime}" | 8 | RUNTIME_DIR="${EXECUTOR_RUNTIME_DIR:-$HOME/.executor/runtime}" |
| | 9 | BOOTSTRAP_ARCHIVE_FILENAME="executor-bootstrap-project.tar.gz" |
| 9 | REQUESTED_VERSION="${VERSION:-}" | 10 | REQUESTED_VERSION="${VERSION:-}" |
| 10 | RESOLVED_VERSION="" | 11 | RESOLVED_VERSION="" |
| 11 | BINARY_PATH="" | 12 | BINARY_PATH="" |
| @@ -15,6 +16,9 @@ SCRIPT_FILE="${BASH_SOURCE[0]:-$0}" · 3 unmodified lines |
| 15 | SCRIPT_DIR="$(cd -- "$(dirname -- "${SCRIPT_FILE}")" >/dev/null 2>&1 && pwd)" | 16 | SCRIPT_DIR="$(cd -- "$(dirname -- "${SCRIPT_FILE}")" >/dev/null 2>&1 && pwd)" |
| 16 | LOCAL_BINARY_CANDIDATE="$SCRIPT_DIR/dist/executor" | 17 | LOCAL_BINARY_CANDIDATE="$SCRIPT_DIR/dist/executor" |
| 17 | LOCAL_WEB_CANDIDATE="$SCRIPT_DIR/dist/release" | 18 | LOCAL_WEB_CANDIDATE="$SCRIPT_DIR/dist/release" |
| | 19 | LOCAL_BOOTSTRAP_CANDIDATE="$LOCAL_WEB_CANDIDATE/$BOOTSTRAP_ARCHIVE_FILENAME" |
| | 20 | CHECKSUMS_FILE="" |
| | 21 | CHECKSUMS_FETCHED="0" |
| 18 | | 22 | |
| 19 | RED='\033[0;31m' | 23 | RED='\033[0;31m' |
| 20 | MUTED='\033[0;2m' | 24 | MUTED='\033[0;2m' |
| @@ -38,6 +42,7 @@ Environment: · 17 unmodified lines |
| 38 | EXECUTOR_REPO GitHub repository to install from (default: RhysSullivan/executor) | 42 | EXECUTOR_REPO GitHub repository to install from (default: RhysSullivan/executor) |
| 39 | EXECUTOR_INSTALL_DIR Install directory (default: ~/.executor/bin) | 43 | EXECUTOR_INSTALL_DIR Install directory (default: ~/.executor/bin) |
| 40 | EXECUTOR_WEB_INSTALL_DIR Web bundle directory (default: ~/.executor/runtime/web) | 44 | EXECUTOR_WEB_INSTALL_DIR Web bundle directory (default: ~/.executor/runtime/web) |
| | 45 | EXECUTOR_BOOTSTRAP_PROJECT_ARCHIVE Optional local bootstrap archive override |
| 41 | EOF | 46 | EOF |
| 42 | } | 47 | } |
| 43 | | 48 | |
| @@ -112,9 +117,97 @@ SERVICE_DIR="$RUNTIME_DIR/services" · 68 unmodified lines |
| 112 | LOG_DIR="$RUNTIME_DIR/logs" | 117 | LOG_DIR="$RUNTIME_DIR/logs" |
| 113 | BACKEND_PID_FILE="$SERVICE_DIR/backend.pid" | 118 | BACKEND_PID_FILE="$SERVICE_DIR/backend.pid" |
| 114 | WEB_PID_FILE="$SERVICE_DIR/web.pid" | 119 | WEB_PID_FILE="$SERVICE_DIR/web.pid" |
| | 120 | WORK_DIR="$(mktemp -d)" |
| | 121 | trap 'rm -rf "$WORK_DIR"' EXIT |
| 115 | mkdir -p "$INSTALL_DIR" | 122 | mkdir -p "$INSTALL_DIR" |
| 116 | mkdir -p "$WEB_INSTALL_DIR" | 123 | mkdir -p "$WEB_INSTALL_DIR" |
| 117 | | 124 | |
| | 125 | require_command() { |
| | 126 | local command_name="$1" |
| | 127 | local install_hint="$2" |
| | 128 | if command -v "$command_name" >/dev/null 2>&1; then |
| | 129 | return |
| | 130 | fi |
| | 131 | |
| | 132 | echo -e "${RED}Missing required dependency: ${command_name}${NC}" |
| | 133 | echo "Install hint: ${install_hint}" |
| | 134 | exit 1 |
| | 135 | } |
| | 136 | |
| | 137 | sha256_of_file() { |
| | 138 | local target="$1" |
| | 139 | if command -v sha256sum >/dev/null 2>&1; then |
| | 140 | sha256sum "$target" | awk '{print $1}' |
| | 141 | return |
| | 142 | fi |
| | 143 | |
| | 144 | if command -v shasum >/dev/null 2>&1; then |
| | 145 | shasum -a 256 "$target" | awk '{print $1}' |
| | 146 | return |
| | 147 | fi |
| | 148 | |
| | 149 | echo -e "${RED}Missing checksum utility (sha256sum or shasum)${NC}" |
| | 150 | exit 1 |
| | 151 | } |
| | 152 | |
| | 153 | ensure_install_prerequisites() { |
| | 154 | require_command "curl" "Install curl from your OS package manager." |
| | 155 | require_command "tar" "Install tar from your OS package manager." |
| | 156 | if command -v sha256sum >/dev/null 2>&1 || command -v shasum >/dev/null 2>&1; then |
| | 157 | return |
| | 158 | fi |
| | 159 | |
| | 160 | echo -e "${RED}Missing required dependency: sha256sum or shasum${NC}" |
| | 161 | echo "Install hint: coreutils (sha256sum) or perl-Digest-SHA tools (shasum)." |
| | 162 | exit 1 |
| | 163 | } |
| | 164 | |
| | 165 | download_release_checksums() { |
| | 166 | if [[ "$CHECKSUMS_FETCHED" == "1" ]]; then |
| | 167 | return |
| | 168 | fi |
| | 169 | |
| | 170 | CHECKSUMS_FETCHED="1" |
| | 171 | local checksums_url |
| | 172 | if [[ -z "$REQUESTED_VERSION" ]]; then |
| | 173 | checksums_url="https://github.com/${REPO}/releases/latest/download/checksums.txt" |
| | 174 | else |
| | 175 | checksums_url="https://github.com/${REPO}/releases/download/v${RESOLVED_VERSION}/checksums.txt" |
| | 176 | fi |
| | 177 | |
| | 178 | local destination="$WORK_DIR/checksums.txt" |
| | 179 | if curl -fsSL "$checksums_url" -o "$destination"; then |
| | 180 | CHECKSUMS_FILE="$destination" |
| | 181 | fi |
| | 182 | } |
| | 183 | |
| | 184 | verify_release_checksum_if_available() { |
| | 185 | local downloaded_file="$1" |
| | 186 | local artifact_name="$2" |
| | 187 | download_release_checksums |
| | 188 | |
| | 189 | if [[ -z "$CHECKSUMS_FILE" || ! -f "$CHECKSUMS_FILE" ]]; then |
| | 190 | return |
| | 191 | fi |
| | 192 | |
| | 193 | local expected |
| | 194 | expected="$(grep -E "[[:xdigit:]]+[[:space:]]+${artifact_name}$" "$CHECKSUMS_FILE" | awk '{print $1}' | head -n1)" |
| | 195 | if [[ -z "$expected" ]]; then |
| | 196 | return |
| | 197 | fi |
| | 198 | |
| | 199 | local actual |
| | 200 | actual="$(sha256_of_file "$downloaded_file")" |
| | 201 | if [[ "$actual" != "$expected" ]]; then |
| | 202 | echo -e "${RED}Checksum mismatch for ${artifact_name}${NC}" |
| | 203 | echo " expected: ${expected}" |
| | 204 | echo " actual: ${actual}" |
| | 205 | exit 1 |
| | 206 | fi |
| | 207 | } |
| | 208 | |
| | 209 | ensure_install_prerequisites |
| | 210 | |
| 118 | install_local_binary() { | 211 | install_local_binary() { |
| 119 | local src="$1" | 212 | local src="$1" |
| 120 | local tmp_target | 213 | local tmp_target |
| @@ -151,8 +244,7 @@ install_web_bundle_from_archive() { · 30 unmodified lines |
| 151 | | 244 | |
| 152 | install_web_bundle() { | 245 | install_web_bundle() { |
| 153 | local web_url | 246 | local web_url |
| 154 | local temp_archive | 247 | local temp_archive="$WORK_DIR/$web_filename" |
| 155 | temp_archive="$(mktemp)" | | |
| 156 | | 248 | |
| 157 | if [[ -z "$REQUESTED_VERSION" ]]; then | 249 | if [[ -z "$REQUESTED_VERSION" ]]; then |
| 158 | web_url="https://github.com/${REPO}/releases/latest/download/${web_filename}" | 250 | web_url="https://github.com/${REPO}/releases/latest/download/${web_filename}" |
| @@ -161,12 +253,11 @@ install_web_bundle() { · 2 unmodified lines |
| 161 | fi | 253 | fi |
| 162 | | 254 | |
| 163 | if curl -fsSL "$web_url" -o "$temp_archive"; then | 255 | if curl -fsSL "$web_url" -o "$temp_archive"; then |
| | 256 | verify_release_checksum_if_available "$temp_archive" "$web_filename" |
| 164 | echo -e "${MUTED}Installing web bundle${NC} ${web_filename}" | 257 | echo -e "${MUTED}Installing web bundle${NC} ${web_filename}" |
| 165 | install_web_bundle_from_archive "$temp_archive" | 258 | install_web_bundle_from_archive "$temp_archive" |
| 166 | rm -f "$temp_archive" | | |
| 167 | return | 259 | return |
| 168 | fi | 260 | fi |
| 169 | rm -f "$temp_archive" | | |
| 170 | | 261 | |
| 171 | local local_web_archive="$LOCAL_WEB_CANDIDATE/${web_filename}" | 262 | local local_web_archive="$LOCAL_WEB_CANDIDATE/${web_filename}" |
| 172 | if [[ -f "$local_web_archive" ]]; then | 263 | if [[ -f "$local_web_archive" ]]; then |
| @@ -200,8 +291,7 @@ else · 27 unmodified lines |
| 200 | url="https://github.com/${REPO}/releases/download/v${version}/${filename}" | 291 | url="https://github.com/${REPO}/releases/download/v${version}/${filename}" |
| 201 | fi | 292 | fi |
| 202 | | 293 | |
| 203 | tmp_dir="$(mktemp -d)" | 294 | tmp_dir="$WORK_DIR" |
| 204 | trap 'rm -rf "$tmp_dir"' EXIT | | |
| 205 | | 295 | |
| 206 | echo -e "${MUTED}Installing ${APP}${NC} ${version:-latest}" | 296 | echo -e "${MUTED}Installing ${APP}${NC} ${version:-latest}" |
| 207 | if ! curl -fsSL "$url" -o "$tmp_dir/$filename"; then | 297 | if ! curl -fsSL "$url" -o "$tmp_dir/$filename"; then |
| @@ -217,6 +307,7 @@ else · 9 unmodified lines |
| 217 | exit 1 | 307 | exit 1 |
| 218 | fi | 308 | fi |
| 219 | else | 309 | else |
| | 310 | verify_release_checksum_if_available "$tmp_dir/$filename" "$filename" |
| 220 | tar -xzf "$tmp_dir/$filename" -C "$tmp_dir" | 311 | tar -xzf "$tmp_dir/$filename" -C "$tmp_dir" |
| 221 | | 312 | |
| 222 | if [[ ! -f "$tmp_dir/$APP" ]]; then | 313 | if [[ ! -f "$tmp_dir/$APP" ]]; then |
| @@ -347,19 +438,24 @@ download_bootstrap_project_archive() { · 124 unmodified lines |
| 347 | return 1 | 438 | return 1 |
| 348 | fi | 439 | fi |
| 349 | | 440 | |
| 350 | local urls=() | 441 | if [[ -z "$REQUESTED_VERSION" ]]; then |
| 351 | if [[ -n "$RESOLVED_VERSION" ]]; then | 442 | local latest_url="https://github.com/${REPO}/releases/latest/download/${BOOTSTRAP_ARCHIVE_FILENAME}" |
| 352 | urls+=("https://github.com/${REPO}/archive/refs/tags/v${RESOLVED_VERSION}.tar.gz") | 443 | if curl -fsSL "$latest_url" -o "$destination"; then |
| 353 | urls+=("https://github.com/${REPO}/archive/refs/tags/${RESOLVED_VERSION}.tar.gz") | 444 | verify_release_checksum_if_available "$destination" "$BOOTSTRAP_ARCHIVE_FILENAME" |
| 354 | fi | | |
| 355 | urls+=("https://github.com/${REPO}/archive/refs/heads/main.tar.gz") | | |
| 356 | | | |
| 357 | local url | | |
| 358 | for url in "${urls[@]}"; do | | |
| 359 | if curl -fsSL "$url" -o "$destination"; then | | |
| 360 | return 0 | 445 | return 0 |
| 361 | fi | 446 | fi |
| 362 | done | 447 | else |
| | 448 | local versioned_url="https://github.com/${REPO}/releases/download/v${RESOLVED_VERSION}/${BOOTSTRAP_ARCHIVE_FILENAME}" |
| | 449 | if curl -fsSL "$versioned_url" -o "$destination"; then |
| | 450 | verify_release_checksum_if_available "$destination" "$BOOTSTRAP_ARCHIVE_FILENAME" |
| | 451 | return 0 |
| | 452 | fi |
| | 453 | fi |
| | 454 | |
| | 455 | if [[ -f "$LOCAL_BOOTSTRAP_CANDIDATE" ]]; then |
| | 456 | cp "$LOCAL_BOOTSTRAP_CANDIDATE" "$destination" |
| | 457 | return 0 |
| | 458 | fi |
| 363 | | 459 | |
| 364 | return 1 | 460 | return 1 |
| 365 | } | 461 | } |
| @@ -367,7 +463,7 @@ download_bootstrap_project_archive() { · 1 unmodified line |
| 367 | prepare_release_bootstrap_project() { | 463 | prepare_release_bootstrap_project() { |
| 368 | local bootstrap_root="$RUNTIME_DIR/bootstrap-project" | 464 | local bootstrap_root="$RUNTIME_DIR/bootstrap-project" |
| 369 | local version_file="$bootstrap_root/.executor-bootstrap-version" | 465 | local version_file="$bootstrap_root/.executor-bootstrap-version" |
| 370 | local cache_key="${RESOLVED_VERSION:-main}" | 466 | local cache_key="${RESOLVED_VERSION:-latest}" |
| 371 | | 467 | |
| 372 | if [[ -f "$version_file" ]] && [[ "$(cat "$version_file" 2>/dev/null || true)" == "$cache_key" ]]; then | 468 | if [[ -f "$version_file" ]] && [[ "$(cat "$version_file" 2>/dev/null || true)" == "$cache_key" ]]; then |
| 373 | if is_convex_project_dir "$bootstrap_root"; then | 469 | if is_convex_project_dir "$bootstrap_root"; then |
| @@ -380,10 +476,8 @@ prepare_release_bootstrap_project() { · 6 unmodified lines |
| 380 | fi | 476 | fi |
| 381 | fi | 477 | fi |
| 382 | | 478 | |
| 383 | local archive_file | 479 | local archive_file="$WORK_DIR/$BOOTSTRAP_ARCHIVE_FILENAME" |
| 384 | archive_file="$(mktemp)" | | |
| 385 | if ! download_bootstrap_project_archive "$archive_file"; then | 480 | if ! download_bootstrap_project_archive "$archive_file"; then |
| 386 | rm -f "$archive_file" | | |
| 387 | printf "" | 481 | printf "" |
| 388 | return | 482 | return |
| 389 | fi | 483 | fi |
| @@ -391,12 +485,10 @@ prepare_release_bootstrap_project() { · 1 unmodified line |
| 391 | rm -rf "$bootstrap_root" | 485 | rm -rf "$bootstrap_root" |
| 392 | mkdir -p "$bootstrap_root" | 486 | mkdir -p "$bootstrap_root" |
| 393 | if ! tar -xzf "$archive_file" -C "$bootstrap_root" --strip-components=1; then | 487 | if ! tar -xzf "$archive_file" -C "$bootstrap_root" --strip-components=1; then |
| 394 | rm -f "$archive_file" | | |
| 395 | rm -rf "$bootstrap_root" | 488 | rm -rf "$bootstrap_root" |
| 396 | printf "" | 489 | printf "" |
| 397 | return | 490 | return |
| 398 | fi | 491 | fi |
| 399 | rm -f "$archive_file" | | |
| 400 | | 492 | |
| 401 | local project_dir="$bootstrap_root" | 493 | local project_dir="$bootstrap_root" |
| 402 | if is_convex_project_dir "$bootstrap_root"; then | 494 | if is_convex_project_dir "$bootstrap_root"; then |