update vscode
This commit is contained in:
387
vscodeEvalExtension/node_modules/@vscode/test-electron/out/download.js
generated
vendored
Normal file
387
vscodeEvalExtension/node_modules/@vscode/test-electron/out/download.js
generated
vendored
Normal file
@@ -0,0 +1,387 @@
|
||||
"use strict";
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.downloadAndUnzipVSCode = exports.download = exports.defaultCachePath = exports.fetchTargetInferredVersion = exports.fetchInsiderVersions = exports.fetchStableVersions = void 0;
|
||||
const cp = require("child_process");
|
||||
const fs = require("fs");
|
||||
const os_1 = require("os");
|
||||
const path = require("path");
|
||||
const semver = require("semver");
|
||||
const stream_1 = require("stream");
|
||||
const util_1 = require("util");
|
||||
const progress_1 = require("./progress");
|
||||
const request = require("./request");
|
||||
const util_2 = require("./util");
|
||||
const extensionRoot = process.cwd();
|
||||
const pipelineAsync = util_1.promisify(stream_1.pipeline);
|
||||
const vscodeStableReleasesAPI = `https://update.code.visualstudio.com/api/releases/stable`;
|
||||
const vscodeInsiderReleasesAPI = `https://update.code.visualstudio.com/api/releases/insider`;
|
||||
const downloadDirNameFormat = /^vscode-(?<platform>[a-z]+)-(?<version>[0-9.]+)$/;
|
||||
const makeDownloadDirName = (platform, version) => `vscode-${platform}-${version}`;
|
||||
const DOWNLOAD_ATTEMPTS = 3;
|
||||
exports.fetchStableVersions = util_2.onceWithoutRejections((timeout) => request.getJSON(vscodeStableReleasesAPI, timeout));
|
||||
exports.fetchInsiderVersions = util_2.onceWithoutRejections((timeout) => request.getJSON(vscodeInsiderReleasesAPI, timeout));
|
||||
/**
|
||||
* Returns the stable version to run tests against. Attempts to get the latest
|
||||
* version from the update sverice, but falls back to local installs if
|
||||
* not available (e.g. if the machine is offline).
|
||||
*/
|
||||
async function fetchTargetStableVersion({ timeout, cachePath, platform }) {
|
||||
try {
|
||||
const versions = await exports.fetchStableVersions(timeout);
|
||||
return versions[0];
|
||||
}
|
||||
catch (e) {
|
||||
return fallbackToLocalEntries(cachePath, platform, e);
|
||||
}
|
||||
}
|
||||
async function fetchTargetInferredVersion(options) {
|
||||
if (!options.extensionsDevelopmentPath) {
|
||||
return fetchTargetStableVersion(options);
|
||||
}
|
||||
// load all engines versions from all development paths. Then, get the latest
|
||||
// stable version (or, latest Insiders version) that satisfies all
|
||||
// `engines.vscode` constraints.
|
||||
const extPaths = Array.isArray(options.extensionsDevelopmentPath)
|
||||
? options.extensionsDevelopmentPath
|
||||
: [options.extensionsDevelopmentPath];
|
||||
const maybeExtVersions = await Promise.all(extPaths.map(getEngineVersionFromExtension));
|
||||
const extVersions = maybeExtVersions.filter(util_2.isDefined);
|
||||
const matches = (v) => !extVersions.some((range) => !semver.satisfies(v, range, { includePrerelease: true }));
|
||||
try {
|
||||
const stable = await exports.fetchStableVersions(options.timeout);
|
||||
const found1 = stable.find(matches);
|
||||
if (found1) {
|
||||
return found1;
|
||||
}
|
||||
const insiders = await exports.fetchInsiderVersions(options.timeout);
|
||||
const found2 = insiders.find(matches);
|
||||
if (found2) {
|
||||
return found2;
|
||||
}
|
||||
const v = extVersions.join(', ');
|
||||
console.warn(`No version of VS Code satisfies all extension engine constraints (${v}). Falling back to stable.`);
|
||||
return stable[0]; // 🤷
|
||||
}
|
||||
catch (e) {
|
||||
return fallbackToLocalEntries(options.cachePath, options.platform, e);
|
||||
}
|
||||
}
|
||||
exports.fetchTargetInferredVersion = fetchTargetInferredVersion;
|
||||
async function getEngineVersionFromExtension(extensionPath) {
|
||||
var _a;
|
||||
try {
|
||||
const packageContents = await fs.promises.readFile(path.join(extensionPath, 'package.json'), 'utf8');
|
||||
const packageJson = JSON.parse(packageContents);
|
||||
return (_a = packageJson === null || packageJson === void 0 ? void 0 : packageJson.engines) === null || _a === void 0 ? void 0 : _a.vscode;
|
||||
}
|
||||
catch {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
async function fallbackToLocalEntries(cachePath, platform, fromError) {
|
||||
const entries = await fs.promises.readdir(cachePath).catch(() => []);
|
||||
const [fallbackTo] = entries
|
||||
.map((e) => downloadDirNameFormat.exec(e))
|
||||
.filter(util_2.isDefined)
|
||||
.filter((e) => e.groups.platform === platform)
|
||||
.map((e) => e.groups.version)
|
||||
.sort((a, b) => Number(b) - Number(a));
|
||||
if (fallbackTo) {
|
||||
console.warn(`Error retrieving VS Code versions, using already-installed version ${fallbackTo}`, fromError);
|
||||
return fallbackTo;
|
||||
}
|
||||
throw fromError;
|
||||
}
|
||||
async function isValidVersion(version, platform, timeout) {
|
||||
if (version === 'insiders' || version === 'stable') {
|
||||
return true;
|
||||
}
|
||||
if (util_2.isStableVersionIdentifier(version)) {
|
||||
const stableVersionNumbers = await exports.fetchStableVersions(timeout);
|
||||
if (stableVersionNumbers.includes(version)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (util_2.isInsiderVersionIdentifier(version)) {
|
||||
const insiderVersionNumbers = await exports.fetchInsiderVersions(timeout);
|
||||
if (insiderVersionNumbers.includes(version)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (/^[0-9a-f]{40}$/.test(version)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
function getFilename(contentDisposition) {
|
||||
const parts = contentDisposition.split(';').map((s) => s.trim());
|
||||
for (const part of parts) {
|
||||
const match = /^filename="?([^"]*)"?$/i.exec(part);
|
||||
if (match) {
|
||||
return match[1];
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
/**
|
||||
* Download a copy of VS Code archive to `.vscode-test`.
|
||||
*
|
||||
* @param version The version of VS Code to download such as '1.32.0'. You can also use
|
||||
* `'stable'` for downloading latest stable release.
|
||||
* `'insiders'` for downloading latest Insiders.
|
||||
*/
|
||||
async function downloadVSCodeArchive(options) {
|
||||
var _a, _b, _c;
|
||||
if (!fs.existsSync(options.cachePath)) {
|
||||
fs.mkdirSync(options.cachePath);
|
||||
}
|
||||
const timeout = options.timeout;
|
||||
const downloadUrl = util_2.getVSCodeDownloadUrl(options.version, options.platform);
|
||||
(_a = options.reporter) === null || _a === void 0 ? void 0 : _a.report({ stage: progress_1.ProgressReportStage.ResolvingCDNLocation, url: downloadUrl });
|
||||
const res = await request.getStream(downloadUrl, timeout);
|
||||
if (res.statusCode !== 302) {
|
||||
throw 'Failed to get VS Code archive location';
|
||||
}
|
||||
const url = res.headers.location;
|
||||
if (!url) {
|
||||
throw 'Failed to get VS Code archive location';
|
||||
}
|
||||
const contentSHA256 = res.headers['x-sha256'];
|
||||
res.destroy();
|
||||
const download = await request.getStream(url, timeout);
|
||||
const totalBytes = Number(download.headers['content-length']);
|
||||
const contentDisposition = download.headers['content-disposition'];
|
||||
const fileName = contentDisposition ? getFilename(contentDisposition) : undefined;
|
||||
const isZip = (_b = fileName === null || fileName === void 0 ? void 0 : fileName.endsWith('zip')) !== null && _b !== void 0 ? _b : url.endsWith('.zip');
|
||||
const timeoutCtrl = new request.TimeoutController(timeout);
|
||||
(_c = options.reporter) === null || _c === void 0 ? void 0 : _c.report({
|
||||
stage: progress_1.ProgressReportStage.Downloading,
|
||||
url,
|
||||
bytesSoFar: 0,
|
||||
totalBytes,
|
||||
});
|
||||
let bytesSoFar = 0;
|
||||
download.on('data', (chunk) => {
|
||||
var _a;
|
||||
bytesSoFar += chunk.length;
|
||||
timeoutCtrl.touch();
|
||||
(_a = options.reporter) === null || _a === void 0 ? void 0 : _a.report({
|
||||
stage: progress_1.ProgressReportStage.Downloading,
|
||||
url,
|
||||
bytesSoFar,
|
||||
totalBytes,
|
||||
});
|
||||
});
|
||||
download.on('end', () => {
|
||||
var _a;
|
||||
timeoutCtrl.dispose();
|
||||
(_a = options.reporter) === null || _a === void 0 ? void 0 : _a.report({
|
||||
stage: progress_1.ProgressReportStage.Downloading,
|
||||
url,
|
||||
bytesSoFar: totalBytes,
|
||||
totalBytes,
|
||||
});
|
||||
});
|
||||
timeoutCtrl.signal.addEventListener('abort', () => {
|
||||
download.emit('error', new request.TimeoutError(timeout));
|
||||
download.destroy();
|
||||
});
|
||||
return {
|
||||
stream: download,
|
||||
format: isZip ? 'zip' : 'tgz',
|
||||
sha256: contentSHA256,
|
||||
length: totalBytes,
|
||||
};
|
||||
}
|
||||
/**
|
||||
* Unzip a .zip or .tar.gz VS Code archive stream.
|
||||
*/
|
||||
async function unzipVSCode(reporter, extractDir, platform, { format, stream, length, sha256 }) {
|
||||
const stagingFile = path.join(os_1.tmpdir(), `vscode-test-${Date.now()}.zip`);
|
||||
const checksum = util_2.validateStream(stream, length, sha256);
|
||||
if (format === 'zip') {
|
||||
try {
|
||||
reporter.report({ stage: progress_1.ProgressReportStage.ExtractingSynchonrously });
|
||||
// note: this used to use Expand-Archive, but this caused a failure
|
||||
// on longer file paths on windows. And we used to use the streaming
|
||||
// "unzipper", but the module was very outdated and a bit buggy.
|
||||
// Instead, use jszip. It's well-used and actually 8x faster than
|
||||
// Expand-Archive on my machine.
|
||||
if (process.platform === 'win32') {
|
||||
const [buffer, JSZip] = await Promise.all([util_2.streamToBuffer(stream), Promise.resolve().then(() => require('jszip'))]);
|
||||
await checksum;
|
||||
const content = await JSZip.loadAsync(buffer);
|
||||
// extract file with jszip
|
||||
for (const filename of Object.keys(content.files)) {
|
||||
const file = content.files[filename];
|
||||
const filepath = path.join(extractDir, filename);
|
||||
if (file.dir) {
|
||||
continue;
|
||||
}
|
||||
// vscode update zips are trusted, but check for zip slip anyway.
|
||||
if (!util_2.isSubdirectory(extractDir, filepath)) {
|
||||
throw new Error(`Invalid zip file: ${filename}`);
|
||||
}
|
||||
await fs.promises.mkdir(path.dirname(filepath), { recursive: true });
|
||||
await pipelineAsync(file.nodeStream(), fs.createWriteStream(filepath));
|
||||
}
|
||||
}
|
||||
else {
|
||||
// darwin or *nix sync
|
||||
await pipelineAsync(stream, fs.createWriteStream(stagingFile));
|
||||
await checksum;
|
||||
await spawnDecompressorChild('unzip', ['-q', stagingFile, '-d', extractDir]);
|
||||
}
|
||||
}
|
||||
finally {
|
||||
fs.unlink(stagingFile, () => undefined);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// tar does not create extractDir by default
|
||||
if (!fs.existsSync(extractDir)) {
|
||||
fs.mkdirSync(extractDir);
|
||||
}
|
||||
// The CLI is a singular binary that doesn't have a wrapper component to remove
|
||||
const s = platform.includes('cli-') ? 0 : 1;
|
||||
await spawnDecompressorChild('tar', ['-xzf', '-', `--strip-components=${s}`, '-C', extractDir], stream);
|
||||
await checksum;
|
||||
}
|
||||
}
|
||||
function spawnDecompressorChild(command, args, input) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const child = cp.spawn(command, args, { stdio: 'pipe' });
|
||||
if (input) {
|
||||
input.on('error', reject);
|
||||
input.pipe(child.stdin);
|
||||
}
|
||||
child.stderr.pipe(process.stderr);
|
||||
child.stdout.pipe(process.stdout);
|
||||
child.on('error', reject);
|
||||
child.on('exit', (code) => code === 0 ? resolve() : reject(new Error(`Failed to unzip archive, exited with ${code}`)));
|
||||
});
|
||||
}
|
||||
exports.defaultCachePath = path.resolve(extensionRoot, '.vscode-test');
|
||||
const COMPLETE_FILE_NAME = 'is-complete';
|
||||
/**
|
||||
* Download and unzip a copy of VS Code.
|
||||
* @returns Promise of `vscodeExecutablePath`.
|
||||
*/
|
||||
async function download(options = {}) {
|
||||
let version = options === null || options === void 0 ? void 0 : options.version;
|
||||
const { platform = util_2.systemDefaultPlatform, cachePath = exports.defaultCachePath, reporter = new progress_1.ConsoleReporter(process.stdout.isTTY), timeout = 15000, } = options;
|
||||
if (version === 'stable') {
|
||||
version = await fetchTargetStableVersion({ timeout, cachePath, platform });
|
||||
}
|
||||
else if (version) {
|
||||
/**
|
||||
* Only validate version against server when no local download that matches version exists
|
||||
*/
|
||||
if (!fs.existsSync(path.resolve(cachePath, `vscode-${platform}-${version}`))) {
|
||||
if (!(await isValidVersion(version, platform, timeout))) {
|
||||
throw Error(`Invalid version ${version}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
version = await fetchTargetInferredVersion({
|
||||
timeout,
|
||||
cachePath,
|
||||
platform,
|
||||
extensionsDevelopmentPath: options.extensionDevelopmentPath,
|
||||
});
|
||||
}
|
||||
if (platform === 'win32-archive' && semver.satisfies(version, '>= 1.85.0', { includePrerelease: true })) {
|
||||
throw new Error('Windows 32-bit is no longer supported from v1.85 onwards');
|
||||
}
|
||||
reporter.report({ stage: progress_1.ProgressReportStage.ResolvedVersion, version });
|
||||
const downloadedPath = path.resolve(cachePath, makeDownloadDirName(platform, version));
|
||||
if (fs.existsSync(path.join(downloadedPath, COMPLETE_FILE_NAME))) {
|
||||
if (util_2.isInsiderVersionIdentifier(version)) {
|
||||
reporter.report({ stage: progress_1.ProgressReportStage.FetchingInsidersMetadata });
|
||||
const { version: currentHash, date: currentDate } = util_2.insidersDownloadDirMetadata(downloadedPath, platform);
|
||||
const { version: latestHash, timestamp: latestTimestamp } = version === 'insiders'
|
||||
? await util_2.getLatestInsidersMetadata(util_2.systemDefaultPlatform)
|
||||
: await util_2.getInsidersVersionMetadata(util_2.systemDefaultPlatform, version);
|
||||
if (currentHash === latestHash) {
|
||||
reporter.report({ stage: progress_1.ProgressReportStage.FoundMatchingInstall, downloadedPath });
|
||||
return Promise.resolve(util_2.insidersDownloadDirToExecutablePath(downloadedPath, platform));
|
||||
}
|
||||
else {
|
||||
try {
|
||||
reporter.report({
|
||||
stage: progress_1.ProgressReportStage.ReplacingOldInsiders,
|
||||
downloadedPath,
|
||||
oldDate: currentDate,
|
||||
oldHash: currentHash,
|
||||
newDate: new Date(latestTimestamp),
|
||||
newHash: latestHash,
|
||||
});
|
||||
await fs.promises.rm(downloadedPath, { force: true, recursive: true });
|
||||
}
|
||||
catch (err) {
|
||||
reporter.error(err);
|
||||
throw Error(`Failed to remove outdated Insiders at ${downloadedPath}.`);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (util_2.isStableVersionIdentifier(version)) {
|
||||
reporter.report({ stage: progress_1.ProgressReportStage.FoundMatchingInstall, downloadedPath });
|
||||
return Promise.resolve(util_2.downloadDirToExecutablePath(downloadedPath, platform));
|
||||
}
|
||||
else {
|
||||
reporter.report({ stage: progress_1.ProgressReportStage.FoundMatchingInstall, downloadedPath });
|
||||
return Promise.resolve(util_2.insidersDownloadDirToExecutablePath(downloadedPath, platform));
|
||||
}
|
||||
}
|
||||
for (let i = 0;; i++) {
|
||||
try {
|
||||
await fs.promises.rm(downloadedPath, { recursive: true, force: true });
|
||||
const download = await downloadVSCodeArchive({
|
||||
version,
|
||||
platform,
|
||||
cachePath,
|
||||
reporter,
|
||||
timeout,
|
||||
});
|
||||
// important! do not put anything async here, since unzipVSCode will need
|
||||
// to start consuming the stream immediately.
|
||||
await unzipVSCode(reporter, downloadedPath, platform, download);
|
||||
await fs.promises.writeFile(path.join(downloadedPath, COMPLETE_FILE_NAME), '');
|
||||
reporter.report({ stage: progress_1.ProgressReportStage.NewInstallComplete, downloadedPath });
|
||||
break;
|
||||
}
|
||||
catch (error) {
|
||||
if (i++ < DOWNLOAD_ATTEMPTS) {
|
||||
reporter.report({
|
||||
stage: progress_1.ProgressReportStage.Retrying,
|
||||
attempt: i,
|
||||
error: error,
|
||||
totalAttempts: DOWNLOAD_ATTEMPTS,
|
||||
});
|
||||
}
|
||||
else {
|
||||
reporter.error(error);
|
||||
throw Error(`Failed to download and unzip VS Code ${version}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
reporter.report({ stage: progress_1.ProgressReportStage.NewInstallComplete, downloadedPath });
|
||||
if (util_2.isStableVersionIdentifier(version)) {
|
||||
return util_2.downloadDirToExecutablePath(downloadedPath, platform);
|
||||
}
|
||||
else {
|
||||
return util_2.insidersDownloadDirToExecutablePath(downloadedPath, platform);
|
||||
}
|
||||
}
|
||||
exports.download = download;
|
||||
async function downloadAndUnzipVSCode(versionOrOptions, platform, reporter, extractSync) {
|
||||
return await download(typeof versionOrOptions === 'object'
|
||||
? versionOrOptions
|
||||
: { version: versionOrOptions, platform, reporter, extractSync });
|
||||
}
|
||||
exports.downloadAndUnzipVSCode = downloadAndUnzipVSCode;
|
||||
Reference in New Issue
Block a user