code-server/lib/vscode/extensions/vscode-test-resolver/src/download.ts

117 lines
4.1 KiB
TypeScript

/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as https from 'https';
import * as fs from 'fs';
import * as path from 'path';
import * as cp from 'child_process';
import { parse as parseUrl } from 'url';
function ensureFolderExists(loc: string) {
if (!fs.existsSync(loc)) {
const parent = path.dirname(loc);
if (parent) {
ensureFolderExists(parent);
}
fs.mkdirSync(loc);
}
}
function getDownloadUrl(updateUrl: string, commit: string, platform: string, quality: string): string {
return `${updateUrl}/commit:${commit}/server-${platform}/${quality}`;
}
async function downloadVSCodeServerArchive(updateUrl: string, commit: string, quality: string, destDir: string): Promise<string> {
ensureFolderExists(destDir);
const platform = process.platform === 'win32' ? 'win32-x64' : process.platform === 'darwin' ? 'darwin' : 'linux-x64';
const downloadUrl = getDownloadUrl(updateUrl, commit, platform, quality);
return new Promise((resolve, reject) => {
console.log(`Downloading VS Code Server from: ${downloadUrl}`);
const requestOptions: https.RequestOptions = parseUrl(downloadUrl);
https.get(requestOptions, res => {
if (res.statusCode !== 302) {
reject('Failed to get VS Code server archive location');
}
const archiveUrl = res.headers.location;
if (!archiveUrl) {
reject('Failed to get VS Code server archive location');
return;
}
const archiveRequestOptions: https.RequestOptions = parseUrl(archiveUrl);
if (archiveUrl.endsWith('.zip')) {
const archivePath = path.resolve(destDir, `vscode-server-${commit}.zip`);
const outStream = fs.createWriteStream(archivePath);
outStream.on('close', () => {
resolve(archivePath);
});
https.get(archiveRequestOptions, res => {
res.pipe(outStream);
});
} else {
const zipPath = path.resolve(destDir, `vscode-server-${commit}.tgz`);
const outStream = fs.createWriteStream(zipPath);
https.get(archiveRequestOptions, res => {
res.pipe(outStream);
});
outStream.on('close', () => {
resolve(zipPath);
});
}
});
});
}
/**
* Unzip a .zip or .tar.gz VS Code archive
*/
function unzipVSCodeServer(vscodeArchivePath: string, extractDir: string) {
if (vscodeArchivePath.endsWith('.zip')) {
const tempDir = fs.mkdtempSync('vscode-server');
if (process.platform === 'win32') {
cp.spawnSync('powershell.exe', [
'-NoProfile',
'-ExecutionPolicy', 'Bypass',
'-NonInteractive',
'-NoLogo',
'-Command',
`Microsoft.PowerShell.Archive\\Expand-Archive -Path "${vscodeArchivePath}" -DestinationPath "${tempDir}"`
]);
} else {
cp.spawnSync('unzip', [vscodeArchivePath, '-d', `${tempDir}`]);
}
fs.renameSync(path.join(tempDir, process.platform === 'win32' ? 'vscode-server-win32-x64' : 'vscode-server-darwin'), extractDir);
} else {
// tar does not create extractDir by default
if (!fs.existsSync(extractDir)) {
fs.mkdirSync(extractDir);
}
cp.spawnSync('tar', ['-xzf', vscodeArchivePath, '-C', extractDir, '--strip-components', '1']);
}
}
export async function downloadAndUnzipVSCodeServer(updateUrl: string, commit: string, quality: string = 'stable', destDir: string): Promise<string> {
const extractDir = path.join(destDir, commit);
if (fs.existsSync(extractDir)) {
console.log(`Found ${extractDir}. Skipping download.`);
} else {
console.log(`Downloading VS Code Server ${quality} - ${commit} into ${extractDir}.`);
try {
const vscodeArchivePath = await downloadVSCodeServerArchive(updateUrl, commit, quality, destDir);
if (fs.existsSync(vscodeArchivePath)) {
unzipVSCodeServer(vscodeArchivePath, extractDir);
// Remove archive
fs.unlinkSync(vscodeArchivePath);
}
} catch (err) {
throw Error(`Failed to download and unzip VS Code ${quality} - ${commit}`);
}
}
return Promise.resolve(extractDir);
}