@@ -12,8 +12,10 @@ const execFile = Util.promisify(ChildProcess.execFile);
12
12
13
13
async function run ( ) {
14
14
try {
15
- const params = { } ;
16
- for ( const key of [ "crystal" , "arch" , "destination" ] ) {
15
+ const params = getPlatform ( ) === Windows ?
16
+ { crystal : "nightly" , shards : "false" } :
17
+ { crystal : "latest" , shards : "true" } ;
18
+ for ( const key of [ "crystal" , "shards" , "arch" , "destination" ] ) {
17
19
let value ;
18
20
if ( ( value = Core . getInput ( key ) ) ) {
19
21
params [ key ] = value ;
@@ -27,7 +29,7 @@ async function run() {
27
29
if ( ! func ) {
28
30
throw `Platform "${ getPlatform ( ) } " is not supported` ;
29
31
}
30
- await func ( params ) ;
32
+ await maybeInstallShards ( params , func ( params ) ) ;
31
33
32
34
Core . info ( "[command]crystal --version" ) ;
33
35
const { stdout} = await execFile ( "crystal" , [ "--version" ] ) ;
@@ -57,10 +59,12 @@ function checkArch(arch, allowed) {
57
59
58
60
const Latest = "latest" ;
59
61
const Nightly = "nightly" ;
62
+ const Any = "true" ;
63
+ const None = "false" ;
60
64
const NumericVersion = / ^ \d [ . \d ] + \d $ / ;
61
65
62
66
function checkVersion ( version , allowed ) {
63
- const numericVersion = version . match ( NumericVersion ) && version ;
67
+ const numericVersion = NumericVersion . test ( version ) && version ;
64
68
allowed [ allowed . indexOf ( NumericVersion ) ] = numericVersion ;
65
69
66
70
if ( allowed . includes ( version ) ) {
@@ -73,30 +77,50 @@ function checkVersion(version, allowed) {
73
77
}
74
78
75
79
async function installCrystalForLinux ( {
76
- crystal = Latest ,
80
+ crystal,
81
+ shards,
77
82
arch = getArch ( ) ,
78
83
destination = null ,
79
84
} ) {
80
85
checkVersion ( crystal , [ Latest , Nightly , NumericVersion ] ) ;
81
86
const suffixes = { "x86_64" : "linux-x86_64" , "x86" : "linux-i686" } ;
82
87
checkArch ( arch , Object . keys ( suffixes ) ) ;
83
88
84
- return Promise . all ( [
85
- installAptPackages (
86
- "libevent-dev libgmp-dev libpcre3-dev libssl-dev libxml2-dev libyaml-dev" . split ( " " ) ,
87
- ) ,
88
- installBinaryRelease ( { crystal, suffix : suffixes [ arch ] , destination} ) ,
89
- ] ) ;
89
+ const p = installAptPackages (
90
+ "libevent-dev libgmp-dev libpcre3-dev libssl-dev libxml2-dev libyaml-dev" . split ( " " ) ,
91
+ ) ;
92
+ const path = await installBinaryRelease ( { crystal, shards, suffix : suffixes [ arch ] , destination} ) ;
93
+
94
+ Core . info ( "Setting up environment for Crystal" ) ;
95
+ Core . addPath ( Path . join ( path , "bin" ) ) ;
96
+ if ( shards === None ) {
97
+ try {
98
+ await FS . unlink ( Path . join ( path , "bin" , "shards" ) ) ;
99
+ } catch ( e ) { }
100
+ }
101
+ await p ;
90
102
}
91
103
92
104
async function installCrystalForMac ( {
93
- crystal = Latest ,
105
+ crystal,
106
+ shards,
94
107
arch = "x86_64" ,
95
108
destination = null ,
96
109
} ) {
97
110
checkVersion ( crystal , [ Latest , Nightly , NumericVersion ] ) ;
98
111
checkArch ( arch , [ "x86_64" ] ) ;
99
- return installBinaryRelease ( { crystal, suffix : "darwin-x86_64" , destination} ) ;
112
+ const path = await installBinaryRelease ( {
113
+ crystal, shards, suffix : "darwin-x86_64" , destination,
114
+ } ) ;
115
+
116
+ Core . info ( "Setting up environment for Crystal" ) ;
117
+ Core . addPath ( Path . join ( path , "embedded" , "bin" ) ) ;
118
+ Core . addPath ( Path . join ( path , "bin" ) ) ;
119
+ if ( shards === None ) {
120
+ try {
121
+ await FS . unlink ( Path . join ( path , "embedded" , "bin" , "shards" ) ) ;
122
+ } catch ( e ) { }
123
+ }
100
124
}
101
125
102
126
async function installAptPackages ( packages ) {
@@ -112,43 +136,121 @@ async function installAptPackages(packages) {
112
136
}
113
137
114
138
async function installBinaryRelease ( { crystal, suffix, destination} ) {
115
- let path ;
116
139
if ( crystal === Nightly ) {
117
- path = await downloadCrystalNightly ( suffix , destination ) ;
140
+ return downloadCrystalNightly ( suffix , destination ) ;
118
141
} else {
119
142
if ( crystal === Latest ) {
120
143
crystal = null ;
121
144
}
122
- path = await downloadCrystalRelease ( suffix , crystal , destination ) ;
145
+ return downloadCrystalRelease ( suffix , crystal , destination ) ;
123
146
}
147
+ }
124
148
125
- Core . info ( "Setting up environment" ) ;
126
- Core . addPath ( Path . join ( path , "embedded" , "bin" ) ) ;
149
+ async function maybeInstallShards ( { shards, destination} , crystalPromise ) {
150
+ const allowed = [ Nightly , NumericVersion , Any , None ] ;
151
+ if ( getPlatform ( ) !== Windows ) {
152
+ allowed . push ( Latest ) ;
153
+ } else if ( shards === Any ) {
154
+ shards = Nightly ;
155
+ }
156
+ checkVersion ( shards , allowed ) ;
157
+ if ( ! [ Any , None ] . includes ( shards ) ) {
158
+ if ( destination ) {
159
+ destination = Path . join ( destination , "shards" ) ;
160
+ }
161
+ await installShards ( { shards, destination} , crystalPromise ) ;
162
+ } else {
163
+ await crystalPromise ;
164
+ }
165
+ if ( shards !== None ) {
166
+ Core . info ( "[command]shards --version" ) ;
167
+ const { stdout} = await execFile ( "shards" , [ "--version" ] ) ;
168
+ Core . info ( stdout ) ;
169
+ }
170
+ }
171
+
172
+ async function installShards ( { shards, destination} , crystalPromise ) {
173
+ if ( NumericVersion . test ( shards ) ) {
174
+ shards = "v" + shards ;
175
+ }
176
+ const { ref, path} = await downloadSource ( {
177
+ name : "Shards" , apiBase : GitHubApiBaseShards , version : shards , destination,
178
+ } ) ;
179
+ Core . setOutput ( "shards" , ref ) ;
180
+ await crystalPromise ;
181
+
182
+ Core . info ( "Building Shards" ) ;
183
+ Core . info ( "[command]make" ) ;
184
+ const { stdout} = await execFile ( "make" , { cwd : path } ) ;
185
+ Core . startGroup ( "Finished building Shards" ) ;
186
+ Core . info ( stdout ) ;
187
+ Core . endGroup ( ) ;
188
+
189
+ Core . info ( "Setting up environment for Shards" ) ;
127
190
Core . addPath ( Path . join ( path , "bin" ) ) ;
128
191
}
129
192
130
193
const GitHubApiBase = "/repos/crystal-lang/crystal" ;
194
+ const GitHubApiBaseShards = "/repos/crystal-lang/shards" ;
131
195
const CircleApiBase = "https://circleci.com/api/v1.1/project/github/crystal-lang/crystal" ;
132
196
133
- async function downloadCrystalRelease ( suffix , tag = null , destination = null ) {
134
- Core . info ( "Looking for latest Crystal release" ) ;
135
-
197
+ async function findRelease ( { name, apiBase, tag} ) {
198
+ Core . info ( `Looking for latest ${ name } release` ) ;
136
199
const releasesResp = await githubGet ( {
137
- url : GitHubApiBase + "/releases/" + ( tag ? "tags/" + tag : "latest" ) ,
200
+ url : apiBase + "/releases/" + ( tag ? "tags/" + tag : "latest" ) ,
138
201
} ) ;
139
202
const release = releasesResp . data ;
140
- Core . info ( "Found " + release [ "html_url" ] ) ;
203
+ Core . info ( `Found ${ name } release ${ release [ "html_url" ] } ` ) ;
204
+ return release ;
205
+ }
206
+
207
+ async function findLatestCommit ( { name, apiBase, branch = "master" } ) {
208
+ Core . info ( `Looking for latest ${ name } commit` ) ;
209
+ const commitsResp = await githubGet ( {
210
+ url : apiBase + "/commits/" + branch ,
211
+ } ) ;
212
+ const commit = commitsResp . data ;
213
+ Core . info ( `Found ${ name } commit ${ commit [ "html_url" ] } ` ) ;
214
+ return commit [ "sha" ] ;
215
+ }
216
+
217
+ async function downloadCrystalRelease ( suffix , version = null , destination = null ) {
218
+ const release = await findRelease ( { name : "Crystal" , apiBase : GitHubApiBase , version} ) ;
141
219
Core . setOutput ( "crystal" , release [ "tag_name" ] ) ;
142
220
143
221
const asset = release [ "assets" ] . find ( ( a ) => a [ "name" ] . endsWith ( [ `-${ suffix } .tar.gz` ] ) ) ;
144
222
145
- Core . info ( " Downloading Crystal build" ) ;
223
+ Core . info ( ` Downloading Crystal build from ${ asset [ "browser_download_url" ] } ` ) ;
146
224
const downloadedPath = await ToolCache . downloadTool ( asset [ "browser_download_url" ] ) ;
147
225
148
226
Core . info ( "Extracting Crystal build" ) ;
149
227
return onlySubdir ( await ToolCache . extractTar ( downloadedPath , destination ) ) ;
150
228
}
151
229
230
+ async function downloadSource ( { name, apiBase, version = null , destination = null } ) {
231
+ let ref = version ;
232
+ if ( version === Nightly ) {
233
+ ref = await findLatestCommit ( { name, apiBase} ) ;
234
+ } else if ( version === Latest ) {
235
+ const release = await findRelease ( { name, apiBase} ) ;
236
+ ref = release [ "tag_name" ] ;
237
+ }
238
+
239
+ const zipballLinkResp = await githubGet ( {
240
+ url : apiBase + "/zipball/:ref" ,
241
+ "ref" : ref ,
242
+ request : { redirect : "manual" } ,
243
+ } ) ;
244
+ const downloadUrl = zipballLinkResp . headers [ "location" ] ;
245
+
246
+ Core . info ( `Downloading ${ name } source from ${ downloadUrl } ` ) ;
247
+ const downloadedPath = await ToolCache . downloadTool ( downloadUrl ) ;
248
+ Core . info ( `Extracting ${ name } source` ) ;
249
+ const path = await onlySubdir ( await ToolCache . extractZip ( downloadedPath , destination ) ) ;
250
+
251
+ return { ref, path} ;
252
+ }
253
+
152
254
async function downloadCrystalNightly ( suffix , destination = null ) {
153
255
Core . info ( "Looking for latest Crystal build" ) ;
154
256
@@ -166,18 +268,16 @@ async function downloadCrystalNightly(suffix, destination = null) {
166
268
throw "Could not find a matching nightly build" ;
167
269
}
168
270
}
169
- Core . info ( " Found " + build [ "build_url" ] ) ;
271
+ Core . info ( ` Found Crystal build ${ build [ "build_url" ] } ` ) ;
170
272
Core . setOutput ( "crystal" , build [ "vcs_revision" ] ) ;
171
273
172
274
const req = `/${ build [ "build_num" ] } /artifacts` ;
173
275
const resp = await fetch ( CircleApiBase + req ) ;
174
276
const artifacts = await resp . json ( ) ;
175
277
const artifact = artifacts . find ( ( a ) => a [ "path" ] . endsWith ( `-${ suffix } .tar.gz` ) ) ;
176
- Core . info ( "Found " + artifact [ "url" ] ) ;
177
278
178
- Core . info ( " Downloading Crystal build" ) ;
279
+ Core . info ( ` Downloading Crystal build from ${ artifact [ "url" ] } ` ) ;
179
280
const downloadedPath = await ToolCache . downloadTool ( artifact [ "url" ] ) ;
180
-
181
281
Core . info ( "Extracting Crystal build" ) ;
182
282
return onlySubdir ( await ToolCache . extractTar ( downloadedPath , destination ) ) ;
183
283
}
@@ -190,11 +290,8 @@ async function installCrystalForWindows({
190
290
checkVersion ( crystal , [ Nightly ] ) ;
191
291
checkArch ( arch , [ "x86_64" ] ) ;
192
292
const path = await downloadCrystalNightlyForWindows ( destination ) ;
193
- await setupCrystalForWindows ( path ) ;
194
- }
195
293
196
- async function setupCrystalForWindows ( path ) {
197
- Core . info ( "Setting up environment" ) ;
294
+ Core . info ( "Setting up environment for Crystal" ) ;
198
295
const vars = await variablesForVCBuildTools ( ) ;
199
296
addPathToVars ( vars , "PATH" , path ) ;
200
297
addPathToVars ( vars , "LIB" , path ) ;
@@ -253,25 +350,9 @@ async function downloadCrystalNightlyForWindows(destination = null) {
253
350
"per_page" : 1 ,
254
351
} ) ;
255
352
const [ workflowRun ] = runsResp . data [ "workflow_runs" ] ;
256
- const { "head_sha" : ref , "id" : runId } = workflowRun ;
257
- Core . info ( "Found " + workflowRun [ "html_url" ] ) ;
258
- Core . setOutput ( "crystal" , ref ) ;
259
-
260
- const fetchSrcTask = async ( destDir ) => {
261
- const zipballLinkResp = await githubGet ( {
262
- url : GitHubApiBase + "/zipball/:ref" ,
263
- "ref" : ref ,
264
- request : { redirect : "manual" } ,
265
- } ) ;
266
- const downloadUrl = zipballLinkResp . headers [ "location" ] ;
267
- Core . info ( "Found " + downloadUrl ) ;
268
-
269
- Core . info ( "Downloading Crystal source" ) ;
270
- const downloadedPath = await ToolCache . downloadTool ( downloadUrl ) ;
271
-
272
- Core . info ( "Extracting Crystal source" ) ;
273
- return onlySubdir ( await ToolCache . extractZip ( downloadedPath , destDir ) ) ;
274
- } ;
353
+ const { "head_sha" : version , "id" : runId } = workflowRun ;
354
+ Core . info ( `Found Crystal release ${ workflowRun [ "html_url" ] } ` ) ;
355
+ Core . setOutput ( "crystal" , version ) ;
275
356
276
357
const fetchExeTask = async ( ) => {
277
358
const artifactsResp = await githubGet ( {
@@ -291,8 +372,8 @@ async function downloadCrystalNightlyForWindows(destination = null) {
291
372
return ToolCache . downloadTool ( downloadUrl ) ;
292
373
} ;
293
374
294
- const [ srcPath , exeDownloadedPath ] = await Promise . all ( [
295
- fetchSrcTask ( destination ) ,
375
+ const [ { path : srcPath } , exeDownloadedPath ] = await Promise . all ( [
376
+ downloadSource ( { name : "Crystal" , apiBase : GitHubApiBase , version , destination} ) ,
296
377
fetchExeTask ( ) ,
297
378
] ) ;
298
379
0 commit comments