playa 0.1.142

Image sequence player (EXR, PNG, JPEG, TIFF, .MP4). Pure Rust with optional OpenEXR/FFmpeg support.
Documentation
#!/usr/bin/env pwsh
# Bootstrap script for playa project
# Checks dependencies, builds xtask, and runs commands
#
# Usage:
#   .\bootstrap.ps1                    # Show bootstrap help
#   .\bootstrap.ps1 tag-dev patch      # Run xtask command
#   .\bootstrap.ps1 build --release    # Run xtask command
#   .\bootstrap.ps1 test               # Run all tests via xtask
#   .\bootstrap.ps1 install            # Install playa from crates.io (checks FFmpeg dependencies)
#   .\bootstrap.ps1 publish            # Publish crate to crates.io

# Set default vcpkg paths if not already set
if (-not $env:VCPKG_ROOT) {
    if (Test-Path 'C:\vcpkg') {
        $env:VCPKG_ROOT = 'C:\vcpkg'
    }
}

if ($env:VCPKG_ROOT -and -not $env:VCPKGRS_TRIPLET) {
    $env:VCPKGRS_TRIPLET = 'x64-windows-static-md-release'
}

if ($env:VCPKG_ROOT -and $env:VCPKGRS_TRIPLET) {
    $env:PKG_CONFIG_PATH = Join-Path $env:VCPKG_ROOT "installed\$env:VCPKGRS_TRIPLET\lib\pkgconfig"
}

# Check if cargo is installed
if (-not (Get-Command cargo -ErrorAction SilentlyContinue)) {
    Write-Host 'Error: Rust/Cargo not found!' -ForegroundColor Red
    Write-Host ''
    Write-Host 'Please install Rust from: https://rustup.rs/'
    exit 1
}

# Setup Visual Studio environment using vcv-rs (fast) or vcvars64.bat (fallback)
Write-Host 'Setting up build environment...'

# Try vcv-rs first (~50x faster than vcvars64.bat)
$vcvFound = $false
if (Get-Command vcv-rs -ErrorAction SilentlyContinue) {
    try {
        vcv-rs -q -f ps | Invoke-Expression
        $vcvFound = $true
        Write-Host '[OK] Visual Studio environment configured (vcv-rs)' -ForegroundColor Green
    } catch {
        Write-Host '  vcv-rs failed, falling back to vcvars64.bat...' -ForegroundColor Yellow
    }
} else {
    # vcv-rs not found - try to install it
    Write-Host '  vcv-rs not found, installing...'
    cargo install vcv-rs --quiet 2>$null
    if ($LASTEXITCODE -eq 0 -and (Get-Command vcv-rs -ErrorAction SilentlyContinue)) {
        try {
            vcv-rs -q -f ps | Invoke-Expression
            $vcvFound = $true
            Write-Host '[OK] Visual Studio environment configured (vcv-rs)' -ForegroundColor Green
        } catch {
            Write-Host '  vcv-rs failed after install, falling back...' -ForegroundColor Yellow
        }
    }
}

