#!/usr/bin/env powershell [CmdletBinding(PositionalBinding = $false)] param ( [ValidateSet('amd64', 'arm64')] [Alias('arch')] [string]$architecture = $( $defaultArchitecture = 'amd64' $arch = try { & go env GOARCH } catch { Write-Warning "Failed retriving the host architecture, using default ($defaultArchitecture). Is Go installed?" return $defaultArchitecture } if ($arch -cnotin @('arm64', 'amd64')) { Write-Warning "Unsupported architecture $arch. Using default ($defaultArchitecture)." return $defaultArchitecture } return $arch ), [parameter(ValueFromRemainingArguments)][object[]]$params = @() ) . ./contrib/cirrus/win-lib.ps1 # Targets function Podman-Remote { New-Item -ItemType Directory -Force -Path './bin/windows' $buildInfo = Get-Date -UFormat %s -Millisecond 0 $buildInfo = "-X github.com/containers/podman/v6/libpod/define.buildInfo=$buildInfo " $commit = Git-Commit $commit = "-X github.com/containers/podman/v6/libpod/define.gitCommit=$commit " $ENV:GOARCH = $architecture Run-Command "go build --ldflags `"$commit $buildInfo `" --tags `"$remotetags`" --o ./bin/windows/podman.exe ./cmd/podman/." } function Make-Clean { $paths = @( # Files generated by the `podman` target "$PSScriptRoot\bin\windows" # Files generated by the `installer` target "$PSScriptRoot\test\version\version.exe" "$PSScriptRoot\contrib\win-installer\artifacts" "$PSScriptRoot\contrib\win-installer\current" "$PSScriptRoot\contrib\win-installer\docs" "$PSScriptRoot\contrib\win-installer\fetch" "$PSScriptRoot\contrib\win-installer\wix\obj" "$PSScriptRoot\contrib\win-installer\*.log" "$PSScriptRoot\contrib\win-installer\*.msi" "$PSScriptRoot\contrib\win-installer\*.wixpdb" "$PSScriptRoot\contrib\win-installer\shasums" # Files generated by the `installer-legacy` target "$PSScriptRoot\contrib\win-installer-legacy\artifacts" "$PSScriptRoot\contrib\win-installer-legacy\current" "$PSScriptRoot\contrib\win-installer-legacy\docs" "$PSScriptRoot\contrib\win-installer-legacy\en-us" "$PSScriptRoot\contrib\win-installer-legacy\fetch" "$PSScriptRoot\contrib\win-installer-legacy\obj" "$PSScriptRoot\contrib\win-installer-legacy\*.log" "$PSScriptRoot\contrib\win-installer-legacy\*.exe" "$PSScriptRoot\contrib\win-installer-legacy\*.wixpdb" # Files generated by the Documentation target "$PSScriptRoot\docs\build\remote\podman-*.html" "$PSScriptRoot\docs\build\remote\podman-for-windows.html" ) foreach ($path in $paths) { if (Test-Path -Path $path -PathType Container) { Remove-Item $path -Recurse -Force -Confirm:$false } elseif (Test-Path -Path $path -PathType Leaf) { Remove-Item $path -Force -Confirm:$false } } } function Local-Unit { Build-Ginkgo $skippackages = 'hack,internal\domain\infra\abi,internal\domain\infra\tunnel,libpod\lock\shm,pkg\api\handlers\libpod,pkg\api\handlers\utils,pkg\bindings,' $skippackages += 'pkg\domain\infra\abi,pkg\emulation,pkg\machine\apple,pkg\machine\applehv,pkg\machine\e2e,pkg\machine\libkrun,' $skippackages += 'pkg\machine\provider,pkg\machine\proxyenv,pkg\machine\qemu,pkg\specgen\generate,pkg\systemd,test\e2e,test\utils,cmd\rootlessport,' $skippackages += 'pkg\pidhandle' if ($null -eq $ENV:GINKGOTIMEOUT) { $ENV:GINKGOTIMEOUT = '--timeout=15m' } Run-Command "./bin/ginkgo.exe -vv -r --tags `"$remotetags`" ${ENV:GINKGOTIMEOUT} --trace --no-color --skip-package `"$skippackages`"" } function Local-Machine { param ( [string]$files ); Build-Ginkgo if ($files) { $files = "--focus-file ""$files""" } elseif ($FOCUS_FILE) { $files = "--focus-file ""$FOCUS_FILE"" --silence-skips" } if ($FOCUS) { $focus = "--focus ""$FOCUS"" --silence-skips" } if ($null -eq $ENV:GINKGOTIMEOUT) { $ENV:GINKGOTIMEOUT = '--timeout=50m' } Run-Command "./bin/ginkgo.exe -vv --tags `"$remotetags`" ${ENV:GINKGOTIMEOUT} --trace --no-color $focus $files pkg/machine/e2e/." } # Expect starting directory to be /podman function Win-SSHProxy { param ( [string]$Version ); New-Item -ItemType Directory -Force -Path './bin/windows' if (-Not $Version) { $match = Select-String -Path "$PSScriptRoot\go.mod" -Pattern 'github.com/containers/gvisor-tap-vsock\s+(v[\d\.]+)' $Version = $match.Matches.Groups[1].Value } Write-Host "Downloading gvproxy version $version" if ($architecture -eq 'amd64') { curl.exe -sSL -o './bin/windows/gvproxy.exe' --retry 5 "https://github.com/containers/gvisor-tap-vsock/releases/download/$Version/gvproxy-windowsgui.exe" curl.exe -sSL -o './bin/windows/win-sshproxy.exe' --retry 5 "https://github.com/containers/gvisor-tap-vsock/releases/download/$Version/win-sshproxy.exe" } else { curl.exe -sSL -o './bin/windows/gvproxy.exe' --retry 5 "https://github.com/containers/gvisor-tap-vsock/releases/download/$Version/gvproxy-windows-arm64.exe" curl.exe -sSL -o './bin/windows/win-sshproxy.exe' --retry 5 "https://github.com/containers/gvisor-tap-vsock/releases/download/$Version/win-sshproxy-arm64.exe" } } function Installer { param ( [string]$version, [string]$suffix = 'dev', [string]$installerPath = "$PSScriptRoot\contrib\win-installer" ); Write-Host "Building the windows installer for $architecture" # Check for the files to include in the installer $requiredArtifacts = @( "$PSScriptRoot\bin\windows\podman.exe" "$PSScriptRoot\bin\windows\gvproxy.exe" "$PSScriptRoot\bin\windows\win-sshproxy.exe" "$PSScriptRoot\docs\build\remote\podman-for-windows.html" ) $requiredArtifacts | ForEach-Object { if (!(Test-Path -Path $PSItem -PathType Leaf)) { Write-Host "$PSItem not found." Write-Host "Make 'podman', 'win-gvproxy' and 'docs' (or 'docs-using-podman') before making the installer:" Write-Host ' .\winmake.ps1 podman-remote' Write-Host ' .\winmake.ps1 win-gvproxy' Write-Host ' .\winmake.ps1 docs or .\winmake.ps1 docs-using-podman' Exit 1 } } # Create the ZIP file with the full client distribution $zipFileDest = "$installerPath\current" Build-Distribution-Zip-File -destinationPath $zipFileDest if (-Not $version) { # Get Podman version from local source code $version = Get-Podman-Version } # Run build.ps1 if ($installerPath -eq "$PSScriptRoot\contrib\win-installer-legacy") { $ENV:PODMAN_ARCH = $architecture # This is used by the "build.ps1" script Run-Command "$installerPath\build.ps1 $version $suffix `"$zipFileDest`"" } else { Run-Command "$installerPath\build.ps1 -Version $version -Architecture $architecture -LocalReleaseDirPath `"$zipFileDest`"" } } function Test-Installer { param ( [string]$version, [ValidateSet('wsl', 'hyperv')] [string]$provider = 'wsl' ); if (-Not $version) { # Get Podman version from local source code $version = Get-Podman-Version } $msiPath = "$PSScriptRoot\contrib\win-installer\podman-${version}.msi" if (!(Test-Path -Path $msiPath -PathType Leaf)) { Write-Host "MSI executable not found in path $msiPath." Write-Host "Make 'installer' before making the installer test:" Write-Host ' .\winmake.ps1 installer' Exit 1 } $nextMsiPath = "$PSScriptRoot\contrib\win-installer\podman-9.9.9.msi" if (!(Test-Path -Path $nextMsiPath -PathType Leaf)) { Write-Host 'The automated tests include testing the upgrade from current version to a future version.' Write-Host 'That requires a version 9.9.9 of the installer:' Write-Host ' .\winmake.ps1 installer 9.9.9' Write-Host 'Build it and retry running installertest.' Exit 1 } $command = "$PSScriptRoot\contrib\win-installer\test.ps1" $command += ' -scenario all' $command += " -provider $provider" $command += " -msiPath $msiPath" $command += " -nextMsiPath $nextMsiPath" Run-Command "${command}" } function Test-Installer-Legacy { param ( [string]$version, [ValidateSet('dev', 'prod')] [string]$flavor = 'dev', [ValidateSet('wsl', 'hyperv')] [string]$provider = 'wsl' ); if (-Not $version) { # Get Podman version from local source code $version = Get-Podman-Version } if ($flavor -eq 'prod') { $suffix = '' } else { $suffix = '-dev' } $setupExePath = "$PSScriptRoot\contrib\win-installer-legacy\podman-${version}${suffix}-setup.exe" if (!(Test-Path -Path $setupExePath -PathType Leaf)) { Write-Host "Setup executable not found in path $setupExePath." Write-Host "Make 'installer' before making the installer test:" Write-Host ' .\winmake.ps1 installer-legacy' Exit 1 } $nextSetupExePath = "$PSScriptRoot\contrib\win-installer-legacy\podman-9.9.9-dev-setup.exe" if (!(Test-Path -Path $nextSetupExePath -PathType Leaf)) { Write-Host 'The automated tests include testing the upgrade from current version to a future version.' Write-Host 'That requires a version 9.9.9 of the installer:' Write-Host ' .\winmake.ps1 installer-legacy 9.9.9' Write-Host 'Build it and retry running installertest.' Exit 1 } $command = "$PSScriptRoot\contrib\win-installer-legacy\test-installer.ps1" $command += ' -scenario all' $command += " -provider $provider" $command += " -setupExePath $setupExePath" $command += " -nextSetupExePath $nextSetupExePath" Run-Command "${command}" } function Documentation { Write-Host 'Generating the documentation artifacts' # Check that pandoc is installed if (!(Get-Command -Name 'pandoc' -ErrorAction SilentlyContinue)) { Write-Host 'Pandoc not found. Pandoc is required to convert the documentation Markdown files into HTML files.' Write-Host "Alternatively, use '.\winmake docs-using-podman' to use a container to run pandoc and generate the documentation." Exit 1 } # Check that the podman client is built $podmanClient = "$PSScriptRoot\bin\windows\podman.exe" if (!(Test-Path -Path $podmanClient -PathType Leaf)) { Write-Host "$podmanClient not found. Make 'podman-remote' before 'documentation'." Exit 1 } Run-Command "$PSScriptRoot\docs\make.ps1 $podmanClient" } # DocumentationUsingPodman generates documentation with pandoc running in a container. # This is usefult on Windows arm64 where pandoc is not available. # It's also useful to generate documentation identical to CI. # It requires the podman client to be built and a podman machine running. # The whole podman git repository is bind mounted in the container at /podman. # The documentation is generated by running the command `make podman-remote-windows-docs`. # The generated documentation is stored in the directory docs/build/remote. function DocumentationUsingPodman { Write-Host 'Generating documentation artifacts' # Check that podman has been built $podmanClient = "${PSScriptRoot}\bin\windows\podman.exe" if (!(Test-Path -Path $podmanClient -PathType Leaf)) { Write-Host "$podmanClient not found. Make 'podman-remote' before 'documentation'." Exit 1 } # Check that a podman machine exist $currentMachine = (& ${podmanClient} machine info -f json | ConvertFrom-Json).Host.CurrentMachine if (!$currentMachine) { Write-Host "Podman machine doesn't exist. Initialize and start one before running the validate script." Exit 1 } # Check that the podman machine is running $state = (& ${podmanClient} machine info -f json | ConvertFrom-Json).Host.MachineState if ($state -ne 'Running') { Write-Host 'Podman machine is not running. Start the machine before running the validate script.' Exit 1 } Write-Host 'Building the image to generate the documentation' Run-Command "${podmanClient} build --build-arg TARGET_OS=windows -t podman-docs-generator ${PSScriptRoot}/docs" Write-Host 'Starting the container to run the documentation build' Run-Command "${podmanClient} run -t --rm -v ${PSScriptRoot}:/podman podman-docs-generator" } function Validate { $podmanExecutable = 'podman' $podmanSrcVolumeMount = "${PSScriptRoot}:/go/src/github.com/containers/podman" # All files bind mounted from a Windows host are marked as executable. # That makes the pre-commit hook "check-executables-have-shebangs" fail. # Setting the environment variable "SKIP=check-executables-have-shebangs" # allow to skip that pre-commit hook. $podmanEnvVariable = '-e SKIP=check-executables-have-shebangs' $podmanRunArgs = "--rm -v $podmanSrcVolumeMount --security-opt label=disable -t -w /go/src/github.com/containers/podman $podmanEnvVariable" $validateImage = 'quay.io/libpod/validatepr:latest' $validateCommand = 'make .validatepr' # Check that podman is installed if (!(Get-Command -Name $podmanExecutable -ErrorAction SilentlyContinue)) { Write-Host "$podmanExecutable not found. $podmanExecutable is required to run the validate script." Exit 1 } # Check that a podman machine exist $currentMachine = (podman machine info -f json | ConvertFrom-Json).Host.CurrentMachine if (!$currentMachine) { Write-Host "Podman machine doesn't exist. Initialize and start one before running the validate script." Exit 1 } # Check that the podman machine is running $state = (podman machine info -f json | ConvertFrom-Json).Host.MachineState if ($state -ne 'Running') { Write-Host 'Podman machine is not running. Start the machine before running the validate script.' Exit 1 } Run-Command "$podmanExecutable run $podmanRunArgs $validateImage $validateCommand" } function Lint { # Check that golangci-lint is installed if (!(Get-Command -Name 'golangci-lint' -ErrorAction SilentlyContinue)) { Write-Host 'The tool "golangci-lint" not found. Install https://golangci-lint.run/ before running the lint script.' Exit 1 } # Check that pre-commit is installed if (!(Get-Command -Name 'pre-commit' -ErrorAction SilentlyContinue)) { Write-Host 'The tool "pre-commit" not found. Install https://pre-commit.com/ before running the lint script.' Exit 1 } Run-Command 'pre-commit run --all-files' Run-Command "golangci-lint run --timeout=10m --build-tags=`"$remotetags`" $PSScriptRoot\cmd\podman" } # Helpers function Build-Ginkgo { if (Test-Path -Path ./bin/ginkgo.exe -PathType Leaf) { return } Write-Host 'Building Ginkgo' Run-Command 'go build -o ./bin/ginkgo.exe ./vendor/github.com/onsi/ginkgo/v2/ginkgo' } function Git-Commit { # git is not installed by default on windows, # so if we can't get the commit, we don't include this info Get-Command git -ErrorAction SilentlyContinue | out-null if (!$?) { return } $commit = git rev-parse HEAD $dirty = git status --porcelain --untracked-files=no if ($dirty) { $commit = "$commit-dirty" } return $commit } function Build-Distribution-Zip-File { param ( [string]$destinationPath ); $binariesFolder = "$PSScriptRoot\bin\windows" $documentationFolder = "$PSScriptRoot\docs\build\remote\" $zipFile = "$destinationPath\podman-remote-release-windows_$architecture.zip" # Create a temporary folder to store the distribution files $tempFolder = New-Item -ItemType Directory -Force -Path "$env:TEMP\podman-windows" # Copy bin\windows\ content to the temporary folder Copy-Item -Recurse -Force -Path "$binariesFolder\*" -Destination "$tempFolder\" # Copy docs\build\remote to the temporary folder Copy-Item -Recurse -Force -Path "$documentationFolder" -Destination "$tempFolder\docs\" # If $destination path doesn't exist, create it if (-Not (Test-Path -Path $destinationPath -PathType Container)) { New-Item -ItemType Directory -Force -Path $destinationPath } # Create the ZIP file with the full client distribution Compress-Archive -Path "$tempFolder\*" -DestinationPath $zipFile -Force # Delete the temporary folder Remove-Item -Recurse -Force -Path "$tempFolder" } function Get-Podman-Version { $versionSrc = "$PSScriptRoot\test\version\" $versionBin = "$PSScriptRoot\test\version\version.exe" Run-Command "go build --o `"$versionBin`" `"$versionSrc`"" $version = Invoke-Expression "$versionBin" # Remove the '-dev' suffix from the version $version = $version -replace '-.*', '' return $version } # Init script $target = $params[0] $remotetags = 'remote exclude_graphdriver_btrfs containers_image_openpgp' switch ($target) { { $_ -in '', 'podman-remote', 'podman' } { Podman-Remote } 'localunit' { Local-Unit } 'localmachine' { if ($params.Count -gt 1) { $files = $params[1] } Local-Machine -files $files } 'clean' { Make-Clean } { $_ -in 'win-sshproxy', 'win-gvproxy' } { if ($params.Count -gt 1) { $ref = $params[1] } Win-SSHProxy($ref) } 'installer' { if ($params.Count -gt 1) { Installer -version $params[1] } else { Installer } } 'installertest' { if ($params.Count -gt 1) { Test-Installer -provider $params[1] } else { Test-Installer } } 'installer-legacy' { if ($params.Count -gt 1) { Installer -version $params[1] -installerPath $PSScriptRoot\contrib\win-installer-legacy } else { Installer -installerPath $PSScriptRoot\contrib\win-installer-legacy } } 'installertest-legacy' { if ($params.Count -gt 1) { Test-Installer-Legacy -provider $params[1] } else { Test-Installer-Legacy } } 'docs' { Documentation } 'docs-using-podman' { DocumentationUsingPodman } 'validatepr' { Validate } 'lint' { Lint } default { Write-Host 'Usage: ' $MyInvocation.MyCommand.Name ' [options] [<-architecture|-arch>=]' Write-Host Write-Host 'Example: Build podman-remote ' Write-Host ' .\winmake podman-remote' Write-Host Write-Host 'Example: Run all unit tests ' Write-Host ' .\winmake localunit' Write-Host Write-Host 'Example: Run all machine tests ' Write-Host ' .\winmake localmachine' Write-Host Write-Host 'Example: Run specfic machine tests ' Write-Host ' .\winmake localmachine 'basic_test.go"" Write-Host Write-Host 'Example: Download win-gvproxy and win-sshproxy helpers' Write-Host ' .\winmake win-gvproxy' Write-Host Write-Host 'Example: Build the windows installer' Write-Host ' .\winmake installer' Write-Host Write-Host 'Example: Run windows installer tests' Write-Host ' .\winmake installertest hyperv' Write-Host Write-Host 'Example: Generate the documentation artifacts' Write-Host ' .\winmake docs' Write-Host Write-Host 'Example: Generate the documentation artifacts by running pandoc in a container' Write-Host ' .\winmake docs-using-podman' Write-Host Write-Host 'Example: Validate code changes before submitting a PR' Write-Host ' .\winmake validatepr' Write-Host Write-Host 'Example: Run linters' Write-Host ' .\winmake lint' } }