@@ -28,11 +28,13 @@ import * as tc from '@actions/tool-cache';
28
28
29
29
import { Context } from '../context' ;
30
30
import { Docker } from './docker' ;
31
+ import { ImageTools } from '../buildx/imagetools' ;
32
+ import { Undock } from '../undock/undock' ;
31
33
import { Exec } from '../exec' ;
32
34
import { Util } from '../util' ;
33
35
import { limaYamlData , dockerServiceLogsPs1 , setupDockerWinPs1 } from './assets' ;
36
+
34
37
import { GitHubRelease } from '../types/github' ;
35
- import { HubRepository } from '../hubRepository' ;
36
38
import { Image } from '../types/oci/config' ;
37
39
38
40
export interface InstallSourceImage {
@@ -57,6 +59,8 @@ export interface InstallOpts {
57
59
daemonConfig ?: string ;
58
60
rootless ?: boolean ;
59
61
localTCPPort ?: number ;
62
+
63
+ undock : Undock ;
60
64
}
61
65
62
66
interface LimaImage {
@@ -72,6 +76,7 @@ export class Install {
72
76
private readonly daemonConfig ?: string ;
73
77
private readonly rootless : boolean ;
74
78
private readonly localTCPPort ?: number ;
79
+ private readonly undock : Undock ;
75
80
76
81
private _version : string | undefined ;
77
82
private _toolDir : string | undefined ;
@@ -91,36 +96,13 @@ export class Install {
91
96
this . daemonConfig = opts . daemonConfig ;
92
97
this . rootless = opts . rootless || false ;
93
98
this . localTCPPort = opts . localTCPPort ;
99
+ this . undock = opts . undock ;
94
100
}
95
101
96
102
get toolDir ( ) : string {
97
103
return this . _toolDir || Context . tmpDir ( ) ;
98
104
}
99
105
100
- async downloadStaticArchive ( component : 'docker' | 'docker-rootless-extras' , src : InstallSourceArchive ) : Promise < string > {
101
- const release : GitHubRelease = await Install . getRelease ( src . version ) ;
102
- this . _version = release . tag_name . replace ( / ^ v + | v + $ / g, '' ) ;
103
- core . debug ( `docker.Install.download version: ${ this . _version } ` ) ;
104
-
105
- const downloadURL = this . downloadURL ( component , this . _version , src . channel ) ;
106
- core . info ( `Downloading ${ downloadURL } ` ) ;
107
-
108
- const downloadPath = await tc . downloadTool ( downloadURL ) ;
109
- core . debug ( `docker.Install.download downloadPath: ${ downloadPath } ` ) ;
110
-
111
- let extractFolder ;
112
- if ( os . platform ( ) == 'win32' ) {
113
- extractFolder = await tc . extractZip ( downloadPath , extractFolder ) ;
114
- } else {
115
- extractFolder = await tc . extractTar ( downloadPath , extractFolder ) ;
116
- }
117
- if ( Util . isDirectory ( path . join ( extractFolder , component ) ) ) {
118
- extractFolder = path . join ( extractFolder , component ) ;
119
- }
120
- core . debug ( `docker.Install.download extractFolder: ${ extractFolder } ` ) ;
121
- return extractFolder ;
122
- }
123
-
124
106
public async download ( ) : Promise < string > {
125
107
let extractFolder : string ;
126
108
let cacheKey : string ;
@@ -132,35 +114,8 @@ export class Install {
132
114
this . _version = tag ;
133
115
cacheKey = `docker-image` ;
134
116
135
- core . info ( `Downloading docker cli from dockereng/cli-bin:${ tag } ` ) ;
136
- const cli = await HubRepository . build ( 'dockereng/cli-bin' ) ;
137
- extractFolder = await cli . extractImage ( tag ) ;
138
-
139
- const moby = await HubRepository . build ( 'moby/moby-bin' ) ;
140
- if ( [ 'win32' , 'linux' ] . includes ( platform ) ) {
141
- core . info ( `Downloading dockerd from moby/moby-bin:${ tag } ` ) ;
142
- await moby . extractImage ( tag , extractFolder ) ;
143
- } else if ( platform == 'darwin' ) {
144
- // On macOS, the docker daemon binary will be downloaded inside the lima VM.
145
- // However, we will get the exact git revision from the image config
146
- // to get the matching systemd unit files.
147
- core . info ( `Getting git revision from moby/moby-bin:${ tag } ` ) ;
148
-
149
- // There's no macOS image for moby/moby-bin - a linux daemon is run inside lima.
150
- const manifest = await moby . getPlatformManifest ( tag , 'linux' ) ;
151
-
152
- const config = await moby . getJSONBlob < Image > ( manifest . config . digest ) ;
153
- core . debug ( `Config ${ JSON . stringify ( config . config ) } ` ) ;
154
-
155
- this . gitCommit = config . config ?. Labels ?. [ 'org.opencontainers.image.revision' ] ;
156
- if ( ! this . gitCommit ) {
157
- core . warning ( `No git revision can be determined from the image. Will use master.` ) ;
158
- this . gitCommit = 'master' ;
159
- }
160
- core . info ( `Git revision is ${ this . gitCommit } ` ) ;
161
- } else {
162
- core . warning ( `dockerd not supported on ${ platform } , only the Docker cli will be available` ) ;
163
- }
117
+ core . info ( `Downloading Docker ${ tag } from image` ) ;
118
+ extractFolder = await this . downloadSourceImage ( platform ) ;
164
119
break ;
165
120
}
166
121
case 'archive' : {
@@ -170,10 +125,10 @@ export class Install {
170
125
this . _version = version ;
171
126
172
127
core . info ( `Downloading Docker ${ version } from ${ this . source . channel } at download.docker.com` ) ;
173
- extractFolder = await this . downloadStaticArchive ( 'docker' , this . source ) ;
128
+ extractFolder = await this . downloadSourceArchive ( 'docker' , this . source ) ;
174
129
if ( this . rootless ) {
175
130
core . info ( `Downloading Docker rootless extras ${ version } from ${ this . source . channel } at download.docker.com` ) ;
176
- const extrasFolder = await this . downloadStaticArchive ( 'docker-rootless-extras' , this . source ) ;
131
+ const extrasFolder = await this . downloadSourceArchive ( 'docker-rootless-extras' , this . source ) ;
177
132
fs . readdirSync ( extrasFolder ) . forEach ( file => {
178
133
const src = path . join ( extrasFolder , file ) ;
179
134
const dest = path . join ( extractFolder , file ) ;
@@ -191,7 +146,9 @@ export class Install {
191
146
}
192
147
// eslint-disable-next-line @typescript-eslint/no-unused-vars
193
148
files . forEach ( function ( file , index ) {
194
- fs . chmodSync ( path . join ( extractFolder , file ) , '0755' ) ;
149
+ if ( ! Util . isDirectory ( path . join ( extractFolder , file ) ) ) {
150
+ fs . chmodSync ( path . join ( extractFolder , file ) , '0755' ) ;
151
+ }
195
152
} ) ;
196
153
} ) ;
197
154
@@ -203,6 +160,69 @@ export class Install {
203
160
return tooldir ;
204
161
}
205
162
163
+ private async downloadSourceImage ( platform : string ) : Promise < string > {
164
+ const dest = path . join ( Context . tmpDir ( ) , 'docker-install-image' ) ;
165
+
166
+ const cliImage = `dockereng/cli-bin:${ this . _version } ` ;
167
+ core . info ( `Downloading docker cli from ${ cliImage } ` ) ;
168
+ await this . undock . run ( {
169
+ source : cliImage ,
170
+ dist : dest
171
+ } ) ;
172
+
173
+ const engineImage = `moby/moby-bin:${ this . _version } ` ;
174
+ if ( [ 'win32' , 'linux' ] . includes ( platform ) ) {
175
+ core . info ( `Downloading docker engine from ${ engineImage } ` ) ;
176
+ await this . undock . run ( {
177
+ source : cliImage ,
178
+ dist : dest
179
+ } ) ;
180
+ } else if ( platform == 'darwin' ) {
181
+ // On macOS, the docker daemon binary will be downloaded inside the lima VM.
182
+ // However, we will get the exact git revision from the image config
183
+ // to get the matching systemd unit files. There's no macOS image for
184
+ // moby/moby-bin - a linux daemon is run inside lima.
185
+ const engineImageConfig = ( await new ImageTools ( ) . inspectImage ( engineImage ) ) as Record < string , Image > ;
186
+ core . debug ( `docker.Install.downloadSourceImage engineImageConfig: ${ JSON . stringify ( engineImageConfig ) } ` ) ;
187
+
188
+ this . gitCommit = engineImageConfig [ 'linux/arm64' ] . config ?. Labels ?. [ 'org.opencontainers.image.revision' ] ;
189
+ if ( ! this . gitCommit ) {
190
+ core . warning ( `No git revision can be determined from the image. Will use default branch as Git revision.` ) ;
191
+ this . gitCommit = 'master' ;
192
+ }
193
+
194
+ core . debug ( `docker.Install.downloadSourceImage gitCommit: ${ this . gitCommit } ` ) ;
195
+ } else {
196
+ core . warning ( `Docker engine not supported on ${ platform } , only the Docker cli will be available` ) ;
197
+ }
198
+
199
+ return dest ;
200
+ }
201
+
202
+ private async downloadSourceArchive ( component : 'docker' | 'docker-rootless-extras' , src : InstallSourceArchive ) : Promise < string > {
203
+ const release : GitHubRelease = await Install . getRelease ( src . version ) ;
204
+ this . _version = release . tag_name . replace ( / ^ v + | v + $ / g, '' ) ;
205
+ core . debug ( `docker.Install.downloadSourceArchive version: ${ this . _version } ` ) ;
206
+
207
+ const downloadURL = this . downloadURL ( component , this . _version , src . channel ) ;
208
+ core . info ( `Downloading ${ downloadURL } ` ) ;
209
+
210
+ const downloadPath = await tc . downloadTool ( downloadURL ) ;
211
+ core . debug ( `docker.Install.downloadSourceArchive downloadPath: ${ downloadPath } ` ) ;
212
+
213
+ let extractFolder ;
214
+ if ( os . platform ( ) == 'win32' ) {
215
+ extractFolder = await tc . extractZip ( downloadPath , extractFolder ) ;
216
+ } else {
217
+ extractFolder = await tc . extractTar ( downloadPath , extractFolder ) ;
218
+ }
219
+ if ( Util . isDirectory ( path . join ( extractFolder , component ) ) ) {
220
+ extractFolder = path . join ( extractFolder , component ) ;
221
+ }
222
+ core . debug ( `docker.Install.downloadSourceArchive extractFolder: ${ extractFolder } ` ) ;
223
+ return extractFolder ;
224
+ }
225
+
206
226
public async install ( ) : Promise < string > {
207
227
if ( ! this . toolDir ) {
208
228
throw new Error ( 'toolDir must be set. Run download first.' ) ;
0 commit comments