From ab2860b478714f1507544f55f8a94ea5cc3d4f0a Mon Sep 17 00:00:00 2001 From: justiceadams Date: Wed, 3 Dec 2025 11:03:07 -0800 Subject: [PATCH 1/7] write a custom curl retry method --- .../scripts/install-and-build-with-sdk.sh | 44 ++++++++++++++++--- 1 file changed, 37 insertions(+), 7 deletions(-) diff --git a/.github/workflows/scripts/install-and-build-with-sdk.sh b/.github/workflows/scripts/install-and-build-with-sdk.sh index 63b1dc0e..b8f988d3 100755 --- a/.github/workflows/scripts/install-and-build-with-sdk.sh +++ b/.github/workflows/scripts/install-and-build-with-sdk.sh @@ -17,6 +17,36 @@ log() { printf -- "** %s\n" "$*" >&2; } error() { printf -- "** ERROR: %s\n" "$*" >&2; } fatal() { error "$@"; exit 1; } +# Retry configuration +CURL_MAX_RETRIES=5 +CURL_RETRY_DELAY=5 +CURL_TIMEOUT=300 + +curl_with_retry() { + local attempt=1 + local exit_code=0 + + while [ $attempt -le $CURL_MAX_RETRIES ]; do + if [ $attempt -gt 1 ]; then + log "Retry attempt $attempt of $CURL_MAX_RETRIES after ${CURL_RETRY_DELAY}s delay..." + sleep $CURL_RETRY_DELAY + fi + + # Run curl with connection timeout and max time limits + if curl --connect-timeout 30 --max-time $CURL_TIMEOUT --retry 3 --retry-delay 2 --retry-max-time 60 "$@"; then + return 0 + else + exit_code=$? + log "curl failed with exit code $exit_code on attempt $attempt" + fi + + attempt=$((attempt + 1)) + done + + error "curl failed after $CURL_MAX_RETRIES attempts" + return $exit_code +} + # Parse command line options INSTALL_ANDROID=false INSTALL_STATIC_LINUX=false @@ -125,7 +155,7 @@ find_latest_swift_version() { log "Fetching releases from swift.org API..." local releases_json - releases_json=$(curl -fsSL "${SWIFT_API_INSTALL_ROOT}/releases.json") || fatal "Failed to fetch Swift releases" + releases_json=$(curl_with_retry -fsSL "${SWIFT_API_INSTALL_ROOT}/releases.json") || fatal "Failed to fetch Swift releases" # Find all releases that start with the minor version (e.g, "6.1") # Sort them and get the latest one @@ -212,7 +242,7 @@ find_latest_sdk_snapshot() { log "Fetching development snapshots from swift.org API..." local sdk_json - sdk_json=$(curl -fsSL "${SWIFT_API_INSTALL_ROOT}/dev/${version}/${sdk_name}-sdk.json") || fatal "Failed to fetch ${sdk_name}-sdk development snapshots" + sdk_json=$(curl_with_retry -fsSL "${SWIFT_API_INSTALL_ROOT}/dev/${version}/${sdk_name}-sdk.json") || fatal "Failed to fetch ${sdk_name}-sdk development snapshots" # Extract the snapshot tag from the "dir" field of the first (newest) element local snapshot_tag @@ -400,16 +430,16 @@ download_and_verify() { local temp_sig="${output_file}.sig" log "Downloading ${url}" - curl -fsSL "$url" -o "$output_file" + curl_with_retry -fsSL "$url" -o "$output_file" log "Downloading signature" - curl -fsSL "$sig_url" -o "$temp_sig" + curl_with_retry -fsSL "$sig_url" -o "$temp_sig" log "Setting up GPG for verification" local gnupghome gnupghome="$(mktemp -d)" export GNUPGHOME="$gnupghome" - curl -fSsL https://swift.org/keys/all-keys.asc | zcat -f | gpg --import - >/dev/null 2>&1 + curl_with_retry -fSsL https://swift.org/keys/all-keys.asc | zcat -f | gpg --import - >/dev/null 2>&1 log "Verifying signature" if gpg --batch --verify "$temp_sig" "$output_file" >/dev/null 2>&1; then @@ -445,7 +475,7 @@ download_and_extract_toolchain() { # Check if toolchain is available local http_code - http_code=$(curl -sSL --head -w "%{http_code}" -o /dev/null "$toolchain_url") + http_code=$(curl_with_retry -sSL --head -w "%{http_code}" -o /dev/null "$toolchain_url") if [[ "$http_code" == "404" ]]; then log "Toolchain not found: ${toolchain_filename}" log "Exiting workflow..." @@ -579,7 +609,7 @@ install_android_sdk() { if [[ ! -d "${ANDROID_NDK_HOME:-}" ]]; then # permit the "--android-ndk" flag to override the default local android_ndk_version="${ANDROID_NDK_VERSION:-r27d}" - curl -fsSL -o ndk.zip --retry 3 https://dl.google.com/android/repository/android-ndk-"${android_ndk_version}"-"$(uname -s)".zip + curl_with_retry -fsSL -o ndk.zip https://dl.google.com/android/repository/android-ndk-"${android_ndk_version}"-"$(uname -s)".zip command -v unzip >/dev/null || install_package unzip unzip -q ndk.zip rm ndk.zip From 4146fa5a94fbf1b9bad6d76604448bc70d129303 Mon Sep 17 00:00:00 2001 From: justiceadams Date: Wed, 3 Dec 2025 11:21:04 -0800 Subject: [PATCH 2/7] retry SDK install --- .../scripts/install-and-build-with-sdk.sh | 56 ++++++++++++++----- 1 file changed, 41 insertions(+), 15 deletions(-) diff --git a/.github/workflows/scripts/install-and-build-with-sdk.sh b/.github/workflows/scripts/install-and-build-with-sdk.sh index b8f988d3..8ea229c7 100755 --- a/.github/workflows/scripts/install-and-build-with-sdk.sh +++ b/.github/workflows/scripts/install-and-build-with-sdk.sh @@ -22,6 +22,9 @@ CURL_MAX_RETRIES=5 CURL_RETRY_DELAY=5 CURL_TIMEOUT=300 +SDK_INSTALL_MAX_RETRIES=5 +SDK_INSTALL_INITIAL_RETRY_DELAY=10 + curl_with_retry() { local attempt=1 local exit_code=0 @@ -47,6 +50,41 @@ curl_with_retry() { return $exit_code } +swift_sdk_install_with_retry() { + local swift_executable="$1" + local sdk_url="$2" + local checksum="$3" + local sdk_type="$4" + + local attempt=1 + local retry_delay=$SDK_INSTALL_INITIAL_RETRY_DELAY + + while [ $attempt -le $SDK_INSTALL_MAX_RETRIES ]; do + if [ $attempt -gt 1 ]; then + log "Retry attempt $attempt of $SDK_INSTALL_MAX_RETRIES for ${sdk_type} SDK installation after ${retry_delay}s delay..." + sleep $retry_delay + fi + + log "Attempt $attempt: Installing ${sdk_type} SDK from ${sdk_url}" + + if "$swift_executable" sdk install "$sdk_url" --checksum "$checksum"; then + log "✅ ${sdk_type} SDK installed successfully" + return 0 + else + local exit_code=$? + log "swift sdk install failed with exit code $exit_code on attempt $attempt" + + # Exponential backoff: double the delay each time + retry_delay=$((retry_delay * 2)) + fi + + attempt=$((attempt + 1)) + done + + error "${sdk_type} SDK installation failed after $SDK_INSTALL_MAX_RETRIES attempts" + return 1 +} + # Parse command line options INSTALL_ANDROID=false INSTALL_STATIC_LINUX=false @@ -586,11 +624,7 @@ install_android_sdk() { local android_sdk_filename="${android_sdk_bundle_name}.tar.gz" local sdk_url="${ANDROID_SDK_DOWNLOAD_ROOT}/${ANDROID_SDK_TAG}/${android_sdk_filename}" - log "Running: ${SWIFT_EXECUTABLE_FOR_ANDROID_SDK} sdk install ${sdk_url} --checksum ${ANDROID_SDK_CHECKSUM}" - - if "$SWIFT_EXECUTABLE_FOR_ANDROID_SDK" sdk install "$sdk_url" --checksum "$ANDROID_SDK_CHECKSUM"; then - log "✅ Android Swift SDK installed successfully" - else + if ! swift_sdk_install_with_retry "$SWIFT_EXECUTABLE_FOR_ANDROID_SDK" "$sdk_url" "$ANDROID_SDK_CHECKSUM" "Android Swift"; then fatal "Failed to install Android Swift SDK" fi @@ -632,11 +666,7 @@ install_static_linux_sdk() { local static_linux_sdk_filename="${STATIC_LINUX_SDK_TAG}_static-linux-0.0.1.artifactbundle.tar.gz" local sdk_url="${STATIC_LINUX_SDK_DOWNLOAD_ROOT}/${STATIC_LINUX_SDK_TAG}/${static_linux_sdk_filename}" - log "Running: ${SWIFT_EXECUTABLE_FOR_STATIC_LINUX_SDK} sdk install ${sdk_url} --checksum ${STATIC_LINUX_SDK_CHECKSUM}" - - if "$SWIFT_EXECUTABLE_FOR_STATIC_LINUX_SDK" sdk install "$sdk_url" --checksum "$STATIC_LINUX_SDK_CHECKSUM"; then - log "✅ Static Linux Swift SDK installed successfully" - else + if ! swift_sdk_install_with_retry "$SWIFT_EXECUTABLE_FOR_STATIC_LINUX_SDK" "$sdk_url" "$STATIC_LINUX_SDK_CHECKSUM" "Static Linux Swift"; then fatal "Failed to install Static Linux Swift SDK" fi @@ -655,11 +685,7 @@ install_wasm_sdk() { local wasm_sdk_filename="${WASM_SDK_TAG}_wasm.artifactbundle.tar.gz" local sdk_url="${WASM_SDK_DOWNLOAD_ROOT}/${WASM_SDK_TAG}/${wasm_sdk_filename}" - log "Running: ${SWIFT_EXECUTABLE_FOR_WASM_SDK} sdk install ${sdk_url} --checksum ${WASM_SDK_CHECKSUM}" - - if "$SWIFT_EXECUTABLE_FOR_WASM_SDK" sdk install "$sdk_url" --checksum "$WASM_SDK_CHECKSUM"; then - log "✅ Swift SDK for Wasm installed successfully" - else + if ! swift_sdk_install_with_retry "$SWIFT_EXECUTABLE_FOR_WASM_SDK" "$sdk_url" "$WASM_SDK_CHECKSUM" "Swift Wasm"; then fatal "Failed to install Swift SDK for Wasm" fi From dcc3a9289efde5e5dbe308277860a46944c945e2 Mon Sep 17 00:00:00 2001 From: justiceadams Date: Wed, 3 Dec 2025 11:34:02 -0800 Subject: [PATCH 3/7] retry windows install --- .../scripts/windows/swift/install-swift.ps1 | 62 ++++++++++++++++++- 1 file changed, 59 insertions(+), 3 deletions(-) diff --git a/.github/workflows/scripts/windows/swift/install-swift.ps1 b/.github/workflows/scripts/windows/swift/install-swift.ps1 index 811a53da..1f270469 100644 --- a/.github/workflows/scripts/windows/swift/install-swift.ps1 +++ b/.github/workflows/scripts/windows/swift/install-swift.ps1 @@ -9,6 +9,53 @@ ## See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors ## ##===----------------------------------------------------------------------===## + +# Retry configuration +$MaxRetries = 5 +$RetryDelay = 5 + +function Invoke-WebRequestWithRetry { + param ( + [string]$Uri, + [string]$OutFile, + [int]$TimeoutSec = 300 + ) + + $attempt = 1 + + while ($attempt -le $MaxRetries) { + try { + if ($attempt -gt 1) { + Write-Host "Retry attempt $attempt of $MaxRetries after ${RetryDelay}s delay..." + Start-Sleep -Seconds $RetryDelay + } + + # Use -Resume to support partial downloads if the connection drops + Invoke-WebRequest -Uri $Uri -OutFile $OutFile -TimeoutSec $TimeoutSec -UseBasicParsing + + Write-Host "Download completed successfully" + return $true + } + catch { + Write-Host "Download failed on attempt $attempt`: $($_.Exception.Message)" + + # Clean up partial download if it exists + if (Test-Path $OutFile) { + Remove-Item -Force $OutFile -ErrorAction SilentlyContinue + } + + if ($attempt -eq $MaxRetries) { + Write-Host "Download failed after $MaxRetries attempts" + throw + } + } + + $attempt++ + } + + return $false +} + function Install-Swift { param ( [string]$Url, @@ -16,9 +63,18 @@ function Install-Swift { ) Set-Variable ErrorActionPreference Stop Set-Variable ProgressPreference SilentlyContinue - Write-Host -NoNewLine ('Downloading {0} ... ' -f $url) - Invoke-WebRequest -Uri $url -OutFile installer.exe - Write-Host 'SUCCESS' + + Write-Host "Downloading $Url ... " + + try { + Invoke-WebRequestWithRetry -Uri $Url -OutFile installer.exe + Write-Host 'SUCCESS' + } + catch { + Write-Host "FAILED: $($_.Exception.Message)" + exit 1 + } + Write-Host -NoNewLine ('Verifying SHA256 ({0}) ... ' -f $Sha256) $Hash = Get-FileHash installer.exe -Algorithm sha256 if ($Hash.Hash -eq $Sha256 -or $Sha256 -eq "") { From a27b4ea368b85221a366627301c8a479b16a79c8 Mon Sep 17 00:00:00 2001 From: justiceadams Date: Wed, 3 Dec 2025 12:22:23 -0800 Subject: [PATCH 4/7] check windows download for corruption and ensure file length is valid --- .../scripts/windows/swift/install-swift.ps1 | 46 +++++++++++++++++-- 1 file changed, 41 insertions(+), 5 deletions(-) diff --git a/.github/workflows/scripts/windows/swift/install-swift.ps1 b/.github/workflows/scripts/windows/swift/install-swift.ps1 index 1f270469..5a2337b4 100644 --- a/.github/workflows/scripts/windows/swift/install-swift.ps1 +++ b/.github/workflows/scripts/windows/swift/install-swift.ps1 @@ -29,11 +29,47 @@ function Invoke-WebRequestWithRetry { Write-Host "Retry attempt $attempt of $MaxRetries after ${RetryDelay}s delay..." Start-Sleep -Seconds $RetryDelay } - - # Use -Resume to support partial downloads if the connection drops - Invoke-WebRequest -Uri $Uri -OutFile $OutFile -TimeoutSec $TimeoutSec -UseBasicParsing - - Write-Host "Download completed successfully" + + Write-Host "Attempt $attempt`: Downloading from $Uri" + + # Clean up any existing partial download + if (Test-Path $OutFile) { + Remove-Item -Force $OutFile -ErrorAction SilentlyContinue + } + + # Get expected file size from HTTP headers + $headRequest = Invoke-WebRequest -Uri $Uri -Method Head -UseBasicParsing -TimeoutSec 30 + $expectedSize = $null + if ($headRequest.Headers.ContainsKey('Content-Length')) { + $expectedSize = [long]$headRequest.Headers['Content-Length'][0] + Write-Host "Expected file size: $($expectedSize / 1MB) MB" + } + + # Download with progress tracking disabled for better performance + $webClient = New-Object System.Net.WebClient + $webClient.DownloadFile($Uri, $OutFile) + $webClient.Dispose() + + # Verify file exists and has content + if (-not (Test-Path $OutFile)) { + throw "Download completed but file not found at $OutFile" + } + + $actualSize = (Get-Item $OutFile).Length + Write-Host "Downloaded file size: $($actualSize / 1MB) MB" + + # Verify file size matches expected size + if ($expectedSize -and $actualSize -ne $expectedSize) { + throw "File size mismatch. Expected: $expectedSize bytes, Got: $actualSize bytes" + } + + # Verify file is not corrupted by checking if it's a valid PE executable + $fileBytes = [System.IO.File]::ReadAllBytes($OutFile) + if ($fileBytes.Length -lt 2 -or $fileBytes[0] -ne 0x4D -or $fileBytes[1] -ne 0x5A) { + throw "Downloaded file is not a valid executable (missing MZ header)" + } + + Write-Host "Download completed and verified successfully" return $true } catch { From 72a2ab28b20f6e758379b9536624293790905c3e Mon Sep 17 00:00:00 2001 From: justiceadams Date: Wed, 3 Dec 2025 16:00:12 -0800 Subject: [PATCH 5/7] account for partially installed sdks --- .../scripts/install-and-build-with-sdk.sh | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/.github/workflows/scripts/install-and-build-with-sdk.sh b/.github/workflows/scripts/install-and-build-with-sdk.sh index 8ea229c7..aeabc7fa 100755 --- a/.github/workflows/scripts/install-and-build-with-sdk.sh +++ b/.github/workflows/scripts/install-and-build-with-sdk.sh @@ -59,9 +59,26 @@ swift_sdk_install_with_retry() { local attempt=1 local retry_delay=$SDK_INSTALL_INITIAL_RETRY_DELAY + # Extract SDK name from URL for checking if already installed + local sdk_filename + sdk_filename=$(basename "$sdk_url") + local sdk_name="${sdk_filename%.tar.gz}" + while [ $attempt -le $SDK_INSTALL_MAX_RETRIES ]; do if [ $attempt -gt 1 ]; then log "Retry attempt $attempt of $SDK_INSTALL_MAX_RETRIES for ${sdk_type} SDK installation after ${retry_delay}s delay..." + + # Before retrying, check if SDK was partially installed and remove it + log "Checking for partially installed SDK..." + if "$swift_executable" sdk list 2>/dev/null | grep -q "^${sdk_name}"; then + log "Found partially installed SDK, attempting to remove it..." + if "$swift_executable" sdk remove "$sdk_name" 2>/dev/null; then + log "Successfully removed partially installed SDK" + else + log "Warning: Failed to remove partially installed SDK, continuing anyway..." + fi + fi + sleep $retry_delay fi From c11fd46577c209a04cc2124011379c2bda62544e Mon Sep 17 00:00:00 2001 From: justiceadams Date: Thu, 4 Dec 2025 08:34:55 -0800 Subject: [PATCH 6/7] add retry logic to install-vsb.ps1 --- .../workflows/scripts/windows/install-vsb.ps1 | 170 +++++++++++++++--- 1 file changed, 141 insertions(+), 29 deletions(-) diff --git a/.github/workflows/scripts/windows/install-vsb.ps1 b/.github/workflows/scripts/windows/install-vsb.ps1 index 931cbbbc..4dbb1752 100644 --- a/.github/workflows/scripts/windows/install-vsb.ps1 +++ b/.github/workflows/scripts/windows/install-vsb.ps1 @@ -9,35 +9,147 @@ ## See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors ## ##===----------------------------------------------------------------------===## -$VSB='https://download.visualstudio.microsoft.com/download/pr/5536698c-711c-4834-876f-2817d31a2ef2/c792bdb0fd46155de19955269cac85d52c4c63c23db2cf43d96b9390146f9390/vs_BuildTools.exe' -$VSB_SHA256='C792BDB0FD46155DE19955269CAC85D52C4C63C23DB2CF43D96B9390146F9390' -Set-Variable ErrorActionPreference Stop -Set-Variable ProgressPreference SilentlyContinue -Write-Host -NoNewLine ('Downloading {0} ... ' -f ${VSB}) -Invoke-WebRequest -Uri $VSB -OutFile $env:TEMP\vs_buildtools.exe -Write-Host 'SUCCESS' -Write-Host -NoNewLine ('Verifying SHA256 ({0}) ... ' -f $VSB_SHA256) -$Hash = Get-FileHash $env:TEMP\vs_buildtools.exe -Algorithm sha256 -if ($Hash.Hash -eq $VSB_SHA256) { - Write-Host 'SUCCESS' -} else { - Write-Host ('FAILED ({0})' -f $Hash.Hash) - exit 1 + +# Retry configuration +$MaxRetries = 5 +$RetryDelay = 5 + +function Invoke-WebRequestWithRetry { + param ( + [string]$Uri, + [string]$OutFile, + [int]$TimeoutSec = 300 + ) + + $attempt = 1 + + while ($attempt -le $MaxRetries) { + try { + if ($attempt -gt 1) { + Write-Host "Retry attempt $attempt of $MaxRetries after ${RetryDelay}s delay..." + Start-Sleep -Seconds $RetryDelay + } + + Write-Host "Attempt $attempt`: Downloading from $Uri" + + # Clean up any existing partial download + if (Test-Path $OutFile) { + Remove-Item -Force $OutFile -ErrorAction SilentlyContinue + } + + # Get expected file size from HTTP headers + $headRequest = Invoke-WebRequest -Uri $Uri -Method Head -UseBasicParsing -TimeoutSec 30 + $expectedSize = $null + if ($headRequest.Headers.ContainsKey('Content-Length')) { + $expectedSize = [long]$headRequest.Headers['Content-Length'][0] + Write-Host "Expected file size: $([math]::Round($expectedSize / 1MB, 2)) MB" + } + + # Download with progress tracking disabled for better performance + $webClient = New-Object System.Net.WebClient + $webClient.DownloadFile($Uri, $OutFile) + $webClient.Dispose() + + # Verify file exists and has content + if (-not (Test-Path $OutFile)) { + throw "Download completed but file not found at $OutFile" + } + + $actualSize = (Get-Item $OutFile).Length + Write-Host "Downloaded file size: $([math]::Round($actualSize / 1MB, 2)) MB" + + # Verify file size matches expected size + if ($expectedSize -and $actualSize -ne $expectedSize) { + throw "File size mismatch. Expected: $expectedSize bytes, Got: $actualSize bytes" + } + + # Verify file is not corrupted by checking if it's a valid PE executable + $fileBytes = [System.IO.File]::ReadAllBytes($OutFile) + if ($fileBytes.Length -lt 2 -or $fileBytes[0] -ne 0x4D -or $fileBytes[1] -ne 0x5A) { + throw "Downloaded file is not a valid executable (missing MZ header)" + } + + Write-Host "Download completed and verified successfully" + return $true + } + catch { + Write-Host "Download failed on attempt $attempt`: $($_.Exception.Message)" + + # Clean up partial download if it exists + if (Test-Path $OutFile) { + Remove-Item -Force $OutFile -ErrorAction SilentlyContinue + } + + if ($attempt -eq $MaxRetries) { + Write-Host "Download failed after $MaxRetries attempts" + throw + } + } + + $attempt++ + } + + return $false } -Write-Host -NoNewLine 'Installing Visual Studio Build Tools ... ' -$Process = - Start-Process $env:TEMP\vs_buildtools.exe -Wait -PassThru -NoNewWindow -ArgumentList @( - '--quiet', - '--wait', - '--norestart', - '--nocache', - '--add', 'Microsoft.VisualStudio.Component.Windows11SDK.22000', - '--add', 'Microsoft.VisualStudio.Component.VC.Tools.x86.x64' + +function Install-VisualStudioBuildTools { + param ( + [string]$Url, + [string]$Sha256 ) -if ($Process.ExitCode -eq 0 -or $Process.ExitCode -eq 3010) { - Write-Host 'SUCCESS' -} else { - Write-Host ('FAILED ({0})' -f $Process.ExitCode) - exit 1 + + Set-Variable ErrorActionPreference Stop + Set-Variable ProgressPreference SilentlyContinue + + $installerPath = "$env:TEMP\vs_buildtools.exe" + + Write-Host "Downloading Visual Studio Build Tools from $Url" + + try { + Invoke-WebRequestWithRetry -Uri $Url -OutFile $installerPath + Write-Host 'Download SUCCESS' + } + catch { + Write-Host "Download FAILED: $($_.Exception.Message)" + exit 1 + } + + Write-Host -NoNewLine ('Verifying SHA256 ({0}) ... ' -f $Sha256) + $Hash = Get-FileHash $installerPath -Algorithm sha256 + if ($Hash.Hash -eq $VSB_SHA256) { + Write-Host 'SUCCESS' + } else { + Write-Host ('FAILED ({0})' -f $Hash.Hash) + exit 1 + } + + Write-Host -NoNewLine 'Installing Visual Studio Build Tools ... ' + try { + $Process = Start-Process $installerPath -Wait -PassThru -NoNewWindow -ArgumentList @( + '--quiet', + '--wait', + '--norestart', + '--nocache', + '--add', 'Microsoft.VisualStudio.Component.Windows11SDK.22000', + '--add', 'Microsoft.VisualStudio.Component.VC.Tools.x86.x64' + ) + if ($Process.ExitCode -eq 0 -or $Process.ExitCode -eq 3010) { + Write-Host 'SUCCESS' + } else { + Write-Host ('FAILED ({0})' -f $Process.ExitCode) + exit 1 + } + } + catch { + Write-Host "FAILED: $($_.Exception.Message)" + Remove-Item -Force $installerPath -ErrorAction SilentlyContinue + exit 1 + } + + Remove-Item -Force $installerPath -ErrorAction SilentlyContinue } -Remove-Item -Force $env:TEMP\vs_buildtools.exe \ No newline at end of file + +$VSB = 'https://download.visualstudio.microsoft.com/download/pr/5536698c-711c-4834-876f-2817d31a2ef2/c792bdb0fd46155de19955269cac85d52c4c63c23db2cf43d96b9390146f9390/vs_BuildTools.exe' +$VSB_SHA256 = 'C792BDB0FD46155DE19955269CAC85D52C4C63C23DB2CF43D96B9390146F9390' + +Install-VisualStudioBuildTools -Url $VSB -Sha256 $VSB_SHA256 From 9c4305a2962a27565ffaaa38051d776ab2450a41 Mon Sep 17 00:00:00 2001 From: justiceadams Date: Thu, 4 Dec 2025 09:25:59 -0800 Subject: [PATCH 7/7] remove file with retry on windows --- .../workflows/scripts/windows/install-vsb.ps1 | 43 ++++++++++++- .../scripts/windows/swift/install-swift.ps1 | 62 ++++++++++++++++--- 2 files changed, 93 insertions(+), 12 deletions(-) diff --git a/.github/workflows/scripts/windows/install-vsb.ps1 b/.github/workflows/scripts/windows/install-vsb.ps1 index 36a3113e..439e4975 100644 --- a/.github/workflows/scripts/windows/install-vsb.ps1 +++ b/.github/workflows/scripts/windows/install-vsb.ps1 @@ -92,6 +92,40 @@ function Invoke-WebRequestWithRetry { return $false } +function Remove-FileWithRetry { + param ( + [string]$Path + ) + + $attempt = 1 + + while ($attempt -le $MaxRetries) { + try { + if (Test-Path $Path) { + Remove-Item -Force $Path -ErrorAction Stop + Write-Host "Successfully removed $Path" + return $true + } else { + return $true + } + } + catch { + if ($attempt -eq $MaxRetries) { + Write-Host "Warning: Failed to remove $Path after $MaxRetries attempts: $($_.Exception.Message)" + Write-Host "The file may be locked by another process. It will be cleaned up later." + return $false + } + + Write-Host "Attempt $attempt to remove $Path failed, retrying in ${RetryDelay}s..." + Start-Sleep -Seconds $RetryDelay + } + + $attempt++ + } + + return $false +} + function Install-VisualStudioBuildTools { param ( [string]$Url, @@ -111,15 +145,17 @@ function Install-VisualStudioBuildTools { } catch { Write-Host "Download FAILED: $($_.Exception.Message)" + Remove-FileWithRetry -Path $installerPath exit 1 } Write-Host -NoNewLine ('Verifying SHA256 ({0}) ... ' -f $Sha256) $Hash = Get-FileHash $installerPath -Algorithm sha256 - if ($Hash.Hash -eq $VSB_SHA256) { + if ($Hash.Hash -eq $Sha256) { Write-Host 'SUCCESS' } else { Write-Host ('FAILED ({0})' -f $Hash.Hash) + Remove-FileWithRetry -Path $installerPath exit 1 } @@ -138,16 +174,17 @@ function Install-VisualStudioBuildTools { Write-Host 'SUCCESS' } else { Write-Host ('FAILED ({0})' -f $Process.ExitCode) + Remove-FileWithRetry -Path $installerPath exit 1 } } catch { Write-Host "FAILED: $($_.Exception.Message)" - Remove-Item -Force $installerPath -ErrorAction SilentlyContinue + Remove-FileWithRetry -Path $installerPath exit 1 } - Remove-Item -Force $installerPath -ErrorAction SilentlyContinue + Remove-FileWithRetry -Path $installerPath } $VSB = 'https://download.visualstudio.microsoft.com/download/pr/5536698c-711c-4834-876f-2817d31a2ef2/c792bdb0fd46155de19955269cac85d52c4c63c23db2cf43d96b9390146f9390/vs_BuildTools.exe' diff --git a/.github/workflows/scripts/windows/swift/install-swift.ps1 b/.github/workflows/scripts/windows/swift/install-swift.ps1 index 5a2337b4..23e06a33 100644 --- a/.github/workflows/scripts/windows/swift/install-swift.ps1 +++ b/.github/workflows/scripts/windows/swift/install-swift.ps1 @@ -92,6 +92,40 @@ function Invoke-WebRequestWithRetry { return $false } +function Remove-FileWithRetry { + param ( + [string]$Path + ) + + $attempt = 1 + + while ($attempt -le $MaxRetries) { + try { + if (Test-Path $Path) { + Remove-Item -Force $Path -ErrorAction Stop + Write-Host "Successfully removed $Path" + return $true + } else { + return $true + } + } + catch { + if ($attempt -eq $MaxRetries) { + Write-Host "Warning: Failed to remove $Path after $MaxRetries attempts: $($_.Exception.Message)" + Write-Host "The file may be locked by another process. It will be cleaned up later." + return $false + } + + Write-Host "Attempt $attempt to remove $Path failed, retrying in ${RetryDelay}s..." + Start-Sleep -Seconds $RetryDelay + } + + $attempt++ + } + + return $false +} + function Install-Swift { param ( [string]$Url, @@ -108,6 +142,7 @@ function Install-Swift { } catch { Write-Host "FAILED: $($_.Exception.Message)" + Remove-FileWithRetry -Path installer.exe exit 1 } @@ -117,18 +152,27 @@ function Install-Swift { Write-Host 'SUCCESS' } else { Write-Host ('FAILED ({0})' -f $Hash.Hash) + Remove-FileWithRetry -Path installer.exe exit 1 } Write-Host -NoNewLine 'Installing Swift ... ' - $Process = Start-Process installer.exe -Wait -PassThru -NoNewWindow -ArgumentList @( - '/quiet', - '/norestart' - ) - if ($Process.ExitCode -eq 0) { - Write-Host 'SUCCESS' - } else { - Write-Host ('FAILED ({0})' -f $Process.ExitCode) + try { + $Process = Start-Process installer.exe -Wait -PassThru -NoNewWindow -ArgumentList @( + '/quiet', + '/norestart' + ) + if ($Process.ExitCode -eq 0) { + Write-Host 'SUCCESS' + } else { + Write-Host ('FAILED ({0})' -f $Process.ExitCode) + Remove-FileWithRetry -Path installer.exe + exit 1 + } + } + catch { + Write-Host "FAILED: $($_.Exception.Message)" + Remove-FileWithRetry -Path installer.exe exit 1 } - Remove-Item -Force installer.exe + Remove-FileWithRetry -Path installer.exe } \ No newline at end of file