aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOpenShift Merge Robot <openshift-merge-robot@users.noreply.github.com>2022-09-08 12:26:50 +0200
committerGitHub <noreply@github.com>2022-09-08 12:26:50 +0200
commitd729dd8c2e6556de10c4543c018fbebffa265a5e (patch)
treeb374d334aef07d3b699e4f4bdf3861de48206b75
parente46bcd72f8d6528dbafb1ad1b34abeb0177a8b77 (diff)
parent744878a71cb225fca6cf6b8f322539b717559614 (diff)
downloadpodman-d729dd8c2e6556de10c4543c018fbebffa265a5e.tar.gz
podman-d729dd8c2e6556de10c4543c018fbebffa265a5e.tar.bz2
podman-d729dd8c2e6556de10c4543c018fbebffa265a5e.zip
Merge pull request #15610 from n1hility/release-workflow
Introduce a new signed Windows installer with automated build process
-rw-r--r--.cirrus.yml24
-rw-r--r--.github/workflows/upload-win-installer.yml96
-rw-r--r--Makefile5
-rw-r--r--RELEASE_PROCESS.md37
-rw-r--r--cmd/podman-msihooks/main.go46
-rw-r--r--cmd/podman-wslkerninst/event-hook.go73
-rw-r--r--cmd/podman-wslkerninst/main.go103
-rw-r--r--contrib/cirrus/win-installer-install.ps16
-rw-r--r--contrib/cirrus/win-installer-main.ps160
-rw-r--r--contrib/win-installer/README.md28
-rw-r--r--contrib/win-installer/build-burn.bat7
-rw-r--r--contrib/win-installer/build-hooks.bat4
-rw-r--r--contrib/win-installer/build-msi.bat8
-rw-r--r--contrib/win-installer/build.ps1156
-rw-r--r--contrib/win-installer/burn.wxs43
-rw-r--r--contrib/win-installer/check.ps163
-rw-r--r--contrib/win-installer/podman-theme.wxl68
-rw-r--r--contrib/win-installer/podman-theme.xml97
-rw-r--r--contrib/win-installer/podman-ui.wxs62
-rw-r--r--contrib/win-installer/podman.wxs84
-rw-r--r--contrib/win-installer/process-release.ps1158
-rw-r--r--contrib/win-installer/resources/podman-banner.pngbin0 -> 4069 bytes
-rw-r--r--contrib/win-installer/resources/podman-banner2.pngbin0 -> 12002 bytes
-rw-r--r--contrib/win-installer/resources/podman-dialog.pngbin0 -> 14142 bytes
-rw-r--r--contrib/win-installer/resources/podman-logo.icobin0 -> 15086 bytes
-rw-r--r--contrib/win-installer/resources/podman-logo.pngbin0 -> 7153 bytes
-rw-r--r--contrib/win-installer/resources/podman-sidebar.pngbin0 -> 13016 bytes
-rw-r--r--contrib/win-installer/welcome-install-dlg.wxs31
-rw-r--r--pkg/machine/wsl/machine.go14
-rw-r--r--pkg/machine/wsl/util_windows.go15
-rw-r--r--vendor/golang.org/x/sys/windows/svc/eventlog/install.go81
-rw-r--r--vendor/golang.org/x/sys/windows/svc/eventlog/log.go70
-rw-r--r--vendor/modules.txt1
33 files changed, 1428 insertions, 12 deletions
diff --git a/.cirrus.yml b/.cirrus.yml
index dc0735836..5d9500e92 100644
--- a/.cirrus.yml
+++ b/.cirrus.yml
@@ -14,6 +14,8 @@ env:
GOPATH: &gopath "/var/tmp/go"
GOCACHE: "${GOPATH}/cache"
GOSRC: &gosrc "/var/tmp/go/src/github.com/containers/podman"
+ # Store the unaltered default location, for tasks that need it
+ CIRRUS_DEFAULT_WORK: ${CIRRUS_WORKING_DIR}
CIRRUS_WORKING_DIR: *gosrc
# The default is 'sh' if unspecified
CIRRUS_SHELL: "/bin/bash"
@@ -60,9 +62,10 @@ env:
# Curl-command prefix for downloading task artifacts, simply add the
# the url-encoded task name, artifact name, and path as a suffix.
+ ART_URL: https://api.cirrus-ci.com/v1/artifact/build/${CIRRUS_BUILD_ID}
ARTCURL: >-
curl --retry 5 --retry-delay 8 --fail --location -O
- --url https://api.cirrus-ci.com/v1/artifact/build/${CIRRUS_BUILD_ID}
+ --url ${ART_URL}
# Default timeout for each task
@@ -1019,6 +1022,7 @@ success_task:
- consistency_aarch64
- alt_build
- osx_alt_build
+ - win_installer
- docker-py_test
- unit_test
- apiv2_test
@@ -1103,6 +1107,24 @@ artifacts_task:
type: application/octet-stream
+win_installer_task:
+ name: "Verify Win Installer Build"
+ alias: win_installer
+ depends_on:
+ - alt_build
+ windows_container:
+ image: cirrusci/windowsservercore:2019
+ env:
+ PATH: "${PATH};C:\\ProgramData\\chocolatey\\bin"
+ CIRRUS_SHELL: powershell
+ CIRRUS_CLONE_DEPTH: 1
+ # Fake version, we are only testing the installer functions, so version doesn't matter
+ WIN_INST_VER: 9.9.9
+ CIRRUS_WORKING_DIR: "${CIRRUS_DEFAULT_WORK}"
+ install_script: '.\contrib\cirrus\win-installer-install.ps1'
+ main_script: '.\contrib\cirrus\win-installer-main.ps1'
+
+
# When a new tag is pushed, confirm that the code and commits
# meet criteria for an official release.
release_task:
diff --git a/.github/workflows/upload-win-installer.yml b/.github/workflows/upload-win-installer.yml
new file mode 100644
index 000000000..125100a28
--- /dev/null
+++ b/.github/workflows/upload-win-installer.yml
@@ -0,0 +1,96 @@
+name: Upload Windows Installer
+
+on:
+ release:
+ types: [created, published, edited]
+ workflow_dispatch:
+ inputs:
+ version:
+ description: 'Release version to build and upload (e.g. "4.2.1")'
+ required: true
+jobs:
+ build:
+ runs-on: windows-latest
+ env:
+ FETCH_BASE_URL: ${{ github.server_url }}/${{ github.repository }}
+ steps:
+ - name: Determine version
+ id: getversion
+ run: |
+ $version = "${{ inputs.version }}"
+ if ($version.Length -lt 1) {
+ $version = "${{ github.event.release.tag_name }}"
+ if ($version.Length -lt 1) {
+ Write-Host "Could not determine version!"
+ Exit 1
+ }
+ }
+ Write-Output "::set-output name=version::$version"
+ - uses: actions/checkout@v3
+ - name: Check
+ id: check
+ run: |
+ Push-Location contrib\win-installer
+ .\check.ps1 ${{steps.getversion.outputs.version}}
+ $code = $LASTEXITCODE
+ if ($code -eq 2) {
+ Write-Output "::set-output name=already-exists::true"
+ Pop-Location
+ Exit 0
+ }
+ Write-Output "UPLOAD_ASSET_NAME=$env:UPLOAD_ASSET_NAME" | Out-File -FilePath $env:GITHUB_ENV -Append
+ Pop-Location
+ Exit $code
+ - name: Set up Go
+ uses: actions/setup-go@v3
+ if: steps.check.outputs.already-exists != 'true'
+ with:
+ go-version: 1.18
+ - name: Setup Signature Tooling
+ if: steps.Check.outputs.already-exists != 'true'
+ run: |
+ dotnet tool install --global AzureSignTool --version 3.0.0
+ echo "CERT_NAME=${{secrets.AZ_CERT_NAME}}" | Out-File -FilePath $env:GITHUB_ENV -Append
+ echo "VAULT_ID=${{secrets.AZ_VAULT_ID}}" | Out-File -FilePath $env:GITHUB_ENV -Append
+ echo "APP_ID=${{secrets.AZ_APP_ID}}" | Out-File -FilePath $env:GITHUB_ENV -Append
+ echo "TENANT_ID=${{secrets.AZ_TENANT_ID}}" | Out-File -FilePath $env:GITHUB_ENV -Append
+ echo "CLIENT_SECRET=${{secrets.AZ_CLIENT_SECRET}}" | Out-File -FilePath $env:GITHUB_ENV -Append
+ - name: Build
+ id: build
+ if: steps.check.outputs.already-exists != 'true'
+ run: |
+ Push-Location contrib\win-installer
+ .\build.ps1 ${{steps.getversion.outputs.version}} prod
+ $code = $LASTEXITCODE
+ if ($code -eq 2) {
+ Write-Output "::set-output name=artifact-missing::true"
+ Pop-Location
+ Exit 0
+ }
+ Pop-Location
+ Exit $code
+ - name: Upload
+ if: steps.check.outputs.already-exists != 'true' && steps.build.outputs.artifact-missing != 'true'
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ run: |
+ Push-Location contrib\win-installer
+ $version = "${{ steps.getversion.outputs.version }}"
+ if ($version[0] -ne "v") {
+ $version = "v$version"
+ }
+ gh release upload $version $ENV:UPLOAD_ASSET_NAME
+ if ($LASTEXITCODE -ne 0) {
+ .\check.ps1 $version
+ if ($LASTEXITCODE -eq 2) {
+ Write-Host "Another job uploaded before us, skipping"
+ Pop-Location
+ Exit 0
+ }
+ Pop-Location
+ Exit 1
+ }
+ if (Test-Path -Path shasums) {
+ gh release upload --clobber $version shasums
+ }
+ Pop-Location
diff --git a/Makefile b/Makefile
index 0ced638a6..a42f1f181 100644
--- a/Makefile
+++ b/Makefile
@@ -690,6 +690,9 @@ podman-remote-release-%.zip: test/version/version ## Build podman-remote for %=$
else \
$(MAKE) $(GOPLAT) podman-remote; \
fi
+ if [[ "$(GOOS)" == "windows" ]]; then \
+ $(MAKE) $(GOPLAT) TMPDIR="" win-sshproxy; \
+ fi
cp -r ./docs/build/remote/$(GOOS) "$(TMPDIR)/$(SUBDIR)/docs/"
cp ./contrib/remote/containers.conf "$(TMPDIR)/$(SUBDIR)/"
$(MAKE) $(GOPLAT) $(_DSTARGS) SELINUXOPT="" install.remote
@@ -752,6 +755,8 @@ install.remote:
install ${SELINUXOPT} -d -m 755 $(DESTDIR)$(BINDIR)
install ${SELINUXOPT} -m 755 $(SRCBINDIR)/podman$(BINSFX) \
$(DESTDIR)$(BINDIR)/podman$(BINSFX)
+ test "${GOOS}" != "windows" || \
+ install -m 755 $(SRCBINDIR)/win-sshproxy.exe $(DESTDIR)$(BINDIR)
test -z "${SELINUXOPT}" || \
chcon --verbose --reference=$(DESTDIR)$(BINDIR)/podman-remote \
bin/podman-remote
diff --git a/RELEASE_PROCESS.md b/RELEASE_PROCESS.md
index 66cc74693..17590be97 100644
--- a/RELEASE_PROCESS.md
+++ b/RELEASE_PROCESS.md
@@ -244,18 +244,17 @@ spelled with complete minutiae.
$ make podman-remote-release-darwin_amd64.zip \
podman-remote-release-darwin_arm64.zip \
podman-remote-release-windows_amd64.zip \
- podman.msi \
podman-remote-static
$ mv podman-* bin/
$ cd bin/
$ tar -cvzf podman-remote-static.tar.gz podman-remote-static
- $ sha256sum *.zip *.msi *.tar.gz > shasums
+ $ sha256sum *.zip *.tar.gz > shasums
```
1. The `podman-vX.Y.Z.dmg` file is produced manually by someone in
possession of a developer signing key.
1. In the directory where you downloaded the archives, run
- `sha256sum *.tar.gz *.zip *.msi > shasums` to generate SHA sums.
+ `sha256sum *.tar.gz *.zip > shasums` to generate SHA sums.
1. Go to `https://github.com/containers/podman/releases/tag/vX.Y.Z` and
press the "Edit Release" button. Change the name to the form `vX.Y.Z`
1. If this is a release candidate be certain to click the pre-release
@@ -273,4 +272,34 @@ spelled with complete minutiae.
* podman-vX.Y.Z.msi
* podman-remote-static.tar.gz
* shasums
- 1. Save the release.
+ 1. Click the Publish button to make the release (or pre-release)
+ available.
+ 1. Check the "Actions" tab, after the publish you should see a job
+ automatically launch to build the windows installer (named after
+ the release). There may be more than one running due to the multiple
+ event states triggered, but this can be ignored, as any duplicates
+ will gracefully back-off. The job takes 5-6 minutes to complete.
+ 1. Confirm the podman-[version]-setup.exe file is now on the release
+ page. This might not be the case if you accidentally published the
+ release before uploading the binaries, as the job may look before
+ they are available. If that happens, you can either manually kick
+ off the job (see below), or just make a harmless edit to the
+ release (e.g. add an extra whitespace character somewhere). As
+ long as the body content is different in some way, a new run will
+ be triggered.
+
+ ## Manually Triggering Windows Installer Build & Upload
+
+
+ ### *CLI Approach*
+ 1. Install the GitHub CLI (e.g. `sudo dnf install gh`)
+ 1. Run (replacing below version number to release version)
+ ```
+ gh workflow run "Upload Windows Installer" -F version="4.2.0"
+ ```
+ ### *GUI Approach*
+ 1. Go to the "Actions" tab
+ 1. On the left pick the "Update Windows Installer" category
+ 1. A blue box will appear above the job list with a right side drop
+ -down. Click the drop-down and specify the version number in the
+ dialog that appears
diff --git a/cmd/podman-msihooks/main.go b/cmd/podman-msihooks/main.go
new file mode 100644
index 000000000..903c91abb
--- /dev/null
+++ b/cmd/podman-msihooks/main.go
@@ -0,0 +1,46 @@
+//go:build windows
+// +build windows
+
+package main
+
+import (
+ "C"
+ "syscall"
+ "unsafe"
+
+ "github.com/containers/podman/v4/pkg/machine/wsl"
+)
+
+const KernelWarning = "WSL Kernel installation did not complete successfully. " +
+ "Podman machine will attempt to install this at a later time. " +
+ "You can also manually complete the installation using the " +
+ "\"wsl --update\" command."
+
+//export CheckWSL
+func CheckWSL(hInstall uint32) uint32 {
+ installed := wsl.IsWSLInstalled()
+ feature := wsl.IsWSLFeatureEnabled()
+ setMsiProperty(hInstall, "HAS_WSL", strBool(installed))
+ setMsiProperty(hInstall, "HAS_WSLFEATURE", strBool(feature))
+
+ return 0
+}
+
+func setMsiProperty(hInstall uint32, name string, value string) {
+ nameW, _ := syscall.UTF16PtrFromString(name)
+ valueW, _ := syscall.UTF16PtrFromString(value)
+
+ msi := syscall.NewLazyDLL("msi")
+ proc := msi.NewProc("MsiSetPropertyW")
+ _, _, _ = proc.Call(uintptr(hInstall), uintptr(unsafe.Pointer(nameW)), uintptr(unsafe.Pointer(valueW)))
+
+}
+func strBool(val bool) string {
+ if val {
+ return "1"
+ }
+
+ return "0"
+}
+
+func main() {}
diff --git a/cmd/podman-wslkerninst/event-hook.go b/cmd/podman-wslkerninst/event-hook.go
new file mode 100644
index 000000000..a5c23e4cf
--- /dev/null
+++ b/cmd/podman-wslkerninst/event-hook.go
@@ -0,0 +1,73 @@
+//go:build windows
+// +build windows
+
+package main
+
+import (
+ "bytes"
+ "fmt"
+
+ "github.com/sirupsen/logrus"
+ "golang.org/x/sys/windows/svc/eventlog"
+)
+
+// Logrus hook that delegates to windows event log
+type EventLogHook struct {
+ events *eventlog.Log
+}
+
+type LogFormat struct {
+ name string
+}
+
+func (f *LogFormat) Format(entry *logrus.Entry) ([]byte, error) {
+ var b *bytes.Buffer
+
+ if entry.Buffer != nil {
+ b = entry.Buffer
+ } else {
+ b = &bytes.Buffer{}
+ }
+
+ fmt.Fprintf(b, "[%-5s] %s: %s", entry.Level.String(), f.name, entry.Message)
+
+ for key, value := range entry.Data {
+ fmt.Fprintf(b, " {%s = %s}", key, value)
+ }
+
+ b.WriteByte('\n')
+ return b.Bytes(), nil
+}
+
+func NewEventHook(events *eventlog.Log, name string) *EventLogHook {
+ logrus.SetFormatter(&LogFormat{name})
+ return &EventLogHook{events}
+}
+
+func (hook *EventLogHook) Fire(entry *logrus.Entry) error {
+ line, err := entry.String()
+ if err != nil {
+ return err
+ }
+
+ switch entry.Level {
+ case logrus.PanicLevel:
+ return hook.events.Error(1002, line)
+ case logrus.FatalLevel:
+ return hook.events.Error(1001, line)
+ case logrus.ErrorLevel:
+ return hook.events.Error(1000, line)
+ case logrus.WarnLevel:
+ return hook.events.Warning(1000, line)
+ case logrus.InfoLevel:
+ return hook.events.Info(1000, line)
+ case logrus.DebugLevel, logrus.TraceLevel:
+ return hook.events.Info(1001, line)
+ default:
+ return nil
+ }
+}
+
+func (hook *EventLogHook) Levels() []logrus.Level {
+ return logrus.AllLevels
+}
diff --git a/cmd/podman-wslkerninst/main.go b/cmd/podman-wslkerninst/main.go
new file mode 100644
index 000000000..0485db13c
--- /dev/null
+++ b/cmd/podman-wslkerninst/main.go
@@ -0,0 +1,103 @@
+//go:build windows
+// +build windows
+
+package main
+
+import (
+ "fmt"
+ "os"
+ "path"
+ "syscall"
+ "time"
+ "unsafe"
+
+ "github.com/containers/podman/v4/pkg/machine/wsl"
+ "github.com/sirupsen/logrus"
+ "golang.org/x/sys/windows/svc/eventlog"
+)
+
+const (
+ MB_ICONWARNING = 0x00000030
+ MB_OK = 0x00000000
+ MB_DEFBUTTON1 = 0x00000000
+)
+
+const KernelWarning = "WSL Kernel installation did not complete successfully. " +
+ "Podman machine will attempt to install this at a later time. " +
+ "You can also manually complete the installation using the " +
+ "\"wsl --update\" command."
+
+func setupLogging(name string) (*eventlog.Log, error) {
+ // Reuse the Built-in .NET Runtime Source so that we do not
+ // have to provide a messaage table and modify the system
+ // event configuration
+ log, err := eventlog.Open(".NET Runtime")
+ if err != nil {
+ return nil, err
+ }
+
+ logrus.AddHook(NewEventHook(log, name))
+ logrus.SetLevel(logrus.InfoLevel)
+
+ return log, nil
+}
+
+func installWslKernel() error {
+ logrus.Info("Installing WSL Kernel update")
+ var (
+ err error
+ )
+ backoff := 500 * time.Millisecond
+ for i := 1; i < 6; i++ {
+ err = wsl.SilentExec("wsl", "--update")
+ if err == nil {
+ break
+ }
+
+ // In case of unusual circumstances (e.g. race with installer actions)
+ // retry a few times
+ logrus.Warn("An error occurred attempting the WSL Kernel update, retrying...")
+ time.Sleep(backoff)
+ backoff *= 2
+ }
+
+ if err != nil {
+ err = fmt.Errorf("could not install WSL Kernel: %w", err)
+ }
+
+ return err
+}
+
+// Creates an "warn" style pop-up window
+func warn(title string, caption string) int {
+ format := MB_ICONWARNING | MB_OK | MB_DEFBUTTON1
+
+ user32 := syscall.NewLazyDLL("user32.dll")
+ captionPtr, _ := syscall.UTF16PtrFromString(caption)
+ titlePtr, _ := syscall.UTF16PtrFromString(title)
+ ret, _, _ := user32.NewProc("MessageBoxW").Call(
+ uintptr(0),
+ uintptr(unsafe.Pointer(captionPtr)),
+ uintptr(unsafe.Pointer(titlePtr)),
+ uintptr(format))
+
+ return int(ret)
+}
+
+func main() {
+ args := os.Args
+ setupLogging(path.Base(args[0]))
+ if wsl.IsWSLInstalled() {
+ // nothing to do
+ logrus.Info("WSL Kernel already installed")
+ return
+ }
+
+ result := installWslKernel()
+ if result != nil {
+ logrus.Error(result.Error())
+ _ = warn("Podman Setup", KernelWarning)
+ }
+
+ logrus.Info("WSL Kernel update successful")
+}
diff --git a/contrib/cirrus/win-installer-install.ps1 b/contrib/cirrus/win-installer-install.ps1
new file mode 100644
index 000000000..f3fc4508d
--- /dev/null
+++ b/contrib/cirrus/win-installer-install.ps1
@@ -0,0 +1,6 @@
+# Update service is required for dotnet 3.5 (dep of wix)
+Set-Service -Name wuauserv -StartupType "Manual"
+choco install -y wixtoolset mingw golang archiver
+if ($LASTEXITCODE -ne 0) {
+ Exit 1
+}
diff --git a/contrib/cirrus/win-installer-main.ps1 b/contrib/cirrus/win-installer-main.ps1
new file mode 100644
index 000000000..64a94ee63
--- /dev/null
+++ b/contrib/cirrus/win-installer-main.ps1
@@ -0,0 +1,60 @@
+ # Powershell doesn't exit after
+ function CheckExit {
+ if ($LASTEXITCODE -ne 0) {
+ Exit $LASTEXITCODE
+ }
+}
+function DownloadFile {
+ param(
+ [Parameter(Mandatory)]
+ [string]$url,
+ [Parameter(Mandatory)]
+ [string]$file,
+ [Int]$retries=5,
+ [Int]$delay=8
+ )
+ $ProgressPreference = 'SilentlyContinue';
+ Write-Host "Downloading $url to $file"
+ For($i = 0;;) {
+ Try {
+ Invoke-WebRequest -UseBasicParsing -ErrorAction Stop -Uri $url -OutFile $file
+ Break
+ } Catch {
+ if (++$i -gt $retries) {
+ throw $_.Exception
+ }
+ Write-Host "Download failed - retrying:" $_.Exception.Response.StatusCode
+ Start-Sleep -Seconds $delay
+ }
+ }
+}
+# Drop global envs which have unix paths, defaults are fine
+Remove-Item Env:\GOPATH
+Remove-Item Env:\GOSRC
+Remove-Item Env:\GOCACHE
+
+Set-Location contrib\win-installer
+
+# Download and extract alt_build win release zip
+$url = "${ENV:ART_URL}/Windows Cross/repo/repo.tbz"
+# Arc requires extension to be "tbz2"
+DownloadFile "$url" "repo.tbz2"
+arc unarchive repo.tbz2 .; CheckExit
+
+# Build Installer
+.\build.ps1 $Env:WIN_INST_VER dev repo; CheckExit
+
+# Run the installer silently and WSL install option disabled (prevent reboots, wsl requirements)
+# We need AllowOldWin=1 for server 2019 (cirrus image), can be dropped after server 2022
+$ret = Start-Process -Wait -PassThru ".\podman-${ENV:WIN_INST_VER}-dev-setup.exe" -ArgumentList "/install /quiet WSLCheckbox=0 AllowOldWin=1 /log inst.log"
+if ($ret.ExitCode -ne 0) {
+ Write-Host "Install failed, dumping log"
+ Get-Content inst.log
+ Exit $ret.ExitCode
+}
+if (! ((Test-Path -Path "C:\Program Files\RedHat\Podman\podman.exe") -and `
+ (Test-Path -Path "C:\Program Files\RedHat\Podman\win-sshproxy.exe"))) {
+ Write-Host "Expected podman.exe and win-sshproxy.exe, one or both not present after install"
+ Exit 1
+}
+Write-Host "Installer verification successful!"
diff --git a/contrib/win-installer/README.md b/contrib/win-installer/README.md
new file mode 100644
index 000000000..9cd1d29a5
--- /dev/null
+++ b/contrib/win-installer/README.md
@@ -0,0 +1,28 @@
+# Windows Installer Build
+
+## Requirements
+
+1. Win 10+
+2. Golang
+3. MingW
+4. Dotnet SDK (if AzureSignTool)
+5. AzureSignTool (optional)
+6. WiX Toolset
+
+## Usage
+
+```
+.\build.ps1 <version> [prod|dev] [release_dir]
+```
+
+## One off build (-dev output (default), unsigned (default))
+
+```
+.\build.ps1 4.2.0
+```
+
+## Build with a pre-downloaded win release zip in my-download dir
+
+```
+.\build.ps1 4.2.0 dev my-download
+```
diff --git a/contrib/win-installer/build-burn.bat b/contrib/win-installer/build-burn.bat
new file mode 100644
index 000000000..637a4e744
--- /dev/null
+++ b/contrib/win-installer/build-burn.bat
@@ -0,0 +1,7 @@
+@if "%1" == "" (
+ @echo "usage: build-burn.bat <version>"
+ @exit /b 1
+)
+
+candle -ext WixUIExtension -ext WixUtilExtension -ext WixBalExtension -arch x64 -dManSource="docs" -dVERSION="%1" burn.wxs || exit /b 1
+light -ext WixUIExtension -ext WixUtilExtension -ext WixBalExtension .\burn.wixobj -out podman-setup.exe || exit /b 1
diff --git a/contrib/win-installer/build-hooks.bat b/contrib/win-installer/build-hooks.bat
new file mode 100644
index 000000000..d663f87b8
--- /dev/null
+++ b/contrib/win-installer/build-hooks.bat
@@ -0,0 +1,4 @@
+cd ../..
+go build -buildmode=c-shared -o contrib/win-installer/artifacts/podman-msihooks.dll ./cmd/podman-msihooks || exit /b 1
+go build -ldflags -H=windowsgui -o contrib/win-installer/artifacts/podman-wslkerninst.exe ./cmd/podman-wslkerninst || exit /b 1
+cd contrib/win-installer
diff --git a/contrib/win-installer/build-msi.bat b/contrib/win-installer/build-msi.bat
new file mode 100644
index 000000000..28a77734d
--- /dev/null
+++ b/contrib/win-installer/build-msi.bat
@@ -0,0 +1,8 @@
+@if "%1" == "" (
+ @echo "usage: build-msi.bat <version>"
+ @exit /b 1
+)
+
+heat dir docs -var var.ManSource -cg ManFiles -dr INSTALLDIR -gg -g1 -srd -out pages.wxs || exit /b 1
+candle -ext WixUIExtension -ext WixUtilExtension -ext .\artifacts\PanelSwWixExtension.dll -arch x64 -dManSource="docs" -dVERSION="%1" podman.wxs pages.wxs podman-ui.wxs welcome-install-dlg.wxs || exit /b 1
+light -ext WixUIExtension -ext WixUtilExtension -ext .\artifacts\PanelSwWixExtension.dll .\podman.wixobj .\pages.wixobj .\podman-ui.wixobj .\welcome-install-dlg.wixobj -out podman.msi || exit /b 1
diff --git a/contrib/win-installer/build.ps1 b/contrib/win-installer/build.ps1
new file mode 100644
index 000000000..ba1b97548
--- /dev/null
+++ b/contrib/win-installer/build.ps1
@@ -0,0 +1,156 @@
+function ExitOnError() {
+ if ($LASTEXITCODE -ne 0) {
+ Exit 1
+ }
+}
+
+function FetchPanel() {
+ Remove-Item -Recurse -Force -Path fetch -ErrorAction SilentlyContinue | Out-Null
+ New-Item -Force -ItemType Directory fetch | Out-Null
+ Push-Location fetch
+
+ $ProgressPreference = 'SilentlyContinue'
+ Invoke-WebRequest -UseBasicParsing -OutFile nuget.exe -ErrorAction Stop `
+ -Uri https://dist.nuget.org/win-x86-commandline/latest/nuget.exe
+
+ .\nuget.exe install PanelSwWixExtension
+ $code = $LASTEXITCODE
+ Pop-Location
+ if ($code -gt 0) {
+ Exit 1
+ }
+ $loc = Get-ChildItem -Recurse -Path fetch -Name PanelSwWixExtension.dll
+ if (!$loc) {
+ Write-Host "Could not locate PanelSwWixExtension.dll"
+ Exit 1
+ }
+
+ Copy-Item -Path fetch/$loc -Destination artifacts/PanelSwWixExtension.dll -ErrorAction Stop
+}
+
+function SignItem() {
+ param(
+ [Parameter(Mandatory)]
+ [string[]]$fileNames
+ )
+
+ foreach ($val in $ENV:APP_ID, $ENV:TENANT_ID, $ENV:CLIENT_SECRET, $ENV:CERT_NAME) {
+ if (!$val) {
+ Write-Host "Skipping signing (no config)"
+ Return
+ }
+ }
+
+ CheckCommand AzureSignTool.exe "AzureSignTool"
+
+ AzureSignTool.exe sign -du "https://github.com/containers/podman" `
+ -kvu "https://$ENV:VAULT_ID.vault.azure.net" `
+ -kvi $ENV:APP_ID `
+ -kvt $ENV:TENANT_ID `
+ -kvs $ENV:CLIENT_SECRET `
+ -kvc $ENV:CERT_NAME `
+ -tr http://timestamp.digicert.com $fileNames
+
+ ExitOnError
+}
+
+function CheckCommand() {
+ param(
+ [Parameter(Mandatory)]
+ [string] $cmd,
+ [Parameter(Mandatory)]
+ [string] $description
+ )
+
+ if (! (Get-Command $cmd -errorAction SilentlyContinue)) {
+ Write-Host "Required dep `"$description`" is not installed"
+ Exit 1
+ }
+}
+
+function CheckRequirements() {
+ CheckCommand "gcc" "MingW CC"
+ CheckCommand "candle" "WiX Toolset"
+ CheckCommand "go" "Golang"
+}
+
+
+if ($args.Count -lt 1 -or $args[0].Length -lt 1) {
+ Write-Host "Usage: " $MyInvocation.MyCommand.Name "<version> [dev|prod] [release_dir]"
+ Write-Host
+ Write-Host 'Uses Env Vars: '
+ Write-Host ' $ENV:FETCH_BASE_URL - GitHub Repo Address to locate release on'
+ Write-Host 'Env Settings for signing (optional)'
+ Write-Host ' $ENV:VAULT_ID'
+ Write-Host ' $ENV:APP_ID'
+ Write-Host ' $ENV:TENANT_ID'
+ Write-Host ' $ENV:CLIENT_SECRET'
+ Write-Host ' $ENV:CERT_NAME'
+ Write-Host
+ Write-Host "Example: Download and build from the official Github release (dev output): "
+ Write-Host " .\build.ps1 4.2.0"
+ Write-Host
+ Write-Host "Example: Build a dev build from a pre-download release "
+ Write-Host " .\build.ps1 4.2.0 dev fetchdir"
+ Write-Host
+
+ Exit 1
+}
+
+# Pre-set to standard locations in-case build env does not refresh paths
+$Env:Path="$Env:Path;C:\Program Files (x86)\WiX Toolset v3.11\bin;C:\ProgramData\chocolatey\lib\mingw\tools\install\mingw64\bin;;C:\Program Files\Go\bin"
+
+CheckRequirements
+
+$version = $args[0]
+
+if ($version[0] -eq "v") {
+ $version = $version.Substring(1)
+}
+
+$suffix = "-dev"
+if ($args.Count -gt 1 -and $args[1] -eq "prod") {
+ $suffix = ""
+}
+
+$releaseDir = ""
+if ($args.Count -gt 2) {
+ $releaseDir = $args[2]
+}
+
+.\process-release.ps1 $version $releaseDir
+if ($LASTEXITCODE -eq 2) {
+ Write-Host "Skip signaled, relaying skip"
+ Exit 2
+}
+if ($ENV:INSTVER -eq "") {
+ Write-Host "process-release did not define an install version!"
+ Exit 1
+}
+
+FetchPanel
+
+.\build-hooks.bat; ExitOnError
+SignItem @("artifacts/win-sshproxy.exe",
+ "artifacts/podman.exe",
+ "artifacts/podman-msihooks.dll",
+ "artifacts/podman-wslkerninst.exe")
+
+.\build-msi.bat $ENV:INSTVER; ExitOnError
+SignItem @("podman.msi")
+
+.\build-burn.bat $ENV:INSTVER; ExitOnError
+insignia -ib podman-setup.exe -o engine.exe; ExitOnError
+SignItem @("engine.exe")
+
+$file = "podman-$version$suffix-setup.exe"
+insignia -ab engine.exe podman-setup.exe -o $file; ExitOnError
+SignItem @("$file")
+
+if (Test-Path -Path shasums) {
+ $hash = (Get-FileHash -Algorithm SHA256 $file).Hash.ToLower()
+ Write-Output "$hash $file" | Out-File -Append -FilePath shasums
+}
+
+Write-Host "Complete"
+Get-ChildItem "podman-$version$suffix-setup.exe"
diff --git a/contrib/win-installer/burn.wxs b/contrib/win-installer/burn.wxs
new file mode 100644
index 000000000..f4534e5fd
--- /dev/null
+++ b/contrib/win-installer/burn.wxs
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi" xmlns:bal="http://schemas.microsoft.com/wix/BalExtension" xmlns:util="http://schemas.microsoft.com/wix/UtilExtension">
+ <?ifndef var.VERSION?>
+ <?error VERSION must be defined via command line argument?>
+ <?endif?>
+ <Bundle Name="Podman" Version="$(var.VERSION)" Manufacturer="Red Hat"
+ UpgradeCode="f3e1f40a-a791-49b7-9bc6-050975293353" IconSourceFile="resources\podman-logo.ico"
+ Compressed="yes">
+ <BootstrapperApplicationRef Id="WixStandardBootstrapperApplication.HyperlinkSidebarLicense">
+ <bal:WixStandardBootstrapperApplication LicenseUrl=""
+ ThemeFile="podman-theme.xml"
+ LocalizationFile="podman-theme.wxl"
+ LogoFile="resources\podman-banner2.png"
+ LogoSideFile="resources\podman-sidebar.png"
+ SuppressOptionsUI="yes"
+ ShowVersion="yes"/>
+ </BootstrapperApplicationRef>
+ <Variable Name='InstallFolder' Type='string' Value='[ProgramFiles64Folder]RedHat\Podman'/>
+ <Variable Name="VERSION" Value="$(var.VERSION)"/>
+ <Variable Name="WSLCheckbox" Type="numeric" Value="1" bal:Overridable="yes"/>
+ <Variable Name="AllowOldWin" Type="numeric" Value="0" bal:Overridable="yes"/>
+ <Variable Name="LaunchTarget" Value="explorer.exe"/>
+ <Variable Name="LaunchArguments" Value="&quot;[InstallFolder]\podman-for-windows.html&quot;"/>
+
+ <util:RegistrySearch Id="PreviousVersionSearch" Variable="PreviousVersion" Result="value" Root="HKLM" Key="SOFTWARE\[WixBundleManufacturer]\Updates\[WixBundleName]" Value="PackageVersion"/>
+ <util:RegistrySearch Id="PreviousInstallFolderSearch" Root="HKLM" Key="SOFTWARE\[WixBundleManufacturer]\[WixBundleName]" Value="InstallDir" Variable="PreviousInstallFolder"/>
+ <util:RegistrySearch Id="CurrentBuild" Variable="CBNumber" Result="value" Root="HKLM" Key="SOFTWARE\Microsoft\Windows NT\CurrentVersion" Value="CurrentBuildNumber"/>
+ <bal:Condition Message="Windows 10 (19041) or later is required to run this application.">
+ <![CDATA[VersionNT >= v10.0 AND (CBNumber >= 19041 OR AllowOldWin = 1)]]>
+ </bal:Condition>
+ <bal:Condition Message="You have an installed development, pre-release version, or alternative build identifying as the same version of this installer. You must uninstall the existing version of Podman first, before proceeding.">
+ <![CDATA[WixBundleAction <> 5 OR WixBundleInstalled OR WixBundleForcedRestartPackage OR PreviousVersion <> VERSION]]>
+ </bal:Condition>
+ <Chain>
+ <MsiPackage Id="Setup" SourceFile="podman.msi" Vital="yes">
+ <MsiProperty Name="INSTALLDIR" Value="[InstallFolder]" />
+ <MsiProperty Name="WITH_WSL" Value="[WSLCheckbox]"/>
+ </MsiPackage>
+ <ExePackage DisplayName="WSL Kernel Install" InstallCondition="WSLCheckbox = 1" SourceFile="artifacts\podman-wslkerninst.exe"/>
+ </Chain>
+ <OptionalUpdateRegistration/>
+ </Bundle>
+</Wix>
diff --git a/contrib/win-installer/check.ps1 b/contrib/win-installer/check.ps1
new file mode 100644
index 000000000..6e3aa9c2e
--- /dev/null
+++ b/contrib/win-installer/check.ps1
@@ -0,0 +1,63 @@
+function SkipExists {
+ param(
+ [Parameter(Mandatory)]
+ [string]$url,
+ [Parameter(Mandatory)]
+ [string]$desc
+ )
+ try {
+ Invoke-WebRequest -Method HEAD -UseBasicParsing -ErrorAction Stop -Uri $url
+ Write-Host "$desc already uploaded, skipping..."
+ Exit 2
+ } Catch {
+ if ($_.Exception.Response.StatusCode -eq 404) {
+ Write-Host "$desc does not exist, continuing..."
+ Return
+ }
+
+ throw $_.Exception
+ }
+}
+
+function SkipNotExists {
+ param(
+ [Parameter(Mandatory)]
+ [string]$url,
+ [Parameter(Mandatory)]
+ [string]$desc
+ )
+ $ret = ""
+ try {
+ Invoke-WebRequest -Method HEAD -UseBasicParsing -ErrorAction Stop -Uri $url
+ Write-Host "$desc exists, continuing..."
+ } Catch {
+ if ($_.Exception.Response.StatusCode -eq 404) {
+ Write-Host "$desc does not exist, skipping ..."
+ Exit 2
+ }
+
+ throw $_.Exception
+ }
+}
+
+if ($args.Count -lt 1 -or $args[0].Length -lt 2) {
+ Write-Host "Usage: " $MyInvocation.MyCommand.Name "<version>"
+ Exit 1
+}
+
+$release = $args[0]
+$version = $release
+if ($release[0] -eq "v") {
+ $version = $release.Substring(1)
+} else {
+ $release = "v$release"
+}
+
+$base_url = "$ENV:FETCH_BASE_URL"
+if ($base_url.Length -le 0) {
+ $base_url = "https://github.com/containers/podman"
+}
+
+$ENV:UPLOAD_ASSET_NAME = "podman-$version-setup.exe"
+SkipExists "$base_url/releases/download/$release/podman-$version-setup.exe" "Installer"
+SkipNotExists "$base_url/releases/download/$release/podman-remote-release-windows_amd64.zip" "Windows client zip"
diff --git a/contrib/win-installer/podman-theme.wxl b/contrib/win-installer/podman-theme.wxl
new file mode 100644
index 000000000..7fea09054
--- /dev/null
+++ b/contrib/win-installer/podman-theme.wxl
@@ -0,0 +1,68 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. -->
+
+
+<WixLocalization Culture="en-us" Language="1033" xmlns="http://schemas.microsoft.com/wix/2006/localization">
+ <String Id="Caption">[WixBundleName] [VERSION] Setup</String>
+ <String Id="Title">[WixBundleName] [VERSION]</String>
+ <String Id="InstallHeader">Welcome to [WixBundleName] Setup</String>
+ <String Id="InstallMessage">Welcome to the [WixBundleName] [VERSION] setup wizard. This will install [WixBundleName] on your computer.
+
+Additionally, you have the option to also install WSL (required by podman) if it is not already enabled. This operation requires a reboot during the installation process. Alternatively, you can deselect the WSL checkbox, and install WSL manually using the wsl --install command.
+
+Finally, click install to continue, or Close to abort the installation.</String>
+ <String Id="InstallVersion">Version [WixBundleVersion]</String>
+ <String Id="ConfirmCancelMessage">Are you sure you want to cancel?</String>
+ <String Id="ExecuteUpgradeRelatedBundleMessage">Previous version</String>
+ <String Id="HelpHeader">Setup Help</String>
+ <String Id="HelpText">/install | /repair | /uninstall | /layout [directory] - installs, repairs, uninstalls or
+ creates a complete local copy of the bundle in directory. Install is the default.
+
+/passive | /quiet - displays minimal UI with no prompts or displays no UI and
+ no prompts. By default UI and all prompts are displayed.
+
+/norestart - suppress any attempts to restart. By default UI will prompt before restart.
+/log log.txt - logs to a specific file. By default a log file is created in %TEMP%.</String>
+ <String Id="HelpCloseButton">&amp;Close</String>
+ <String Id="InstallLicenseLinkText">[WixBundleName] &lt;a href="#"&gt;license terms&lt;/a&gt;.</String>
+ <String Id="InstallAcceptCheckbox">I &amp;agree to the license terms and conditions</String>
+ <String Id="InstallOptionsButton">&amp;Options</String>
+ <String Id="InstallInstallButton">&amp;Install</String>
+ <String Id="InstallCloseButton">&amp;Close</String>
+ <String Id="OptionsHeader">Setup Options</String>
+ <String Id="OptionsLocationLabel">Install location:</String>
+ <String Id="OptionsBrowseButton">&amp;Browse</String>
+ <String Id="OptionsOkButton">&amp;OK</String>
+ <String Id="OptionsCancelButton">&amp;Cancel</String>
+ <String Id="ProgressHeader">Setup Progress</String>
+ <String Id="ProgressLabel">Processing:</String>
+ <String Id="OverallProgressPackageText">Initializing...</String>
+ <String Id="ProgressCancelButton">&amp;Cancel</String>
+ <String Id="ModifyHeader">Modify Setup</String>
+ <String Id="ModifyRepairButton">&amp;Repair</String>
+ <String Id="ModifyUninstallButton">&amp;Uninstall</String>
+ <String Id="ModifyCloseButton">&amp;Close</String>
+ <String Id="SuccessRepairHeader">Repair Successfully Completed</String>
+ <String Id="SuccessUninstallHeader">Uninstall Successfully Completed</String>
+ <String Id="SuccessInstallHeader">Installation Successfully Completed</String>
+ <String Id="SuccessHeader">Setup Successful</String>
+ <String Id="SuccessLaunchButton">&amp;Open Guide &amp;&amp; Close</String>
+ <String Id="SuccessRestartText">You must restart your computer before you can use the software.</String>
+ <String Id="SuccessRestartButton">&amp;Restart</String>
+ <String Id="SuccessCloseButton">&amp;Close</String>
+ <String Id="FailureHeader">Setup Failed</String>
+ <String Id="FailureInstallHeader">Setup Failed</String>
+ <String Id="FailureUninstallHeader">Uninstall Failed</String>
+ <String Id="FailureRepairHeader">Repair Failed</String>
+ <String Id="FailureHyperlinkLogText">One or more issues caused the setup to fail. Please fix the issues and then retry setup. For more information see the &lt;a href="#"&gt;log file&lt;/a&gt;.</String>
+ <String Id="FailureRestartText">You must restart your computer to complete the rollback of the software.</String>
+ <String Id="FailureRestartButton">&amp;Restart</String>
+ <String Id="FailureCloseButton">&amp;Close</String>
+ <String Id="FilesInUseHeader">Files In Use</String>
+ <String Id="FilesInUseLabel">The following applications are using files that need to be updated:</String>
+ <String Id="FilesInUseCloseRadioButton">Close the &amp;applications and attempt to restart them.</String>
+ <String Id="FilesInUseDontCloseRadioButton">&amp;Do not close applications. A reboot will be required.</String>
+ <String Id="FilesInUseOkButton">&amp;OK</String>
+ <String Id="FilesInUseCancelButton">&amp;Cancel</String>
+ <String Id="ErrorFailNoActionReboot">No action was taken as a system reboot is required.</String>
+</WixLocalization>
diff --git a/contrib/win-installer/podman-theme.xml b/contrib/win-installer/podman-theme.xml
new file mode 100644
index 000000000..8d7be5d72
--- /dev/null
+++ b/contrib/win-installer/podman-theme.xml
@@ -0,0 +1,97 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. -->
+
+
+<Theme xmlns="http://wixtoolset.org/schemas/thmutil/2010">
+ <Window Width="600" Height="450" HexStyle="100a0000" FontId="0">#(loc.Title) Setup</Window>
+ <Font Id="0" Height="-12" Weight="500" Foreground="000000" Background="FFFFFF">Segoe UI</Font>
+ <Font Id="1" Height="-24" Weight="500" Foreground="000000">Segoe UI</Font>
+ <Font Id="2" Height="-22" Weight="500" Foreground="666666">Segoe UI</Font>
+ <Font Id="3" Height="-12" Weight="500" Foreground="000000" Background="FFFFFF">Segoe UI</Font>
+ <Font Id="4" Height="-12" Weight="500" Foreground="ff0000" Background="FFFFFF" Underline="yes">Segoe UI</Font>
+ <Font Id="5" Height="-28" Weight="500" Foreground="666666">Segoe UI</Font>
+ <Font Id="6" Height="-12" Weight="600" Foreground="000000" Background="FFFFFF">Segoe UI</Font>
+ <!-- Divider -->
+ <Font Id="7" Height="-24" Weight="500" Foreground="000000" Background="E0E0E0">Segoe UI</Font>
+ <Text X="11" Y="-45" Width="-11" Height="2" FontId="7" Visible="yes"></Text>
+ <Page Name="Help">
+ <Image X="11" Y="11" Width="206" Height="64" ImageFile="logo.png"/>
+ <Text X="11" Y="80" Width="-11" Height="32" FontId="2" DisablePrefix="yes">#(loc.HelpHeader)</Text>
+ <Text X="11" Y="121" Width="-11" Height="-35" FontId="3" DisablePrefix="yes">#(loc.HelpText)</Text>
+ <Button Name="HelpCancelButton" X="-11" Y="-11" Width="75" Height="23" TabStop="yes" FontId="0">#(loc.HelpCloseButton)</Button>
+ </Page>
+ <Page Name="Install">
+ <Image X="11" Y="11" Width="165" Height="364" ImageFile="logoside.png"/>
+ <Text X="185" Y="11" Width="-11" Height="40" FontId="5" DisablePrefix="yes">#(loc.InstallHeader)</Text>
+ <Text X="185" Y="82" Width="-11" Height="160" FontId="3" DisablePrefix="yes">#(loc.InstallMessage)</Text><!-- HexStyle="0x800000" -->
+
+ <Hypertext Name="EulaHyperlink" X="185" Y="-111" Width="-11" Height="17" TabStop="yes" FontId="3" HideWhenDisabled="yes">#(loc.InstallLicenseLinkText)</Hypertext>
+ <Text Name="InstallVersion" X="185" Y="-61" Width="-11" Height="17" FontId="3" DisablePrefix="yes" HideWhenDisabled="yes">#(loc.InstallVersion)</Text>
+ <Checkbox Name="WSLCheckbox" X="185" Y="250" Width="-11" Height="17" TabStop="yes" FontId="6" HideWhenDisabled="yes">Install WSL if not present</Checkbox>
+ <Button Name="OptionsButton" X="-171" Y="-11" Width="75" Height="23" TabStop="yes" FontId="0" HideWhenDisabled="yes">#(loc.InstallOptionsButton)</Button>
+ <Button Name="InstallButton" X="-91" Y="-11" Width="75" Height="23" TabStop="yes" FontId="0">#(loc.InstallInstallButton)</Button>
+ <Button Name="WelcomeCancelButton" X="-11" Y="-11" Width="75" Height="23" TabStop="yes" FontId="0">#(loc.InstallCloseButton)</Button>
+ </Page>
+ <Page Name="Options">
+ <Image X="11" Y="11" Width="206" Height="64" ImageFile="logo.png"/>
+ <Text X="11" Y="80" Width="-11" Height="30" FontId="2" DisablePrefix="yes">#(loc.OptionsHeader)</Text>
+ <Text X="11" Y="121" Width="-11" Height="17" FontId="3">#(loc.OptionsLocationLabel)</Text>
+ <Editbox Name="FolderEditbox" X="11" Y="143" Width="-91" Height="21" TabStop="yes" FontId="3" FileSystemAutoComplete="yes" />
+ <Button Name="BrowseButton" X="-11" Y="142" Width="75" Height="23" TabStop="yes" FontId="3">#(loc.OptionsBrowseButton)</Button>
+
+ <Button Name="OptionsOkButton" X="-91" Y="-11" Width="75" Height="23" TabStop="yes" FontId="0">#(loc.OptionsOkButton)</Button>
+ <Button Name="OptionsCancelButton" X="-11" Y="-11" Width="75" Height="23" TabStop="yes" FontId="0">#(loc.OptionsCancelButton)</Button>
+ </Page>
+ <Page Name="FilesInUse">
+ <Image X="11" Y="11" Width="206" Height="64" ImageFile="logo.png"/>
+ <Text X="11" Y="80" Width="-11" Height="30" FontId="2" DisablePrefix="yes">#(loc.FilesInUseHeader)</Text>
+ <Text X="11" Y="121" Width="-11" Height="34" FontId="3" DisablePrefix="yes">#(loc.FilesInUseLabel)</Text>
+ <Text Name="FilesInUseText" X="11" Y="150" Width="-11" Height="-86" FontId="3" DisablePrefix="yes" HexStyle="0x0000000C"></Text>
+
+ <Button Name="FilesInUseCloseRadioButton" X="11" Y="-70" Width="-11" Height="23" TabStop="yes" FontId="0" HideWhenDisabled="yes" HexStyle="0x000009">#(loc.FilesInUseCloseRadioButton)</Button>
+ <Button Name="FilesInUseDontCloseRadioButton" X="11" Y="-50" Width="-11" Height="23" TabStop="yes" FontId="0" HideWhenDisabled="yes" HexStyle="0x000009">#(loc.FilesInUseDontCloseRadioButton)</Button>
+
+ <Button Name="FilesInUseOkButton" X="-91" Y="-11" Width="75" Height="23" TabStop="yes" FontId="0" HideWhenDisabled="yes">#(loc.FilesInUseOkButton)</Button>
+ <Button Name="FilesInUseCancelButton" X="-11" Y="-11" Width="75" Height="23" TabStop="yes" FontId="0">#(loc.FilesInUseCancelButton)</Button>
+ </Page>
+ <Page Name="Progress">
+ <Image X="11" Y="11" Width="206" Height="64" ImageFile="logo.png"/>
+ <Text X="11" Y="80" Width="-11" Height="30" FontId="2" DisablePrefix="yes">#(loc.ProgressHeader)</Text>
+ <Text X="11" Y="141" Width="70" Height="17" FontId="3" DisablePrefix="yes">#(loc.ProgressLabel)</Text>
+ <Text Name="OverallProgressPackageText" X="85" Y="141" Width="-11" Height="17" FontId="3" DisablePrefix="yes">#(loc.OverallProgressPackageText)</Text>
+ <Progressbar Name="OverallCalculatedProgressbar" X="11" Y="163" Width="-11" Height="20" />
+ <Button Name="ProgressCancelButton" X="-11" Y="-11" Width="75" Height="23" TabStop="yes" FontId="0">#(loc.ProgressCancelButton)</Button>
+ </Page>
+ <Page Name="Modify">
+ <Text X="185" Y="11" Width="-11" Height="32" FontId="1" DisablePrefix="yes">#(loc.Title)</Text>
+ <Image X="11" Y="11" Width="165" Height="364" ImageFile="logoside.png"/>
+ <Text X="185" Y="50" Width="-11" Height="30" FontId="2" DisablePrefix="yes">#(loc.ModifyHeader)</Text>
+ <Button Name="RepairButton" X="-171" Y="-11" Width="75" Height="23" TabStop="yes" FontId="0" HideWhenDisabled="yes">#(loc.ModifyRepairButton)</Button>
+ <Button Name="UninstallButton" X="-91" Y="-11" Width="75" Height="23" TabStop="yes" FontId="0">#(loc.ModifyUninstallButton)</Button>
+ <Button Name="ModifyCancelButton" X="-11" Y="-11" Width="75" Height="23" TabStop="yes" FontId="0">#(loc.ModifyCloseButton)</Button>
+ </Page>
+ <Page Name="Success">
+ <Text X="185" Y="11" Width="-11" Height="32" FontId="1" DisablePrefix="yes">#(loc.Title)</Text>
+ <Image X="11" Y="11" Width="165" Height="364" ImageFile="logoside.png"/>
+ <Text Name="SuccessHeader" X="185" Y="50" Width="-11" Height="30" FontId="2" HideWhenDisabled="yes" DisablePrefix="yes">#(loc.SuccessHeader)</Text>
+ <Text Name="SuccessInstallHeader" X="185" Y="50" Width="-11" Height="100" FontId="2" HideWhenDisabled="yes" DisablePrefix="yes">#(loc.SuccessInstallHeader)</Text>
+ <Text Name="SuccessRepairHeader" X="185" Y="50" Width="-11" Height="100" FontId="2" HideWhenDisabled="yes" DisablePrefix="yes">#(loc.SuccessRepairHeader)</Text>
+ <Text Name="SuccessUninstallHeader" X="185" Y="50" Width="-11" Height="30" FontId="2" HideWhenDisabled="yes" DisablePrefix="yes">#(loc.SuccessUninstallHeader)</Text>
+ <Button Name="LaunchButton" X="-91" Y="-11" Width="125" Height="23" TabStop="yes" FontId="0" HideWhenDisabled="yes">#(loc.SuccessLaunchButton)</Button>
+ <Text Name="SuccessRestartText" X="185" Y="-51" Width="400" Height="34" FontId="3" HideWhenDisabled="yes" DisablePrefix="yes">#(loc.SuccessRestartText)</Text>
+ <Button Name="SuccessRestartButton" X="-91" Y="-11" Width="75" Height="23" TabStop="yes" FontId="0" HideWhenDisabled="yes">#(loc.SuccessRestartButton)</Button>
+ <Button Name="SuccessCancelButton" X="-11" Y="-11" Width="75" Height="23" TabStop="yes" FontId="0">#(loc.SuccessCloseButton)</Button>
+ </Page>
+ <Page Name="Failure">
+ <Image X="11" Y="11" Width="165" Height="364" ImageFile="logoside.png"/>
+ <Text Name="FailureHeader" X="185" Y="50" Width="-11" Height="30" FontId="2" HideWhenDisabled="yes" DisablePrefix="yes">#(loc.FailureHeader)</Text>
+ <Text Name="FailureInstallHeader" X="185" Y="50" Width="-11" Height="30" FontId="2" HideWhenDisabled="yes" DisablePrefix="yes">#(loc.FailureInstallHeader)</Text>
+ <Text Name="FailureUninstallHeader" X="185" Y="50" Width="-11" Height="30" FontId="2" HideWhenDisabled="yes" DisablePrefix="yes">#(loc.FailureUninstallHeader)</Text>
+ <Text Name="FailureRepairHeader" X="185" Y="50" Width="-11" Height="30" FontId="2" HideWhenDisabled="yes" DisablePrefix="yes">#(loc.FailureRepairHeader)</Text>
+ <Hypertext Name="FailureLogFileLink" X="185" Y="121" Width="-11" Height="68" FontId="3" TabStop="yes" HideWhenDisabled="yes">#(loc.FailureHyperlinkLogText)</Hypertext>
+ <Hypertext Name="FailureMessageText" X="185" Y="-115" Width="-11" Height="80" FontId="3" TabStop="yes" HideWhenDisabled="yes" />
+ <Text Name="FailureRestartText" X="185" Y="-57" Width="-11" Height="80" FontId="3" HideWhenDisabled="yes" DisablePrefix="yes">#(loc.FailureRestartText)</Text>
+ <Button Name="FailureRestartButton" X="-91" Y="-11" Width="75" Height="23" TabStop="yes" FontId="0" HideWhenDisabled="yes">#(loc.FailureRestartButton)</Button>
+ <Button Name="FailureCloseButton" X="-11" Y="-11" Width="75" Height="23" TabStop="yes" FontId="0">#(loc.FailureCloseButton)</Button>
+ </Page>
+</Theme>
diff --git a/contrib/win-installer/podman-ui.wxs b/contrib/win-installer/podman-ui.wxs
new file mode 100644
index 000000000..127045950
--- /dev/null
+++ b/contrib/win-installer/podman-ui.wxs
@@ -0,0 +1,62 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. -->
+
+<!--
+First-time install dialog sequence:
+ - WixUI_WelcomeEulaDlg
+
+Maintenance dialog sequence:
+ WixUI_MaintenanceWelcomeDlg
+ - WixUI_MaintenanceTypeDlg
+ - WixUI_VerifyReadyDlg
+
+Patch dialog sequence:
+ - WixUI_WelcomeDlg
+ - WixUI_VerifyReadyDlg
+-->
+
+<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
+ <Fragment>
+ <UI Id="PodmanUI">
+ <TextStyle Id="WixUI_Font_Normal" FaceName="Tahoma" Size="8" />
+ <TextStyle Id="WixUI_Font_Bigger" FaceName="Tahoma" Size="12" />
+ <TextStyle Id="WixUI_Font_Title" FaceName="Tahoma" Size="9" Bold="yes" />
+
+ <Property Id="DefaultUIFont" Value="WixUI_Font_Normal" />
+ <Property Id="WixUI_Mode" Value="Minimal" />
+
+ <DialogRef Id="ErrorDlg" />
+ <DialogRef Id="FatalError" />
+ <DialogRef Id="FilesInUse" />
+ <DialogRef Id="MsiRMFilesInUse" />
+ <DialogRef Id="PrepareDlg" />
+ <DialogRef Id="ProgressDlg" />
+ <DialogRef Id="ResumeDlg" />
+ <DialogRef Id="UserExit" />
+ <DialogRef Id="WelcomeDlg" />
+ <DialogRef Id="WelcomeInstallDlg" />
+
+ <Publish Dialog="ExitDialog" Control="Finish" Event="EndDialog" Value="Return" Order="999">1</Publish>
+
+ <Publish Dialog="VerifyReadyDlg" Control="Back" Event="NewDialog" Value="MaintenanceTypeDlg">1</Publish>
+
+ <Publish Dialog="MaintenanceWelcomeDlg" Control="Next" Event="NewDialog" Value="MaintenanceTypeDlg">1</Publish>
+
+ <Publish Dialog="MaintenanceTypeDlg" Control="RepairButton" Event="NewDialog" Value="VerifyReadyDlg">1</Publish>
+ <Publish Dialog="MaintenanceTypeDlg" Control="RemoveButton" Event="NewDialog" Value="VerifyReadyDlg">1</Publish>
+ <Publish Dialog="MaintenanceTypeDlg" Control="Back" Event="NewDialog" Value="MaintenanceWelcomeDlg">1</Publish>
+
+ <Publish Dialog="WelcomeDlg" Control="Next" Event="NewDialog" Value="VerifyReadyDlg">Installed AND PATCH</Publish>
+ <Publish Dialog="VerifyReadyDlg" Control="Back" Event="NewDialog" Value="WelcomeDlg" Order="2">Installed AND PATCH</Publish>
+
+ <InstallUISequence>
+ <Show Dialog="WelcomeDlg" Before="WelcomeInstallDlg">Installed AND PATCH</Show>
+ <Show Dialog="WelcomeInstallDlg" Before="ProgressDlg">(NOT Installed) AND NOT AFTERREBOOT</Show>
+ </InstallUISequence>
+
+ <Property Id="ARPNOMODIFY" Value="1" />
+ </UI>
+
+ <UIRef Id="WixUI_Common" />
+ </Fragment>
+</Wix>
diff --git a/contrib/win-installer/podman.wxs b/contrib/win-installer/podman.wxs
new file mode 100644
index 000000000..b61bb2802
--- /dev/null
+++ b/contrib/win-installer/podman.wxs
@@ -0,0 +1,84 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi"
+ xmlns:PanelSW="http://schemas.panel-sw.co.il/wix/WixExtension">
+
+ <?ifndef var.VERSION?>
+ <?error VERSION must be defined via command line argument?>
+ <?endif?>
+
+ <Product Name="Podman $(var.VERSION)" Id="*" UpgradeCode="696BAB5D-CA1F-4B05-B123-320F245B8D6D" Version="$(var.VERSION)" Language="1033" Manufacturer="Red Hat Inc.">
+
+ <Package Id="*" Platform="x64" Keywords="Installer" Description="Red Hat's Podman $(var.VERSION) Installer" Comments="Apache 2.0 License" Manufacturer="Red Hat Inc." InstallScope="perMachine" InstallerVersion="200" Compressed="yes"/>
+
+ <Media Id="1" Cabinet="Podman.cab" EmbedCab="yes"/>
+ <MajorUpgrade AllowDowngrades="yes"/>
+ <Property Id="DiskPrompt" Value="Red Hat's Podman $(var.VERSION) Installation"/>
+ <SetProperty Id="WSL_INSTALL" Before="AppSearch" Value="1" Sequence="first">NOT (WITH_WSL = 0)</SetProperty>
+ <Directory Id="TARGETDIR" Name="SourceDir">
+ <Directory Id="ProgramFiles64Folder" Name="PFiles">
+ <Directory Id="RedHatPFiles" Name="RedHat">
+ <Directory Id="INSTALLDIR" Name="Podman">
+ <Component Id="INSTALLDIR_Component" Guid="14B310C4-9B5D-4DA5-ADF9-B9D008E4CD82" Win64="yes">
+ <CreateFolder/>
+ </Component>
+ <Component Id="MainExecutable" Guid="73752F94-6589-4C7B-ABED-39D655A19714" Win64="yes">
+ <File Id="MainExecutableFile" Name="podman.exe" Source="artifacts/podman.exe" KeyPath="yes"/>
+ </Component>
+ <Component Id="WinSshProxyExecutable" Guid="0DA730AB-2F97-40E8-A8FC-356E88EAA4D2" Win64="yes">
+ <File Id="WinSshProxyExecutableFile" Name="win-sshproxy.exe" Source="artifacts/win-sshproxy.exe" KeyPath="yes"/>
+ </Component>
+ <Component Id="GuideHTMLComponent" Guid="8B23C76B-F7D4-4030-8C46-1B5729E616B5" Win64="yes">
+ <File Id="GuideHTMLFile" Name="welcome-podman.html" Source="docs/podman-for-windows.html" KeyPath="yes"/>
+ </Component>
+ </Directory>
+ </Directory>
+ </Directory>
+ <Directory Id="EnvEntries">
+ <Component Id="EnvEntriesComponent" Guid="b662ec43-0e0e-4018-8bf3-061904bb8f5b" Win64="yes">
+ <CreateFolder />
+ <Environment Id='UpdatePath' Name='PATH' Action='set' Permanent='no' System='yes' Part='last' Value='[INSTALLDIR]' />
+ </Component>
+ </Directory>
+ </Directory>
+
+ <CustomAction Id="OpenGuide" BinaryKey="WixCA" DllEntry="WixShellExec" Impersonate="yes" />
+ <CustomAction Id="CheckWSL" BinaryKey="PodmanHooks" Execute="immediate" DllEntry="CheckWSL" />
+ <CustomActionRef Id="WixBroadcastEnvironmentChange" />
+ <ComponentGroup Id="WSLFeature" Directory="INSTALLDIR">
+ <Component>
+ <Condition>(NOT Installed) AND WSL_INSTALL = 1 AND HAS_WSLFEATURE = 0</Condition>
+ <File Source="$(sys.SOURCEFILEPATH)"/>
+ <PanelSW:Dism EnableFeature="VirtualMachinePlatform" ErrorHandling="prompt"/>
+ <PanelSW:Dism EnableFeature="Microsoft-Windows-Subsystem-Linux" ErrorHandling="prompt"/>
+ </Component>
+ </ComponentGroup>
+ <Feature Id="Complete" Level="1">
+ <ComponentRef Id="INSTALLDIR_Component"/>
+ <ComponentRef Id="EnvEntriesComponent"/>
+ <ComponentRef Id="MainExecutable"/>
+ <ComponentRef Id="WinSshProxyExecutable"/>
+ <ComponentRef Id="GuideHTMLComponent"/>
+ <ComponentGroupRef Id="ManFiles"/>
+ <ComponentGroupRef Id="WSLFeature"/>
+ </Feature>
+
+ <Icon Id="podman.ico" SourceFile="resources/podman-logo.ico"/>
+ <Property Id="ARPPRODUCTICON" Value="podman.ico"/>
+ <Property Id="WixShellExecTarget" Value="[#GuideHTMLFile]" />
+ <Property Id="WIXUI_EXITDIALOGOPTIONALCHECKBOXTEXT" Value="Show Getting Started Guide" />
+ <Property Id="WIXUI_EXITDIALOGOPTIONALCHECKBOX" Value="1" />
+ <WixVariable Id="WixUIBannerBmp" Value="resources\podman-banner.png" />
+ <WixVariable Id="WixUIDialogBmp" Value="resources\podman-dialog.png" />
+ <UIRef Id="PodmanUI"/>
+ <UI>
+ <Publish Dialog="ExitDialog" Control="Finish" Event="DoAction"
+ Value="OpenGuide">WIXUI_EXITDIALOGOPTIONALCHECKBOX = 1 and NOT Installed</Publish>
+ </UI>
+
+ <InstallExecuteSequence>
+ <Custom Action="CheckWSL" After="SetWSL_INSTALL">WSL_INSTALL = 1</Custom>
+ <ForceReboot Before="StopServices">(NOT Installed) AND WSL_INSTALL = 1 AND HAS_WSLFEATURE = 0 AND NOT AFTERREBOOT</ForceReboot>
+ </InstallExecuteSequence>
+ <Binary Id="PodmanHooks" SourceFile="artifacts/podman-msihooks.dll" />
+ </Product>
+</Wix>
diff --git a/contrib/win-installer/process-release.ps1 b/contrib/win-installer/process-release.ps1
new file mode 100644
index 000000000..ba7b47f4b
--- /dev/null
+++ b/contrib/win-installer/process-release.ps1
@@ -0,0 +1,158 @@
+function Copy-Artifact {
+ param(
+ [Parameter(Mandatory)]
+ [string]$fileName
+ )
+ $file = Get-ChildItem -Recurse -Path . -Name $fileName
+ if (!$file) {
+ throw "Could not find $filename"
+ }
+ Write-Host "file:" $file
+ Copy-Item -Path $file -Destination "..\artifacts\$filename" -ErrorAction Stop
+}
+
+function DownloadOrSkip {
+ param(
+ [Parameter(Mandatory)]
+ [string]$url,
+ [Parameter(Mandatory)]
+ [string]$file
+ )
+ $ProgressPreference = 'SilentlyContinue';
+ try {
+ Invoke-WebRequest -UseBasicParsing -ErrorAction Stop -Uri $url -OutFile $file
+ } Catch {
+ if ($_.Exception.Response.StatusCode -eq 404) {
+ Write-Host "URL not available, signaling skip:"
+ Write-Host "URL: $url"
+ Exit 2
+ }
+
+ throw $_.Exception
+ }
+}
+
+function DownloadOptional {
+ param(
+ [Parameter(Mandatory)]
+ [string]$url,
+ [Parameter(Mandatory)]
+ [string]$file
+ )
+ $ProgressPreference = 'SilentlyContinue';
+ try {
+ Invoke-WebRequest -UseBasicParsing -ErrorAction Stop -Uri $url -OutFile $file
+ } Catch {
+ }
+
+ Return
+}
+
+
+if ($args.Count -lt 1) {
+ Write-Host "Usage: " $MyInvocation.MyCommand.Name "<version> [release_dir]"
+ Exit 1
+}
+
+$releaseDir = ""
+if ($args.Count -gt 1 -and $args[1].Length -gt 0) {
+ $path = $args[1]
+ $releaseDir = (Resolve-Path -Path "$path" -ErrorAction Stop).Path
+}
+
+
+$base_url = "$ENV:FETCH_BASE_URL"
+if ($base_url.Length -le 0) {
+ $base_url = "https://github.com/containers/podman"
+}
+
+$version = $args[0]
+if ($version -notmatch '^v?([0-9]+\.[0-9]+\.[0-9]+)(-.*)?$') {
+ Write-Host "Invalid version"
+ Exit 1
+}
+
+# WiX burn requires a QWORD version only, numeric only
+$Env:INSTVER=$Matches[1]
+
+if ($version[0] -ne 'v') {
+ $version = 'v' + $version
+}
+
+$restore = 0
+$exitCode = 0
+
+try {
+ Write-Host "Cleaning up old artifacts"
+ Remove-Item -Force -Recurse -Path .\docs -ErrorAction SilentlyContinue | Out-Null
+ Remove-Item -Force -Recurse -Path .\artifacts -ErrorAction SilentlyContinue | Out-Null
+ Remove-Item -Force -Recurse -Path .\fetch -ErrorAction SilentlyContinue | Out-Null
+
+ New-Item fetch -ItemType Directory | Out-Null
+ New-Item artifacts -ItemType Directory | Out-Null
+
+ Write-Host "Fetching zip release"
+
+ Push-Location fetch -ErrorAction Stop
+ $restore = 1
+ $ProgressPreference = 'SilentlyContinue';
+
+ if ($releaseDir.Length -gt 0) {
+ Copy-Item -Path "$releaseDir/podman-remote-release-windows_amd64.zip" "release.zip"
+ } else {
+ DownloadOrSkip "$base_url/releases/download/$version/podman-remote-release-windows_amd64.zip" "release.zip"
+ DownloadOptional "$base_url/releases/download/$version/shasums" ..\shasums
+ }
+ Expand-Archive -Path release.zip
+ $loc = Get-ChildItem -Recurse -Path . -Name win-sshproxy.exe
+ if (!$loc) {
+ if ($releaseDir.Length -gt 0) {
+ throw "Release dir only supports zip which includes win-sshproxy.exe"
+ }
+ Write-Host "Old release, zip does not include win-sshproxy.exe, fetching via msi"
+ DownloadOrSkip "$base_url/releases/download/$version/podman-$version.msi" "podman.msi"
+ dark -x expand ./podman.msi
+ if (!$?) {
+ throw "Dark command failed"
+ }
+ $loc = Get-ChildItem -Recurse -Path expand -Name 4A2AD125-34E7-4BD8-BE28-B2A9A5EDBEB5
+ if (!$loc) {
+ throw "Could not obtain win-sshproxy.exe"
+ }
+ Copy-Item -Path "expand\$loc" -Destination "win-sshproxy.exe" -ErrorAction Stop
+ Remove-Item -Recurse -Force -Path expand
+ }
+
+ Write-Host "Copying artifacts"
+ Foreach ($fileName in "win-sshproxy.exe", "podman.exe") {
+ Copy-Artifact($fileName)
+ }
+
+ $docsloc = Get-ChildItem -Path . -Name docs -Recurse
+ $loc = Get-ChildItem -Recurse -Path . -Name podman-for-windows.html
+ if (!$loc) {
+ Write-Host "Old release did not include welcome page, using podman-machine instead"
+ $loc = Get-ChildItem -Recurse -Path . -Name podman-machine.html
+ Copy-Item -Path $loc -Destination "$docsloc\podman-for-windows.html"
+ }
+
+ Write-Host "Copying docs"
+ Copy-Item -Recurse -Path $docsloc -Destination ..\docs -ErrorAction Stop
+ Write-Host "Done!"
+
+ if (!$loc) {
+ throw "Could not find docs"
+ }
+}
+catch {
+ Write-Host $_
+
+ $exitCode = 1
+}
+finally {
+ if ($restore) {
+ Pop-Location
+ }
+}
+
+exit $exitCode
diff --git a/contrib/win-installer/resources/podman-banner.png b/contrib/win-installer/resources/podman-banner.png
new file mode 100644
index 000000000..e5070db98
--- /dev/null
+++ b/contrib/win-installer/resources/podman-banner.png
Binary files differ
diff --git a/contrib/win-installer/resources/podman-banner2.png b/contrib/win-installer/resources/podman-banner2.png
new file mode 100644
index 000000000..88ee1bfad
--- /dev/null
+++ b/contrib/win-installer/resources/podman-banner2.png
Binary files differ
diff --git a/contrib/win-installer/resources/podman-dialog.png b/contrib/win-installer/resources/podman-dialog.png
new file mode 100644
index 000000000..cf0c49d98
--- /dev/null
+++ b/contrib/win-installer/resources/podman-dialog.png
Binary files differ
diff --git a/contrib/win-installer/resources/podman-logo.ico b/contrib/win-installer/resources/podman-logo.ico
new file mode 100644
index 000000000..cb1dab6a7
--- /dev/null
+++ b/contrib/win-installer/resources/podman-logo.ico
Binary files differ
diff --git a/contrib/win-installer/resources/podman-logo.png b/contrib/win-installer/resources/podman-logo.png
new file mode 100644
index 000000000..5df6453a8
--- /dev/null
+++ b/contrib/win-installer/resources/podman-logo.png
Binary files differ
diff --git a/contrib/win-installer/resources/podman-sidebar.png b/contrib/win-installer/resources/podman-sidebar.png
new file mode 100644
index 000000000..cc0249706
--- /dev/null
+++ b/contrib/win-installer/resources/podman-sidebar.png
Binary files differ
diff --git a/contrib/win-installer/welcome-install-dlg.wxs b/contrib/win-installer/welcome-install-dlg.wxs
new file mode 100644
index 000000000..cc0f1c643
--- /dev/null
+++ b/contrib/win-installer/welcome-install-dlg.wxs
@@ -0,0 +1,31 @@
+<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
+ <Fragment>
+ <UI>
+ <Dialog Id="WelcomeInstallDlg" Width="370" Height="270" Title="!(loc.WelcomeDlg_Title)">
+ <Control Id="Bitmap" Type="Bitmap" X="0" Y="0" Width="370" Height="234" TabSkip="no" Text="!(loc.WelcomeDlgBitmap)" />
+ <Control Id="Title" Type="Text" X="135" Y="20" Width="220" Height="60" Transparent="yes" NoPrefix="yes" Text="!(loc.WelcomeDlgTitle)" />
+ <Control Id="BottomLine" Type="Line" X="0" Y="234" Width="370" Height="0" />
+ <Control Id="Description" Type="Text" X="135" Y="80" Width="220" Height="60" Transparent="yes" NoPrefix="yes" Text="!(loc.WelcomeDlgDescription)" />
+ <Control Id="WSLInstallCheckbox" Type="CheckBox" X="135" Y="135" Width="226" Height="18" CheckBoxValue="1" Property="WSL_INSTALL" Default="no" Text="Install WSL Feature (if needed)" />
+
+ <Control Id="Back" Type="PushButton" X="156" Y="243" Width="56" Height="17" Disabled="yes" Text="!(loc.WixUIBack)"/>
+ <Control Id="Install" Type="PushButton" ElevationShield="yes" X="212" Y="243" Width="80" Height="17" Default="yes" Text="!(loc.WelcomeEulaDlgInstall)">
+ <Publish Event="SpawnWaitDialog" Value="WaitForCostingDlg">!(wix.WixUICostingPopupOptOut) OR CostingComplete = 1</Publish>
+ <Publish Event="EndDialog" Value="Return"><![CDATA[OutOfDiskSpace <> 1]]></Publish>
+ <Publish Event="SpawnDialog" Value="OutOfRbDiskDlg">OutOfDiskSpace = 1 AND OutOfNoRbDiskSpace = 0 AND (PROMPTROLLBACKCOST="P" OR NOT PROMPTROLLBACKCOST)</Publish>
+ <Publish Event="EndDialog" Value="Return">OutOfDiskSpace = 1 AND OutOfNoRbDiskSpace = 0 AND PROMPTROLLBACKCOST="D"</Publish>
+ <Publish Event="EnableRollback" Value="False">OutOfDiskSpace = 1 AND OutOfNoRbDiskSpace = 0 AND PROMPTROLLBACKCOST="D"</Publish>
+ <Publish Event="SpawnDialog" Value="OutOfDiskDlg">(OutOfDiskSpace = 1 AND OutOfNoRbDiskSpace = 1) OR (OutOfDiskSpace = 1 AND PROMPTROLLBACKCOST="F")</Publish>
+ </Control>
+ <Control Id="Cancel" Type="PushButton" X="304" Y="243" Width="56" Height="17" Cancel="yes" Text="!(loc.WixUICancel)">
+ <Publish Event="SpawnDialog" Value="CancelDlg">1</Publish>
+ </Control>
+
+ </Dialog>
+ </UI>
+
+ <InstallUISequence>
+ <Show Dialog="WelcomeInstallDlg" Before="ProgressDlg" Overridable="yes">NOT Installed</Show>
+ </InstallUISequence>
+ </Fragment>
+</Wix>
diff --git a/pkg/machine/wsl/machine.go b/pkg/machine/wsl/machine.go
index 8b6d74817..7e453823f 100644
--- a/pkg/machine/wsl/machine.go
+++ b/pkg/machine/wsl/machine.go
@@ -638,13 +638,13 @@ func installScripts(dist string) error {
}
func checkAndInstallWSL(opts machine.InitOptions) (bool, error) {
- if isWSLInstalled() {
+ if IsWSLInstalled() {
return true, nil
}
admin := hasAdminRights()
- if !isWSLFeatureEnabled() {
+ if !IsWSLFeatureEnabled() {
return false, attemptFeatureInstall(opts, admin)
}
@@ -1105,9 +1105,10 @@ func waitPipeExists(pipeName string, retries int, checkFailure func() error) err
return err
}
-func isWSLInstalled() bool {
- cmd := exec.Command("wsl", "--status")
+func IsWSLInstalled() bool {
+ cmd := SilentExecCmd("wsl", "--status")
out, err := cmd.StdoutPipe()
+ cmd.Stderr = nil
if err != nil {
return false
}
@@ -1131,9 +1132,8 @@ func isWSLInstalled() bool {
return true
}
-func isWSLFeatureEnabled() bool {
- cmd := exec.Command("wsl", "--set-default-version", "2")
- return cmd.Run() == nil
+func IsWSLFeatureEnabled() bool {
+ return SilentExec("wsl", "--set-default-version", "2") == nil
}
func isWSLRunning(dist string) (bool, error) {
diff --git a/pkg/machine/wsl/util_windows.go b/pkg/machine/wsl/util_windows.go
index 6c74e5652..6613bde1f 100644
--- a/pkg/machine/wsl/util_windows.go
+++ b/pkg/machine/wsl/util_windows.go
@@ -6,6 +6,7 @@ import (
"fmt"
"io/ioutil"
"os"
+ "os/exec"
"path/filepath"
"strings"
"syscall"
@@ -343,3 +344,17 @@ func sendQuit(tid uint32) {
postMessage := user32.NewProc("PostThreadMessageW")
postMessage.Call(uintptr(tid), WM_QUIT, 0, 0)
}
+
+func SilentExec(command string, args ...string) error {
+ cmd := exec.Command(command, args...)
+ cmd.SysProcAttr = &syscall.SysProcAttr{CreationFlags: 0x08000000}
+ cmd.Stdout = nil
+ cmd.Stderr = nil
+ return cmd.Run()
+}
+
+func SilentExecCmd(command string, args ...string) *exec.Cmd {
+ cmd := exec.Command(command, args...)
+ cmd.SysProcAttr = &syscall.SysProcAttr{CreationFlags: 0x08000000}
+ return cmd
+}
diff --git a/vendor/golang.org/x/sys/windows/svc/eventlog/install.go b/vendor/golang.org/x/sys/windows/svc/eventlog/install.go
new file mode 100644
index 000000000..43e324f4b
--- /dev/null
+++ b/vendor/golang.org/x/sys/windows/svc/eventlog/install.go
@@ -0,0 +1,81 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build windows
+// +build windows
+
+package eventlog
+
+import (
+ "errors"
+
+ "golang.org/x/sys/windows"
+ "golang.org/x/sys/windows/registry"
+)
+
+const (
+ // Log levels.
+ Info = windows.EVENTLOG_INFORMATION_TYPE
+ Warning = windows.EVENTLOG_WARNING_TYPE
+ Error = windows.EVENTLOG_ERROR_TYPE
+)
+
+const addKeyName = `SYSTEM\CurrentControlSet\Services\EventLog\Application`
+
+// Install modifies PC registry to allow logging with an event source src.
+// It adds all required keys and values to the event log registry key.
+// Install uses msgFile as the event message file. If useExpandKey is true,
+// the event message file is installed as REG_EXPAND_SZ value,
+// otherwise as REG_SZ. Use bitwise of log.Error, log.Warning and
+// log.Info to specify events supported by the new event source.
+func Install(src, msgFile string, useExpandKey bool, eventsSupported uint32) error {
+ appkey, err := registry.OpenKey(registry.LOCAL_MACHINE, addKeyName, registry.CREATE_SUB_KEY)
+ if err != nil {
+ return err
+ }
+ defer appkey.Close()
+
+ sk, alreadyExist, err := registry.CreateKey(appkey, src, registry.SET_VALUE)
+ if err != nil {
+ return err
+ }
+ defer sk.Close()
+ if alreadyExist {
+ return errors.New(addKeyName + `\` + src + " registry key already exists")
+ }
+
+ err = sk.SetDWordValue("CustomSource", 1)
+ if err != nil {
+ return err
+ }
+ if useExpandKey {
+ err = sk.SetExpandStringValue("EventMessageFile", msgFile)
+ } else {
+ err = sk.SetStringValue("EventMessageFile", msgFile)
+ }
+ if err != nil {
+ return err
+ }
+ err = sk.SetDWordValue("TypesSupported", eventsSupported)
+ if err != nil {
+ return err
+ }
+ return nil
+}
+
+// InstallAsEventCreate is the same as Install, but uses
+// %SystemRoot%\System32\EventCreate.exe as the event message file.
+func InstallAsEventCreate(src string, eventsSupported uint32) error {
+ return Install(src, "%SystemRoot%\\System32\\EventCreate.exe", true, eventsSupported)
+}
+
+// Remove deletes all registry elements installed by the correspondent Install.
+func Remove(src string) error {
+ appkey, err := registry.OpenKey(registry.LOCAL_MACHINE, addKeyName, registry.SET_VALUE)
+ if err != nil {
+ return err
+ }
+ defer appkey.Close()
+ return registry.DeleteKey(appkey, src)
+}
diff --git a/vendor/golang.org/x/sys/windows/svc/eventlog/log.go b/vendor/golang.org/x/sys/windows/svc/eventlog/log.go
new file mode 100644
index 000000000..f37b4b510
--- /dev/null
+++ b/vendor/golang.org/x/sys/windows/svc/eventlog/log.go
@@ -0,0 +1,70 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build windows
+// +build windows
+
+// Package eventlog implements access to Windows event log.
+package eventlog
+
+import (
+ "errors"
+ "syscall"
+
+ "golang.org/x/sys/windows"
+)
+
+// Log provides access to the system log.
+type Log struct {
+ Handle windows.Handle
+}
+
+// Open retrieves a handle to the specified event log.
+func Open(source string) (*Log, error) {
+ return OpenRemote("", source)
+}
+
+// OpenRemote does the same as Open, but on different computer host.
+func OpenRemote(host, source string) (*Log, error) {
+ if source == "" {
+ return nil, errors.New("Specify event log source")
+ }
+ var s *uint16
+ if host != "" {
+ s = syscall.StringToUTF16Ptr(host)
+ }
+ h, err := windows.RegisterEventSource(s, syscall.StringToUTF16Ptr(source))
+ if err != nil {
+ return nil, err
+ }
+ return &Log{Handle: h}, nil
+}
+
+// Close closes event log l.
+func (l *Log) Close() error {
+ return windows.DeregisterEventSource(l.Handle)
+}
+
+func (l *Log) report(etype uint16, eid uint32, msg string) error {
+ ss := []*uint16{syscall.StringToUTF16Ptr(msg)}
+ return windows.ReportEvent(l.Handle, etype, 0, eid, 0, 1, 0, &ss[0], nil)
+}
+
+// Info writes an information event msg with event id eid to the end of event log l.
+// When EventCreate.exe is used, eid must be between 1 and 1000.
+func (l *Log) Info(eid uint32, msg string) error {
+ return l.report(windows.EVENTLOG_INFORMATION_TYPE, eid, msg)
+}
+
+// Warning writes an warning event msg with event id eid to the end of event log l.
+// When EventCreate.exe is used, eid must be between 1 and 1000.
+func (l *Log) Warning(eid uint32, msg string) error {
+ return l.report(windows.EVENTLOG_WARNING_TYPE, eid, msg)
+}
+
+// Error writes an error event msg with event id eid to the end of event log l.
+// When EventCreate.exe is used, eid must be between 1 and 1000.
+func (l *Log) Error(eid uint32, msg string) error {
+ return l.report(windows.EVENTLOG_ERROR_TYPE, eid, msg)
+}
diff --git a/vendor/modules.txt b/vendor/modules.txt
index cc3d7b6a7..f1d4758e4 100644
--- a/vendor/modules.txt
+++ b/vendor/modules.txt
@@ -794,6 +794,7 @@ golang.org/x/sys/plan9
golang.org/x/sys/unix
golang.org/x/sys/windows
golang.org/x/sys/windows/registry
+golang.org/x/sys/windows/svc/eventlog
# golang.org/x/term v0.0.0-20220526004731-065cf7ba2467
## explicit
golang.org/x/term