vcpkg-tool/vcpkg-artifacts/vcpkg.ts

88 строки
3.0 KiB
TypeScript

// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
import { spawn } from 'child_process';
import { i } from './i18n';
import { DownloadEvents } from './interfaces/events';
import { Session } from './session';
import { Uri } from './util/uri';
function streamVcpkg(vcpkgCommand: string | undefined, args: Array<string>, listener: (chunk: any) => void): Promise<void> {
return new Promise((accept, reject) => {
if (!vcpkgCommand) {
reject(i`VCPKG_COMMAND was not set`);
return;
}
const subproc = spawn(vcpkgCommand, args, { stdio: ['ignore', 'pipe', 'pipe'] });
subproc.stdout.on('data', listener);
subproc.stderr.pipe(process.stdout);
subproc.on('error', (err) => { reject(err); });
subproc.on('close', (code: number, signal) => {
if (code === 0) {
accept();
return;
}
reject(i`Running vcpkg internally returned a nonzero exit code: ${code}`);
});
});
}
async function runVcpkg(vcpkgCommand: string | undefined, args: Array<string>): Promise<string> {
let result = '';
await streamVcpkg(vcpkgCommand, args, (chunk) => { result += chunk; });
return result.trimEnd();
}
export function vcpkgFetch(session: Session, fetchKey: string): Promise<string> {
return runVcpkg(session.vcpkgCommand, ['fetch', fetchKey, '--x-stderr-status']).then((output) => {
return output;
}, (error) => {
if (fetchKey === 'git') {
session.channels.warning('failed to fetch git, falling back to attempting to use git from the PATH');
return Promise.resolve('git');
}
return Promise.reject(error);
});
}
export async function vcpkgExtract(session: Session, archive: string, target:string, strip?:number|string): Promise<string> {
const args: Array<string> = ['z-extract', archive, target];
if (strip)
{
args.push(`--strip=${strip}`);
}
return runVcpkg(session.vcpkgCommand, args);}
export async function vcpkgDownload(session: Session, destination: string, sha512: string | undefined, uris: Array<Uri>, events: Partial<DownloadEvents>) : Promise<void> {
const args = ['x-download', destination, '--z-machine-readable-progress'];
if (sha512) {
args.push(`--sha512=${sha512}`);
} else {
args.push('--skip-sha512');
}
for (const uri of uris) {
events.downloadProgress?.(uri, destination, 0);
const uriArgs = [...args, `--url=${uri.toString()}`];
try {
await streamVcpkg(session.vcpkgCommand, uriArgs, (chunk) => {
const match = /(\d+)(\.\d+)?%\s*$/.exec(chunk);
if (!match) { return; }
const number = parseFloat(match[1]);
// throwing out 100s avoids displaying temporarily full progress bars resulting from redirects getting resolved
if (number && number < 100) {
events.downloadProgress?.(uri, destination, number);
}
});
return;
} catch {
session.channels.warning(i`failed to download from ${uri.toString()}`);
}
}
throw new Error(i`failed to download ${destination} from any source`);
}