2022-06-07 01:53:59 +03:00
|
|
|
// Copyright (c) Microsoft Corporation.
|
|
|
|
// Licensed under the MIT License.
|
|
|
|
|
|
|
|
import { spawn } from 'child_process';
|
|
|
|
import { i } from './i18n';
|
2022-12-10 07:29:09 +03:00
|
|
|
import { DownloadEvents } from './interfaces/events';
|
2022-06-07 01:53:59 +03:00
|
|
|
import { Session } from './session';
|
2022-12-10 07:29:09 +03:00
|
|
|
import { Uri } from './util/uri';
|
2022-06-07 01:53:59 +03:00
|
|
|
|
2022-12-10 07:29:09 +03:00
|
|
|
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;
|
|
|
|
}
|
2022-06-07 01:53:59 +03:00
|
|
|
|
2022-12-10 07:29:09 +03:00
|
|
|
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(); }
|
|
|
|
reject(i`Running vcpkg internally returned a nonzero exit code: ${code}`);
|
2022-06-07 01:53:59 +03:00
|
|
|
});
|
2022-12-10 07:29:09 +03:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
Add z-extract command / artifacts uses z-extract (#1039)
* Make commands physical design consistent.
In the vcpkg technical review meeting today we said:
* We want commands.Xxx.cpp for every "vcpkg Xxx" subcommand, rather than Xxx.cpp.
* We want x- commands to not have the x in their code names or x- in their file names, and z- commands have the z in their code names and z- in their file names.
* Command cpps have dashes.
Drive by fixes as part of this audit:
* FooCommand structs are gone, all users were stateless and are better served by plain function pointers. This also allows the command tables to be constexpr.
* commands.interface.h is dead, as it only existed to declare those structs that are dead.
Future changes:
* I really want all the Commands::Xxx and the commands namespace itself to go away. But ran out of time to sell this to the team.
* Xxx::COMMAND_STRUCTURE => XxxCommandMetadata
* Xxx::perform_and_exit => xxx_command_and_exit
Notes:build, install, and export probably deserve to have functionality split out, but that would probably be intricate so I have not attempted to do it here.
export.*.cpp seem like they *really* shouldn't be separate .cpps.
* Missed some _command s.
* wip
* wip
* format
* minimal impl
* add .xz
* Add help text for command
* vcpkg-artifacts uses x-extract
* format
* oops
* x-extract -> z-extract
* rename extract_archive_to_empty -> extract_archive and rename the old extract_archive to set_directory_to_archive_content
* fix comment
* wip
* add strip setting
* add strip option localized message
* format
* wip
* Add testing for strip mapping
* add --extract-type option to bypass file extension detection
* format
* wip
* test
* wip
* wip
* wip
* forward slash delim for non-windows
* wip
* try again
* maybe fix paths for non-windows
* use generic_Xxx
* use + instead of /
* convert back to path
* use appropriate path separators in test
* set VCPKG_COMMAND env variable
* set VCPKG_COMMAND
* set VCPKG_COMMAND in yaml
* wip
* use matrix.preset
* remove archive unit test from artifacts
* debug
* const everything
* create destination if it does not exist
* use fsPath instead
* bug fixes and remove installers
* fix end-to-end check
* wip
* wip
* debug messages
* fix strip for macos and linux
* print output
* wip
* cleanup
* format
* rename to command_extract_and_exit as per convention
* response to feedback
* remove the extract-type option and just fall back to cmake
* fix strip_map to proper behavior, better temp dir handling, etc
* fix unit tests
* for real this time
* wip
* wip
* reuse logic for is_slash functionality
* oops
* testing
* test
* testing
* verify problem
* try this
* fix
* use Strings::strto<int> instead of std::stoi
* add AUTO option + unit test
* add strip=AUTO
* switch artifacts to use strip=AUTO
* format
* cleanup
* fix compiler warnings
* fix conversion
* format
* remove magic -1, respond to feedback, format
* update localized messages
* add e2e
* test executable bits on non-windows
* oops
* better naming
* try this
* update end2end
* for real this time
* verify file exists
* print UnixMode
* oops
* fix indentation
* look for the right unixMode
* Simplify tests.
* Delete unreferenced test assets, add archive start events back.
* remove = from #define
* format
* minor fix
* Fix casing for enum class
* rename strip_map and get_common_prefix_count and add minimum documentation
* wip
* missed a couple renames
* rename test folder from "archive" to "folder0"
* remove then from artifact caller
* some structural changes
* enforce relationship between stripMode and stripCount
* use files is_slash
* check strip option is >=0
* format
* minor refactoring
* remove empty entries from get_archive_deploy_operations
* minor refactor
* adds testing for guess_extraction_type and get_strip_setting
* add testing for get_strip_setting
* minor feedback
---------
Co-authored-by: Billy Robert O'Neal III <bion@microsoft.com>
2023-08-01 01:54:26 +03:00
|
|
|
export async function vcpkgExtract(session: Session, archive: string, target:string, strip:string): Promise<string> {
|
|
|
|
return runVcpkg(session.vcpkgCommand, ['z-extract', archive, target, strip]);
|
|
|
|
}
|
|
|
|
|
2022-12-10 07:29:09 +03:00
|
|
|
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');
|
2022-06-07 01:53:59 +03:00
|
|
|
}
|
|
|
|
|
2022-12-10 07:29:09 +03:00
|
|
|
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);
|
|
|
|
}
|
2022-06-07 01:53:59 +03:00
|
|
|
});
|
2022-12-10 07:29:09 +03:00
|
|
|
|
|
|
|
return;
|
|
|
|
} catch {
|
|
|
|
session.channels.warning(i`failed to download from ${uri.toString()}`);
|
|
|
|
}
|
2022-06-07 01:53:59 +03:00
|
|
|
}
|
2022-12-10 07:29:09 +03:00
|
|
|
|
|
|
|
throw new Error(i`failed to download ${destination} from any source`);
|
2022-06-07 01:53:59 +03:00
|
|
|
}
|