# Fallback to vcvars64.bat if vcv-rs didn't work
if (-not $vcvFound) {
    $vswhere = Join-Path ${env:ProgramFiles(x86)} 'Microsoft Visual Studio\Installer\vswhere.exe'
    if (Test-Path $vswhere) {
        $installPath = & $vswhere -latest -property installationPath
        if ($installPath) {
            $vcvars = Join-Path $installPath 'VC\Auxiliary\Build\vcvars64.bat'
            if (Test-Path $vcvars) {
                # Import VS environment variables
                $output = cmd /c "`"$vcvars`" && set" 2>&1
                $output | ForEach-Object {
                    if ($_ -match '^([^=]+)=(.*)$') {
                        Set-Item -Path "env:$($matches[1])" -Value $matches[2]
                    }
                }
                Write-Host '[OK] Visual Studio environment configured (vcvars64.bat)' -ForegroundColor Green
            }
        }
    }
}

# Verify vcpkg configuration
if ($env:VCPKG_ROOT) {
    Write-Host "[OK] vcpkg configured: $env:VCPKG_ROOT" -ForegroundColor Green
    Write-Host "[OK] triplet: $env:VCPKGRS_TRIPLET" -ForegroundColor Green
}

# Clear LIBCLANG_PATH if it points to non-MSVC clang (e.g. ESP32 Xtensa)
# bindgen will use its bundled libclang which works with MSVC headers
if ($env:LIBCLANG_PATH -and $env:LIBCLANG_PATH -match 'esp|xtensa') {
    Write-Host "[WARN] Clearing LIBCLANG_PATH (ESP32 clang incompatible with MSVC)" -ForegroundColor Yellow
    Remove-Item Env:LIBCLANG_PATH -ErrorAction SilentlyContinue
}

Write-Host ''

Write-Host 'Checking dependencies...'
Write-Host ''

# Check if cargo-binstall is installed
if (-not (cargo binstall --version 2>$null)) {
    Write-Host '[1/3] Installing cargo-binstall...'
    cargo install cargo-binstall
    if ($LASTEXITCODE -ne 0) {
        Write-Host 'Error: Failed to install cargo-binstall' -ForegroundColor Red
        exit 1
    }
    Write-Host '  [OK] cargo-binstall installed' -ForegroundColor Green
} else {
    Write-Host '[1/3] [OK] cargo-binstall already installed' -ForegroundColor Green
}

# Check if cargo-release is installed
if (-not (cargo release --version 2>$null)) {
    Write-Host '[2/3] Installing cargo-release...'
    cargo binstall cargo-release --no-confirm
    if ($LASTEXITCODE -ne 0) {
        Write-Host '  Falling back to cargo install...'
        cargo install cargo-release
        if ($LASTEXITCODE -ne 0) {
            Write-Host 'Error: Failed to install cargo-release' -ForegroundColor Red
            exit 1
        }
    }
    Write-Host '  [OK] cargo-release installed' -ForegroundColor Green
} else {
    Write-Host '[2/3] [OK] cargo-release already installed' -ForegroundColor Green
}

# Check if cargo-packager is installed
if (-not (cargo packager --version 2>$null)) {
    Write-Host '[3/3] Installing cargo-packager...'
    cargo binstall cargo-packager --version 0.11.7 --no-confirm
    if ($LASTEXITCODE -ne 0) {
        Write-Host '  Falling back to cargo install...'
        cargo install cargo-packager --version 0.11.7 --locked
        if ($LASTEXITCODE -ne 0) {
            Write-Host 'Error: Failed to install cargo-packager' -ForegroundColor Red
            exit 1
        }
    }
    Write-Host '  [OK] cargo-packager installed' -ForegroundColor Green
} else {
    Write-Host '[3/3] [OK] cargo-packager already installed' -ForegroundColor Green
}

Write-Host ''
Write-Host 'Dependencies ready!' -ForegroundColor Green
Write-Host ''

# Check if xtask is built
if (-not (Test-Path 'target\debug\xtask.exe')) {
    Write-Host 'Building xtask...'
    cargo build -p xtask
    if ($LASTEXITCODE -ne 0) {
        Write-Host 'Error: Failed to build xtask' -ForegroundColor Red
        exit 1
    }
    Write-Host '[OK] xtask built' -ForegroundColor Green
    Write-Host ''
}

# Handle special commands
if ($args[0] -eq 'publish') {
    Write-Host 'Publishing crate to crates.io...'
    Write-Host ''
    cargo publish
    exit $LASTEXITCODE
}

if ($args[0] -eq 'python') {
    Write-Host 'Building Python module (playa-py)...'
    Write-Host ''
    
    # Check if maturin is installed
    if (-not (Get-Command maturin -ErrorAction SilentlyContinue)) {
        Write-Host 'Installing maturin...'
        cargo binstall maturin --no-confirm
        if ($LASTEXITCODE -ne 0) {
            Write-Host '  Falling back to pip install...'
            pip install maturin
            if ($LASTEXITCODE -ne 0) {
                Write-Host 'Error: Failed to install maturin' -ForegroundColor Red
                exit 1
            }
        }
        Write-Host '[OK] maturin installed' -ForegroundColor Green
    } else {
        Write-Host '[OK] maturin found' -ForegroundColor Green
    }
    Write-Host ''
    
    # Build Python wheel
    $manifestPath = 'crates\playa-py\Cargo.toml'
    if ($args[1] -eq 'develop' -or $args[1] -eq 'dev') {
        # Development install (editable)
        Write-Host 'Installing in development mode...'
        maturin develop --manifest-path $manifestPath --release
    } elseif ($args[1] -eq 'install') {
        # Build and install
        Write-Host 'Building and installing...'
        maturin develop --manifest-path $manifestPath --release
    } else {
        # Default: build wheel only
        Write-Host 'Building wheel...'
        maturin build --manifest-path $manifestPath --release
    }
    
    if ($LASTEXITCODE -eq 0) {
        Write-Host ''
        Write-Host '[OK] Python module built successfully!' -ForegroundColor Green
        Write-Host ''
        Write-Host 'Usage:'
        Write-Host '  import playa'
        Write-Host '  playa.run(file="path/to/image.exr", autoplay=True)'
    }
    exit $LASTEXITCODE
}

if ($args[0] -eq 'install') {
    Write-Host 'Checking FFmpeg dependencies...'
    Write-Host ''

    # Determine vcpkg root
    $vcpkgRoot = $env:VCPKG_ROOT
    if (-not $vcpkgRoot) {
        $vcpkgRoot = 'C:\vcpkg'
    }

    # Check vcpkg
    if (-not (Test-Path $vcpkgRoot)) {
        Write-Host "Error: vcpkg not found at $vcpkgRoot" -ForegroundColor Red
        Write-Host ''
        $installVcpkg = Read-Host 'Install vcpkg? (y/N)'
        if ($installVcpkg -eq 'y' -or $installVcpkg -eq 'Y') {
            Write-Host 'Installing vcpkg...'
            git clone https://github.com/microsoft/vcpkg.git $vcpkgRoot
            & "$vcpkgRoot\bootstrap-vcpkg.bat"
            Write-Host '[OK] vcpkg installed' -ForegroundColor Green
        } else {
            Write-Host 'Installation cancelled.'
            exit 1
        }
    } else {
        Write-Host '[OK] vcpkg found' -ForegroundColor Green
    }

    # Check FFmpeg
    $triplet = $env:VCPKGRS_TRIPLET
    if (-not $triplet) {
        $triplet = 'x64-windows-static-md-release'
    }
    $ffmpegPath = Join-Path $vcpkgRoot "installed\$triplet\lib\pkgconfig\libavutil.pc"
    if (-not (Test-Path $ffmpegPath)) {
        Write-Host ''
        Write-Host 'Error: FFmpeg not found' -ForegroundColor Red
        Write-Host ''
        $installFfmpeg = Read-Host 'Install FFmpeg via vcpkg? (y/N)'
        if ($installFfmpeg -eq 'y' -or $installFfmpeg -eq 'Y') {
            Write-Host 'Installing FFmpeg with hardware acceleration support...'
            $vcpkgExe = Join-Path $vcpkgRoot 'vcpkg.exe'
            & $vcpkgExe install "ffmpeg[core,avcodec,avdevice,avfilter,avformat,swresample,swscale,nvcodec]:$triplet"
            Write-Host '[OK] FFmpeg installed' -ForegroundColor Green
        } else {
            Write-Host 'Installation cancelled.'
            exit 1
        }
    } else {
        Write-Host '[OK] FFmpeg found' -ForegroundColor Green
    }

    # Check pkg-config
    if (-not (Get-Command pkg-config -ErrorAction SilentlyContinue)) {
        Write-Host ''
        Write-Host 'Error: pkg-config not found' -ForegroundColor Red
        Write-Host ''
        $installPkgConfig = Read-Host 'Install pkg-config via vcpkg? (y/N)'
        if ($installPkgConfig -eq 'y' -or $installPkgConfig -eq 'Y') {
            Write-Host 'Installing pkg-config...'
            $vcpkgExe = Join-Path $vcpkgRoot 'vcpkg.exe'
            & $vcpkgExe install "pkgconf:$triplet"
            Write-Host '[OK] pkg-config installed' -ForegroundColor Green
        } else {
            Write-Host 'Installation cancelled.'
            exit 1
        }
    } else {
        Write-Host '[OK] pkg-config found' -ForegroundColor Green
    }

    Write-Host ''
    Write-Host 'Installing playa from crates.io...'
    Write-Host ''
    cargo install playa
    exit $LASTEXITCODE
}

# Run xtask with all arguments
if ($args.Count -eq 0) {
    # No arguments - show bootstrap help
    Write-Host 'Bootstrap script for playa project'
    Write-Host ''
    Write-Host 'USAGE:'
    Write-Host '  .\bootstrap.ps1 [COMMAND] [OPTIONS]'
    Write-Host ''
    Write-Host 'SPECIAL COMMANDS:'
    Write-Host '  install            Install playa from crates.io (checks FFmpeg deps)'
    Write-Host '  publish            Publish crate to crates.io'
    Write-Host '  python             Build Python wheel only'
    Write-Host '  python install     Build and install Python module'
    Write-Host '  python dev         Install in development mode (editable)'
    Write-Host ''
    Write-Host 'XTASK COMMANDS (forwarded to cargo xtask):'
    Write-Host '  build              Build playa (use --openexr for full EXR support)'
    Write-Host '  test               Run all tests (unit + integration)'
    Write-Host '  post               Copy native libraries (OpenEXR builds only)'
    Write-Host '  verify             Verify dependencies present'
    Write-Host '  deploy             Install to system'
    Write-Host '  tag-dev            Create dev tag (triggers Build workflow)'
    Write-Host '  tag-rel            Create release tag (triggers Release workflow)'
    Write-Host '  pr                 Create PR: dev -> main'
    Write-Host '  changelog          Preview unreleased CHANGELOG.md'
    Write-Host '  wipe               Clean target directory from stale binaries'
    Write-Host '  wipe-wf            Delete all GitHub workflow runs'
    Write-Host '  pre                Linux only: Patch OpenEXR headers'
    Write-Host ''
    Write-Host 'EXAMPLES:'
    Write-Host '  .\bootstrap.ps1                    # Show this help'
    Write-Host '  .\bootstrap.ps1 build --release    # Build release binary'
    Write-Host '  .\bootstrap.ps1 test               # Run all tests'
    Write-Host '  .\bootstrap.ps1 tag-dev patch      # Create v0.1.x-dev tag'
    Write-Host ''
    Write-Host 'For xtask command details, run: .\bootstrap.ps1 [command] --help'
} else {
    # Pass all arguments to xtask
    cargo xtask @args
    exit $LASTEXITCODE
}