forked from microsoft/rushstack
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathinstall-run.ts
More file actions
104 lines (88 loc) · 3.44 KB
/
install-run.ts
File metadata and controls
104 lines (88 loc) · 3.44 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.
// See LICENSE in the project root for license information.
// This file was generated by a tool. Modifying this file will produce unexpected behavior.
//
// This script is used to install and invoke a tool from a CI definition.
import * as childProcess from 'child_process';
import {
installAndRun,
IPackageSpecifier,
getNpmPath,
runWithErrorPrinting
} from './install-run-common';
/**
* Parse a package specifier (in the form of name\@version) into name and version parts.
*/
function parsePackageSpecifier(rawPackageSpecifier: string): IPackageSpecifier {
rawPackageSpecifier = (rawPackageSpecifier || '').trim();
const separatorIndex: number = rawPackageSpecifier.lastIndexOf('@');
let name: string;
let version: string | undefined = undefined;
if (separatorIndex === 0) {
// The specifier starts with a scope and doesn't have a version specified
name = rawPackageSpecifier;
} else if (separatorIndex === -1) {
// The specifier doesn't have a version
name = rawPackageSpecifier;
} else {
name = rawPackageSpecifier.substring(0, separatorIndex);
version = rawPackageSpecifier.substring(separatorIndex + 1);
}
if (!name) {
throw new Error(`Invalid package specifier: ${rawPackageSpecifier}`);
}
return { name, version };
}
/**
* Resolve a package specifier to a static version
*/
function resolvePackageVersion({ name, version }: IPackageSpecifier): string {
if (!version) {
version = '*'; // If no version is specified, use the latest version
}
if (version.match(/[\*\^\~]/ig)) {
// If the version contains the characters "*", "^", or "~", we need to figure out what the
// version resolves to
try {
const npmPath: string = getNpmPath();
// This returns something that looks like:
// @microsoft/rush@3.0.0 '3.0.0'
// @microsoft/rush@3.0.1 '3.0.1'
// ...
// @microsoft/rush@3.0.20 '3.0.20'
// <blank line>
const npmViewVersionOutput: string = childProcess.execSync(
`${npmPath} view ${name}@${version} version --no-update-notifier`,
{ stdio: [] }
).toString();
const versionLines: string[] = npmViewVersionOutput.split('\n').filter((line) => !!line);
const latestVersion: string | undefined = versionLines[versionLines.length - 1];
if (!latestVersion) {
throw new Error('No versions found for the specified version range.');
}
const versionMatches: string[] | null = latestVersion.match(/^.+\s\'(.+)\'$/);
if (!versionMatches) {
throw new Error(`Invalid npm output ${latestVersion}`);
}
return versionMatches[1];
} catch (e) {
throw new Error(`Unable to resolve version ${version} of package ${name}: ${e}`);
}
} else {
return version;
}
}
function run(): void {
runWithErrorPrinting(() => {
// tslint:disable-next-line:no-unused-variable
const [ nodePath, scriptPath, rawPackageSpecifier, packageBinName, ...packageBinArgs ]: string[] = process.argv;
const packageSpecifier: IPackageSpecifier = parsePackageSpecifier(rawPackageSpecifier);
const name: string = packageSpecifier.name;
const version: string = resolvePackageVersion(packageSpecifier);
if (packageSpecifier.version !== version) {
console.log(`Resolved to ${name}@${version}`);
}
installAndRun(nodePath, name, version, packageBinName, packageBinArgs);
});
}
run();