diff --git a/.github/scripts/install-ffmpeg-linux.sh b/.github/scripts/install-ffmpeg-linux.sh new file mode 100755 index 00000000..acdb52c3 --- /dev/null +++ b/.github/scripts/install-ffmpeg-linux.sh @@ -0,0 +1,39 @@ +#!/bin/bash +# Script to install ffmpeg on Linux with timeout and retry +# Usage: install-ffmpeg-linux.sh + +set -e + +TIMEOUT_SECONDS=60 +URL="https://johnvansickle.com/ffmpeg/releases/ffmpeg-release-amd64-static.tar.xz" +PATTERN="ffmpeg-*-amd64-static" + +echo "Downloading and installing ffmpeg..." + +# Try to download and install ffmpeg with timeout +if timeout "$TIMEOUT_SECONDS" wget -q "$URL" && \ + timeout "$TIMEOUT_SECONDS" tar -xf ffmpeg-release-amd64-static.tar.xz; then + sudo mv ${PATTERN}/ffmpeg /usr/local/bin/ + sudo mv ${PATTERN}/ffprobe /usr/local/bin/ + rm -rf ${PATTERN}* + echo "ffmpeg installed successfully on first attempt" +else + echo "First attempt failed or timed out, retrying..." + # Clean up any partial downloads + rm -rf ${PATTERN}* 2>/dev/null || true + # Retry with timeout + if timeout "$TIMEOUT_SECONDS" wget -q "$URL" && \ + timeout "$TIMEOUT_SECONDS" tar -xf ffmpeg-release-amd64-static.tar.xz; then + sudo mv ${PATTERN}/ffmpeg /usr/local/bin/ + sudo mv ${PATTERN}/ffprobe /usr/local/bin/ + rm -rf ${PATTERN}* + echo "ffmpeg installed successfully on second attempt" + else + echo "ffmpeg installation failed after 2 attempts" + exit 1 + fi +fi + +# Verify installation +ffmpeg -version | head -n1 +echo "ffmpeg installation complete" diff --git a/.github/scripts/install-ffmpeg-macos.sh b/.github/scripts/install-ffmpeg-macos.sh new file mode 100755 index 00000000..a3b6448c --- /dev/null +++ b/.github/scripts/install-ffmpeg-macos.sh @@ -0,0 +1,76 @@ +#!/bin/bash +# Script to install ffmpeg on macOS with timeout and retry +# Usage: install-ffmpeg-macos.sh +# Example: install-ffmpeg-macos.sh lib/mac + +set -e + +TARGET_DIR="${1:-lib/mac}" +TIMEOUT_SECONDS=60 +URL="https://evermeet.cx/ffmpeg/getrelease/ffmpeg/zip" + +echo "Downloading and installing ffmpeg for macOS..." + +# Function to run command with timeout using Python +# Only used internally with controlled commands (no user input) +run_with_timeout() { + local timeout=$1 + shift + # Pass command as separate arguments to avoid injection issues + python3 -c ' +import subprocess +import sys + +timeout = int(sys.argv[1]) +cmd = sys.argv[2:] + +try: + result = subprocess.run( + cmd, + timeout=timeout, + capture_output=False + ) + sys.exit(result.returncode) +except subprocess.TimeoutExpired: + sys.exit(124) +' "$timeout" "$@" +} + +# Function to attempt download and extraction +attempt_install() { + local TEMP_DIR=$(mktemp -d) + cd "$TEMP_DIR" + + if run_with_timeout "$TIMEOUT_SECONDS" wget -q "$URL" -O ffmpeg.zip && \ + run_with_timeout "$TIMEOUT_SECONDS" unzip -q ffmpeg.zip; then + chmod +x ffmpeg + mv ffmpeg "$GITHUB_WORKSPACE/$TARGET_DIR/ffmpeg" + cd "$GITHUB_WORKSPACE" + chmod -R u+w "$TEMP_DIR" || true + rm -rf "$TEMP_DIR" + return 0 + else + cd "$GITHUB_WORKSPACE" + chmod -R u+w "$TEMP_DIR" || true + rm -rf "$TEMP_DIR" + return 1 + fi +} + +# First attempt +if attempt_install; then + echo "ffmpeg downloaded successfully on first attempt" +else + echo "First attempt failed or timed out, retrying..." + # Retry + if attempt_install; then + echo "ffmpeg downloaded successfully on second attempt" + else + echo "ffmpeg installation failed after 2 attempts" + exit 1 + fi +fi + +# Verify installation +"$GITHUB_WORKSPACE/$TARGET_DIR/ffmpeg" -version | head -n1 +echo "ffmpeg installation complete" diff --git a/.github/workflows/copilot-setup-steps.yml b/.github/workflows/copilot-setup-steps.yml index de73fa00..8512ab66 100644 --- a/.github/workflows/copilot-setup-steps.yml +++ b/.github/workflows/copilot-setup-steps.yml @@ -82,12 +82,7 @@ jobs: tttool --help || { echo "Error: tttool installation failed"; exit 1; } - name: Install ffmpeg (static build) - run: | - wget -q https://johnvansickle.com/ffmpeg/releases/ffmpeg-release-amd64-static.tar.xz - tar -xf ffmpeg-release-amd64-static.tar.xz - sudo mv ffmpeg-*-amd64-static/ffmpeg /usr/local/bin/ - sudo mv ffmpeg-*-amd64-static/ffprobe /usr/local/bin/ - rm -rf ffmpeg-*-amd64-static* + run: .github/scripts/install-ffmpeg-linux.sh - name: Install Python dependencies run: | diff --git a/.github/workflows/e2e-tests.yml b/.github/workflows/e2e-tests.yml index 03f1cee6..cf2106ee 100644 --- a/.github/workflows/e2e-tests.yml +++ b/.github/workflows/e2e-tests.yml @@ -90,12 +90,7 @@ jobs: tttool --help || { echo "Error: tttool installation failed"; exit 1; } - name: Install ffmpeg (static build) - run: | - wget -q https://johnvansickle.com/ffmpeg/releases/ffmpeg-release-amd64-static.tar.xz - tar -xf ffmpeg-release-amd64-static.tar.xz - sudo mv ffmpeg-*-amd64-static/ffmpeg /usr/local/bin/ - sudo mv ffmpeg-*-amd64-static/ffprobe /usr/local/bin/ - rm -rf ffmpeg-*-amd64-static* + run: .github/scripts/install-ffmpeg-linux.sh - name: Install Python dependencies run: | diff --git a/.github/workflows/release-executables.yml b/.github/workflows/release-executables.yml index 1f6fa3a5..3ab863fa 100644 --- a/.github/workflows/release-executables.yml +++ b/.github/workflows/release-executables.yml @@ -67,21 +67,76 @@ jobs: run: | Write-Host "Downloading ffmpeg for Windows" - # Download ffmpeg to temp directory - $tempDir = New-Item -ItemType Directory -Path (Join-Path $env:TEMP "ffmpeg-temp-$(Get-Random)") - $url = "https://www.gyan.dev/ffmpeg/builds/ffmpeg-release-essentials.zip" - $zipPath = Join-Path $tempDir "ffmpeg.zip" - Invoke-WebRequest -Uri $url -OutFile $zipPath - - # Extract to temp directory - Expand-Archive -Path $zipPath -DestinationPath $tempDir -Force - - # Find and move ffmpeg.exe - $ffmpegDir = Get-ChildItem -Path $tempDir -Directory -Filter "ffmpeg-*" | Select-Object -First 1 - Move-Item -Path (Join-Path $ffmpegDir.FullName "bin/ffmpeg.exe") -Destination lib/win/ffmpeg.exe -Force + # Function to download and extract ffmpeg with timeout + function Install-Ffmpeg { + param([int]$TimeoutSeconds = 60) + + $tempDir = New-Item -ItemType Directory -Path (Join-Path $env:TEMP "ffmpeg-temp-$(Get-Random)") + $url = "https://www.gyan.dev/ffmpeg/builds/ffmpeg-release-essentials.zip" + $zipPath = Join-Path $tempDir "ffmpeg.zip" + + try { + # Download with timeout + $job = Start-Job -ScriptBlock { + param($url, $zipPath) + Invoke-WebRequest -Uri $url -OutFile $zipPath + } -ArgumentList $url, $zipPath + + if (Wait-Job -Job $job -Timeout $TimeoutSeconds) { + Receive-Job -Job $job + Remove-Job -Job $job -Force + + # Extract with timeout + $extractJob = Start-Job -ScriptBlock { + param($zipPath, $tempDir) + Expand-Archive -Path $zipPath -DestinationPath $tempDir -Force + } -ArgumentList $zipPath, $tempDir + + if (Wait-Job -Job $extractJob -Timeout $TimeoutSeconds) { + Receive-Job -Job $extractJob + Remove-Job -Job $extractJob -Force + + # Find and move ffmpeg.exe + $ffmpegDir = Get-ChildItem -Path $tempDir -Directory -Filter "ffmpeg-*" | Select-Object -First 1 + Move-Item -Path (Join-Path $ffmpegDir.FullName "bin/ffmpeg.exe") -Destination lib/win/ffmpeg.exe -Force + return $true + } else { + Stop-Job -Job $extractJob + Remove-Job -Job $extractJob -Force + return $false + } + } else { + Stop-Job -Job $job + Remove-Job -Job $job -Force + return $false + } + } finally { + # Cleanup temp directory + if (Test-Path $tempDir) { + Remove-Item -Recurse -Force $tempDir -ErrorAction SilentlyContinue + } + } + } - # Cleanup temp directory - Remove-Item -Recurse -Force $tempDir + # Try first attempt + Write-Host "Attempting to download ffmpeg (attempt 1)..." + if (Install-Ffmpeg -TimeoutSeconds 60) { + Write-Host "ffmpeg installed successfully on first attempt" + } else { + Write-Host "First attempt failed or timed out, retrying..." + # Clean up any stale temp directories (Install-Ffmpeg cleans up its own temp dir in finally block) + Get-ChildItem -Path $env:TEMP -Directory -Filter "ffmpeg-temp-*" -ErrorAction SilentlyContinue | + Remove-Item -Recurse -Force -ErrorAction SilentlyContinue + + # Retry + Write-Host "Attempting to download ffmpeg (attempt 2)..." + if (Install-Ffmpeg -TimeoutSeconds 60) { + Write-Host "ffmpeg installed successfully on second attempt" + } else { + Write-Host "ffmpeg installation failed after 2 attempts" + exit 1 + } + } # Verify lib/win/ffmpeg.exe -version @@ -171,28 +226,7 @@ jobs: } - name: Download ffmpeg for macOS - run: | - echo "Downloading ffmpeg for macOS" - - # Create temp directory for extraction - TEMP_DIR=$(mktemp -d) - cd "$TEMP_DIR" - - # Download ffmpeg static build for macOS - wget -q "https://evermeet.cx/ffmpeg/getrelease/ffmpeg/zip" -O ffmpeg.zip - unzip -q ffmpeg.zip - - # Move binary to lib/mac - chmod +x ffmpeg - mv ffmpeg "$GITHUB_WORKSPACE/lib/mac/ffmpeg" - - # Cleanup temp directory - change permissions first to ensure deletion succeeds - cd "$GITHUB_WORKSPACE" - chmod -R u+w "$TEMP_DIR" || true - rm -rf "$TEMP_DIR" - - # Verify - lib/mac/ffmpeg -version + run: .github/scripts/install-ffmpeg-macos.sh lib/mac - name: Build macOS executable with PyInstaller run: | diff --git a/setup_e2e_environment.sh b/setup_e2e_environment.sh index 773d973c..f3cb6776 100755 --- a/setup_e2e_environment.sh +++ b/setup_e2e_environment.sh @@ -138,10 +138,25 @@ print_success "tttool installed successfully" print_step "Step 4: Installing ffmpeg" if ! command -v ffmpeg &> /dev/null; then echo "=> Installing ffmpeg..." >> "$INSTALL_LOG" - sudo apt-get install -y ffmpeg >> "$INSTALL_LOG" 2>&1 + # Try with 60 second timeout + if timeout 60 sudo apt-get install -y ffmpeg >> "$INSTALL_LOG" 2>&1; then + print_success "ffmpeg installed on first attempt" + else + echo "=> First attempt failed or timed out, retrying..." >> "$INSTALL_LOG" + echo "Retrying ffmpeg installation (timeout or failure on first attempt)..." + # Retry with 60 second timeout + if timeout 60 sudo apt-get install -y ffmpeg >> "$INSTALL_LOG" 2>&1; then + print_success "ffmpeg installed on second attempt" + else + print_error "ffmpeg installation failed after 2 attempts" + echo "ffmpeg installation failed after 2 attempts" >> "$INSTALL_LOG" + exit 1 + fi + fi +else + print_success "ffmpeg already installed" fi ffmpeg -version | head -n1 -print_success "ffmpeg installed" print_step "Step 5: Installing Python dependencies" PIP_LOG="/tmp/pip_install.log"