Browse code

Windows: make.ps1 and Dockerfile for native builds

Signed-off-by: John Howard <jhoward@microsoft.com>
(cherry picked from commit 155435b6ceeb05b2927ecc726216666b898b6459)
Signed-off-by: Victor Vieux <victorvieux@gmail.com>

John Howard authored on 2016/11/18 06:54:56
Showing 3 changed files
... ...
@@ -2,7 +2,7 @@
2 2
 
3 3
 # -----------------------------------------------------------------------------------------
4 4
 # This file describes the standard way to build Docker in a container on Windows
5
-# Server 2016.
5
+# Server 2016 or Windows 10.
6 6
 #
7 7
 # Maintainer: @jhowardmsft
8 8
 # -----------------------------------------------------------------------------------------
... ...
@@ -11,21 +11,25 @@
11 11
 # Prerequisites:
12 12
 # --------------
13 13
 #
14
-# 1. Windows Server 2016 with all Windows updates applied. Pre-release versions
15
-#    of Windows are not supported (eg Windows Server 2016 TP5). The build number
16
-#    must be at least 14393. This can be confirmed, for example, by running the
17
-#    following from an elevated PowerShell prompt - this sample output is from a 
18
-#    fully up to date machine as at late October 2016:
14
+# 1. Windows Server 2016 or Windows 10 with all Windows updates applied. The major 
15
+#    build number must be at least 14393. This can be confirmed, for example, by 
16
+#    running the following from an elevated PowerShell prompt - this sample output 
17
+#    is from a fully up to date machine as at mid-November 2016:
19 18
 #
20 19
 #    >> PS C:\> $(gin).WindowsBuildLabEx
21
-#    >> 14393.321.amd64fre.rs1_release_inmarket.161004-2338
20
+#    >> 14393.447.amd64fre.rs1_release_inmarket.161102-0100
22 21
 #
23 22
 # 2. Git for Windows (or another git client) must be installed. https://git-scm.com/download/win.
24 23
 #
25 24
 # 3. The machine must be configured to run containers. For example, by following
26 25
 #    the quick start guidance at https://msdn.microsoft.com/en-us/virtualization/windowscontainers/quick_start/quick_start or
27 26
 #    https://github.com/docker/labs/blob/master/windows/windows-containers/Setup.md
28
-
27
+#
28
+# 4. If building in a Hyper-V VM: For Windows Server 2016 using Windows Server
29
+#    containers as the default option, it is recommended you have at least 1GB 
30
+#    of memory assigned; For Windows 10 where Hyper-V Containers are employed, you
31
+#    should have at least 4GB of memory assigned. Note also, to run Hyper-V 
32
+#    containers in a VM, it is necessary to configure the VM for nested virtualization.
29 33
 
30 34
 # -----------------------------------------------------------------------------------------
31 35
 
... ...
@@ -63,18 +67,16 @@
63 63
 #    >>   docker build -t nativebuildimage -f Dockerfile.windows .
64 64
 #
65 65
 #
66
-# 4. Build the docker executable binaries in a container:
66
+# 4. Build the docker executable binaries:
67 67
 #
68
-#    >>   docker run --name binaries nativebuildimage sh -c 'cd /c/go/src/github.com/docker/docker; hack/make.sh binary'
68
+#    >>   docker run --name binaries nativebuildimage hack\make.ps1 -Binary
69 69
 #
70 70
 #
71
-# 5. Copy the binaries out of the above container, replacing HostPath with an appropriate destination 
71
+# 5. Copy the binaries out of the container, replacing HostPath with an appropriate destination 
72 72
 #    folder on the host system where you want the binaries to be located.
73 73
 #
74
-#    >>   $v=$(Get-Content ".\VERSION" -raw).ToString().Replace("`n","").Trim()
75
-#    >>   docker cp binaries:C:\go\src\github.com\docker\docker\bundles\$v\binary-client\docker-$v.exe C:\HostPath\docker.exe
76
-#    >>   docker cp binaries:C:\go\src\github.com\docker\docker\bundles\$v\binary-daemon\dockerd.exe C:\HostPath\dockerd.exe
77
-#    >>   docker cp binaries:C:\go\src\github.com\docker\docker\bundles\$v\binary-daemon\docker-proxy-$v.exe C:\HostPath\docker-proxy.exe
74
+#    >>   docker cp binaries:C:\go\src\github.com\docker\docker\bundles\docker.exe C:\HostPath\docker.exe
75
+#    >>   docker cp binaries:C:\go\src\github.com\docker\docker\bundles\dockerd.exe C:\HostPath\dockerd.exe
78 76
 #
79 77
 #
80 78
 # 6. (Optional) Remove the interim container holding the built executable binaries:
... ...
@@ -88,6 +90,39 @@
88 88
 #    image which has all the components required to build the binaries already installed.
89 89
 #
90 90
 #    >>    docker rmi nativebuildimage
