action.yml 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186
  1. name: 'Restore Cache'
  2. inputs:
  3. cache_path:
  4. description: 'Path where cache should be restored'
  5. required: true
  6. type: string
  7. cache_key:
  8. description: 'Primary key to restore cache'
  9. required: true
  10. type: string
  11. restore_keys:
  12. description: 'Multiline list of keys (fallback prefixes)'
  13. required: false
  14. type: string
  15. default: ""
  16. cache_bucket:
  17. description: 'The tag name for the release (e.g., general-cache)'
  18. required: false
  19. default: 'general-cache'
  20. debug:
  21. description: 'Enable Logs'
  22. required: false
  23. type: boolean
  24. default: false
  25. outputs:
  26. cache-hit:
  27. description: 'Returns "true" if a cache was found and restored, otherwise "false"'
  28. value: ${{ steps.restore.outputs.cache-hit }}
  29. runs:
  30. using: 'composite'
  31. steps:
  32. - name: Detect and Download Cache
  33. id: restore
  34. shell: bash
  35. env:
  36. TARGET_REPO: "${{ github.repository }}"
  37. run: |
  38. # Detect and Download Cache
  39. if [ "${{ inputs.debug }}" = "true" ]; then set -x; fi
  40. cd "$GITHUB_WORKSPACE"
  41. TAG_NAME="${{ inputs.cache_bucket }}"
  42. BASE_URL="https://github.com/${TARGET_REPO}/releases/download/$TAG_NAME"
  43. ASSETS_URL="https://github.com/${TARGET_REPO}/releases/expanded_assets/$TAG_NAME"
  44. ARIA2_OPTS=(
  45. "-x16" "-s16" "-k1M" "-j5" "--file-allocation=none"
  46. "--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"
  47. "--header=Accept: */*"
  48. "--header=Connection: keep-alive"
  49. )
  50. if [ "${{ inputs.debug }}" != "true" ]; then
  51. ARIA2_OPTS+=("--quiet" "--summary-interval=0" "--console-log-level=error")
  52. fi
  53. echo "::group:: Fetching Asset List"
  54. HTTP_RESPONSE=$(curl -sL -A "Mozilla/5.0" -w "%{http_code}" "$ASSETS_URL" -o assets.html || echo "404")
  55. if [ "$HTTP_RESPONSE" -eq 200 ]; then
  56. ALL_ASSETS=$(grep -oP "download/$TAG_NAME/\K[^\"' ]+" assets.html | sort -u || echo "")
  57. else
  58. echo "Status $HTTP_RESPONSE: Failed to fetch assets from scraper endpoint."
  59. ALL_ASSETS=""
  60. fi
  61. rm -f assets.html
  62. if [ -z "$ALL_ASSETS" ]; then
  63. echo "No assets found in bucket '$TAG_NAME'. Skipping search."
  64. echo "cache-hit=false" >> "$GITHUB_OUTPUT"
  65. echo "::endgroup::"
  66. else
  67. echo "Successfully fetched asset list. Has $(echo "$ALL_ASSETS" | wc -l) assets."
  68. echo "::endgroup::"
  69. SEARCH_LIST=$(printf "%s\n%s" "${{ inputs.cache_key }}" "${{ inputs.restore_keys }}" | sed '/^$/d')
  70. FOUND=false
  71. while read -r KEY; do
  72. [ -z "$KEY" ] && continue
  73. echo "::group:: Searching Prefix: $KEY"
  74. MATCH=$(echo "$ALL_ASSETS" | grep "^cache-$KEY" | sort -r | head -n 1 || true)
  75. if [ -z "$MATCH" ]; then
  76. echo "Not found."
  77. echo "::endgroup::"
  78. continue
  79. fi
  80. BASE_FILENAME=$(echo "$MATCH" | sed -E 's/\.(tzst|tar)(\.part[a-z]{2})?$//')
  81. EXT=$(echo "$MATCH" | grep -oP '\.(tzst|tar)' | head -n 1)
  82. [[ "$MATCH" == *".part"* ]] && IS_SPLIT=true || IS_SPLIT=false
  83. [ "$EXT" = ".tzst" ] && COMPRESSED=true || COMPRESSED=false
  84. FOUND=true
  85. echo "✅ Hit! Restoring $BASE_FILENAME$EXT"
  86. echo "::endgroup::"
  87. echo "::group:: Downloading Cache"
  88. download_asset() {
  89. local filename="$1"
  90. local url="$2"
  91. local max_retries=3
  92. local attempt=1
  93. while [ $attempt -le $max_retries ]; do
  94. echo " Attempt $attempt: Downloading $filename..."
  95. if timeout 10m aria2c "${ARIA2_OPTS[@]}" --retry-wait=10 --max-tries=10 -o "$filename" "$url"; then
  96. return 0
  97. fi
  98. echo " ⚠️ Download failed or timed out. Retrying in 5s..."
  99. sleep 5
  100. attempt=$((attempt + 1))
  101. done
  102. return 1
  103. }
  104. if [ "$IS_SPLIT" = "true" ]; then
  105. for part in {a..z}{a..z}; do
  106. PART_NAME="$BASE_FILENAME$EXT.part$part"
  107. if echo "$ALL_ASSETS" | grep -q "^$PART_NAME$"; then
  108. if ! download_asset "$PART_NAME" "$BASE_URL/$PART_NAME"; then
  109. echo "::error::Failed to download $PART_NAME after multiple retries."
  110. exit 1
  111. fi
  112. else break; fi
  113. done
  114. else
  115. if ! download_asset "$BASE_FILENAME$EXT" "$BASE_URL/$BASE_FILENAME$EXT"; then
  116. echo "::error::Failed to download $BASE_FILENAME$EXT after multiple retries."
  117. exit 1
  118. fi
  119. fi
  120. echo "::endgroup::"
  121. echo "::group:: Extracting Cache"
  122. mkdir -p "${{ inputs.cache_path }}"
  123. FINAL_ARCHIVE="$BASE_FILENAME$EXT"
  124. EXTRACT_DIR="$(dirname "${{ inputs.cache_path }}")"
  125. extract_cache() {
  126. local cmd="$1"
  127. if [ "${{ inputs.debug }}" = "true" ]; then
  128. sh -c "$cmd"
  129. else
  130. sh -c "$cmd" > /dev/null 2>&1
  131. fi
  132. }
  133. if [ "$IS_SPLIT" = "true" ]; then
  134. PARTS=$(ls "$FINAL_ARCHIVE.part"* | sort | tr '\n' ' ')
  135. if [ "$COMPRESSED" = "true" ]; then
  136. extract_cache "cat $PARTS | tar -I 'zstd -d -T0' -xvf - -C '$EXTRACT_DIR'"
  137. else
  138. extract_cache "cat $PARTS | tar -xvf - -C '$EXTRACT_DIR'"
  139. fi
  140. rm -f $PARTS
  141. else
  142. if [ "$COMPRESSED" = "true" ]; then
  143. extract_cache "tar -I 'zstd -d -T0' -xvf '$FINAL_ARCHIVE' -C '$EXTRACT_DIR'"
  144. else
  145. extract_cache "tar -xvf '$FINAL_ARCHIVE' -C '$EXTRACT_DIR'"
  146. fi
  147. rm -f "$FINAL_ARCHIVE"
  148. fi
  149. echo "✅ Restore complete."
  150. echo "::endgroup::"
  151. break
  152. done <<< "$SEARCH_LIST"
  153. if [ "$FOUND" = "false" ]; then
  154. echo "⚠️ No cache matches found. Proceeding with fresh run."
  155. echo "cache-hit=false" >> "$GITHUB_OUTPUT"
  156. else
  157. echo "cache-hit=true" >> "$GITHUB_OUTPUT"
  158. fi
  159. fi