···44# To generate all the templated files, run this from the root of the repo:
55# make -f .gitlab-ci/ci-scripts.mk
6677-# These also all have their template named the same with a .template suffix.
77+# These also all have their template named the same with a .jinja suffix.
88FILES_IN_SUBDIR := \
99 .gitlab-ci/distributions \
1010 .gitlab-ci/reprepro.sh \
11111212CONFIG_FILE := .gitlab-ci/config.yml
1313-all: .gitlab-ci.yml $(FILES_IN_SUBDIR)
1313+OUTPUTS := .gitlab-ci.yml \
1414+ $(FILES_IN_SUBDIR)
1515+1616+all: $(OUTPUTS)
1717+ chmod +x .gitlab-ci/*.sh
1418.PHONY: all
15191620clean:
1717- rm -f .gitlab-ci.yml $(FILES_IN_SUBDIR)
2121+ rm -f $(OUTPUTS)
1822.PHONY: clean
2323+2424+CI_FAIRY := ci-fairy generate-template --config=$(CONFIG_FILE)
19252026# As the default thing for ci-fairy to template, this is special cased
2121-.gitlab-ci.yml: .gitlab-ci/ci.template $(CONFIG_FILE)
2222- ci-fairy generate-template
2727+.gitlab-ci.yml: .gitlab-ci/ci.template .gitlab-ci/win_containers.yml $(CONFIG_FILE)
2828+ $(CI_FAIRY) $< > $@
23292430# Everything else is structured alike
2531$(FILES_IN_SUBDIR): %: %.jinja $(CONFIG_FILE)
2626- ci-fairy generate-template --config=$(CONFIG_FILE) $< > $@
3232+ $(CI_FAIRY) $< > $@
···11+# Copyright 2019-2022, Mesa contributors
22+# Copyright 2022, Collabora, Ltd.
33+# SPDX-License-Identifier: MIT
44+# Based on https://gitlab.freedesktop.org/mesa/mesa/-/blob/8396df5ad90aeb6ab2267811aba2187954562f81/.gitlab-ci/windows/Dockerfile_build
55+66+# escape=`
77+88+ARG base_image
99+FROM ${base_image}
1010+1111+# Make sure any failure in PowerShell scripts is fatal
1212+SHELL ["powershell", "-ExecutionPolicy", "RemoteSigned", "-Command", "$ErrorActionPreference = 'Stop';"]
1313+ENV ErrorActionPreference='Stop'
1414+1515+1616+COPY "monado_deps_build.ps1" "C:/"
1717+RUN "C:/monado_deps_build.ps1"
+16
.gitlab-ci/windows/Dockerfile.vs2022
···11+# Copyright 2019-2022, Mesa contributors
22+# Copyright 2022, Collabora, Ltd.
33+# SPDX-License-Identifier: MIT
44+# Based on https://gitlab.freedesktop.org/mesa/mesa/-/blob/8396df5ad90aeb6ab2267811aba2187954562f81/.gitlab-ci/windows/Dockerfile_build
55+66+# escape=`
77+88+# FROM mcr.microsoft.com/windows:2004
99+FROM mcr.microsoft.com/windows/servercore:ltsc2019
1010+1111+# Make sure any failure in PowerShell scripts is fatal
1212+SHELL ["powershell", "-ExecutionPolicy", "RemoteSigned", "-Command", "$ErrorActionPreference = 'Stop';"]
1313+ENV ErrorActionPreference='Stop'
1414+1515+COPY "monado_deps_vs2022.ps1" "C:/"
1616+RUN "C:/monado_deps_vs2022.ps1"
+70
.gitlab-ci/windows/README.md
···11+# Native Windows GitLab CI builds
22+33+<!--
44+# Copyright 2019-2022, Mesa contributors
55+# Copyright 2022, Collabora, Ltd.
66+# SPDX-License-Identifier: MIT
77+88+Based on https://gitlab.freedesktop.org/mesa/mesa/-/blob/8396df5ad90aeb6ab2267811aba2187954562f81/.gitlab-ci/windows/README.md
99+-->
1010+1111+We are using the same basic approach to Windows CI building as Mesa, just as we
1212+do on Linux. See
1313+<https://gitlab.freedesktop.org/mesa/mesa/-/tree/main/.gitlab-ci/windows> for
1414+the details there. The following is the Mesa readme, lightly modified to fit
1515+Monado.
1616+1717+Unlike Linux, Windows cannot reuse the freedesktop ci-templates as they exist
1818+as we do not have Podman, Skopeo, or even Docker-in-Docker builds available
1919+under Windows.
2020+2121+We still reuse the same model: build a base container with the core operating
2222+system and infrequently-changed build dependencies, then execute Monado builds
2323+only inside that base container. This is open-coded in PowerShell scripts.
2424+2525+## Base container build
2626+2727+The base container build jobs execute the `monado_container.ps1` script which
2828+reproduces the ci-templates behaviour. It looks for the registry image in
2929+the user's namespace, and exits if found. If not found, it tries to copy
3030+the same image tag from the upstream Monado repository. If that is not found,
3131+the image is rebuilt inside the user's namespace.
3232+3333+The rebuild executes `docker build` which calls `monado_deps_*.ps1` inside the
3434+container to fetch and install all build dependencies. This includes Visual
3535+Studio Build Tools (downloaded from Microsoft, under the license which
3636+allows use by open-source projects), and other build tools from Scoop.
3737+(These are done as two separate jobs to allow "resuming from the middle".)
3838+3939+This job is executed inside a Windows shell environment directly inside the
4040+host, without Docker.
4141+4242+## Monado build
4343+4444+The Monado build runs inside the base container, executing `mesa_build.ps1`.
4545+This simply compiles Monado using CMake and Ninja, executing the build and
4646+unit tests.
4747+4848+## Local testing
4949+5050+To try these scripts locally, you need this done once, rebooting after they are complete:
5151+5252+```pwsh
5353+scoop install sudo
5454+sudo Add-MpPreference -ExclusionProcess dockerd.exe
5555+sudo Add-MpPreference -ExclusionProcess docker.exe
5656+winget install stevedore
5757+sudo Add-MpPreference -ExclusionPath c:\ProgramData\docker
5858+```
5959+6060+then this, done when you want to test:
6161+6262+```pwsh
6363+docker context use desktop-windows
6464+```
6565+6666+before doing your normal `docker build .`, etc. (It may still be very slow
6767+despite the virus scanning exclusions.)
6868+6969+If you're having issues accessing the network, see this comment's instructions:
7070+<https://github.com/docker/for-win/issues/9847#issuecomment-832674649>
+61
.gitlab-ci/windows/monado_build.ps1
···11+# Copyright 2019-2022, Mesa contributors
22+# Copyright 2022, Collabora, Ltd.
33+# SPDX-License-Identifier: MIT
44+# Based on https://gitlab.freedesktop.org/mesa/mesa/-/blob/8396df5ad90aeb6ab2267811aba2187954562f81/.gitlab-ci/windows/mesa_build.ps1
55+66+# force the CA cert cache to be rebuilt, in case Meson tries to access anything
77+Write-Host "Refreshing Windows TLS CA cache"
88+(New-Object System.Net.WebClient).DownloadString("https://github.com") > $null
99+1010+$env:PYTHONUTF8 = 1
1111+1212+Get-Date
1313+Write-Host "Compiling Monado"
1414+$sourcedir = (Resolve-Path "$PSScriptRoot/../..")
1515+$builddir = Join-Path $sourcedir "build"
1616+$installdir = Join-Path $sourcedir "install"
1717+$vcpkgdir = "c:\vcpkg"
1818+$toolchainfile = Join-Path $vcpkgdir "scripts/buildsystems/vcpkg.cmake"
1919+2020+Remove-Item -Recurse -Force $installdir -ErrorAction SilentlyContinue
2121+2222+Write-Output "builddir:$builddir"
2323+Write-Output "installdir:$installdir"
2424+Write-Output "sourcedir:$sourcedir"
2525+2626+$installPath = & "C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe" -version 17 -property installationpath
2727+Write-Output "vswhere.exe installPath: $installPath"
2828+$installPath = "C:\BuildTools"
2929+Write-Output "Final installPath: $installPath"
3030+3131+# Note that we can't have $ErrorActionPreference as "Stop" here:
3232+# it "errors" (not finding some shared tool because of our mini build tools install)
3333+# but the error doesn't matter for our use case.
3434+Import-Module (Join-Path $installPath "Common7\Tools\Microsoft.VisualStudio.DevShell.dll")
3535+Enter-VsDevShell -VsInstallPath $installPath -SkipAutomaticLocation -DevCmdArguments '-arch=x64 -no_logo -host_arch=amd64'
3636+3737+Push-Location $sourcedir
3838+$cmakeArgs = @(
3939+ "-S"
4040+ "."
4141+ "-B"
4242+ "$builddir"
4343+ "-GNinja"
4444+ "-DCMAKE_BUILD_TYPE=RelWithDebInfo"
4545+ "-DCMAKE_TOOLCHAIN_FILE=$toolchainfile"
4646+ "-DCMAKE_INSTALL_PREFIX=$installdir"
4747+)
4848+cmake @cmakeArgs
4949+5050+ninja -C $builddir
5151+ninja -C $builddir install test
5252+5353+$buildstatus = $?
5454+Pop-Location
5555+5656+Get-Date
5757+5858+if (!$buildstatus) {
5959+ Write-Host "Monado build or test failed"
6060+ Exit 1
6161+}
+197
.gitlab-ci/windows/monado_container.ps1
···11+# Copyright 2019-2022, Mesa contributors
22+# Copyright 2022, Collabora, Ltd.
33+# SPDX-License-Identifier: MIT
44+# Based on https://gitlab.freedesktop.org/mesa/mesa/-/blob/8396df5ad90aeb6ab2267811aba2187954562f81/.gitlab-ci/windows/mesa_container.ps1
55+66+# Implements the equivalent of ci-templates container-ifnot-exists, using
77+# Docker directly as we don't have buildah/podman/skopeo available under
88+# Windows, nor can we execute Docker-in-Docker
99+[CmdletBinding()]
1010+param (
1111+ # Address for container registry
1212+ [Parameter()]
1313+ [string]
1414+ $RegistryUri,
1515+1616+ # Username for container registry
1717+ [Parameter()]
1818+ [ValidateNotNullOrEmpty()]
1919+ [string]
2020+ $RegistryUsername,
2121+2222+ # The path of the image for this user's fork
2323+ [Parameter()]
2424+ [ValidateNotNullOrEmpty()]
2525+ [string]
2626+ $UserImage,
2727+2828+ # The path of the image in the upstream registry
2929+ [Parameter()]
3030+ [string]
3131+ $UpstreamImage,
3232+3333+ # Dockerfile to build
3434+ [Parameter()]
3535+ [string]
3636+ $Dockerfile = "Dockerfile",
3737+3838+ # Base image to use for this container, if any
3939+ [Parameter()]
4040+ [string]
4141+ $BaseImage,
4242+4343+ # Base image to use for this container, from the upstream repo, if any
4444+ [Parameter()]
4545+ [string]
4646+ $BaseUpstreamImage
4747+)
4848+4949+$RegistryPassword = "$env:CI_REGISTRY_PASSWORD"
5050+5151+$CommonDockerArgs = @(
5252+ "--config"
5353+ "windows-docker.conf"
5454+)
5555+5656+$ErrorActionPreference = 'Stop'
5757+5858+# Returns $true on a zero error code
5959+# If $AllowFailure is not set, throws on a nonzero exit code
6060+function Start-Docker {
6161+ param (
6262+ # Should we just return the exit code on failure instead of throwing?
6363+ [Parameter()]
6464+ [switch]
6565+ $AllowFailure = $false,
6666+6767+ # Should we try to log out before throwing in case of an error?
6868+ [Parameter()]
6969+ [switch]
7070+ $LogoutOnFailure = $false,
7171+7272+ # What arguments should be passed to docker (besides the config)
7373+ [Parameter(Mandatory = $true)]
7474+ [string[]]
7575+ $ArgumentList
7676+ )
7777+ $DockerArgs = $CommonDockerArgs + $ArgumentList
7878+ Write-Verbose ("Will run docker " + ($DockerArgs -join " "))
7979+ $proc = Start-Process -FilePath "docker" -ArgumentList $DockerArgs -NoNewWindow -PassThru -WorkingDirectory "$PSScriptRoot" -Wait
8080+8181+ if ($proc.ExitCode -eq 0) {
8282+ Write-Verbose "Success!"
8383+ return $true
8484+ }
8585+ if (!$AllowFailure) {
8686+ Write-Error ($ArgumentList[0] + " failed")
8787+ if ($LogoutOnFailure) {
8888+ Write-Host "Logging out"
8989+ Start-Process -FilePath "docker" -ArgumentList ($CommonDockerArgs + @("logout", "$RegistryUri")) `
9090+ -NoNewWindow -PassThru -WorkingDirectory "$PSScriptRoot" -Wait
9191+ }
9292+ throw ("docker " + $ArgumentList[0] + " invocation failed")
9393+ }
9494+9595+ return $false
9696+}
9797+9898+# Returns $true if the $Image exists (whether or not we had to copy $UpstreamImage)
9999+function Test-Image {
100100+ param (
101101+ # Image to look for
102102+ [Parameter(Mandatory = $true)]
103103+ [ValidateNotNullOrEmpty()]
104104+ [string]
105105+ $Image,
106106+107107+ # Equivalent image from the upstream repo, if any
108108+ [Parameter()]
109109+ [string]
110110+ $UpstreamImage
111111+ )
112112+113113+ # if the image already exists, great
114114+ Write-Verbose "Looking for $Image"
115115+ # $pullResult = Start-Docker -AllowFailure -ArgumentList ("pull", "$Image")
116116+ docker @CommonDockerArgs pull "$Image"
117117+ if ($?) {
118118+ Write-Host "Image $UserImage exists"
119119+ return $true
120120+ }
121121+ if (!$UpstreamImage) {
122122+ Write-Host "Cannot find $Image"
123123+ return $false
124124+ }
125125+ # if it's only upstream, copy it
126126+ Write-Host "Cannot find $Image, looking for upstream $UpstreamImage"
127127+ docker @CommonDockerArgs pull "$UpstreamImage"
128128+ if ($?) {
129129+ Write-Host "Found upstream image, copying image from upstream $UpstreamImage to user $Image"
130130+ Start-Docker -LogoutOnFailure -ArgumentList ("tag", "$UpstreamImage", "$Image")
131131+ Start-Docker -LogoutOnFailure -ArgumentList ("push", "$Image")
132132+ return $true
133133+ }
134134+ Write-Host "Cannot find $Image nor $UpstreamImage"
135135+ return $false
136136+}
137137+138138+Write-Host "Will log in to $RegistryUri as $RegistryUsername"
139139+Write-Host "Will check for image $UserImage - if it does not exist but $UpstreamImage does, we copy that one, otherwise we need to build it."
140140+if ($BaseImage) {
141141+ Write-Host "This image builds on $BaseImage so we will check for it."
142142+ if ($BaseUpstreamImage) {
143143+ Write-Host "If it is missing but $BaseUpstreamImage exists, we copy that one. If both are missing, we error out."
144144+ } else {
145145+ Write-Host "If it is missing, we error out."
146146+ }
147147+}
148148+149149+# Start-Docker -ArgumentList ("login", "-u", "$RegistryUsername", "--password-stdin", "$RegistryPassword", "$RegistryUri")
150150+$loginProc = Start-Process -FilePath "docker" -ArgumentList ($CommonDockerArgs + @("login", "-u", "$RegistryUsername", "--password", "$RegistryPassword", "$RegistryUri")) `
151151+ -NoNewWindow -PassThru -WorkingDirectory "$PSScriptRoot" -Wait
152152+if ($loginProc.ExitCode -ne 0) {
153153+ throw "docker login failed"
154154+}
155155+156156+# if the image already exists, don't rebuild it
157157+$imageResult = Test-Image -Image $UserImage -UpstreamImage $UpstreamImage
158158+if ($imageResult) {
159159+ Write-Host "User image $UserImage already exists; not rebuilding"
160160+ Start-Docker -ArgumentList ("logout", "$RegistryUri")
161161+ Exit 0
162162+}
163163+164164+165165+# do we need a base image?
166166+if ($BaseImage) {
167167+ $baseImageResult = Test-Image -Image "$BaseImage" -UpstreamImage "$BaseUpstreamImage"
168168+ if (!$baseImageResult) {
169169+ throw "Could not find base image: neither '$BaseImage' nor '$BaseUpstreamImage' exist."
170170+ }
171171+}
172172+173173+Write-Host "No image found at $UserImage or $UpstreamImage; rebuilding, this may take a while"
174174+$DockerBuildArgs = @(
175175+ "build"
176176+ "--no-cache"
177177+ "-t"
178178+ "$UserImage"
179179+ "-f"
180180+ "$Dockerfile"
181181+)
182182+183183+if ($BaseImage) {
184184+ $DockerBuildArgs += @(
185185+ "--build-arg"
186186+ "base_image=$BaseImage"
187187+ )
188188+}
189189+190190+$DockerBuildArgs += "."
191191+Start-Docker -LogoutOnFailure -ArgumentList (, $DockerBuildArgs)
192192+193193+Get-Date
194194+195195+Write-Host "Done building image, now pushing $UserImage"
196196+Start-Docker -LogoutOnFailure -ArgumentList ("push", "$UserImage")
197197+Start-Docker -ArgumentList ("logout", "$RegistryUri")