Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/extensions/copilot/script/build/downloadBinary.ts
13389 views
1
/*---------------------------------------------------------------------------------------------
2
* Copyright (c) Microsoft Corporation. All rights reserved.
3
* Licensed under the MIT License. See License.txt in the project root for license information.
4
*--------------------------------------------------------------------------------------------*/
5
import * as crypto from 'crypto';
6
import * as fs from 'fs';
7
import * as https from 'https';
8
import * as path from 'path';
9
import * as tar from 'tar';
10
import * as zlib from 'zlib';
11
12
const REPO_ROOT = path.join(__dirname, '..', '..');
13
14
export interface IBinary {
15
url: string;
16
sha256: string;
17
destination: string;
18
}
19
20
export async function ensureBinary(binary: IBinary) {
21
const binaryPath = path.join(REPO_ROOT, binary.destination);
22
if (fs.existsSync(binaryPath)) {
23
const sha256 = await computeSha256(binaryPath);
24
if (sha256 === binary.sha256) {
25
console.log(`Binary ${binary.destination} already exists and matches expected checksum.`);
26
return;
27
}
28
console.log(`Binary ${binary.destination} already exists but does not match expected checksum. \n - Expected: ${binary.sha256}\n - Actual: ${sha256}\nRe-downloading...`);
29
}
30
31
console.log(`Downloading binary ${binary.destination}...`);
32
await fs.promises.mkdir(path.dirname(binaryPath), { recursive: true });
33
const tempPath = path.join(path.dirname(binaryPath), crypto.randomUUID() + '.tgz');
34
try {
35
await downloadFile(binary.url, tempPath);
36
await untar(tempPath, path.dirname(binaryPath), /*strip*/2);
37
const sha256 = await computeSha256(binaryPath);
38
if (sha256 !== binary.sha256) {
39
throw new Error(`Downloaded binary ${binary.destination} does not match expected checksum. Expected: ${binary.sha256}, actual: ${sha256}.`);
40
}
41
} finally {
42
await fs.promises.unlink(tempPath);
43
}
44
}
45
46
export function computeSha256(filePath: string): Promise<string> {
47
return new Promise((resolve, reject) => {
48
const hash = crypto.createHash('sha256');
49
const stream = fs.createReadStream(filePath);
50
stream.on('error', reject);
51
stream.on('data', (chunk) => hash.update(chunk));
52
stream.on('end', () => resolve(hash.digest('hex')));
53
});
54
}
55
56
export function downloadFile(url: string, tempPath: string, headers?: Record<string, string>): Promise<void> {
57
return new Promise((resolve, reject) => {
58
https.get(url, { headers }, (response) => {
59
if (response.headers.location) {
60
console.log(`Following redirect to ${response.headers.location}`);
61
return downloadFile(response.headers.location, tempPath).then(resolve, reject);
62
}
63
64
if (response.statusCode === 404) {
65
return reject(new Error(`File not found: ${url}`));
66
}
67
68
const file = fs.createWriteStream(tempPath);
69
response.pipe(file);
70
file.on('finish', () => {
71
file.close();
72
resolve();
73
});
74
75
}).on('error', (err) => {
76
fs.unlink(tempPath, () => reject(err));
77
});
78
});
79
}
80
81
export function get(url: string, opts: https.RequestOptions): Promise<string> {
82
return new Promise((resolve, reject) => {
83
let result = '';
84
https.get(url, opts, response => {
85
if (response.headers.location) {
86
console.log(`Following redirect to ${response.headers.location}`);
87
get(response.headers.location, opts).then(resolve, reject);
88
}
89
90
if (response.statusCode !== 200) {
91
reject(new Error('Request failed: ' + response.statusCode));
92
}
93
94
response.on('data', d => {
95
result += d.toString();
96
});
97
98
response.on('end', () => {
99
resolve(result);
100
});
101
102
response.on('error', e => {
103
reject(e);
104
});
105
});
106
});
107
}
108
109
export function untar(filePath: string, destination: string, strip?: number): Promise<void> {
110
return new Promise((resolve, reject) => {
111
const readStream = fs.createReadStream(filePath);
112
const writeStream = zlib.createGunzip();
113
const extractStream = tar.extract({
114
cwd: destination,
115
strip,
116
strict: true,
117
onentry: (entry: any) => {
118
console.log(`Extracting ${entry.path}`);
119
}
120
});
121
122
readStream.on('error', reject);
123
writeStream.on('error', reject);
124
extractStream.on('error', reject);
125
126
extractStream.on('end', () => {
127
resolve();
128
});
129
130
readStream.pipe(writeStream).pipe(extractStream);
131
});
132
}
133
134