2020-01-20 14:01:58 +00:00
|
|
|
/**
|
|
|
|
* @license
|
|
|
|
* Copyright 2019-2020 Balena Ltd.
|
|
|
|
*
|
|
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
* you may not use this file except in compliance with the License.
|
|
|
|
* You may obtain a copy of the License at
|
|
|
|
*
|
|
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
*
|
|
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
* See the License for the specific language governing permissions and
|
|
|
|
* limitations under the License.
|
|
|
|
*/
|
|
|
|
|
|
|
|
import { spawn } from 'child_process';
|
2024-12-19 18:31:07 +00:00
|
|
|
import path from 'path';
|
|
|
|
import fs from 'fs';
|
2024-12-16 14:11:57 +00:00
|
|
|
import * as whichMod from 'which';
|
2020-01-20 14:01:58 +00:00
|
|
|
|
|
|
|
export const ROOT = path.join(__dirname, '..');
|
|
|
|
|
|
|
|
export function loadPackageJson() {
|
2024-09-04 17:47:18 +00:00
|
|
|
const packageJsonPath = path.join(ROOT, 'package.json');
|
|
|
|
|
|
|
|
const packageJson = fs.readFileSync(packageJsonPath, 'utf8');
|
|
|
|
return JSON.parse(packageJson);
|
2020-01-20 14:01:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Error handling wrapper around the npm `which` package:
|
|
|
|
* "Like the unix which utility. Finds the first instance of a specified
|
|
|
|
* executable in the PATH environment variable. Does not cache the results,
|
|
|
|
* so hash -r is not needed when the PATH changes."
|
|
|
|
*
|
|
|
|
* @param program Basename of a program, for example 'ssh'
|
|
|
|
* @returns The program's full path, e.g. 'C:\WINDOWS\System32\OpenSSH\ssh.EXE'
|
|
|
|
*/
|
|
|
|
export async function which(program: string): Promise<string> {
|
|
|
|
let programPath: string;
|
|
|
|
try {
|
|
|
|
programPath = await whichMod(program);
|
|
|
|
} catch (err) {
|
|
|
|
if (err.code === 'ENOENT') {
|
|
|
|
throw new Error(`'${program}' program not found. Is it installed?`);
|
|
|
|
}
|
|
|
|
throw err;
|
|
|
|
}
|
|
|
|
return programPath;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Call which(programName) and spawn() with the given arguments. Throw an error
|
|
|
|
* if the process exit code is not zero.
|
|
|
|
*/
|
|
|
|
export async function whichSpawn(
|
|
|
|
programName: string,
|
2022-01-19 21:40:53 +00:00
|
|
|
args: string[] = [],
|
2020-01-20 14:01:58 +00:00
|
|
|
): Promise<void> {
|
|
|
|
const program = await which(programName);
|
|
|
|
let error: Error | undefined;
|
|
|
|
let exitCode: number | undefined;
|
|
|
|
try {
|
|
|
|
exitCode = await new Promise<number>((resolve, reject) => {
|
|
|
|
try {
|
|
|
|
spawn(program, args, { stdio: 'inherit' })
|
|
|
|
.on('error', reject)
|
|
|
|
.on('close', resolve);
|
|
|
|
} catch (err) {
|
2024-12-16 14:11:57 +00:00
|
|
|
reject(err as Error);
|
2020-01-20 14:01:58 +00:00
|
|
|
}
|
|
|
|
});
|
|
|
|
} catch (err) {
|
|
|
|
error = err;
|
|
|
|
}
|
|
|
|
if (error || exitCode) {
|
|
|
|
const msg = [
|
|
|
|
`${programName} failed with exit code ${exitCode}:`,
|
|
|
|
`"${program}" [${args}]`,
|
|
|
|
];
|
|
|
|
if (error) {
|
|
|
|
msg.push(`${error}`);
|
|
|
|
}
|
|
|
|
throw new Error(msg.join('\n'));
|
|
|
|
}
|
|
|
|
}
|