91
+#
92
+
93
+# -----------------------------------------------------------------------------------------
94
+
95
+
96
+#  The validation tests can either run in a container, or directly on the host. To run in a
97
+#  container, ensure you have created the nativebuildimage above. Then run the following
98
+#  from an (elevated) Windows PowerShell prompt:
99
+#
100
+#    >>   docker run --rm nativebuildimage hack\make.ps1 -DCO -PkgImports -GoFormat
101
+
102
+# To run the validation tests on the host, from the root of the repository, run the
103
+# following from a Windows PowerShell prompt (elevation is not required): (Note Go
104
+# must be installed to run these tests)
105
+#
106
+#    >>   hack\make.ps1 -DCO -PkgImports -GoFormat
107
+
108
+# -----------------------------------------------------------------------------------------
109
+
110
+
111
+#  To run unit tests, ensure you have created the nativebuildimage above. Then run the
112
+#  following from an (elevated) Windows PowerShell prompt:
113
+#
114
+#    >>   docker run --rm nativebuildimage hack\make.ps1 -TestUnit
115
+
116
+
117
+# -----------------------------------------------------------------------------------------
118
+
119
+
120
+#  To run all tests and binary build, ensure you have created the nativebuildimage above. Then 
121
+# run the following from an (elevated) Windows PowerShell prompt:
122
+#
123
+#    >>   docker run nativebuildimage hack\make.ps1 -All
91 124
 
92 125
 
93 126
 # -----------------------------------------------------------------------------------------
... ...
@@ -96,28 +131,26 @@
96 96
 # Important notes:
97 97
 # ---------------
98 98
 #
99
-# The posix utilities from git aren't usable interactively as at October 2016. This
100
-# is because they require a console window which isn't present in a container in Windows.
101
-# See the example at the top of this file. Do NOT use -it in that docker run. It will not work.
99
+# Don't attempt to use a bind-mount to pass a local directory as the bundles target
100
+# directory. It does not work (golang attempts for follow a mapped folder incorrectly). 
101
+# Instead, use docker cp as per the example.
102 102
 #
103
-# Don't attempt to use a volume for passing the source through to the container. The posix utilities will
104
-# balk at reparse points. 
103
+# go.zip is not removed from the image as it is used by the Windows CI servers
104
+# to ensure the host and image are running consistent versions of go.
105 105
 #
106
-# The downloaded files are not cleared from the image. go.zip is used by the Windows
107
-# CI servers to ensure the host and image are running consistent versions of go.
106
+# Nanoserver support is a work in progress. Although the image will build if the 
107
+# FROM statement is updated, it will not work when running autogen through hack\make.ps1. 
108
+# It is suspected that the required GCC utilities (eg gcc, windres, windmc) silently
109
+# quit due to the use of console hooks which are not available.
108 110
 #
109
-# The GIT installer isn't very good at unattended install. We use techniques described
110
-# at the links below to force it to set the path and other options accordingly. 
111
-# >> http://superuser.com/questions/944576/git-for-windows-silent-install-silent-arguments 
112
-# and follow through to installer at
113
-# >> https://github.com/ferventcoder/chocolatey-packages/blob/master/automatic/git.install/tools/chocolateyInstall.ps1
111
+# The docker integration tests do not currently run in a container on Windows, predominantly
112
+# due to Windows not supporting privileged mode, so anything using a volume would fail.
113
+# They (along with the rest of the docker CI suite) can be run using 
114
+# https://github.com/jhowardmsft/docker-w2wCIScripts/blob/master/runCI/Invoke-DockerCI.ps1.
114 115
 #
115
-# As of October 2016, this does not work on Windows 10 client, just Windows Server 2016,
116
-# and only with the default isolation mode (process). It does not work with isolation mode
117
-# set to Hyper-V containers (hyperv).
118
-
119 116
 # -----------------------------------------------------------------------------------------
120 117
 
118
+
121 119
 # The number of build steps below are explicitly minimised to improve performance.
122 120
 FROM microsoft/windowsservercore
123 121
 
... ...
@@ -128,55 +161,102 @@ SHELL ["powershell", "-command"]
128 128
 #  - GO_VERSION must be consistent with 'Dockerfile' used by Linux.
129 129
 #  - FROM_DOCKERFILE is used for detection of building within a container.
130 130
 ENV GO_VERSION=1.7.3 `
131
-    GIT_LOCATION=https://github.com/git-for-windows/git/releases/download/v2.10.1.windows.1/Git-2.10.1-64-bit.exe `
131
+    GIT_VERSION=2.10.2 `
132 132
     GOPATH=C:\go `
133 133
     FROM_DOCKERFILE=1
134 134
 
135
-WORKDIR C:\
136
-
137 135
 RUN `
138
-  setx /M Path $($Env:PATH+';C:\gcc\bin;C:\go\bin'); `
139
-  `
140 136
   $ErrorActionPreference = 'Stop'; `
