Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/extensions/copilot/test/simulation/fixtures/generate/issue-7772/builds.ts
13405 views
1
/*---------------------------------------------------------------------------------------------
2
* Copyright (c) Microsoft Corporation. All rights reserved.
3
* Licensed under the MIT License. See LICENSE in the project root for license information.
4
*--------------------------------------------------------------------------------------------*/
5
6
import chalk from 'chalk';
7
import { rmSync } from 'fs';
8
import { dirname, join } from 'path';
9
import { LOGGER, Platform, platform, Runtime } from './constants';
10
import { fileGet, jsonGet } from './fetch';
11
import { exists, getBuildPath, unzip } from './files';
12
13
export interface IBuild {
14
readonly runtime: Runtime;
15
readonly commit: string;
16
}
17
18
interface IBuildMetadata {
19
readonly url: string;
20
readonly productVersion: string;
21
readonly sha256hash: string;
22
}
23
24
class Builds {
25
26
async fetchBuilds(runtime = Runtime.WebLocal, goodCommit?: string, badCommit?: string, releasedOnly?: boolean): Promise<IBuild[]> {
27
28
// Fetch all released insider builds
29
const allBuilds = await this.fetchAllBuilds(runtime, releasedOnly);
30
31
let goodCommitIndex = allBuilds.length - 1; // last build (oldest) by default
32
let badCommitIndex = 0; // first build (newest) by default
33
34
if (typeof goodCommit === 'string') {
35
const candidateGoodCommitIndex = this.indexOf(goodCommit, allBuilds);
36
if (typeof candidateGoodCommitIndex !== 'number') {
37
throw new Error(`Provided good commit ${chalk.green(goodCommit)} was not found in the list of insiders builds. Try running with ${chalk.green('--releasedOnly')} to support older builds.`);
38
}
39
40
goodCommitIndex = candidateGoodCommitIndex;
41
}
42
43
if (typeof badCommit === 'string') {
44
const candidateBadCommitIndex = this.indexOf(badCommit, allBuilds);
45
if (typeof candidateBadCommitIndex !== 'number') {
46
throw new Error(`Provided bad commit ${chalk.green(badCommit)} was not found in the list of insiders builds. Try running with ${chalk.green('--releasedOnly')} to support older builds.`);
47
}
48
49
badCommitIndex = candidateBadCommitIndex;
50
}
51
52
if (badCommitIndex >= goodCommitIndex) {
53
throw new Error(`Provided bad commit ${chalk.green(badCommit)} cannot be older or same as good commit ${chalk.green(goodCommit)}.`);
54
}
55
56
// Build a range based on the bad and good commits if any
57
const buildsInRange = allBuilds.slice(badCommitIndex, goodCommitIndex + 1);
58
59
// Drop those builds that are not on main branch
60
return buildsInRange;
61
}
62
63
private indexOf(commit: string, builds: IBuild[]): number | undefined {
64
for (let i = 0; i < builds.length; i++) {
65
const build = builds[i];
66
if (build.commit === commit) {
67
return i;
68
}
69
}
70
71
return undefined;
72
}
73
74
private async fetchAllBuilds(runtime: Runtime, releasedOnly = false): Promise<IBuild[]> {
75
const url = `https://update.code.visualstudio.com/api/commits/insider/${this.getBuildApiName(runtime)}?released=${releasedOnly}`;
76
console.log(`${chalk.gray('[build]')} fetching all builds from ${chalk.green(url)}...`);
77
const commits = await jsonGet<Array<string>>(url);
78
79
return commits.map(commit => ({ commit, runtime }));
80
}
81
82
private getBuildApiName(runtime: Runtime): string {
83
switch (runtime) {
84
case Runtime.WebLocal:
85
case Runtime.WebRemote:
86
switch (platform) {
87
case Platform.MacOSX64:
88
case Platform.MacOSArm:
89
return 'server-darwin-web';
90
case Platform.LinuxX64:
91
case Platform.LinuxArm:
92
return 'server-linux-x64-web';
93
case Platform.WindowsX64:
94
case Platform.WindowsArm:
95
return 'server-win32-x64-web';
96
}
97
98
case Runtime.DesktopLocal:
99
switch (platform) {
100
case Platform.MacOSX64:
101
return 'darwin';
102
case Platform.MacOSArm:
103
return 'darwin-arm64';
104
case Platform.LinuxX64:
105
return 'linux-x64';
106
case Platform.LinuxArm:
107
return 'linux-arm64';
108
case Platform.WindowsX64:
109
return 'win32-x64';
110
case Platform.WindowsArm:
111
return 'win32-arm64';
112
}
113
}
114
}
115
116
async installBuild({ runtime, commit }: IBuild, options?: { forceReDownload: boolean }): Promise<void> {
117
const buildName = await this.getBuildArchiveName({ runtime, commit });
118
119
const path = join(getBuildPath(commit), buildName);
120
121
const pathExists = await exists(path);
122
if (pathExists && !options?.forceReDownload) {
123
if (LOGGER.verbose) {
124
console.log(`${chalk.gray('[build]')} using ${chalk.green(path)} for the next build to try`);
125
}
126
127
return; // assume the build is cached
128
}
129
130
if (pathExists && options?.forceReDownload) {
131
console.log(`${chalk.gray('[build]')} deleting ${chalk.green(getBuildPath(commit))} and retrying download`);
132
rmSync(getBuildPath(commit), { recursive: true });
133
}
134
135
// Download
136
const url = `https://update.code.visualstudio.com/commit:${commit}/${this.getPlatformName(runtime)}/insider`;
137
console.log(`${chalk.gray('[build]')} downloading build from ${chalk.green(url)}...`);
138
await fileGet(url, path);
139
140
const sha256 = (await this.fetchBuildMeta({ runtime, commit })).sha256hash;
141
console.log(`${chalk.gray('[build]')} validating build sha256 hash...`);
142
143
144
// Unzip
145
let destination: string;
146
if (runtime === Runtime.DesktopLocal && platform === Platform.WindowsX64 || platform === Platform.WindowsArm) {
147
// zip does not contain a single top level folder to use...
148
destination = path.substring(0, path.lastIndexOf('.zip'));
149
} else {
150
// zip contains a single top level folder to use
151
destination = dirname(path);
152
}
153
console.log(`${chalk.gray('[build]')} unzipping build to ${chalk.green(destination)}...`);
154
await unzip(path, destination);
155
}
156
157
private async getBuildArchiveName({ runtime, commit }: IBuild): Promise<string> {
158
switch (runtime) {
159
160
// We currently do not have ARM enabled servers
161
// so we fallback to x64 until we ship ARM.
162
case Runtime.WebLocal:
163
case Runtime.WebRemote:
164
switch (platform) {
165
case Platform.MacOSX64:
166
return 'vscode-server-darwin-x64-web.zip';
167
case Platform.MacOSArm:
168
return 'vscode-server-darwin-arm64-web.zip';
169
case Platform.LinuxX64:
170
return 'vscode-server-linux-arm64-web.tar.gz';
171
case Platform.LinuxArm:
172
return 'vscode-server-linux-x64-web.tar.gz';
173
case Platform.WindowsX64:
174
case Platform.WindowsArm:
175
return 'vscode-server-win32-x64-web.zip';
176
}
177
178
// Every platform has its own name scheme, hilarious right?
179
// - macOS: just the name, nice! (e.g. VSCode-darwin.zip)
180
// - Linux: includes some unix timestamp (e.g. code-insider-x64-1639979337.tar.gz)
181
// - Windows: includes the version (e.g. VSCode-win32-x64-1.64.0-insider.zip)
182
case Runtime.DesktopLocal:
183
switch (platform) {
184
case Platform.MacOSX64:
185
return 'VSCode-darwin.zip';
186
case Platform.MacOSArm:
187
return 'VSCode-darwin-arm64.zip';
188
case Platform.LinuxX64:
189
case Platform.LinuxArm:
190
return (await this.fetchBuildMeta({ runtime, commit })).url.split('/').pop()!; // e.g. https://az764295.vo.msecnd.net/insider/807bf598bea406dcb272a9fced54697986e87768/code-insider-x64-1639979337.tar.gz
191
case Platform.WindowsX64:
192
case Platform.WindowsArm: {
193
const buildMeta = await this.fetchBuildMeta({ runtime, commit });
194
195
return platform === Platform.WindowsX64 ? `VSCode-win32-x64-${buildMeta.productVersion}.zip` : `VSCode-win32-arm64-${buildMeta.productVersion}.zip`;
196
}
197
}
198
}
199
}
200
201
async getBuildName({ runtime, commit }: IBuild): Promise<string> {
202
switch (runtime) {
203
case Runtime.WebLocal:
204
case Runtime.WebRemote:
205
switch (platform) {
206
case Platform.MacOSX64:
207
return 'vscode-server-darwin-x64-web';
208
case Platform.MacOSArm:
209
return 'vscode-server-darwin-arm64-web';
210
case Platform.LinuxX64:
211
return 'vscode-server-linux-arm64-web';
212
case Platform.LinuxArm:
213
return 'vscode-server-linux-x64-web';
214
case Platform.WindowsX64:
215
case Platform.WindowsArm:
216
return 'vscode-server-win32-x64-web';
217
}
218
219
// Here, only Windows does not play by our rules and adds the version number
220
// - Windows: includes the version (e.g. VSCode-win32-x64-1.64.0-insider)
221
case Runtime.DesktopLocal:
222
switch (platform) {
223
case Platform.MacOSX64:
224
case Platform.MacOSArm:
225
return 'Visual Studio Code - Insiders.app';
226
case Platform.LinuxX64:
227
return 'VSCode-linux-x64';
228
case Platform.LinuxArm:
229
return 'VSCode-linux-arm64';
230
case Platform.WindowsX64:
231
case Platform.WindowsArm: {
232
const buildMeta = await this.fetchBuildMeta({ runtime, commit });
233
234
return platform === Platform.WindowsX64 ? `VSCode-win32-x64-${buildMeta.productVersion}` : `VSCode-win32-arm64-${buildMeta.productVersion}`;
235
}
236
}
237
}
238
}
239
240
private getPlatformName(runtime: Runtime): string {
241
switch (runtime) {
242
case Runtime.WebLocal:
243
case Runtime.WebRemote:
244
switch (platform) {
245
case Platform.MacOSX64:
246
return 'server-darwin-web';
247
case Platform.MacOSArm:
248
return 'server-darwin-arm64-web';
249
case Platform.LinuxX64:
250
return 'server-linux-x64-web';
251
case Platform.LinuxArm:
252
return 'server-linux-arm64-web';
253
case Platform.WindowsX64:
254
case Platform.WindowsArm:
255
return 'server-win32-x64-web';
256
}
257
258
case Runtime.DesktopLocal:
259
switch (platform) {
260
case Platform.MacOSX64:
261
return 'darwin';
262
case Platform.MacOSArm:
263
return 'darwin-arm64';
264
case Platform.LinuxX64:
265
return 'linux-x64';
266
case Platform.LinuxArm:
267
return 'linux-arm64';
268
case Platform.WindowsX64:
269
return 'win32-x64-archive';
270
case Platform.WindowsArm: {
271
return 'win32-arm64-archive';
272
}
273
}
274
}
275
}
276
277
private fetchBuildMeta({ runtime, commit }: IBuild): Promise<IBuildMetadata> {
278
return jsonGet<IBuildMetadata>(`https://update.code.visualstudio.com/api/versions/commit:${commit}/${this.getBuildApiName(runtime)}/insider`);
279
}
280
281
async getBuildExecutable({ runtime, commit }: IBuild): Promise<string> {
282
const buildPath = getBuildPath(commit);
283
const buildName = await builds.getBuildName({ runtime, commit });
284
285
switch (runtime) {
286
case Runtime.WebLocal:
287
case Runtime.WebRemote:
288
switch (platform) {
289
case Platform.MacOSX64:
290
case Platform.MacOSArm:
291
case Platform.LinuxX64:
292
case Platform.LinuxArm: {
293
const oldLocation = join(buildPath, buildName, 'server.sh');
294
if (await exists(oldLocation)) {
295
return oldLocation; // only valid until 1.64.x
296
}
297
298
return join(buildPath, buildName, 'bin', 'code-server-insiders');
299
}
300
case Platform.WindowsX64:
301
case Platform.WindowsArm: {
302
const oldLocation = join(buildPath, buildName, 'server.cmd');
303
if (await exists(oldLocation)) {
304
return oldLocation; // only valid until 1.64.x
305
}
306
307
return join(buildPath, buildName, 'bin', 'code-server-insiders.cmd');
308
}
309
}
310
311
case Runtime.DesktopLocal:
312
switch (platform) {
313
case Platform.MacOSX64:
314
case Platform.MacOSArm:
315
return join(buildPath, buildName, 'Contents', 'MacOS', 'Electron')
316
case Platform.LinuxX64:
317
case Platform.LinuxArm:
318
return join(buildPath, buildName, 'code-insiders')
319
case Platform.WindowsX64:
320
case Platform.WindowsArm:
321
return join(buildPath, buildName, 'Code - Insiders.exe')
322
}
323
}
324
}
325
}
326
327
export const builds = new Builds();
328
329