/ upload.sh
upload.sh
  1  #!/usr/bin/env bash
  2  set -euo pipefail
  3  
  4  ROOT="target/dx/web/release/web/public"
  5  BASE_URL="http://ceratina.local/api/filesystem/sd"
  6  
  7  c_reset=$'\033[0m'
  8  c_dim=$'\033[2m'
  9  c_bold=$'\033[1m'
 10  c_cyan=$'\033[36m'
 11  c_green=$'\033[32m'
 12  c_yellow=$'\033[33m'
 13  c_red=$'\033[31m'
 14  c_magenta=$'\033[35m'
 15  
 16  printf "\n  ${c_bold}${c_cyan}ceratina deploy${c_reset}\n"
 17  printf "  ${c_dim}──────────────────────────────────────${c_reset}\n"
 18  
 19  # printf "  ${c_dim}Flashing firmware ...${c_reset}\n"
 20  # pio run -t upload || {
 21  #   echo "${c_red}error:${c_reset} firmware flash failed" >&2
 22  #   exit 1
 23  # }
 24  # printf "  ${c_green}flashed${c_reset}\n"
 25  
 26  [ -d "$ROOT" ] || {
 27    echo "${c_red}error:${c_reset} missing dir $ROOT" >&2
 28    exit 1
 29  }
 30  
 31  # ── Prune stale assets ────────────────────────────────
 32  # index.html references only the current build's hashed files.
 33  # Previous builds leave orphaned assets that waste upload bandwidth.
 34  if [ -f "$ROOT/index.html" ]; then
 35    stale=0
 36    for f in "$ROOT"/assets/*; do
 37      [ -f "$f" ] || continue
 38      base=$(basename "$f")
 39      # Skip .gz companions — they'll be removed with their source
 40      [[ "$base" == *.gz ]] && continue
 41      # Keep files referenced by index.html
 42      if grep -qF "$base" "$ROOT/index.html"; then
 43        continue
 44      fi
 45      # Keep files referenced by the main JS bundle
 46      main_js=$(grep -o 'assets/web-[^"]*\.js' "$ROOT/index.html" | head -1)
 47      if [ -n "$main_js" ] && [ -f "$ROOT/$main_js" ] && grep -qF "$base" "$ROOT/$main_js"; then
 48        continue
 49      fi
 50      rm -f "$f" "${f}.gz"
 51      ((stale += 1))
 52    done
 53    if ((stale > 0)); then
 54      printf "  ${c_yellow}pruned${c_reset} %d stale assets\n" "$stale"
 55    fi
 56  fi
 57  
 58  HOST="ceratina.local"
 59  printf "  ${c_dim}Waiting for ${HOST} ...${c_reset}"
 60  until ping -c1 -W1 "$HOST" &>/dev/null; do
 61    printf "${c_dim}.${c_reset}"
 62    sleep 1
 63  done
 64  printf " ${c_green}online${c_reset}\n"
 65  
 66  human_size() {
 67    local bytes=$1
 68    if ((bytes >= 1048576)); then
 69      printf "%.1f MB" "$(echo "scale=1; $bytes / 1048576" | bc)"
 70    elif ((bytes >= 1024)); then
 71      printf "%.1f KB" "$(echo "scale=1; $bytes / 1024" | bc)"
 72    else
 73      printf "%d B" "$bytes"
 74    fi
 75  }
 76  
 77  echo
 78  
 79  printf "${c_dim}  Compressing ...${c_reset}"
 80  compressed=0
 81  find "$ROOT" -type f \( -name "*.wasm" -o -name "*.js" -o -name "*.css" -o -name "*.html" -o -name "*.svg" \) | while read f; do
 82    gzip -kf "$f"
 83  done
 84  printf " ${c_green}done${c_reset}\n"
 85  
 86  mapfile -d '' files < <(find "$ROOT" -type f -print0 | sort -z)
 87  total=${#files[@]}
 88  
 89  upload_count=0
 90  skip_count=0
 91  total_bytes=0
 92  for f in "${files[@]}"; do
 93    if [[ "$f" != *.gz ]] && [[ -f "${f}.gz" ]]; then
 94      ((skip_count += 1))
 95    else
 96      ((upload_count += 1))
 97      total_bytes=$((total_bytes + $(stat -f%z "$f" 2>/dev/null || stat -c%s "$f" 2>/dev/null)))
 98    fi
 99  done
100  
101  printf "  ${c_dim}target${c_reset}  %s\n" "$BASE_URL"
102  printf "  ${c_dim}upload${c_reset}  ${c_bold}%d${c_reset} files  ${c_dim}(%s)${c_reset}\n" "$upload_count" "$(human_size $total_bytes)"
103  printf "  ${c_dim}skip${c_reset}    %d files  ${c_dim}(uncompressed originals)${c_reset}\n" "$skip_count"
104  printf "${c_dim}  ──────────────────────────────────────${c_reset}\n"
105  echo
106  
107  start_ts=$(date +%s)
108  uploaded=0
109  uploaded_bytes=0
110  
111  for f in "${files[@]}"; do
112    rel="${f#"$ROOT"/}"
113  
114    if [[ "$f" != *.gz ]] && [[ -f "${f}.gz" ]]; then
115      continue
116    fi
117  
118    ((uploaded += 1))
119    fsize=$(stat -f%z "$f" 2>/dev/null || stat -c%s "$f" 2>/dev/null)
120    uploaded_bytes=$((uploaded_bytes + fsize))
121  
122    ext="${rel##*.}"
123    case "$ext" in
124    gz) icon="$c_magenta" ;;
125    wasm) icon="$c_yellow" ;;
126    js) icon="$c_yellow" ;;
127    css) icon="$c_cyan" ;;
128    html) icon="$c_green" ;;
129    svg | png) icon="$c_magenta" ;;
130    bin) icon="$c_red" ;;
131    *) icon="$c_dim" ;;
132    esac
133  
134    printf "  ${c_dim}[%d/%d]${c_reset} ${icon}%s${c_reset} ${c_dim}(%s)${c_reset}\n" \
135      "$uploaded" "$upload_count" "$rel" "$(human_size $fsize)"
136  
137    if ! curl -X PUT --fail --progress-bar \
138      -o /dev/null \
139      -F "file=@${f}" \
140      "${BASE_URL}/${rel}"; then
141      printf "  ${c_red}FAIL${c_reset} %s\n\n" "$rel"
142      continue
143    fi
144  
145    printf "  ${c_green}  ok${c_reset}\n"
146  done
147  
148  elapsed=$(($(date +%s) - start_ts))
149  echo
150  printf "${c_dim}  ──────────────────────────────────────${c_reset}\n"
151  printf "  ${c_bold}${c_green}done${c_reset}  %d files  ${c_dim}%s in %ss${c_reset}\n" "$uploaded" "$(human_size $uploaded_bytes)" "$elapsed"
152  echo