|
|
"use strict"; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { |
|
|
if (k2 === undefined) k2 = k; |
|
|
var desc = Object.getOwnPropertyDescriptor(m, k); |
|
|
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { |
|
|
desc = { enumerable: true, get: function() { return m[k]; } }; |
|
|
} |
|
|
Object.defineProperty(o, k2, desc); |
|
|
}) : (function(o, m, k, k2) { |
|
|
if (k2 === undefined) k2 = k; |
|
|
o[k2] = m[k]; |
|
|
})); |
|
|
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { |
|
|
Object.defineProperty(o, "default", { enumerable: true, value: v }); |
|
|
}) : function(o, v) { |
|
|
o["default"] = v; |
|
|
}); |
|
|
var __importStar = (this && this.__importStar) || function (mod) { |
|
|
if (mod && mod.__esModule) return mod; |
|
|
var result = {}; |
|
|
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); |
|
|
__setModuleDefault(result, mod); |
|
|
return result; |
|
|
}; |
|
|
Object.defineProperty(exports, "__esModule", { value: true }); |
|
|
exports.killTree = exports.onceWithoutRejections = exports.isSubdirectory = exports.streamToBuffer = exports.validateStream = exports.isDefined = exports.runVSCodeCommand = exports.VSCodeCommandError = exports.hasArg = exports.getProfileArguments = exports.resolveCliArgsFromVSCodeExecutablePath = exports.resolveCliPathFromVSCodeExecutablePath = exports.getLatestInsidersMetadata = exports.getInsidersVersionMetadata = exports.insidersDownloadDirMetadata = exports.insidersDownloadDirToExecutablePath = exports.downloadDirToExecutablePath = exports.urlToOptions = exports.getVSCodeDownloadUrl = exports.Version = exports.systemDefaultPlatform = void 0; |
|
|
const child_process_1 = require("child_process"); |
|
|
const crypto_1 = require("crypto"); |
|
|
const fs_1 = require("fs"); |
|
|
const http_proxy_agent_1 = require("http-proxy-agent"); |
|
|
const https_proxy_agent_1 = require("https-proxy-agent"); |
|
|
const path = __importStar(require("path")); |
|
|
const url_1 = require("url"); |
|
|
const download_1 = require("./download"); |
|
|
const request = __importStar(require("./request")); |
|
|
const windowsPlatforms = new Set(['win32-x64-archive', 'win32-arm64-archive']); |
|
|
const darwinPlatforms = new Set(['darwin-arm64', 'darwin']); |
|
|
switch (process.platform) { |
|
|
case 'darwin': |
|
|
exports.systemDefaultPlatform = process.arch === 'arm64' ? 'darwin-arm64' : 'darwin'; |
|
|
break; |
|
|
case 'win32': |
|
|
exports.systemDefaultPlatform = process.arch === 'arm64' ? 'win32-arm64-archive' : 'win32-x64-archive'; |
|
|
break; |
|
|
default: |
|
|
exports.systemDefaultPlatform = |
|
|
process.arch === 'arm64' ? 'linux-arm64' : process.arch === 'arm' ? 'linux-armhf' : 'linux-x64'; |
|
|
} |
|
|
const UNRELEASED_SUFFIX = '-unreleased'; |
|
|
class Version { |
|
|
static parse(version) { |
|
|
const unreleased = version.endsWith(UNRELEASED_SUFFIX); |
|
|
if (unreleased) { |
|
|
version = version.slice(0, -UNRELEASED_SUFFIX.length); |
|
|
} |
|
|
return new Version(version, !unreleased); |
|
|
} |
|
|
constructor(id, isReleased = true) { |
|
|
this.id = id; |
|
|
this.isReleased = isReleased; |
|
|
} |
|
|
get isCommit() { |
|
|
return /^[0-9a-f]{40}$/.test(this.id); |
|
|
} |
|
|
get isInsiders() { |
|
|
return this.id === 'insiders' || this.id.endsWith('-insider'); |
|
|
} |
|
|
get isStable() { |
|
|
return this.id === 'stable' || /^[0-9]+\.[0-9]+\.[0-9]$/.test(this.id); |
|
|
} |
|
|
toString() { |
|
|
return this.id + (this.isReleased ? '' : UNRELEASED_SUFFIX); |
|
|
} |
|
|
} |
|
|
exports.Version = Version; |
|
|
function getVSCodeDownloadUrl(version, platform) { |
|
|
if (version.id === 'insiders') { |
|
|
return `https://update.code.visualstudio.com/latest/${platform}/insider?released=${version.isReleased}`; |
|
|
} |
|
|
else if (version.isInsiders) { |
|
|
return `https://update.code.visualstudio.com/${version.id}/${platform}/insider?released=${version.isReleased}`; |
|
|
} |
|
|
else if (version.isStable) { |
|
|
return `https://update.code.visualstudio.com/${version.id}/${platform}/stable?released=${version.isReleased}`; |
|
|
} |
|
|
else { |
|
|
|
|
|
return `https://update.code.visualstudio.com/commit:${version.id}/${platform}/insider`; |
|
|
} |
|
|
} |
|
|
exports.getVSCodeDownloadUrl = getVSCodeDownloadUrl; |
|
|
let PROXY_AGENT = undefined; |
|
|
let HTTPS_PROXY_AGENT = undefined; |
|
|
if (process.env.npm_config_proxy) { |
|
|
PROXY_AGENT = new http_proxy_agent_1.HttpProxyAgent(process.env.npm_config_proxy); |
|
|
HTTPS_PROXY_AGENT = new https_proxy_agent_1.HttpsProxyAgent(process.env.npm_config_proxy); |
|
|
} |
|
|
if (process.env.npm_config_https_proxy) { |
|
|
HTTPS_PROXY_AGENT = new https_proxy_agent_1.HttpsProxyAgent(process.env.npm_config_https_proxy); |
|
|
} |
|
|
function urlToOptions(url) { |
|
|
const parsed = new url_1.URL(url); |
|
|
const options = {}; |
|
|
if (PROXY_AGENT && parsed.protocol.startsWith('http:')) { |
|
|
options.agent = PROXY_AGENT; |
|
|
} |
|
|
if (HTTPS_PROXY_AGENT && parsed.protocol.startsWith('https:')) { |
|
|
options.agent = HTTPS_PROXY_AGENT; |
|
|
} |
|
|
return options; |
|
|
} |
|
|
exports.urlToOptions = urlToOptions; |
|
|
function downloadDirToExecutablePath(dir, platform) { |
|
|
if (windowsPlatforms.has(platform)) { |
|
|
return path.resolve(dir, 'Code.exe'); |
|
|
} |
|
|
else if (darwinPlatforms.has(platform)) { |
|
|
return path.resolve(dir, 'Visual Studio Code.app/Contents/MacOS/Electron'); |
|
|
} |
|
|
else { |
|
|
return path.resolve(dir, 'code'); |
|
|
} |
|
|
} |
|
|
exports.downloadDirToExecutablePath = downloadDirToExecutablePath; |
|
|
function insidersDownloadDirToExecutablePath(dir, platform) { |
|
|
if (windowsPlatforms.has(platform)) { |
|
|
return path.resolve(dir, 'Code - Insiders.exe'); |
|
|
} |
|
|
else if (darwinPlatforms.has(platform)) { |
|
|
return path.resolve(dir, 'Visual Studio Code - Insiders.app/Contents/MacOS/Electron'); |
|
|
} |
|
|
else { |
|
|
return path.resolve(dir, 'code-insiders'); |
|
|
} |
|
|
} |
|
|
exports.insidersDownloadDirToExecutablePath = insidersDownloadDirToExecutablePath; |
|
|
function insidersDownloadDirMetadata(dir, platform) { |
|
|
let productJsonPath; |
|
|
if (windowsPlatforms.has(platform)) { |
|
|
productJsonPath = path.resolve(dir, 'resources/app/product.json'); |
|
|
} |
|
|
else if (darwinPlatforms.has(platform)) { |
|
|
productJsonPath = path.resolve(dir, 'Visual Studio Code - Insiders.app/Contents/Resources/app/product.json'); |
|
|
} |
|
|
else { |
|
|
productJsonPath = path.resolve(dir, 'resources/app/product.json'); |
|
|
} |
|
|
const productJson = JSON.parse((0, fs_1.readFileSync)(productJsonPath, 'utf-8')); |
|
|
return { |
|
|
version: productJson.commit, |
|
|
date: new Date(productJson.date), |
|
|
}; |
|
|
} |
|
|
exports.insidersDownloadDirMetadata = insidersDownloadDirMetadata; |
|
|
async function getInsidersVersionMetadata(platform, version, released) { |
|
|
const remoteUrl = `https://update.code.visualstudio.com/api/versions/${version}/${platform}/insider?released=${released}`; |
|
|
return await request.getJSON(remoteUrl, 30_000); |
|
|
} |
|
|
exports.getInsidersVersionMetadata = getInsidersVersionMetadata; |
|
|
async function getLatestInsidersMetadata(platform, released) { |
|
|
const remoteUrl = `https://update.code.visualstudio.com/api/update/${platform}/insider/latest?released=${released}`; |
|
|
return await request.getJSON(remoteUrl, 30_000); |
|
|
} |
|
|
exports.getLatestInsidersMetadata = getLatestInsidersMetadata; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function resolveCliPathFromVSCodeExecutablePath(vscodeExecutablePath, platform = exports.systemDefaultPlatform) { |
|
|
if (platform === 'win32-archive') { |
|
|
throw new Error('Windows 32-bit is no longer supported'); |
|
|
} |
|
|
if (windowsPlatforms.has(platform)) { |
|
|
if (vscodeExecutablePath.endsWith('Code - Insiders.exe')) { |
|
|
return path.resolve(vscodeExecutablePath, '../bin/code-insiders.cmd'); |
|
|
} |
|
|
else { |
|
|
return path.resolve(vscodeExecutablePath, '../bin/code.cmd'); |
|
|
} |
|
|
} |
|
|
else if (darwinPlatforms.has(platform)) { |
|
|
return path.resolve(vscodeExecutablePath, '../../../Contents/Resources/app/bin/code'); |
|
|
} |
|
|
else { |
|
|
if (vscodeExecutablePath.endsWith('code-insiders')) { |
|
|
return path.resolve(vscodeExecutablePath, '../bin/code-insiders'); |
|
|
} |
|
|
else { |
|
|
return path.resolve(vscodeExecutablePath, '../bin/code'); |
|
|
} |
|
|
} |
|
|
} |
|
|
exports.resolveCliPathFromVSCodeExecutablePath = resolveCliPathFromVSCodeExecutablePath; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function resolveCliArgsFromVSCodeExecutablePath(vscodeExecutablePath, options) { |
|
|
const args = [ |
|
|
resolveCliPathFromVSCodeExecutablePath(vscodeExecutablePath, options?.platform ?? exports.systemDefaultPlatform), |
|
|
]; |
|
|
if (!options?.reuseMachineInstall) { |
|
|
args.push(...getProfileArguments(args)); |
|
|
} |
|
|
return args; |
|
|
} |
|
|
exports.resolveCliArgsFromVSCodeExecutablePath = resolveCliArgsFromVSCodeExecutablePath; |
|
|
|
|
|
function getProfileArguments(args) { |
|
|
const out = []; |
|
|
if (!hasArg('extensions-dir', args)) { |
|
|
out.push(`--extensions-dir=${path.join(download_1.defaultCachePath, 'extensions')}`); |
|
|
} |
|
|
if (!hasArg('user-data-dir', args)) { |
|
|
out.push(`--user-data-dir=${path.join(download_1.defaultCachePath, 'user-data')}`); |
|
|
} |
|
|
return out; |
|
|
} |
|
|
exports.getProfileArguments = getProfileArguments; |
|
|
function hasArg(argName, argList) { |
|
|
return argList.some((a) => a === `--${argName}` || a.startsWith(`--${argName}=`)); |
|
|
} |
|
|
exports.hasArg = hasArg; |
|
|
class VSCodeCommandError extends Error { |
|
|
constructor(args, exitCode, stderr, stdout) { |
|
|
super(`'code ${args.join(' ')}' failed with exit code ${exitCode}:\n\n${stderr}\n\n${stdout}`); |
|
|
this.exitCode = exitCode; |
|
|
this.stderr = stderr; |
|
|
this.stdout = stdout; |
|
|
} |
|
|
} |
|
|
exports.VSCodeCommandError = VSCodeCommandError; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
async function runVSCodeCommand(_args, options = {}) { |
|
|
const args = _args.slice(); |
|
|
let executable = await (0, download_1.downloadAndUnzipVSCode)(options); |
|
|
let shell = false; |
|
|
if (!options.reuseMachineInstall) { |
|
|
args.push(...getProfileArguments(args)); |
|
|
} |
|
|
|
|
|
if (!hasArg('extensionTestsPath', args) && !hasArg('extensionDevelopmentPath', args)) { |
|
|
executable = resolveCliPathFromVSCodeExecutablePath(executable, options?.platform ?? exports.systemDefaultPlatform); |
|
|
shell = process.platform === 'win32'; |
|
|
} |
|
|
return new Promise((resolve, reject) => { |
|
|
let stdout = ''; |
|
|
let stderr = ''; |
|
|
const child = (0, child_process_1.spawn)(shell ? `"${executable}"` : executable, args, { |
|
|
stdio: 'pipe', |
|
|
shell, |
|
|
windowsHide: true, |
|
|
...options.spawn, |
|
|
}); |
|
|
child.stdout?.setEncoding('utf-8').on('data', (data) => (stdout += data)); |
|
|
child.stderr?.setEncoding('utf-8').on('data', (data) => (stderr += data)); |
|
|
child.on('error', reject); |
|
|
child.on('exit', (code) => { |
|
|
if (code !== 0) { |
|
|
reject(new VSCodeCommandError(args, code, stderr, stdout)); |
|
|
} |
|
|
else { |
|
|
resolve({ stdout, stderr }); |
|
|
} |
|
|
}); |
|
|
}); |
|
|
} |
|
|
exports.runVSCodeCommand = runVSCodeCommand; |
|
|
|
|
|
function isDefined(arg) { |
|
|
return arg != null; |
|
|
} |
|
|
exports.isDefined = isDefined; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function validateStream(readable, length, sha256) { |
|
|
let actualLen = 0; |
|
|
const checksum = sha256 ? (0, crypto_1.createHash)('sha256') : undefined; |
|
|
return new Promise((resolve, reject) => { |
|
|
readable.on('data', (chunk) => { |
|
|
checksum?.update(chunk); |
|
|
actualLen += chunk.length; |
|
|
}); |
|
|
readable.on('error', reject); |
|
|
readable.on('end', () => { |
|
|
if (actualLen !== length) { |
|
|
return reject(new Error(`Downloaded stream length ${actualLen} does not match expected length ${length}`)); |
|
|
} |
|
|
const digest = checksum?.digest('hex'); |
|
|
if (digest && digest !== sha256) { |
|
|
return reject(new Error(`Downloaded file checksum ${digest} does not match expected checksum ${sha256}`)); |
|
|
} |
|
|
resolve(); |
|
|
}); |
|
|
}); |
|
|
} |
|
|
exports.validateStream = validateStream; |
|
|
|
|
|
function streamToBuffer(readable) { |
|
|
return new Promise((resolve, reject) => { |
|
|
const chunks = []; |
|
|
readable.on('data', (chunk) => chunks.push(chunk)); |
|
|
readable.on('error', reject); |
|
|
readable.on('end', () => resolve(Buffer.concat(chunks))); |
|
|
}); |
|
|
} |
|
|
exports.streamToBuffer = streamToBuffer; |
|
|
|
|
|
function isSubdirectory(parent, child) { |
|
|
const relative = path.relative(parent, child); |
|
|
return !relative.startsWith('..') && !path.isAbsolute(relative); |
|
|
} |
|
|
exports.isSubdirectory = isSubdirectory; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function onceWithoutRejections(fn) { |
|
|
let value; |
|
|
return (...args) => { |
|
|
if (!value) { |
|
|
value = fn(...args).catch((err) => { |
|
|
value = undefined; |
|
|
throw err; |
|
|
}); |
|
|
} |
|
|
return value; |
|
|
}; |
|
|
} |
|
|
exports.onceWithoutRejections = onceWithoutRejections; |
|
|
function killTree(processId, force) { |
|
|
let cp; |
|
|
if (process.platform === 'win32') { |
|
|
const windir = process.env['WINDIR'] || 'C:\\Windows'; |
|
|
|
|
|
|
|
|
cp = (0, child_process_1.spawn)(path.join(windir, 'System32', 'taskkill.exe'), [...(force ? ['/F'] : []), '/T', '/PID', processId.toString()], { stdio: 'inherit' }); |
|
|
} |
|
|
else { |
|
|
|
|
|
cp = (0, child_process_1.spawn)('sh', [path.resolve(__dirname, '../killTree.sh'), processId.toString(), force ? '9' : '15'], { |
|
|
stdio: 'inherit', |
|
|
}); |
|
|
} |
|
|
return new Promise((resolve, reject) => { |
|
|
cp.on('error', reject).on('exit', resolve); |
|
|
}); |
|
|
} |
|
|
exports.killTree = killTree; |
|
|
|