1
1
const Core = require ( "@actions/core" ) ;
2
2
const ToolCache = require ( "@actions/tool-cache" ) ;
3
+ const Cache = require ( "@actions/cache" ) ;
3
4
const IO = require ( "@actions/io" ) ;
4
5
const Octokit = require ( "@octokit/request" ) ;
5
6
const fetch = require ( "node-fetch" ) ;
@@ -13,15 +14,23 @@ const execFile = Util.promisify(ChildProcess.execFile);
13
14
14
15
async function run ( ) {
15
16
try {
16
- const params = getPlatform ( ) === Windows ?
17
- { crystal : "nightly" , shards : "true" } :
18
- { crystal : "latest" , shards : "true" } ;
19
- for ( const key of [ "crystal" , "shards" , "arch" , "destination" ] ) {
17
+ const params = {
18
+ "crystal" : getPlatform ( ) === Windows ? "nightly" : "latest" ,
19
+ "shards" : "true" ,
20
+ } ;
21
+ for ( const key of [ "crystal" , "shards" , "arch" ] ) {
20
22
let value ;
21
23
if ( ( value = Core . getInput ( key ) ) ) {
22
24
params [ key ] = value ;
23
25
}
24
26
}
27
+ params . path = Core . getInput ( "destination" ) || Path . join (
28
+ process . env [ "RUNNER_TEMP" ] , `crystal-${ params . crystal } -${ params . shards } -${ params . arch } ` ,
29
+ ) ;
30
+ if ( params . shards === Any && getPlatform ( ) === Windows ) {
31
+ params . shards = Latest ;
32
+ }
33
+
25
34
const func = {
26
35
[ Linux ] : installCrystalForLinux ,
27
36
[ Mac ] : installCrystalForMac ,
@@ -30,7 +39,10 @@ async function run() {
30
39
if ( ! func ) {
31
40
throw `Platform "${ getPlatform ( ) } " is not supported` ;
32
41
}
33
- await maybeInstallShards ( params , func ( params ) ) ;
42
+ const crystalPromise = func ( params ) ;
43
+ params . path += "-shards" ;
44
+ await maybeInstallShards ( params , crystalPromise ) ;
45
+ await crystalPromise ;
34
46
35
47
const { stdout} = await subprocess ( [ "crystal" , "--version" ] ) ;
36
48
Core . info ( stdout ) ;
@@ -82,20 +94,15 @@ async function subprocess(command, options) {
82
94
return execFile ( file , args , options ) ;
83
95
}
84
96
85
- async function installCrystalForLinux ( {
86
- crystal,
87
- shards,
88
- arch = getArch ( ) ,
89
- destination = null ,
90
- } ) {
97
+ async function installCrystalForLinux ( { crystal, shards, arch = getArch ( ) , path} ) {
91
98
checkVersion ( crystal , [ Latest , Nightly , NumericVersion ] ) ;
92
99
const suffixes = { "x86_64" : "linux-x86_64" , "x86" : "linux-i686" } ;
93
100
checkArch ( arch , Object . keys ( suffixes ) ) ;
94
101
95
102
const depsTask = installAptPackages (
96
103
"libevent-dev libgmp-dev libpcre3-dev libssl-dev libxml2-dev libyaml-dev" . split ( " " ) ,
97
104
) ;
98
- const path = await installBinaryRelease ( { crystal, shards, suffix : suffixes [ arch ] , destination } ) ;
105
+ await installBinaryRelease ( { crystal, shards, suffix : suffixes [ arch ] , path } ) ;
99
106
100
107
Core . info ( "Setting up environment for Crystal" ) ;
101
108
Core . addPath ( Path . join ( path , "bin" ) ) ;
@@ -107,17 +114,10 @@ async function installCrystalForLinux({
107
114
await depsTask ;
108
115
}
109
116
110
- async function installCrystalForMac ( {
111
- crystal,
112
- shards,
113
- arch = "x86_64" ,
114
- destination = null ,
115
- } ) {
117
+ async function installCrystalForMac ( { crystal, shards, arch = "x86_64" , path} ) {
116
118
checkVersion ( crystal , [ Latest , Nightly , NumericVersion ] ) ;
117
119
checkArch ( arch , [ "x86_64" ] ) ;
118
- const path = await installBinaryRelease ( {
119
- crystal, shards, suffix : "darwin-x86_64" , destination,
120
- } ) ;
120
+ await installBinaryRelease ( { crystal, shards, suffix : "darwin-x86_64" , path} ) ;
121
121
122
122
Core . info ( "Setting up environment for Crystal" ) ;
123
123
Core . addPath ( Path . join ( path , "embedded" , "bin" ) ) ;
@@ -149,53 +149,67 @@ async function installAptPackages(packages) {
149
149
Core . endGroup ( ) ;
150
150
}
151
151
152
- async function installBinaryRelease ( { crystal, suffix, destination } ) {
152
+ async function installBinaryRelease ( { crystal, suffix, path } ) {
153
153
if ( crystal === Nightly ) {
154
- return downloadCrystalNightly ( suffix , destination ) ;
154
+ await IO . mv ( await downloadCrystalNightly ( suffix ) , path ) ;
155
155
} else {
156
156
if ( crystal === Latest ) {
157
157
crystal = null ;
158
158
}
159
- return downloadCrystalRelease ( suffix , crystal , destination ) ;
159
+ await IO . mv ( await downloadCrystalRelease ( suffix , crystal ) , path ) ;
160
160
}
161
161
}
162
162
163
- async function maybeInstallShards ( { shards, destination } , crystalPromise ) {
163
+ async function maybeInstallShards ( { shards, path } , crystalPromise ) {
164
164
const allowed = [ Latest , Nightly , NumericVersion , Any , None ] ;
165
- if ( getPlatform ( ) === Windows && shards === Any ) {
166
- shards = Latest ;
167
- }
168
165
checkVersion ( shards , allowed ) ;
169
166
if ( ! [ Any , None ] . includes ( shards ) ) {
170
- if ( destination ) {
171
- destination = Path . join ( destination , "shards" ) ;
172
- }
173
- await installShards ( { shards, destination} , crystalPromise ) ;
174
- } else {
175
- await crystalPromise ;
167
+ await installShards ( { shards, path} , crystalPromise ) ;
176
168
}
177
169
if ( shards !== None ) {
170
+ await crystalPromise ;
178
171
const { stdout} = await subprocess ( [ "shards" , "--version" ] ) ;
179
172
Core . info ( stdout ) ;
180
173
}
181
174
}
182
175
183
- async function installShards ( { shards, destination } , crystalPromise ) {
176
+ async function installShards ( { shards, path } , crystalPromise ) {
184
177
if ( NumericVersion . test ( shards ) ) {
185
178
shards = "v" + shards ;
186
179
}
187
- const { ref, path} = await downloadSource ( {
188
- name : "Shards" , apiBase : GitHubApiBaseShards , version : shards , destination,
189
- } ) ;
180
+ const ref = await findRef ( { name : "Shards" , apiBase : GitHubApiBaseShards , version : shards } ) ;
190
181
Core . setOutput ( "shards" , ref ) ;
191
- await crystalPromise ;
192
182
193
- Core . info ( "Building Shards" ) ;
194
- const { stdout} = await subprocess ( [ "make" ] , { cwd : path } ) ;
195
- Core . startGroup ( "Finished building Shards" ) ;
196
- Core . info ( stdout ) ;
197
- Core . endGroup ( ) ;
183
+ const cacheKey = `install-shards-v1-${ ref } --${ getArch ( ) } -${ getPlatform ( ) } ` ;
184
+ let restored = null ;
185
+ try {
186
+ Core . info ( `Trying to restore cache: key '${ cacheKey } '` ) ;
187
+ restored = await Cache . restoreCache ( [ path ] , cacheKey ) ;
188
+ } catch ( error ) {
189
+ Core . warning ( error . message ) ;
190
+ }
191
+ if ( ! restored ) {
192
+ Core . info ( `Cache not found for key '${ cacheKey } '` ) ;
193
+ const fetchSrcTask = downloadSource ( { name : "Shards" , apiBase : GitHubApiBaseShards , ref} ) ;
194
+ await IO . mv ( await fetchSrcTask , path ) ;
195
+ await crystalPromise ;
198
196
197
+ Core . info ( "Building Shards" ) ;
198
+ const { stdout} = await subprocess ( [ "make" ] , { cwd : path } ) ;
199
+ Core . startGroup ( "Finished building Shards" ) ;
200
+ Core . info ( stdout ) ;
201
+ Core . endGroup ( ) ;
202
+ }
203
+ if ( restored !== cacheKey ) {
204
+ Core . info ( `Saving cache: '${ cacheKey } '` ) ;
205
+ try {
206
+ await Cache . saveCache ( [ path ] , cacheKey ) ;
207
+ } catch ( error ) {
208
+ Core . warning ( error . message ) ;
209
+ }
210
+ }
211
+
212
+ await crystalPromise ;
199
213
Core . info ( "Setting up environment for Shards" ) ;
200
214
Core . addPath ( Path . join ( path , "bin" ) ) ;
201
215
}
@@ -225,7 +239,7 @@ async function findLatestCommit({name, apiBase, branch = "master"}) {
225
239
return commit [ "sha" ] ;
226
240
}
227
241
228
- async function downloadCrystalRelease ( suffix , version = null , destination = null ) {
242
+ async function downloadCrystalRelease ( suffix , version = null ) {
229
243
const release = await findRelease ( { name : "Crystal" , apiBase : GitHubApiBase , version} ) ;
230
244
Core . setOutput ( "crystal" , release [ "tag_name" ] ) ;
231
245
@@ -238,30 +252,31 @@ async function downloadCrystalRelease(suffix, version = null, destination = null
238
252
} ) ;
239
253
240
254
Core . info ( "Extracting Crystal build" ) ;
241
- return onlySubdir ( await ToolCache . extractTar ( downloadedPath , destination ) ) ;
255
+ const extractedPath = await ToolCache . extractTar ( downloadedPath ) ;
256
+ return onlySubdir ( extractedPath ) ;
242
257
}
243
258
244
- async function downloadSource ( { name, apiBase, version = null , destination = null } ) {
245
- let ref = version ;
259
+ async function findRef ( { name, apiBase, version} ) {
246
260
if ( version === Nightly ) {
247
- ref = await findLatestCommit ( { name, apiBase} ) ;
261
+ return findLatestCommit ( { name, apiBase} ) ;
248
262
} else if ( version === Latest ) {
249
263
const release = await findRelease ( { name, apiBase} ) ;
250
- ref = release [ "tag_name" ] ;
264
+ return release [ "tag_name" ] ;
251
265
}
266
+ return version ;
267
+ }
252
268
269
+ async function downloadSource ( { name, apiBase, ref} ) {
253
270
Core . info ( `Downloading ${ name } source for ${ ref } ` ) ;
254
271
const downloadedPath = await githubDownloadViaRedirect ( {
255
272
url : apiBase + "/zipball/:ref" ,
256
273
"ref" : ref ,
257
274
} ) ;
258
275
Core . info ( `Extracting ${ name } source` ) ;
259
- const path = await onlySubdir ( await ToolCache . extractZip ( downloadedPath , destination ) ) ;
260
-
261
- return { ref, path} ;
276
+ return onlySubdir ( await ToolCache . extractZip ( downloadedPath ) ) ;
262
277
}
263
278
264
- async function downloadCrystalNightly ( suffix , destination = null ) {
279
+ async function downloadCrystalNightly ( suffix ) {
265
280
Core . info ( "Looking for latest Crystal build" ) ;
266
281
267
282
let build ;
@@ -289,18 +304,19 @@ async function downloadCrystalNightly(suffix, destination = null) {
289
304
Core . info ( `Downloading Crystal build from ${ artifact [ "url" ] } ` ) ;
290
305
const downloadedPath = await ToolCache . downloadTool ( artifact [ "url" ] ) ;
291
306
Core . info ( "Extracting Crystal build" ) ;
292
- return onlySubdir ( await ToolCache . extractTar ( downloadedPath , destination ) ) ;
307
+ const extractedPath = await ToolCache . extractTar ( downloadedPath ) ;
308
+ return onlySubdir ( extractedPath ) ;
293
309
}
294
310
295
- async function installCrystalForWindows ( { crystal, arch = "x86_64" , destination = null } ) {
311
+ async function installCrystalForWindows ( { crystal, arch = "x86_64" , path } ) {
296
312
checkVersion ( crystal , [ Nightly ] ) ;
297
313
checkArch ( arch , [ "x86_64" ] ) ;
298
- const path = await downloadCrystalNightlyForWindows ( destination ) ;
314
+ await IO . mv ( await downloadCrystalNightlyForWindows ( ) , path ) ;
299
315
300
316
Core . info ( "Setting up environment for Crystal" ) ;
301
317
const vars = await variablesForVCBuildTools ( ) ;
302
- addPathToVars ( vars , "PATH" , path ) ;
303
- addPathToVars ( vars , "LIB" , path ) ;
318
+ addPathToVars ( vars , "PATH" , Path . join ( path , "bin" ) ) ;
319
+ addPathToVars ( vars , "LIB" , Path . join ( path , "bin" ) ) ;
304
320
addPathToVars ( vars , "CRYSTAL_PATH" , Path . join ( path , "src" ) ) ;
305
321
addPathToVars ( vars , "CRYSTAL_PATH" , "lib" ) ;
306
322
for ( const [ k , v ] of vars . entries ( ) ) {
@@ -348,39 +364,40 @@ function* getChangedVars(lines) {
348
364
}
349
365
}
350
366
351
- async function downloadCrystalNightlyForWindows ( destination = null ) {
367
+ async function downloadCrystalNightlyForWindows ( ) {
352
368
Core . info ( "Looking for latest Crystal build" ) ;
353
369
354
370
const runsResp = await githubGet ( {
355
371
url : GitHubApiBase + "/actions/workflows/win.yml/runs?branch=master&event=push&status=success" ,
356
372
"per_page" : 1 ,
357
373
} ) ;
358
374
const [ workflowRun ] = runsResp . data [ "workflow_runs" ] ;
359
- const { "head_sha" : version , "id" : runId } = workflowRun ;
375
+ const { "head_sha" : ref , "id" : runId } = workflowRun ;
360
376
Core . info ( `Found Crystal release ${ workflowRun [ "html_url" ] } ` ) ;
361
- Core . setOutput ( "crystal" , version ) ;
377
+ Core . setOutput ( "crystal" , ref ) ;
362
378
363
- const fetchExeTask = async ( ) => {
379
+ const fetchSrcTask = downloadSource ( { name : "Crystal" , apiBase : GitHubApiBase , ref} ) ;
380
+ const fetchExeTask = ( async ( ) => {
364
381
const artifactsResp = await githubGet ( {
365
382
url : GitHubApiBase + "/actions/runs/:run_id/artifacts" ,
366
383
"run_id" : runId ,
367
384
} ) ;
368
385
const artifact = artifactsResp . data [ "artifacts" ] . find ( ( x ) => x . name === "crystal" ) ;
369
386
370
387
Core . info ( "Downloading Crystal build" ) ;
371
- return githubDownloadViaRedirect ( {
388
+ const downloadedPath = await githubDownloadViaRedirect ( {
372
389
url : GitHubApiBase + "/actions/artifacts/:artifact_id/zip" ,
373
390
"artifact_id" : artifact . id ,
374
391
} ) ;
375
- } ;
376
392
377
- const [ { path : srcPath } , exeDownloadedPath ] = await Promise . all ( [
378
- downloadSource ( { name : "Crystal" , apiBase : GitHubApiBase , version, destination} ) ,
379
- fetchExeTask ( ) ,
380
- ] ) ;
393
+ Core . info ( "Extracting Crystal build" ) ;
394
+ return ToolCache . extractZip ( downloadedPath ) ;
395
+ } ) ( ) ;
381
396
382
- Core . info ( "Extracting Crystal build" ) ;
383
- return ToolCache . extractZip ( exeDownloadedPath , srcPath ) ;
397
+ const path = await fetchSrcTask ;
398
+ await IO . rmRF ( Path . join ( path , "bin" ) ) ;
399
+ await IO . mv ( await fetchExeTask , Path . join ( path , "bin" ) ) ;
400
+ return path ;
384
401
}
385
402
386
403
function githubGet ( request ) {
0 commit comments