2019-04-02 11:26:21 +00:00
|
|
|
/**
|
|
|
|
* @license
|
|
|
|
* Copyright 2019 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.
|
|
|
|
*/
|
2019-05-30 14:19:47 +00:00
|
|
|
|
2019-04-02 11:26:21 +00:00
|
|
|
/**
|
|
|
|
* CLI entrypoint, but see also `bin/balena` and `bin/balena-dev` which
|
|
|
|
* call this function.
|
|
|
|
*/
|
2019-10-15 00:05:40 +00:00
|
|
|
export async function run(
|
|
|
|
cliArgs = process.argv,
|
|
|
|
options: import('./preparser').AppOptions = {},
|
|
|
|
) {
|
|
|
|
// The 'pkgExec' special/internal command provides a Node.js interpreter
|
|
|
|
// for use of the standalone zip package. See pkgExec function.
|
|
|
|
if (cliArgs.length > 3 && cliArgs[2] === 'pkgExec') {
|
|
|
|
return pkgExec(cliArgs[3], cliArgs.slice(4));
|
|
|
|
}
|
|
|
|
|
|
|
|
const { globalInit } = await import('./app-common');
|
|
|
|
const { routeCliFramework } = await import('./preparser');
|
|
|
|
|
2019-04-02 11:26:21 +00:00
|
|
|
// globalInit() must be called very early on (before other imports) because
|
|
|
|
// it sets up Sentry error reporting, global HTTP proxy settings, balena-sdk
|
|
|
|
// shared options, and performs node version requirement checks.
|
2019-08-28 18:51:56 +00:00
|
|
|
globalInit();
|
|
|
|
await routeCliFramework(cliArgs, options);
|
2020-01-03 23:45:40 +00:00
|
|
|
|
|
|
|
// Windows fix: reading from stdin prevents the process from exiting
|
|
|
|
process.stdin.pause();
|
2019-04-02 11:26:21 +00:00
|
|
|
}
|
2019-10-15 00:05:40 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Implements the 'pkgExec' command, used as a way to provide a Node.js
|
|
|
|
* interpreter for child_process.spawn()-like operations when the CLI is
|
|
|
|
* executing as a standalone zip package (built-in Node interpreter) and
|
|
|
|
* the system may not have a separate Node.js installation. A present use
|
|
|
|
* case is a patched version of the 'windosu' package that requires a
|
|
|
|
* Node.js interpreter to spawn a privileged child process.
|
|
|
|
*
|
|
|
|
* @param modFunc Path to a JS module that will be executed via require().
|
|
|
|
* The modFunc argument may optionally contain a function name separated
|
|
|
|
* by '::', for example '::main' in:
|
|
|
|
* 'C:\\snapshot\\balena-cli\\node_modules\\windosu\\lib\\pipe.js::main'
|
|
|
|
* in which case that function is executed in the require'd module.
|
|
|
|
* @param args Optional arguments to passed through process.argv and as
|
|
|
|
* arguments to the function specified via modFunc.
|
|
|
|
*/
|
|
|
|
async function pkgExec(modFunc: string, args: string[]) {
|
|
|
|
const [modPath, funcName] = modFunc.split('::');
|
|
|
|
let replacedModPath = modPath;
|
|
|
|
const match = modPath
|
|
|
|
.replace(/\\/g, '/')
|
|
|
|
.match(/\/snapshot\/balena-cli\/(.+)/);
|
|
|
|
if (match) {
|
|
|
|
replacedModPath = `../${match[1]}`;
|
|
|
|
}
|
|
|
|
process.argv = [process.argv[0], process.argv[1], ...args];
|
|
|
|
try {
|
|
|
|
const mod: any = await import(replacedModPath);
|
|
|
|
if (funcName) {
|
|
|
|
await mod[funcName](...args);
|
|
|
|
}
|
|
|
|
} catch (err) {
|
|
|
|
console.error(`Error executing pkgExec "${modFunc}" [${args.join()}]`);
|
|
|
|
console.error(err);
|
|
|
|
}
|
|
|
|
}
|