浏览代码

fix cache maybe?

trae 3 月之前
父节点
当前提交
018b8022ce
共有 3 个文件被更改,包括 186 次插入293 次删除
  1. 57 168
      .github/actions/cache-restore/action.yml
  2. 126 122
      .github/actions/cache-save/action.yml
  3. 3 3
      .github/workflows/build.yml

+ 57 - 168
.github/actions/cache-restore/action.yml

@@ -1,94 +1,41 @@
 name: 'Restore Cache'
-description: 'Archive, split if necessary, and upload cache to GitHub Releases for later retrieval.'
+description: ""
 
 inputs:
   cache_path:
-    description: 'Single path where cache should be restored (use cache_paths for multiple)'
-    required: false
-    type: string
-  cache_paths:
-    description: 'Multiline list of paths where caches should be restored (one per line)'
-    required: false
+    description: 'Path where cache should be restored'
+    required: true
     type: string
-    default: ""
   cache_key:
-    description: 'Primary key to restore cache (use cache_keys for multiple)'
-    required: false
-    type: string
-  cache_keys:
-    description: 'Multiline list of primary keys to restore caches (one per line, must match cache_paths)'
-    required: false
+    description: 'Primary key to restore cache'
+    required: true
     type: string
-    default: ""
   restore_keys:
     description: 'Multiline list of keys (fallback prefixes)'
     required: false
     type: string
     default: ""
   cache_bucket:
-    description: 'Single tag name for the release (use cache_buckets for multiple)'
-    required: false
+    description: 'The tag name for the release (e.g., general-cache)'
+    required: true
     default: 'general-cache'
-  cache_buckets:
-    description: 'Multiline list of tag names for releases (one per line, must match cache_paths)'
-    required: false
-    type: string
-    default: ""
-  compression_level:
-    description: 'Compression level (0-9). 0 = No compression, 1 = Fast, 19 = Best.'
-    required: false
-    type: number
-    default: 6
-
-outputs:
-  cache-hit:
-    description: 'Returns "true" if at least one cache was found and restored, "false" otherwise'
-    value: ${{ steps.restore.outputs.cache-hit }}
-  cache-key:
-    description: 'The key that matched (primary or fallback). Multiple entries joined by comma.'
-    value: ${{ steps.restore.outputs.cache-key }}
-  cache-size:
-    description: 'Size of restored cache in human-readable format. Multiple entries joined by comma.'
-    value: ${{ steps.restore.outputs.cache-size }}
 
 runs:
   using: 'composite'
   steps:
     - name: Detect and Download Cache
-      id: restore
       shell: bash
-      working-directory: ${{ github.workspace }}
       env:
         TARGET_REPO: "${{ github.repository }}"
       run: |
-        set -euo pipefail
-
-        # Validate and parse inputs
-        PATHS_INPUT="${{ inputs.cache_paths }}"
-        KEYS_INPUT="${{ inputs.cache_keys }}"
-        BUCKETS_INPUT="${{ inputs.cache_buckets }}"
+        # Detect and Download Cache
+        if [ "${{ inputs.debug }}" = "true" ]; then set -x; fi
         
-        # If multiple inputs are empty, fall back to single inputs
-        if [ -z "$PATHS_INPUT" ]; then
-          PATHS_INPUT="${{ inputs.cache_path }}"
-        fi
-        if [ -z "$KEYS_INPUT" ]; then
-          KEYS_INPUT="${{ inputs.cache_key }}"
-        fi
-        if [ -z "$BUCKETS_INPUT" ]; then
-          BUCKETS_INPUT="${{ inputs.cache_bucket }}"
-        fi
-        
-        # Split inputs into arrays
-        IFS=$'\n' read -rd '' -a PATHS_ARRAY <<<"$PATHS_INPUT" || true
-        IFS=$'\n' read -rd '' -a KEYS_ARRAY <<<"$KEYS_INPUT" || true
-        IFS=$'\n' read -rd '' -a BUCKETS_ARRAY <<<"$BUCKETS_INPUT" || true
+        cd "$GITHUB_WORKSPACE"
         
