@@ -20,13 +20,12 @@ import {
20
20
insidersDownloadDirMetadata ,
21
21
insidersDownloadDirToExecutablePath ,
22
22
isDefined ,
23
- isInsiderVersionIdentifier ,
24
- isStableVersionIdentifier ,
25
23
isSubdirectory ,
26
24
onceWithoutRejections ,
27
25
streamToBuffer ,
28
26
systemDefaultPlatform ,
29
27
validateStream ,
28
+ Version ,
30
29
} from './util' ;
31
30
32
31
const extensionRoot = process . cwd ( ) ;
@@ -36,7 +35,7 @@ const vscodeStableReleasesAPI = `https://update.code.visualstudio.com/api/releas
36
35
const vscodeInsiderReleasesAPI = `https://update.code.visualstudio.com/api/releases/insider` ;
37
36
38
37
const downloadDirNameFormat = / ^ v s c o d e - (?< platform > [ a - z ] + ) - (?< version > [ 0 - 9 . ] + ) $ / ;
39
- const makeDownloadDirName = ( platform : string , version : string ) => `vscode-${ platform } -${ version } ` ;
38
+ const makeDownloadDirName = ( platform : string , version : Version ) => `vscode-${ platform } -${ version . id } ` ;
40
39
41
40
const DOWNLOAD_ATTEMPTS = 3 ;
42
41
@@ -50,28 +49,28 @@ interface IFetchInferredOptions extends IFetchStableOptions {
50
49
extensionsDevelopmentPath ?: string | string [ ] ;
51
50
}
52
51
53
- export const fetchStableVersions = onceWithoutRejections ( ( timeout : number ) =>
54
- request . getJSON < string [ ] > ( vscodeStableReleasesAPI , timeout )
52
+ export const fetchStableVersions = onceWithoutRejections ( ( released : boolean , timeout : number ) =>
53
+ request . getJSON < string [ ] > ( ` ${ vscodeStableReleasesAPI } ?released= ${ released } ` , timeout )
55
54
) ;
56
- export const fetchInsiderVersions = onceWithoutRejections ( ( timeout : number ) =>
57
- request . getJSON < string [ ] > ( vscodeInsiderReleasesAPI , timeout )
55
+ export const fetchInsiderVersions = onceWithoutRejections ( ( released : boolean , timeout : number ) =>
56
+ request . getJSON < string [ ] > ( ` ${ vscodeInsiderReleasesAPI } ?released= ${ released } ` , timeout )
58
57
) ;
59
58
60
59
/**
61
60
* Returns the stable version to run tests against. Attempts to get the latest
62
61
* version from the update sverice, but falls back to local installs if
63
62
* not available (e.g. if the machine is offline).
64
63
*/
65
- async function fetchTargetStableVersion ( { timeout, cachePath, platform } : IFetchStableOptions ) : Promise < string > {
64
+ async function fetchTargetStableVersion ( { timeout, cachePath, platform } : IFetchStableOptions ) : Promise < Version > {
66
65
try {
67
- const versions = await fetchStableVersions ( timeout ) ;
68
- return versions [ 0 ] ;
66
+ const versions = await fetchStableVersions ( true , timeout ) ;
67
+ return new Version ( versions [ 0 ] ) ;
69
68
} catch ( e ) {
70
69
return fallbackToLocalEntries ( cachePath , platform , e as Error ) ;
71
70
}
72
71
}
73
72
74
- export async function fetchTargetInferredVersion ( options : IFetchInferredOptions ) {
73
+ export async function fetchTargetInferredVersion ( options : IFetchInferredOptions ) : Promise < Version > {
75
74
if ( ! options . extensionsDevelopmentPath ) {
76
75
return fetchTargetStableVersion ( options ) ;
77
76
}
@@ -87,22 +86,22 @@ export async function fetchTargetInferredVersion(options: IFetchInferredOptions)
87
86
const matches = ( v : string ) => ! extVersions . some ( ( range ) => ! semver . satisfies ( v , range , { includePrerelease : true } ) ) ;
88
87
89
88
try {
90
- const stable = await fetchStableVersions ( options . timeout ) ;
89
+ const stable = await fetchStableVersions ( true , options . timeout ) ;
91
90
const found1 = stable . find ( matches ) ;
92
91
if ( found1 ) {
93
- return found1 ;
92
+ return new Version ( found1 ) ;
94
93
}
95
94
96
- const insiders = await fetchInsiderVersions ( options . timeout ) ;
95
+ const insiders = await fetchInsiderVersions ( true , options . timeout ) ;
97
96
const found2 = insiders . find ( matches ) ;
98
97
if ( found2 ) {
99
- return found2 ;
98
+ return new Version ( found2 ) ;
100
99
}
101
100
102
101
const v = extVersions . join ( ', ' ) ;
103
102
console . warn ( `No version of VS Code satisfies all extension engine constraints (${ v } ). Falling back to stable.` ) ;
104
103
105
- return stable [ 0 ] ; // 🤷
104
+ return new Version ( stable [ 0 ] ) ; // 🤷
106
105
} catch ( e ) {
107
106
return fallbackToLocalEntries ( options . cachePath , options . platform , e as Error ) ;
108
107
}
@@ -129,35 +128,31 @@ async function fallbackToLocalEntries(cachePath: string, platform: string, fromE
129
128
130
129
if ( fallbackTo ) {
131
130
console . warn ( `Error retrieving VS Code versions, using already-installed version ${ fallbackTo } ` , fromError ) ;
132
- return fallbackTo ;
131
+ return new Version ( fallbackTo ) ;
133
132
}
134
133
135
134
throw fromError ;
136
135
}
137
136
138
- async function isValidVersion ( version : string , platform : string , timeout : number ) {
139
- if ( version === 'insiders' || version === 'stable' ) {
137
+ async function isValidVersion ( version : Version , timeout : number ) {
138
+ if ( version . id === 'insiders' || version . id === 'stable' || version . isCommit ) {
140
139
return true ;
141
140
}
142
141
143
- if ( isStableVersionIdentifier ( version ) ) {
144
- const stableVersionNumbers = await fetchStableVersions ( timeout ) ;
145
- if ( stableVersionNumbers . includes ( version ) ) {
142
+ if ( version . isStable ) {
143
+ const stableVersionNumbers = await fetchStableVersions ( version . isReleased , timeout ) ;
144
+ if ( stableVersionNumbers . includes ( version . id ) ) {
146
145
return true ;
147
146
}
148
147
}
149
148
150
- if ( isInsiderVersionIdentifier ( version ) ) {
151
- const insiderVersionNumbers = await fetchInsiderVersions ( timeout ) ;
152
- if ( insiderVersionNumbers . includes ( version ) ) {
149
+ if ( version . isInsiders ) {
150
+ const insiderVersionNumbers = await fetchInsiderVersions ( version . isReleased , timeout ) ;
151
+ if ( insiderVersionNumbers . includes ( version . id ) ) {
153
152
return true ;
154
153
}
155
154
}
156
155
157
- if ( / ^ [ 0 - 9 a - f ] { 40 } $ / . test ( version ) ) {
158
- return true ;
159
- }
160
-
161
156
return false ;
162
157
}
163
158
@@ -267,7 +262,8 @@ async function downloadVSCodeArchive(options: DownloadOptions): Promise<IDownloa
267
262
}
268
263
269
264
const timeout = options . timeout ! ;
270
- const downloadUrl = getVSCodeDownloadUrl ( options . version , options . platform ) ;
265
+ const version = Version . parse ( options . version ) ;
266
+ const downloadUrl = getVSCodeDownloadUrl ( version , options . platform ) ;
271
267
272
268
options . reporter ?. report ( { stage : ProgressReportStage . ResolvingCDNLocation , url : downloadUrl } ) ;
273
269
const res = await request . getStream ( downloadUrl , timeout ) ;
@@ -429,25 +425,27 @@ const COMPLETE_FILE_NAME = 'is-complete';
429
425
* @returns Promise of `vscodeExecutablePath`.
430
426
*/
431
427
export async function download ( options : Partial < DownloadOptions > = { } ) : Promise < string > {
432
- let version = options ?. version ;
428
+ const inputVersion = options ?. version ? Version . parse ( options . version ) : undefined ;
433
429
const {
434
430
platform = systemDefaultPlatform ,
435
431
cachePath = defaultCachePath ,
436
432
reporter = new ConsoleReporter ( process . stdout . isTTY ) ,
437
433
timeout = 15_000 ,
438
434
} = options ;
439
435
440
- if ( version === 'stable' ) {
436
+ let version : Version ;
437
+ if ( inputVersion ?. id === 'stable' ) {
441
438
version = await fetchTargetStableVersion ( { timeout, cachePath, platform } ) ;
442
- } else if ( version ) {
439
+ } else if ( inputVersion ) {
443
440
/**
444
441
* Only validate version against server when no local download that matches version exists
445
442
*/
446
- if ( ! fs . existsSync ( path . resolve ( cachePath , `vscode- ${ platform } - ${ version } ` ) ) ) {
447
- if ( ! ( await isValidVersion ( version , platform , timeout ) ) ) {
448
- throw Error ( `Invalid version ${ version } ` ) ;
443
+ if ( ! fs . existsSync ( path . resolve ( cachePath , makeDownloadDirName ( platform , inputVersion ) ) ) ) {
444
+ if ( ! ( await isValidVersion ( inputVersion , timeout ) ) ) {
445
+ throw Error ( `Invalid version ${ inputVersion . id } ` ) ;
449
446
}
450
447
}
448
+ version = inputVersion ;
451
449
} else {
452
450
version = await fetchTargetInferredVersion ( {
453
451
timeout,
@@ -457,22 +455,22 @@ export async function download(options: Partial<DownloadOptions> = {}): Promise<
457
455
} ) ;
458
456
}
459
457
460
- if ( platform === 'win32-archive' && semver . satisfies ( version , '>= 1.85.0' , { includePrerelease : true } ) ) {
458
+ if ( platform === 'win32-archive' && semver . satisfies ( version . id , '>= 1.85.0' , { includePrerelease : true } ) ) {
461
459
throw new Error ( 'Windows 32-bit is no longer supported from v1.85 onwards' ) ;
462
460
}
463
461
464
- reporter . report ( { stage : ProgressReportStage . ResolvedVersion , version } ) ;
462
+ reporter . report ( { stage : ProgressReportStage . ResolvedVersion , version : version . id } ) ;
465
463
466
464
const downloadedPath = path . resolve ( cachePath , makeDownloadDirName ( platform , version ) ) ;
467
465
if ( fs . existsSync ( path . join ( downloadedPath , COMPLETE_FILE_NAME ) ) ) {
468
- if ( isInsiderVersionIdentifier ( version ) ) {
466
+ if ( version . isInsiders ) {
469
467
reporter . report ( { stage : ProgressReportStage . FetchingInsidersMetadata } ) ;
470
468
const { version : currentHash , date : currentDate } = insidersDownloadDirMetadata ( downloadedPath , platform ) ;
471
469
472
470
const { version : latestHash , timestamp : latestTimestamp } =
473
- version === 'insiders'
474
- ? await getLatestInsidersMetadata ( systemDefaultPlatform )
475
- : await getInsidersVersionMetadata ( systemDefaultPlatform , version ) ;
471
+ version . id === 'insiders' // not qualified with a date
472
+ ? await getLatestInsidersMetadata ( systemDefaultPlatform , version . isReleased )
473
+ : await getInsidersVersionMetadata ( systemDefaultPlatform , version . id , version . isReleased ) ;
476
474
477
475
if ( currentHash === latestHash ) {
478
476
reporter . report ( { stage : ProgressReportStage . FoundMatchingInstall , downloadedPath } ) ;
@@ -493,7 +491,7 @@ export async function download(options: Partial<DownloadOptions> = {}): Promise<
493
491
throw Error ( `Failed to remove outdated Insiders at ${ downloadedPath } .` ) ;
494
492
}
495
493
}
496
- } else if ( isStableVersionIdentifier ( version ) ) {
494
+ } else if ( version . isStable ) {
497
495
reporter . report ( { stage : ProgressReportStage . FoundMatchingInstall , downloadedPath } ) ;
498
496
return Promise . resolve ( downloadDirToExecutablePath ( downloadedPath , platform ) ) ;
499
497
} else {
@@ -507,7 +505,7 @@ export async function download(options: Partial<DownloadOptions> = {}): Promise<
507
505
await fs . promises . rm ( downloadedPath , { recursive : true , force : true } ) ;
508
506
509
507
const download = await downloadVSCodeArchive ( {
510
- version,
508
+ version : version . toString ( ) ,
511
509
platform,
512
510
cachePath,
513
511
reporter,
@@ -536,7 +534,7 @@ export async function download(options: Partial<DownloadOptions> = {}): Promise<
536
534
}
537
535
reporter . report ( { stage : ProgressReportStage . NewInstallComplete , downloadedPath } ) ;
538
536
539
- if ( isStableVersionIdentifier ( version ) ) {
537
+ if ( version . isStable ) {
540
538
return downloadDirToExecutablePath ( downloadedPath , platform ) ;
541
539
} else {
542
540
return insidersDownloadDirToExecutablePath ( downloadedPath , platform ) ;
0 commit comments