137
+  $ProgressPreference = 'SilentlyContinue'; `
138
+  `
139
+  Function Test-Nano() { `
140
+    $EditionId = (Get-ItemProperty -Path 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion' -Name 'EditionID').EditionId; `
141
+    return (($EditionId -eq 'ServerStandardNano') -or ($EditionId -eq 'ServerDataCenterNano') -or ($EditionId -eq 'NanoServer')); `
142
+  }`
143
+  `
141 144
   Function Download-File([string] $source, [string] $target) { `
142
-    $wc = New-Object net.webclient; $wc.Downloadfile($source, $target) `
145
+    if (Test-Nano) { `
146
+      $handler = New-Object System.Net.Http.HttpClientHandler; `
147
+      $client = New-Object System.Net.Http.HttpClient($handler); `
148
+      $client.Timeout = New-Object System.TimeSpan(0, 30, 0); `
149
+      $cancelTokenSource = [System.Threading.CancellationTokenSource]::new(); `
150
+      $responseMsg = $client.GetAsync([System.Uri]::new($source), $cancelTokenSource.Token); `
151
+      $responseMsg.Wait(); `
152
+      if (!$responseMsg.IsCanceled) { `
153
+        $response = $responseMsg.Result; `
154
+        if ($response.IsSuccessStatusCode) { `
155
+          $downloadedFileStream = [System.IO.FileStream]::new($target, [System.IO.FileMode]::Create, [System.IO.FileAccess]::Write); `
156
+          $copyStreamOp = $response.Content.CopyToAsync($downloadedFileStream); `
157
+          $copyStreamOp.Wait(); `
158
+          $downloadedFileStream.Close(); `
159
+          if ($copyStreamOp.Exception -ne $null) { throw $copyStreamOp.Exception } `
160
+        } `
161
+      } else { `
162
+      Throw ("Failed to download " + $source) `
163
+      }`
164
+    } else { `
165
+      $webClient = New-Object System.Net.WebClient; `
166
+      $webClient.DownloadFile($source, $target); `
167
+    } `
143 168
   } `
144 169
   `
170
+  setx /M PATH $('C:\git\bin;C:\git\usr\bin;'+$Env:PATH+';C:\gcc\bin;C:\go\bin'); `
171
+  `
145 172
   Write-Host INFO: Downloading git...; `
146
-  Download-File $Env:GIT_LOCATION gitsetup.exe; `
173
+  $location='https://github.com/git-for-windows/git/releases/download/v'+$env:GIT_VERSION+'.windows.1/PortableGit-'+$env:GIT_VERSION+'-64-bit.7z.exe'; `
174
+  Download-File $location C:\gitsetup.7z.exe; `
147 175
   `
148 176
   Write-Host INFO: Downloading go...; `
149
-  Download-File $('https://golang.org/dl/go'+$Env:GO_VERSION+'.windows-amd64.zip') go.zip; `
177
+  Download-File $('https://golang.org/dl/go'+$Env:GO_VERSION+'.windows-amd64.zip') C:\go.zip; `
150 178
   `
151 179
   Write-Host INFO: Downloading compiler 1 of 3...; `
152
-  Download-File https://raw.githubusercontent.com/jhowardmsft/docker-tdmgcc/master/gcc.zip gcc.zip; `
180
+  Download-File https://raw.githubusercontent.com/jhowardmsft/docker-tdmgcc/master/gcc.zip C:\gcc.zip; `
153 181
   `
154 182
   Write-Host INFO: Downloading compiler 2 of 3...; `
155
-  Download-File https://raw.githubusercontent.com/jhowardmsft/docker-tdmgcc/master/runtime.zip runtime.zip; `
183
+  Download-File https://raw.githubusercontent.com/jhowardmsft/docker-tdmgcc/master/runtime.zip C:\runtime.zip; `
156 184
   `
157 185
   Write-Host INFO: Downloading compiler 3 of 3...; `
158
-  Download-File https://raw.githubusercontent.com/jhowardmsft/docker-tdmgcc/master/binutils.zip binutils.zip; `
186
+  Download-File https://raw.githubusercontent.com/jhowardmsft/docker-tdmgcc/master/binutils.zip C:\binutils.zip; `
159 187
   `
160
-  Write-Host INFO: Installing git...; `
161
-  $installPath = 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall'; `
162
-  $installItem = 'Git_is1'; `
163
-  New-Item -Path $installPath -Name $installItem -Force; `
164
-  $installKey = $installPath+'\'+$installItem; `
165
-  New-ItemProperty $installKey -Name 'Inno Setup CodeFile: Path Option' -Value 'CmdTools' -PropertyType 'String' -Force; `
166
-  New-ItemProperty $installKey -Name 'Inno Setup CodeFile: Bash Terminal Option' -Value 'ConHost' -PropertyType 'String' -Force; `
167
-  New-ItemProperty $installKey -Name 'Inno Setup CodeFile: CRLF Option' -Value 'CRLFCommitAsIs' -PropertyType 'String' -Force; `
168
-  Start-Process gitsetup.exe -ArgumentList '/VERYSILENT /SUPPRESSMSGBOXES /CLOSEAPPLICATIONS /DIR=C:\git\' -Wait; `
188
+  Write-Host INFO: Installing PS7Zip package...; `
189
+  Install-Package PS7Zip -Force | Out-Null; `
190
+  Write-Host INFO: Importing PS7Zip...; `
191
+  Import-Module PS7Zip -Force; `
192
+  New-Item C:\git -ItemType Directory | Out-Null ; `
193
+  cd C:\git; `
194
+  Write-Host INFO: Extracting git...; `
195
+  Expand-7Zip C:\gitsetup.7z.exe | Out-Null; `
196
+  cd C:\; `
169 197
   `
170 198
   Write-Host INFO: Expanding go...; `
171 199
   Expand-Archive C:\go.zip -DestinationPath C:\; `
172 200
   `
173
-  Write-Host INFO: Expanding compiler...; `
201
+  Write-Host INFO: Expanding compiler 1 of 3...; `
174 202
   Expand-Archive C:\gcc.zip -DestinationPath C:\gcc -Force; `
203
+  Write-Host INFO: Expanding compiler 2 of 3...; `
175 204
   Expand-Archive C:\runtime.zip -DestinationPath C:\gcc -Force; `
205
+  Write-Host INFO: Expanding compiler 3 of 3...; `
176 206
   Expand-Archive C:\binutils.zip -DestinationPath C:\gcc -Force; `
177 207
   `
208
+  Write-Host INFO: Removing downloaded files...; `
209
+  Remove-Item C:\gcc.zip; `
210
+  Remove-Item C:\runtime.zip; `
211
+  Remove-Item C:\binutils.zip; `
212
+  Remove-Item C:\gitsetup.7z.exe; `
213
+  `
214
+  Write-Host INFO: Creating source directory...; `
215
+  New-Item -ItemType Directory -Path C:\go\src\github.com\docker\docker | Out-Null; `
216
+  `
217
+  Write-Host INFO: Configuring git core.autocrlf...; `
218
+  C:\git\bin\git config --global core.autocrlf true; `
219
+  `
178 220
   Write-Host INFO: Completed
179 221
 
180
-# Prepare for building
181
-COPY . C:\go\src\github.com\docker\docker
222
+# Make PowerShell the default entrypoint
223
+ENTRYPOINT ["powershell.exe"]
224
+
225
+# Set the working directory to the location of the sources
226
+WORKDIR C:\go\src\github.com\docker\docker
182 227
 
228
+# Copy the sources into the container
229
+COPY . .
183 230
new file mode 100644
... ...
@@ -0,0 +1,401 @@
0
+<#
1
+.NOTES
2
+    Author:  @jhowardmsft
3
+
4
+    Summary: Windows native build script. This is similar to functionality provided
5
+             by hack\make.sh, but uses native Windows PowerShell semantics. It does
6
+             not support the full set of options provided by the Linux counterpart.
7
+             For example:
8
+             
9
+             - You can't cross-build Linux docker binaries on Windows
10
+             - Hashes aren't generated on binaries
11
+             - 'Releasing' isn't supported.
12
+             - Integration tests. This is because they currently cannot run inside a container,
13
+               and require significant external setup. 
14
+             
15
+             It does however provided the minimum necessary to support parts of local Windows 
16
+             development and Windows to Windows CI.
17
+
18
+             Usage Examples (run from repo root): 
19
+                "hack\make.ps1 -Binary" to build the binaries
20
+                "hack\make.ps1 -Client" to build just the client 64-bit binary
21
+                "hack\make.ps1 -TestUnit" to run unit tests
22
+                "hack\make.ps1 -Binary -TestUnit" to build the binaries and run unit tests
23
+                "hack\make.ps1 -All" to run everything this script knows about
24
+
25
+.PARAMETER Client
26
+     Builds the client binaries.
27
+
28
+.PARAMETER Daemon
29
+     Builds the daemon binary.
30
+
31
+.PARAMETER Binary
32
+     Builds the client binaries and the daemon binary. A convenient shortcut to `make.ps1 -Client -Daemon`.
33
+
34
+.PARAMETER Race
35
+     Use -race in go build and go test.
36
+
37
+.PARAMETER Noisy
38
+     Use -v in go build.
39
+
40
+.PARAMETER ForceBuildAll
41
+     Use -a in go build.
42
+
43
+.PARAMETER NoOpt
44
+     Use -gcflags -N -l in go build to disable optimisation (can aide debugging).
45
+
46
+.PARAMETER CommitSuffix
47
+     Adds a custom string to be appended to the commit ID (spaces are stripped).
48
+
49
+.PARAMETER DCO
50
+     Runs the DCO (Developer Certificate Of Origin) test.
51
+
52
+.PARAMETER PkgImports
53
+     Runs the pkg\ directory imports test.
54
+
55
+.PARAMETER GoFormat
56
+     Runs the Go formatting test.
57
+
58
+.PARAMETER TestUnit
59
+     Runs unit tests.
60
+
61
+.PARAMETER All
62
+     Runs everything this script knows about.
63
+
64
+
65
+TODO
66
+- Unify the head commit
67
+- Sort out the GITCOMMIT environment variable in the absense of a .git (longer term)
68
+- Add golint and other checks (swagger maybe?)
69
+
70
+#>
71
+
72
+
73
+param(
74
+    [Parameter(Mandatory=$False)][switch]$Client,
75
+    [Parameter(Mandatory=$False)][switch]$Daemon,
76
+    [Parameter(Mandatory=$False)][switch]$Binary,
77
+    [Parameter(Mandatory=$False)][switch]$Race,
78
+    [Parameter(Mandatory=$False)][switch]$Noisy,
79
+    [Parameter(Mandatory=$False)][switch]$ForceBuildAll,
80
+    [Parameter(Mandatory=$False)][switch]$NoOpt,
81
+    [Parameter(Mandatory=$False)][string]$CommitSuffix="",
82
+    [Parameter(Mandatory=$False)][switch]$DCO,
83
+    [Parameter(Mandatory=$False)][switch]$PkgImports,
84
+    [Parameter(Mandatory=$False)][switch]$GoFormat,
85
+    [Parameter(Mandatory=$False)][switch]$TestUnit,
86
+    [Parameter(Mandatory=$False)][switch]$All
87
+)
88
+
89
+$ErrorActionPreference = "Stop"
90
+$pushed=$False  # To restore the directory if we have temporarily pushed to one.
91
+
92
+# Utility function to get the commit ID of the repository
93
+Function Get-GitCommit() {
94
+    if (-not (Test-Path ".\.git")) {
95
+        # If we don't have a .git directory, but we do have the environment
96
+        # variable DOCKER_GITCOMMIT set, that can override it.
97
+        if ($env:DOCKER_GITCOMMIT.Length -eq 0) {
98
+            Throw ".git directory missing and DOCKER_GITCOMMIT environment variable not specified."
99
+        }
100
+        Write-Host "INFO: Git commit assumed from DOCKER_GITCOMMIT environment variable"
101
+        return $env:DOCKER_GITCOMMIT
102
+    }
103
+    $gitCommit=$(git rev-parse --short HEAD)
104
+    if ($(git status --porcelain --untracked-files=no).Length -ne 0) {
105
+        $gitCommit="$gitCommit-unsupported"
106
+        Write-Host ""
107
+        Write-Warning "This version is unsupported because there are uncommitted file(s)."
108
+        Write-Warning "Either commit these changes, or add them to .gitignore."
109
+        git status --porcelain --untracked-files=no | Write-Warning
110
+        Write-Host ""
111
+    }
112
+    return $gitCommit
113
+}
114
+
115
+# Utility function to get get the current build version of docker
116
+Function Get-DockerVersion() {
117
+    if (-not (Test-Path ".\VERSION")) { Throw "VERSION file not found. Is this running from the root of a docker repository?" }
118
+    return $(Get-Content ".\VERSION" -raw).ToString().Replace("`n","").Trim()
119
+}
120
+
121
+# Utility function to determine if we are running in a container or not.
122
+# In Windows, we get this through an environment variable set in `Dockerfile.Windows`
123
+Function Check-InContainer() {
124
+    if ($env:FROM_DOCKERFILE.Length -eq 0) {
125
+        Write-Host ""
126
+        Write-Warning "Not running in a container. The result might be an incorrect build."
127
+        Write-Host ""
128
+    }
129
+}
130
+
131
+# Utility function to get the commit for HEAD
132
+Function Get-HeadCommit() {
133
+    $head = Invoke-Expression "git rev-parse --verify HEAD"
134
+    if ($LASTEXITCODE -ne 0) { Throw "Failed getting HEAD commit" }
135
+
136
+    return $head
137
+}
138
+
139
+# Utility function to get the commit for upstream
140
+Function Get-UpstreamCommit() {
141
+    Invoke-Expression "git fetch -q https://github.com/docker/docker.git refs/heads/master"
142
+    if ($LASTEXITCODE -ne 0) { Throw "Failed fetching" }
143
+
144
+    $upstream = Invoke-Expression "git rev-parse --verify FETCH_HEAD"
145
+    if ($LASTEXITCODE -ne 0) { Throw "Failed getting upstream commit" }
146
+
147
+    return $upstream
148
+}
149
+
150
+# Build a binary (client or daemon)
151
+Function Execute-Build($type, $additionalBuildTags, $directory) {
152
+    # Generate the build flags
153
+    $buildTags = "autogen"
154
+    if ($Noisy)                     { $verboseParm=" -v" }
155
+    if ($Race)                      { Write-Warning "Using race detector"; $raceParm=" -race"}
156
+    if ($ForceBuildAll)             { $allParm=" -a" }
157
+    if ($NoOpt)                     { $optParm=" -gcflags "+""""+"-N -l"+"""" }
158
+    if ($addtionalBuildTags -ne "") { $buildTags += $(" " + $additionalBuildTags) }
159
+
160
+    # Do the go build in the appropriate directory
161
+    # Note -linkmode=internal is required to be able to debug on Windows.
162
+    # https://github.com/golang/go/issues/14319#issuecomment-189576638
163
+    Write-Host "INFO: Building $type..."
164
+    Push-Location $root\cmd\$directory; $global:pushed=$True
165
+    $buildCommand = "go build" + `
166
+                    $raceParm + `
167
+                    $verboseParm + `
168
+                    $allParm + `
169
+                    $optParm + `
170
+                    " -tags """ + $buildTags + """" + `
171
+                    " -ldflags """ + "-linkmode=internal" + """" + `
172
+                    " -o $root\bundles\"+$directory+".exe"
173
+    Invoke-Expression $buildCommand
174
+    if ($LASTEXITCODE -ne 0) { Throw "Failed to compile $type" }
175
+    Pop-Location; $global:pushed=$False
176
+}
177
+
178
+# Validates the DCO marker is present on each commit
179
+Function Validate-DCO($headCommit, $upstreamCommit) {
180
+    Write-Host "INFO: Validating Developer Certificate of Origin..."
181
+    # Username may only contain alphanumeric characters or dashes and cannot begin with a dash
182
+    $usernameRegex='[a-zA-Z0-9][a-zA-Z0-9-]+'
183
+
184
+    $dcoPrefix="Signed-off-by:"
185
+    $dcoRegex="^(Docker-DCO-1.1-)?$dcoPrefix ([^<]+) <([^<>@]+@[^<>]+)>( \\(github: ($githubUsernameRegex)\\))?$"
186
+
187
+    $counts = Invoke-Expression "git diff --numstat $upstreamCommit...$headCommit"
188
+    if ($LASTEXITCODE -ne 0) { Throw "Failed git diff --numstat" }
189
+
190
+    # Counts of adds and deletes after removing multiple white spaces. AWK anyone? :(
191
+    $adds=0; $dels=0; $($counts -replace '\s+', ' ') | %{ $a=$_.Split(" "); $adds+=[int]$a[0]; $dels+=[int]$a[1] }
192
+    if (($adds -eq 0) -and ($dels -eq 0)) { 
193
+        Write-Warning "DCO validation - nothing to validate!"
194
+        return
195
+    }
196
+
197
+    $commits = Invoke-Expression "git log  $upstreamCommit..$headCommit --format=format:%H%n"
198
+    if ($LASTEXITCODE -ne 0) { Throw "Failed git log --format" }
199
+    $commits = $($commits -split '\s+' -match '\S')
200
+    $badCommits=@()
201
+    $commits | %{ 
202
+        # Skip commits with no content such as merge commits etc
203
+        if ($(git log -1 --format=format: --name-status $_).Length -gt 0) {
204
+            # Ignore exit code on next call - always process regardless
205
+            $commitMessage = Invoke-Expression "git log -1 --format=format:%B --name-status $_"
206
+            if (($commitMessage -match $dcoRegex).Length -eq 0) { $badCommits+=$_ }
207
+        }
208
+    }
209
+    if ($badCommits.Length -eq 0) {
210
+        Write-Host "Congratulations!  All commits are properly signed with the DCO!"
211
+    } else {
212
+        $e = "`nThese commits do not have a proper '$dcoPrefix' marker:`n"
213
+        $badCommits | %{ $e+=" - $_`n"}
214
+        $e += "`nPlease amend each commit to include a properly formatted DCO marker.`n`n"
215
+        $e += "Visit the following URL for information about the Docker DCO:`n"
216
+        $e += "https://github.com/docker/docker/blob/master/CONTRIBUTING.md#sign-your-work`n"
217
+        Throw $e
218
+    }
219
+}
220
+
221
+# Validates that .\pkg\... is safely isolated from internal code
222
+Function Validate-PkgImports($headCommit, $upstreamCommit) {
223
+    Write-Host "INFO: Validating pkg import isolation..."
224
+
225
+    # Get a list of go source-code files which have changed under pkg\. Ignore exit code on next call - always process regardless
226
+    $files=@(); $files = Invoke-Expression "git diff $upstreamCommit...$headCommit --diff-filter=ACMR --name-only -- `'pkg\*.go`'"
227
+    $badFiles=@(); $files | %{
228
+        $file=$_
229
+        # For the current changed file, get its list of dependencies, sorted and uniqued.
230
+        $imports = Invoke-Expression "go list -e -f `'{{ .Deps }}`' $file"
231
+        if ($LASTEXITCODE -ne 0) { Throw "Failed go list for dependencies on $file" }
232
+        $imports = $imports -Replace "\[" -Replace "\]", "" -Split(" ") | Sort-Object | Get-Unique 
233
+        # Filter out what we are looking for
234
+        $imports = $imports -NotMatch "^github.com/docker/docker/pkg/" `
235
+                            -NotMatch "^github.com/docker/docker/vendor" `
236
+                            -Match "^github.com/docker/docker" `
237
+                            -Replace "`n", ""
238
+        $imports | % { $badFiles+="$file imports $_`n" }
239
+    }
240
+    if ($badFiles.Length -eq 0) {
241
+        Write-Host 'Congratulations!  ".\pkg\*.go" is safely isolated from internal code.'
242
+    } else {
243
+        $e = "`nThese files import internal code: (either directly or indirectly)`n"
244
+        $badFiles | %{ $e+=" - $_"}
245
+        Throw $e
246
+    }
247
+}
248
+
249
+# Validates that changed files are correctly go-formatted
250
+Function Validate-GoFormat($headCommit, $upstreamCommit) {
251
+    Write-Host "INFO: Validating go formatting on changed files..."
252
+
253
+    # Verify gofmt is installed
254
+    if ($(Get-Command gofmt -ErrorAction SilentlyContinue) -eq $nil) { Throw "gofmt does not appear to be installed" }
255
+
256
+    # Get a list of all go source-code files which have changed.  Ignore exit code on next call - always process regardless
257
+    $files=@(); $files = Invoke-Expression "git diff $upstreamCommit...$headCommit --diff-filter=ACMR --name-only -- `'*.go`'" 
258
+    $files = $files | Select-String -NotMatch "^vendor/"
259
+    $badFiles=@(); $files | %{
260
+        # Deliberately ignore error on next line - treat as failed
261
+        $content=Invoke-Expression "git show $headCommit`:$_" 
262
+
263
+        # Next set of hoops are to ensure we have LF not CRLF semantics as otherwise gofmt on Windows will not succeed.
264
+        # Also note that gofmt on Windows does not appear to support stdin piping correctly. Hence go through a temporary file.
265
+        $content=$content -join "`n"
266
+        $content+="`n"
267
+        $outputFile=[System.IO.Path]::GetTempFileName()
268
+        if (Test-Path $outputFile) { Remove-Item $outputFile }
269
+        [System.IO.File]::WriteAllText($outputFile, $content, (New-Object System.Text.UTF8Encoding($False)))
270
+        $valid=Invoke-Expression "gofmt -s -l $outputFile"
271
+        Write-Host "Checking $outputFile"
272
+        if ($valid.Length -ne 0) { $badFiles+=$_ }
273
+        if (Test-Path $outputFile) { Remove-Item $outputFile }
274
+    }
275
+    if ($badFiles.Length -eq 0) {
276
+        Write-Host 'Congratulations!  All Go source files are properly formatted.'
277
+    } else {
278
+        $e = "`nThese files are not properly gofmt`'d:`n"
279
+        $badFiles | %{ $e+=" - $_`n"}
280
+        $e+= "`nPlease reformat the above files using `"gofmt -s -w`" and commit the result."
281
+        Throw $e
282
+    }
283
+}
284
+
285
+# Run the unit tests
286
+Function Run-UnitTests() {
287
+    Write-Host "INFO: Running unit tests..."
288
+    $testPath="./..."
289
+    $goListCommand = "go list -e -f '{{if ne .Name """ + '\"github.com/docker/docker\"' + """}}{{.ImportPath}}{{end}}' $testPath"
290
+    $pkgList = $(Invoke-Expression $goListCommand)
291
+    if ($LASTEXITCODE -ne 0) { Throw "go list for unit tests failed" }
292
+    $pkgList = $pkgList | Select-String -Pattern "github.com/docker/docker"
293
+    $pkgList = $pkgList | Select-String -NotMatch "github.com/docker/docker/vendor"
294
+    $pkgList = $pkgList | Select-String -NotMatch "github.com/docker/docker/man"
295
+    $pkgList = $pkgList | Select-String -NotMatch "github.com/docker/docker/integration-cli"
296
+    $pkgList = $pkgList -replace "`r`n", " "
297
+    $goTestCommand = "go test" + $raceParm + " -cover -ldflags -w -tags """ + "autogen daemon" + """ -a """ + "-test.timeout=10m" + """ $pkgList"
298
+    Invoke-Expression $goTestCommand
299
+    if ($LASTEXITCODE -ne 0) { Throw "Unit tests failed" }
300
+}
301
+
302
+# Start of main code.
303
+Try {
304
+    Write-Host -ForegroundColor Cyan "INFO: make.ps1 starting at $(Get-Date)"
305
+    $root=$(pwd)
306
+
307
+    # Handle the "-All" shortcut to turn on all things we can handle.
308
+    if ($All) { $Client=$True; $Daemon=$True; $DCO=$True; $PkgImports=$True; $GoFormat=$True; $TestUnit=$True }
309
+
310
+    # Handle the "-Binary" shortcut to build both client and daemon.
311
+    if ($Binary) { $Client = $True; $Daemon = $True }
312
+
313
+    # Make sure we have something to do
314
+    if (-not($Client) -and -not($Daemon) -and -not($DCO) -and -not($PkgImports) -and -not($GoFormat) -and -not($TestUnit)) { Throw 'Nothing to do. Try adding "-All" for everything I can do' }
315
+
316
+    # Verify git is installed
317
+    if ($(Get-Command git -ErrorAction SilentlyContinue) -eq $nil) { Throw "Git does not appear to be installed" }
318
+
319
+    # Verify go is installed
320
+    if ($(Get-Command go -ErrorAction SilentlyContinue) -eq $nil) { Throw "GoLang does not appear to be installed" }
321
+
322
+    # Get the git commit. This will also verify if we are in a repo or not. Then add a custom string if supplied.
323
+    $gitCommit=Get-GitCommit
324
+    if ($CommitSuffix -ne "") { $gitCommit += "-"+$CommitSuffix -Replace ' ', '' }
325
+
326
+    # Get the version of docker (eg 1.14.0-dev)
327
+    $dockerVersion=Get-DockerVersion
328
+
329
+    # Give a warning if we are not running in a container and are building binaries or running unit tests. 
330
+    # Not relevant for validation tests as these are fine to run outside of a container.
331
+    if ($Client -or $Daemon -or $TestUnit) { Check-InContainer }
332
+
333
+    # Verify GOPATH is set
334
+    if ($env:GOPATH.Length -eq 0) { Throw "Missing GOPATH environment variable. See https://golang.org/doc/code.html#GOPATH" }
335
+
336
+    # Run autogen if building binaries or running unit tests.
337
+    if ($Client -or $Daemon -or $TestUnit) {
338
+        Write-Host "INFO: Invoking autogen..."
339
+        Try { .\hack\make\.go-autogen.ps1 -CommitString $gitCommit -DockerVersion $dockerVersion }
340
+        Catch [Exception] { Throw $_ }
341
+    }
342
+
343
+    # DCO, Package import and Go formatting tests. 
344
+    if ($DCO -or $PkgImports -or $GoFormat) {
345
+        # We need the head and upstream commits for these
346
+        $headCommit=Get-HeadCommit
347
+        $upstreamCommit=Get-UpstreamCommit
348
+
349
+        # Run DCO validation
350
+        if ($DCO) { Validate-DCO $headCommit $upstreamCommit }
351
+
352
+        # Run `gofmt` validation
353
+        if ($GoFormat) { Validate-GoFormat $headCommit $upstreamCommit }
354
+
355
+        # Run pkg isolation validation
356
+        if ($PkgImports) { Validate-PkgImports $headCommit $upstreamCommit }
357
+    }
358
+
359
+    # Build the binaries
360
+    if ($Client -or $Daemon) {
361
+        # Create the bundles directory if it doesn't exist
362
+        if (-not (Test-Path ".\bundles")) { New-Item ".\bundles" -ItemType Directory | Out-Null }
363
+
364
+        # Perform the actual build
365
+        if ($Daemon) { Execute-Build "daemon" "daemon" "dockerd" }
366
+        if ($Client) { Execute-Build "client" "" "docker" }
367
+    }
368
+
369
+    # Run unit tests
370
+    if ($TestUnit) { Run-UnitTests }
371
+
372
+    # Gratuitous ASCII art.
373
+    if ($Daemon -or $Client) {
374
+        Write-Host
375
+        Write-Host -ForegroundColor Green " ________   ____  __."
376
+        Write-Host -ForegroundColor Green " \_____  \ `|    `|/ _`|"
377
+        Write-Host -ForegroundColor Green " /   `|   \`|      `<"
378
+        Write-Host -ForegroundColor Green " /    `|    \    `|  \"
379
+        Write-Host -ForegroundColor Green " \_______  /____`|__ \"
380
+        Write-Host -ForegroundColor Green "         \/        \/"
381
+        Write-Host
382
+    }
383
+}
384
+Catch [Exception] {
385
+    Write-Host -ForegroundColor Red ("`nERROR: make.ps1 failed:`n$_")
386
+
387
+    # More gratuitous ASCII art.
388
+    Write-Host
389
+    Write-Host -ForegroundColor Red  "___________      .__.__             .___"
390
+    Write-Host -ForegroundColor Red  "\_   _____/____  `|__`|  `|   ____   __`| _/"
391
+    Write-Host -ForegroundColor Red  " `|    __) \__  \ `|  `|  `| _/ __ \ / __ `| "
392
+    Write-Host -ForegroundColor Red  " `|     \   / __ \`|  `|  `|_\  ___// /_/ `| "
393
+    Write-Host -ForegroundColor Red  " \___  /  (____  /__`|____/\___  `>____ `| "
394
+    Write-Host -ForegroundColor Red  "     \/        \/             \/     \/ "
395
+    Write-Host
396
+}
397
+Finally {
398
+    if ($global:pushed) { Pop-Location }
399
+    Write-Host -ForegroundColor Cyan "INFO: make.ps1 ended at $(Get-Date)"
400
+}
... ...
@@ -10,16 +10,11 @@
10 10
 
11 11
 .PARAMETER DockerVersion
12 12
      The version such as 1.14.0-dev. This is calculated externally to this script.
13
-
14
-.PARAMETER StaticSQLite
15
-     A string indicating if the daemon binary is compiled with the SQLite
16
-     sources compiled in. This is calculated externally to this script.
17 13
 #>
18 14
 
19 15
 param(
20 16
     [Parameter(Mandatory=$true)][string]$CommitString,
21
-    [Parameter(Mandatory=$true)][string]$DockerVersion,
22
-    [Parameter(Mandatory=$true)][string]$StaticSQLiteString
17
+    [Parameter(Mandatory=$true)][string]$DockerVersion
23 18
 )
24 19
 
25 20
 $ErrorActionPreference = "Stop"
... ...
@@ -48,7 +43,6 @@ const (
48 48
     GitCommit          string = "'+$CommitString+'"
49 49
     Version            string = "'+$DockerVersion+'"
50 50
     BuildTime          string = "'+$buildDateTime+'"
51
-    StaticSQLite       string = "'+$StaticSQLiteString+'"
52 51
 )
53 52
 
54 53
 // AUTOGENERATED FILE; see hack\make\.go-autogen.ps1