-        # Validate array lengths match
-        if [[ ${#PATHS_ARRAY[@]} -ne ${#KEYS_ARRAY[@]} ]] || [[ ${#PATHS_ARRAY[@]} -ne ${#BUCKETS_ARRAY[@]} ]]; then
-          echo "::error::Mismatch in array lengths: paths=${#PATHS_ARRAY[@]}, keys=${#KEYS_ARRAY[@]}, buckets=${#BUCKETS_ARRAY[@]}"
-          exit 1
-        fi
+        TAG_NAME="${{ inputs.cache_bucket }}"
+        BASE_URL="https://github.com/${TARGET_REPO}/releases/download/$TAG_NAME"
+        ASSETS_URL="https://github.com/${TARGET_REPO}/releases/expanded_assets/$TAG_NAME"
         
         ARIA2_OPTS=(
           "-x16" "-s16" "-k1M" "-j5" "--file-allocation=none"
@@ -97,53 +44,36 @@ runs:
           "--header=Connection: keep-alive"
         )
         
-        ARIA2_OPTS+=("--quiet" "--summary-interval=0" "--console-log-level=error")
+        if [ "${{ inputs.debug }}" != "true" ]; then
+          ARIA2_OPTS+=("--quiet" "--summary-interval=0" "--console-log-level=error")
+        fi
         
-        # Collect results
-        OVERALL_HIT=false
-        MATCHED_KEYS=()
-        CACHE_SIZES=()
+        echo "::group:: Fetching Asset List"
+        HTTP_RESPONSE=$(curl -sL -A "Mozilla/5.0" -w "%{http_code}" "$ASSETS_URL" -o assets.html || echo "404")
         
-        # Process each cache entry
-        for ((idx=0; idx<${#PATHS_ARRAY[@]}; idx++)); do
-          CACHE_PATH="${PATHS_ARRAY[$idx]}"
-          CACHE_KEY="${KEYS_ARRAY[$idx]}"
-          CACHE_BUCKET="${BUCKETS_ARRAY[$idx]}"
-          
-          [ -z "$CACHE_PATH" ] && continue
-          
-          TAG_NAME="$CACHE_BUCKET"
-          BASE_URL="https://github.com/${TARGET_REPO}/releases/download/$TAG_NAME"
-          ASSETS_URL="https://github.com/${TARGET_REPO}/releases/expanded_assets/$TAG_NAME"
-          
-          echo "::group:: [$((idx+1))/${#PATHS_ARRAY[@]}] Cache: $CACHE_BUCKET - Fetching Asset List"
-          HTTP_RESPONSE=$(curl -sL -A "Mozilla/5.0" -w "%{http_code}" "$ASSETS_URL" -o assets.html || echo "404")
-          
-          if [ "$HTTP_RESPONSE" -eq 200 ]; then
-            ALL_ASSETS=$(grep -oP "download/$TAG_NAME/\K[^\"' ]+" assets.html | sort -u || echo "")
-          else
-            echo "Status $HTTP_RESPONSE: Failed to fetch assets from scraper endpoint."
-            ALL_ASSETS=""
-          fi
-          rm -f assets.html
-          
-          if [ -z "$ALL_ASSETS" ]; then
-            echo "No assets found in bucket '$TAG_NAME'. Skipping."
-            echo "::endgroup::"
-            continue
-          fi
-          
+        if [ "$HTTP_RESPONSE" -eq 200 ]; then
+          ALL_ASSETS=$(grep -oP "download/$TAG_NAME/\K[^\"' ]+" assets.html | sort -u || echo "")
+        else
+          echo "Status $HTTP_RESPONSE: Failed to fetch assets from scraper endpoint."
+          ALL_ASSETS=""
+        fi
+        rm -f assets.html
+        
+        if [ -z "$ALL_ASSETS" ]; then
+          echo "No assets found in bucket '$TAG_NAME'. Skipping search."
+          echo "::endgroup::"
+        else
           echo "Successfully fetched asset list. Has $(echo "$ALL_ASSETS" | wc -l) assets."
           echo "::endgroup::"
           
-          SEARCH_LIST=$(printf "%s\n%s" "$CACHE_KEY" "${{ inputs.restore_keys }}" | sed '/^$/d')
+          SEARCH_LIST=$(printf "%s\n%s" "${{ inputs.cache_key }}" "${{ inputs.restore_keys }}" | sed '/^$/d')
           
           FOUND=false
           while read -r KEY; do
             [ -z "$KEY" ] && continue
-            echo "::group:: [$((idx+1))/${#PATHS_ARRAY[@]}] Searching Prefix: $KEY"
+            echo "::group:: Searching Prefix: $KEY"
             
-            MATCH=$(echo "$ALL_ASSETS" | grep -E "^cache-$KEY.*\.(tzst|tar)(\.part[a-z]{2})?$" | sort -r | head -n 1 || true)
+            MATCH=$(echo "$ALL_ASSETS" | grep "^cache-$KEY" | sort -r | head -n 1 || true)
             
             if [ -z "$MATCH" ]; then
                 echo "Not found."
@@ -152,7 +82,7 @@ runs:
             fi
             
             BASE_FILENAME=$(echo "$MATCH" | sed -E 's/\.(tzst|tar)(\.part[a-z]{2})?$//')
-            EXT=$(echo "$MATCH" | grep -oP '\\.(tzst|tar)' | head -n 1)
+            EXT=$(echo "$MATCH" | grep -oP '\.(tzst|tar)' | head -n 1)
             
             [[ "$MATCH" == *".part"* ]] && IS_SPLIT=true || IS_SPLIT=false
             [ "$EXT" = ".tzst" ] && COMPRESSED=true || COMPRESSED=false
@@ -161,7 +91,7 @@ runs:
             echo "✅ Hit! Restoring $BASE_FILENAME$EXT"
             echo "::endgroup::"
             
-            echo "::group:: [$((idx+1))/${#PATHS_ARRAY[@]}] Downloading Cache"
+            echo "::group:: Downloading Cache"
             
             download_asset() {
               local filename="$1"
@@ -171,35 +101,18 @@ runs:
               
               while [ $attempt -le $max_retries ]; do
                 echo "  Attempt $attempt: Downloading $filename..."
-                # Prefer gh release download (reliable and atomic) when available
-                rm -f "$filename"
-                if command -v gh >/dev/null 2>&1; then
-                  if timeout 10m gh release download "$TAG_NAME" --repo "$TARGET_REPO" --pattern "$filename" -D . >/dev/null 2>&1; then
-                    # gh writes the file with the same name into the current directory
-                    if [ -s "$filename" ]; then
-                      return 0
-                    fi
-                  fi
-                fi
-
-                # Fallback to aria2c
+                
                 if timeout 10m aria2c "${ARIA2_OPTS[@]}" --retry-wait=10 --max-tries=10 -o "$filename" "$url"; then
-                  # ensure file is non-empty
-                  if [ -s "$filename" ]; then
-                    return 0
-                  else
-                    echo "  ⚠️ Downloaded file is empty. Retrying..."
-                    rm -f "$filename"
-                  fi
+                  return 0
                 fi
-
+                
                 echo "  ⚠️ Download failed or timed out. Retrying in 5s..."
                 sleep 5
                 attempt=$((attempt + 1))
               done
               return 1
             }
-
+            
             if [ "$IS_SPLIT" = "true" ]; then
               for part in {a..z}{a..z}; do
                 PART_NAME="$BASE_FILENAME$EXT.part$part"
@@ -218,66 +131,42 @@ runs:
             fi
             echo "::endgroup::"
             
-            echo "::group:: [$((idx+1))/${#PATHS_ARRAY[@]}] Extracting Cache"
-            mkdir -p "$CACHE_PATH"
+            echo "::group:: Extracting Cache"
+            mkdir -p "${{ inputs.cache_path }}"
             FINAL_ARCHIVE="$BASE_FILENAME$EXT"
-            EXTRACT_DIR="$(dirname "$CACHE_PATH")"
+            EXTRACT_DIR="$(dirname "${{ inputs.cache_path }}")"
+            
+            extract_cache() {
+              local cmd="$1"
+              if [ "${{ inputs.debug }}" = "true" ]; then
+                sh -c "$cmd"
+              else
+                sh -c "$cmd" > /dev/null 2>&1
+              fi
+            }
             
             if [ "$IS_SPLIT" = "true" ]; then
               PARTS=$(ls "$FINAL_ARCHIVE.part"* | sort)
               if [ "$COMPRESSED" = "true" ]; then
-                cat $PARTS | tar -I "zstd -d -T0" -xf - -C "$EXTRACT_DIR"
+                extract_cache "cat $PARTS | tar -I 'zstd -d -T0' -xvf - -C '$EXTRACT_DIR'"
               else
-                cat $PARTS | tar -xf - -C "$EXTRACT_DIR"
+                extract_cache "cat $PARTS | tar -xvf - -C '$EXTRACT_DIR'"
               fi
               rm -f $PARTS
             else
               if [ "$COMPRESSED" = "true" ]; then
-                tar -I "zstd -d -T0" -xf "$FINAL_ARCHIVE" -C "$EXTRACT_DIR"
+                extract_cache "tar -I 'zstd -d -T0' -xvf '$FINAL_ARCHIVE' -C '$EXTRACT_DIR'"
               else
-                tar -xf "$FINAL_ARCHIVE" -C "$EXTRACT_DIR"
+                extract_cache "tar -xvf '$FINAL_ARCHIVE' -C '$EXTRACT_DIR'"
               fi
               rm -f "$FINAL_ARCHIVE"
             fi
             echo "✅ Restore complete."
             echo "::endgroup::"
-            
-            # Track results for this entry
-            OVERALL_HIT=true
-            MATCHED_KEYS+=("$KEY")
-            CACHE_SIZE=$(du -sh "$CACHE_PATH" 2>/dev/null | awk '{print $1}' || echo "unknown")
-            CACHE_SIZES+=("$CACHE_SIZE")
-            # Provide a concise summary of restored path (top-level + one level deep)
-            echo "--- Cache restore summary for: $CACHE_PATH ---"
-            if [ -e "$CACHE_PATH" ]; then
-              du -sh "$CACHE_PATH" || true
-              du -h --max-depth=1 "$CACHE_PATH" 2>/dev/null | sort -hr | head -n 10 || true
-              echo "Showing one-level-deep details for top entries (up to 5 each):"
-              while read -r _entry; do
-                entry_path=$(echo "$_entry" | awk '{print $2}')
-                [ -z "$entry_path" ] && continue
-                if [ "$entry_path" = "$CACHE_PATH" ]; then
-                  continue
-                fi
-                echo "-> $entry_path :"
-                du -h --max-depth=1 "$entry_path" 2>/dev/null | sort -hr | head -n 5 || true
-              done < <(du -h --max-depth=1 "$CACHE_PATH" 2>/dev/null | sort -hr | head -n 10)
-            fi
             break
           done <<< "$SEARCH_LIST"
           
           if [ "$FOUND" = "false" ]; then
-              echo "⚠️ No cache matches found for bucket '$CACHE_BUCKET'. Proceeding with fresh run."
-              MATCHED_KEYS+=("none")
-              CACHE_SIZES+=("0B")
+              echo "⚠️ No cache matches found. Proceeding with fresh run."
           fi
-        done
-        
-        # Output results
-        if [ "$OVERALL_HIT" = "true" ]; then
-          echo "cache-hit=true" >> $GITHUB_OUTPUT
-        else
-          echo "cache-hit=false" >> $GITHUB_OUTPUT
-        fi
-        echo "cache-key=$(IFS=,; echo "${MATCHED_KEYS[*]}")" >> $GITHUB_OUTPUT
-        echo "cache-size=$(IFS=,; echo "${CACHE_SIZES[*]}")" >> $GITHUB_OUTPUT
+        fi

+ 126 - 122
.github/actions/cache-save/action.yml

@@ -1,168 +1,172 @@
-name: 'Save Cache'
-description: 'Archive, split if necessary, and upload cache to GitHub Releases for later retrieval.'
+name: 'Restore Cache'
+description: ""
 
 inputs:
   cache_path:
-    description: 'Path where cache is saved'
+    description: 'Path where cache should be restored'
     required: true
     type: string
   cache_key:
-    description: 'Unique key for the cache'
+    description: 'Primary key to restore cache'
     required: true
     type: string
+  restore_keys:
+    description: 'Multiline list of keys (fallback prefixes)'
+    required: false
+    type: string
+    default: ""
   cache_bucket:
     description: 'The tag name for the release (e.g., general-cache)'
     required: true
     default: 'general-cache'
-  github_token:
-    description: 'GitHub Token'
-    required: true
-  compression_level:
-    description: 'Compression level (0-9). 0 = No compression, 1 = Fast, 19 = Best.'
-    required: false
-    type: number
-    default: 6
-  working_dir:
-    description: 'Path where .git folder exists (use only if you clone multiple repos)'
-    required: false
-    type: string
-  debug:
-    description: 'Enable Logs'
-    required: false
-    type: boolean
-    default: false
 
 runs:
   using: 'composite'
   steps:
-    - name: Archive, Split, and Upload Cache
+    - name: Detect and Download Cache
       shell: bash
       env:
-        GH_TOKEN: ${{ inputs.github_token }}
         TARGET_REPO: "${{ github.repository }}"
       run: |
-        # Archive, Split, and Upload Cache
+        # Detect and Download Cache
         if [ "${{ inputs.debug }}" = "true" ]; then set -x; fi
         
-        if [ "${{ inputs.working_dir }}" != "" ]; then 
-          cd "${{ inputs.working_dir }}"
-        fi
-        git config user.name "github-actions[bot]"
-        git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
+        cd "$GITHUB_WORKSPACE"
         
         TAG_NAME="${{ inputs.cache_bucket }}"
-        BASE_FILENAME="cache-${{ inputs.cache_key }}"
+        BASE_URL="https://github.com/${TARGET_REPO}/releases/download/$TAG_NAME"
+        ASSETS_URL="https://github.com/${TARGET_REPO}/releases/expanded_assets/$TAG_NAME"
         
-        if [ "${{ inputs.compression_level }}" -eq 0 ]; then
-          FILENAME="$BASE_FILENAME.tar"
-        else
-          FILENAME="$BASE_FILENAME.tzst"
-        fi
+        ARIA2_OPTS=(
+          "-x16" "-s16" "-k1M" "-j5" "--file-allocation=none"
+          "--header=User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36"
+          "--header=Accept: */*"
+          "--header=Connection: keep-alive"
+        )
         
-        echo "::group:: Checking Release State"
+        if [ "${{ inputs.debug }}" != "true" ]; then
+          ARIA2_OPTS+=("--quiet" "--summary-interval=0" "--console-log-level=error")
+        fi
         
-        git fetch --tags --force
+        echo "::group:: Fetching Asset List"
+        HTTP_RESPONSE=$(curl -sL -A "Mozilla/5.0" -w "%{http_code}" "$ASSETS_URL" -o assets.html || echo "404")
         
-        if ! git rev-parse "$TAG_NAME" >/dev/null 2>&1; then
-          echo "Tag '$TAG_NAME' not found. Creating backdated release..."
-          GIT_COMMITTER_DATE="2015-01-01T12:00:00" git tag -a "$TAG_NAME" -m "General Cache Storage"
-          if git push origin "$TAG_NAME" --force; then
-            gh release create "$TAG_NAME" --title "General Cache" --notes "Automated storage for build assets" --repo "$TARGET_REPO" || true
-          else
-            echo "Push failed, tag might have been created by a parallel job. Continuing..."
-          fi
+        if [ "$HTTP_RESPONSE" -eq 200 ]; then
+          ALL_ASSETS=$(grep -oP "download/$TAG_NAME/\K[^\"' ]+" assets.html | sort -u || echo "")
         else
-          echo "Release '$TAG_NAME' already exists. Ready for upload."
+          echo "Status $HTTP_RESPONSE: Failed to fetch assets from scraper endpoint."
+          ALL_ASSETS=""
         fi
-        echo "::endgroup::"
-        
-        echo "::group:: Archiving Path"
-        echo "Target: ${{ inputs.cache_path }}"
+        rm -f assets.html
         
-        if [ ! -d "${{ inputs.cache_path }}" ] && [ ! -f "${{ inputs.cache_path }}" ]; then
-          echo "⚠️ Target path not found. Skipping cache save."
+        if [ -z "$ALL_ASSETS" ]; then
+          echo "No assets found in bucket '$TAG_NAME'. Skipping search."
           echo "::endgroup::"
         else
-          DIR_NAME=$(dirname "${{ inputs.cache_path }}")
-          BASE_NAME=$(basename "${{ inputs.cache_path }}")
-          
-          if [ "${{ inputs.debug }}" = "true" ]; then
-            if [ "${{ inputs.compression_level }}" -eq 0 ]; then
-              tar --posix -h -cvf "$FILENAME" -C "$DIR_NAME" "$BASE_NAME"
-            else
-              tar --posix -h -I "zstd -T0 -${{ inputs.compression_level }}" -cvf "$FILENAME" -C "$DIR_NAME" "$BASE_NAME"
-            fi
-          else
-            if [ "${{ inputs.compression_level }}" -eq 0 ]; then
-              tar --posix -h -cvf "$FILENAME" -C "$DIR_NAME" "$BASE_NAME" > /dev/null 2>&1
-            else
-              tar --posix -h -I "zstd -T0 -${{ inputs.compression_level }}" -cvf "$FILENAME" -C "$DIR_NAME" "$BASE_NAME" > /dev/null 2>&1
-            fi
-          fi
-          
-          FILE_SIZE=$(stat -c%s "$FILENAME")
-          echo "Archive created: $FILENAME ($FILE_SIZE bytes)"
+          echo "Successfully fetched asset list. Has $(echo "$ALL_ASSETS" | wc -l) assets."
           echo "::endgroup::"
           
-          echo "::group:: Uploading Assets"
-          MAX_SIZE=2000000000 # ~1.86GB
+          SEARCH_LIST=$(printf "%s\n%s" "${{ inputs.cache_key }}" "${{ inputs.restore_keys }}" | sed '/^$/d')
           
-          upload_with_retry() {
-            local file=$1
-            local max_attempts=3
-            for ((i=1; i<=max_attempts; i++)); do
-              echo "  Attempt $i for $file..."
-              local upload_log
-              upload_log=$(mktemp)
+          FOUND=false
+          while read -r KEY; do
+            [ -z "$KEY" ] && continue
+            echo "::group:: Searching Prefix: $KEY"
+            
+            MATCH=$(echo "$ALL_ASSETS" | grep "^cache-$KEY" | sort -r | head -n 1 || true)
+            
+            if [ -z "$MATCH" ]; then
+                echo "Not found."
+                echo "::endgroup::"
+                continue
+            fi
+            
+            BASE_FILENAME=$(echo "$MATCH" | sed -E 's/\.(tzst|tar)(\.part[a-z]{2})?$//')
+            EXT=$(echo "$MATCH" | grep -oP '\.(tzst|tar)' | head -n 1)
+            
+            [[ "$MATCH" == *".part"* ]] && IS_SPLIT=true || IS_SPLIT=false
+            [ "$EXT" = ".tzst" ] && COMPRESSED=true || COMPRESSED=false
+            FOUND=true
+            
+            echo "✅ Hit! Restoring $BASE_FILENAME$EXT"
+            echo "::endgroup::"
+            
+            echo "::group:: Downloading Cache"
+            
+            download_asset() {
+              local filename="$1"
+              local url="$2"
+              local max_retries=3
+              local attempt=1
               
-              if [ "${{ inputs.debug }}" = "true" ]; then
-                if timeout 10m gh release upload "$TAG_NAME" "$file" --clobber --repo "$TARGET_REPO" > >(tee "$upload_log") 2> >(tee -a "$upload_log" >&2); then
-                  rm -f "$upload_log"
-                  echo "  Successfully uploaded $file"
+              while [ $attempt -le $max_retries ]; do
+                echo "  Attempt $attempt: Downloading $filename..."
+                
+                if timeout 10m aria2c "${ARIA2_OPTS[@]}" --retry-wait=10 --max-tries=10 -o "$filename" "$url"; then
                   return 0
                 fi
+                
+                echo "  ⚠️ Download failed or timed out. Retrying in 5s..."
+                sleep 5
+                attempt=$((attempt + 1))
+              done
+              return 1
+            }
+            
+            if [ "$IS_SPLIT" = "true" ]; then
+              for part in {a..z}{a..z}; do
+                PART_NAME="$BASE_FILENAME$EXT.part$part"
+                if echo "$ALL_ASSETS" | grep -q "^$PART_NAME$"; then
+                  if ! download_asset "$PART_NAME" "$BASE_URL/$PART_NAME"; then
+                    echo "::error::Failed to download $PART_NAME after multiple retries."
+                    exit 1
+                  fi
+                else break; fi
+              done
+            else
+              if ! download_asset "$BASE_FILENAME$EXT" "$BASE_URL/$BASE_FILENAME$EXT"; then
+                echo "::error::Failed to download $BASE_FILENAME$EXT after multiple retries."
+                exit 1
+              fi
+            fi
+            echo "::endgroup::"
+            
+            echo "::group:: Extracting Cache"
+            mkdir -p "${{ inputs.cache_path }}"
+            FINAL_ARCHIVE="$BASE_FILENAME$EXT"
+            EXTRACT_DIR="$(dirname "${{ inputs.cache_path }}")"
+            
+            extract_cache() {
+              local cmd="$1"
+              if [ "${{ inputs.debug }}" = "true" ]; then
+                sh -c "$cmd"
               else
-                if timeout 10m gh release upload "$TAG_NAME" "$file" --clobber --repo "$TARGET_REPO" > "$upload_log" 2>&1; then
-                  rm -f "$upload_log"
-                  echo "  Successfully uploaded $file"
-                  return 0
-                fi
+                sh -c "$cmd" > /dev/null 2>&1
               fi
-              
-              local exit_code=$?
-              echo "  ⚠ Attempt $i failed with exit code $exit_code."
-              echo "  └─ Upload output for $file:"
-              sed 's/^/    /' "$upload_log" || true
-              rm -f "$upload_log"
-              if [ "$exit_code" -eq 124 ]; then
-                echo "  ⚠ Attempt $i timed out after 10m. Retrying..."
+            }
+            
+            if [ "$IS_SPLIT" = "true" ]; then
+              PARTS=$(ls "$FINAL_ARCHIVE.part"* | sort)
+              if [ "$COMPRESSED" = "true" ]; then
+                extract_cache "cat $PARTS | tar -I 'zstd -d -T0' -xvf - -C '$EXTRACT_DIR'"
               else
-                echo "  ⚠ Attempt $i failed. Retrying..."
+                extract_cache "cat $PARTS | tar -xvf - -C '$EXTRACT_DIR'"
               fi
-              sleep 5
-            done
-            return 1
-          }
-          
-          if [ "$FILE_SIZE" -gt "$MAX_SIZE" ]; then
-            echo "⚠ File > 2GB. Splitting..."
-            split -b 1500M -a 2 "$FILENAME" "${FILENAME}.part"
-            for part in "${FILENAME}".part*; do
-              echo "Uploading $part..."
-              if ! upload_with_retry "$part"; then
-                echo "::error::Failed to upload part $part after multiple attempts."
-                exit 1
+              rm -f $PARTS
+            else
+              if [ "$COMPRESSED" = "true" ]; then
+                extract_cache "tar -I 'zstd -d -T0' -xvf '$FINAL_ARCHIVE' -C '$EXTRACT_DIR'"
+              else
+                extract_cache "tar -xvf '$FINAL_ARCHIVE' -C '$EXTRACT_DIR'"
               fi
-              rm -f "$part"
-            done
-            rm -rf "$FILENAME"
-          else
-            echo "Uploading $FILENAME..."
-            if ! upload_with_retry "$FILENAME"; then
-              echo "::error::Failed to upload $FILENAME after multiple attempts."
-              exit 1
+              rm -f "$FINAL_ARCHIVE"
             fi
-            rm -f "$FILENAME"
+            echo "✅ Restore complete."
+            echo "::endgroup::"
+            break
+          done <<< "$SEARCH_LIST"
+          
+          if [ "$FOUND" = "false" ]; then
+              echo "⚠️ No cache matches found. Proceeding with fresh run."
           fi
-          echo "::endgroup::"
-        fi
+        fi

+ 3 - 3
.github/workflows/build.yml

@@ -291,7 +291,7 @@ jobs:
       with:
         cache_path: /home/runner/.ccache
         cache_key: ${{ inputs.android_version }}-${{ inputs.kernel_version }}.${{ steps.extract.outputs.sublevel }}-${{ inputs.os_patch_level }}
-        cache_bucket: ccache-cache
+        cache_bucket: "ccache-cache"
         compression_level: 9
         github_token: ${{ secrets.MY_GITHUB_TOKEN }}
 
@@ -301,7 +301,7 @@ jobs:
       with:
         cache_path: /home/runner/.ld_cache
         cache_key: ${{ inputs.android_version }}-${{ inputs.kernel_version }}.${{ steps.extract.outputs.sublevel }}-${{ inputs.os_patch_level }}
-        cache_bucket: lto-cache
+        cache_bucket: "lto-cache"
         compression_level: 9
         github_token: ${{ secrets.MY_GITHUB_TOKEN }}
 
@@ -311,7 +311,7 @@ jobs:
       with:
         cache_path: /home/runner/.cache/bazel
         cache_key: ${{ inputs.android_version }}-${{ inputs.kernel_version }}.${{ steps.extract.outputs.sublevel }}-${{ inputs.os_patch_level }}
-        cache_bucket: bazel-cache
+        cache_bucket: "bazel-cache"
         compression_level: 9
         github_token: ${{ secrets.MY_GITHUB_TOKEN }}