mirror of
https://github.com/balena-io/balena-cli.git
synced 2024-12-21 14:37:47 +00:00
Merge pull request #1455 from balena-io/1428-os-initialize
Fix 'os initialize' (auto sudo execution)
This commit is contained in:
commit
82c486b202
@ -54,35 +54,3 @@ exports.scanDevices =
|
||||
.then (hostnameOrIp) ->
|
||||
console.error("==> Selected device: #{hostnameOrIp}")
|
||||
.nodeify(done)
|
||||
|
||||
exports.sudo =
|
||||
signature: 'internal sudo <command>'
|
||||
description: 'execute arbitrary commands in a privileged subprocess'
|
||||
help: '''
|
||||
Don't use this command directly!
|
||||
|
||||
<command> must be passed as a single argument. That means, you need to make sure
|
||||
you enclose <command> in quotes (eg. balena internal sudo 'ls -alF') if for
|
||||
whatever reason you invoke the command directly or, typically, pass <command>
|
||||
as a single argument to spawn (eg. `spawn('balena', [ 'internal', 'sudo', 'ls -alF' ])`).
|
||||
|
||||
Furthermore, this command will naively split <command> on whitespace and directly
|
||||
forward the parts as arguments to `sudo`, so be careful.
|
||||
'''
|
||||
hidden: true
|
||||
action: (params, options, done) ->
|
||||
os = require('os')
|
||||
Promise = require('bluebird')
|
||||
|
||||
return Promise.try ->
|
||||
if os.platform() is 'win32'
|
||||
windosu = require('windosu')
|
||||
windosu.exec(params.command, {})
|
||||
else
|
||||
{ spawn } = require('child_process')
|
||||
{ wait } = require('rindle')
|
||||
cmd = params.command.split(' ')
|
||||
ps = spawn('sudo', cmd, stdio: 'inherit', env: process.env)
|
||||
wait(ps)
|
||||
|
||||
.nodeify(done)
|
||||
|
@ -128,7 +128,6 @@ capitano.command(actions.util.availableDrives)
|
||||
# ---------- Internal utils ----------
|
||||
capitano.command(actions.internal.osInit)
|
||||
capitano.command(actions.internal.scanDevices)
|
||||
capitano.command(actions.internal.sudo)
|
||||
|
||||
#------------ Local build and deploy -------
|
||||
capitano.command(actions.build)
|
||||
|
54
lib/app.ts
54
lib/app.ts
@ -15,17 +15,63 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { globalInit } from './app-common';
|
||||
import { AppOptions, routeCliFramework } from './preparser';
|
||||
|
||||
/**
|
||||
* CLI entrypoint, but see also `bin/balena` and `bin/balena-dev` which
|
||||
* call this function.
|
||||
*/
|
||||
export async function run(cliArgs = process.argv, options: AppOptions = {}) {
|
||||
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');
|
||||
|
||||
// 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.
|
||||
globalInit();
|
||||
await routeCliFramework(cliArgs, options);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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);
|
||||
}
|
||||
}
|
||||
|
@ -20,11 +20,10 @@ import chalk from 'chalk';
|
||||
import _ = require('lodash');
|
||||
import os = require('os');
|
||||
import visuals = require('resin-cli-visuals');
|
||||
import rindle = require('rindle');
|
||||
import * as ShellEscape from 'shell-escape';
|
||||
|
||||
import { InitializeEmitter, OperationState } from 'balena-device-init';
|
||||
|
||||
const waitStreamAsync = Bluebird.promisify(rindle.wait);
|
||||
const balena = BalenaSdk.fromSharedOptions();
|
||||
|
||||
export function getGroupDefaults(group: {
|
||||
@ -59,19 +58,44 @@ export function stateToString(state: OperationState) {
|
||||
}
|
||||
}
|
||||
|
||||
export function sudo(
|
||||
/**
|
||||
* Execute a child process with admin / superuser privileges, prompting the user for
|
||||
* elevation as needed, and taking care of shell-escaping arguments in a suitable way
|
||||
* for Windows and Linux/Mac.
|
||||
*
|
||||
* @param command Unescaped array of command and args to be executed. If isCLIcmd is
|
||||
* true, the command should not include the 'node' or 'balena' components, for example:
|
||||
* ['internal', 'osinit', ...]. This function will add argv[0] and argv[1] as needed
|
||||
* (taking process.pkg into account -- CLI standalone zip package), and will also
|
||||
* shell-escape the arguments as needed, taking into account the differences between
|
||||
* bash/sh and the Windows cmd.exe in relation to escape characters.
|
||||
* @param msg Optional message for the user, before the password prompt
|
||||
* @param stderr Optional stream to which stderr should be piped
|
||||
* @param isCLIcmd (default: true) Whether the command array is a balena CLI command
|
||||
* (e.g. ['internal', 'osinit', ...]), in which case process.argv[0] and argv[1] are
|
||||
* added as necessary, depending on whether the CLI is running as a standalone zip
|
||||
* package (with Node built in).
|
||||
*/
|
||||
export async function sudo(
|
||||
command: string[],
|
||||
{ stderr, msg }: { stderr?: NodeJS.WritableStream; msg?: string } = {},
|
||||
{
|
||||
stderr,
|
||||
msg,
|
||||
isCLIcmd,
|
||||
}: { stderr?: NodeJS.WritableStream; msg?: string; isCLIcmd?: boolean } = {},
|
||||
) {
|
||||
const { executeWithPrivileges } = require('./sudo');
|
||||
const { executeWithPrivileges } = await import('./sudo');
|
||||
|
||||
if (os.platform() !== 'win32') {
|
||||
console.log(
|
||||
msg || 'If asked please type your computer password to continue',
|
||||
msg ||
|
||||
'Admin privileges required: you may be asked for your computer password to continue.',
|
||||
);
|
||||
}
|
||||
|
||||
return executeWithPrivileges(command, stderr);
|
||||
if (isCLIcmd == null) {
|
||||
isCLIcmd = true;
|
||||
}
|
||||
await executeWithPrivileges(command, stderr, isCLIcmd);
|
||||
}
|
||||
|
||||
export function runCommand(command: string): Bluebird<void> {
|
||||
@ -106,7 +130,7 @@ export async function getOsVersion(
|
||||
return init.getImageOsVersion(image, manifest);
|
||||
}
|
||||
|
||||
export function osProgressHandler(step: InitializeEmitter) {
|
||||
export async function osProgressHandler(step: InitializeEmitter) {
|
||||
step.on('stdout', process.stdout.write.bind(process.stdout));
|
||||
step.on('stderr', process.stderr.write.bind(process.stderr));
|
||||
|
||||
@ -124,7 +148,10 @@ export function osProgressHandler(step: InitializeEmitter) {
|
||||
|
||||
step.on('burn', state => progressBars[state.type].update(state));
|
||||
|
||||
return waitStreamAsync(step);
|
||||
await new Promise((resolve, reject) => {
|
||||
step.on('error', reject);
|
||||
step.on('end', resolve);
|
||||
});
|
||||
}
|
||||
|
||||
export function getArchAndDeviceType(
|
||||
@ -272,3 +299,50 @@ export function getManualSortCompareFunction<T, U = T>(
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Shell argument escaping compatible with sh, bash and Windows cmd.exe.
|
||||
* @param arg Arguments to be escaped
|
||||
* @param detectShell Whether to use the SHELL and ComSpec environment
|
||||
* variables to determine the shell type (sh / bash / cmd.exe). This may be
|
||||
* useful to detect MSYS / MSYS2, which use bash on Windows. However, if the
|
||||
* purpose is to use child_process.spawn(..., {shell: true}) and related
|
||||
* functions, set this to false because child_process.spawn() always uses
|
||||
* env.ComSpec (cmd.exe) on Windows, even when running on MSYS / MSYS2.
|
||||
*/
|
||||
export function shellEscape(args: string[], detectShell = false): string[] {
|
||||
let isWindowsCmdExeShell: boolean;
|
||||
if (detectShell) {
|
||||
isWindowsCmdExeShell =
|
||||
// neither bash nor sh (e.g. not MSYS, MSYS2, WSL)
|
||||
process.env.SHELL == null &&
|
||||
// Windows cmd.exe or PowerShell
|
||||
process.env.ComSpec != null &&
|
||||
process.env.ComSpec.endsWith('cmd.exe');
|
||||
} else {
|
||||
isWindowsCmdExeShell = process.platform === 'win32';
|
||||
}
|
||||
if (isWindowsCmdExeShell) {
|
||||
return args.map(v => windowsCmdExeEscapeArg(v));
|
||||
} else {
|
||||
const shellEscapeFunc: typeof ShellEscape = require('shell-escape');
|
||||
return args.map(v => shellEscapeFunc([v]));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Escape a string argument to be passed through the Windows cmd.exe shell.
|
||||
* cmd.exe escaping has some peculiarities, like using the caret character
|
||||
* instead of a backslash for reserved / metacharacters. Reference:
|
||||
* https://blogs.msdn.microsoft.com/twistylittlepassagesallalike/2011/04/23/everyone-quotes-command-line-arguments-the-wrong-way/
|
||||
*/
|
||||
function windowsCmdExeEscapeArg(arg: string): string {
|
||||
// if it is already double quoted, remove the double quotes
|
||||
if (arg.length > 1 && arg.startsWith('"') && arg.endsWith('"')) {
|
||||
arg = arg.slice(1, -1);
|
||||
}
|
||||
// escape cmd.exe metacharacters with the '^' (caret) character
|
||||
arg = arg.replace(/[()%!^<>&|]/g, '^$&');
|
||||
// duplicate internal double quotes, and double quote overall
|
||||
return `"${arg.replace(/["]/g, '""')}"`;
|
||||
}
|
||||
|
@ -174,7 +174,7 @@ async function getOrSelectLocalDevice(deviceIp?: string): Promise<string> {
|
||||
stream.pipe(process.stderr);
|
||||
|
||||
const { sudo } = await import('../utils/helpers');
|
||||
const command = process.argv.slice(0, 2).concat(['internal', 'scandevices']);
|
||||
const command = ['internal', 'scandevices'];
|
||||
await sudo(command, {
|
||||
stderr: stream,
|
||||
msg:
|
||||
|
@ -14,34 +14,107 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import { spawn, StdioOptions } from 'child_process';
|
||||
|
||||
import * as Bluebird from 'bluebird';
|
||||
import * as rindle from 'rindle';
|
||||
import { ChildProcess, spawn, SpawnOptions } from 'child_process';
|
||||
import { stripIndent } from 'common-tags';
|
||||
import * as _ from 'lodash';
|
||||
|
||||
/**
|
||||
* Execute a child process with admin / superuser privileges, prompting the user for
|
||||
* elevation as needed, and taking care of shell-escaping arguments in a suitable way
|
||||
* for Windows and Linux/Mac.
|
||||
*
|
||||
* @param command Unescaped array of command and args to be executed. If isCLIcmd is
|
||||
* true, the command should not include the 'node' or 'balena' components, for
|
||||
* example: ['internal', 'osinit', ...]. This function will add argv[0] and argv[1]
|
||||
* as needed (taking process.pkg into account -- CLI standalone zip package), and
|
||||
* will also shell-escape the arguments as needed, taking into account the
|
||||
* differences between bash/sh and the Windows cmd.exe in relation to escape
|
||||
* characters.
|
||||
* @param stderr Optional stream to which stderr should be piped
|
||||
* @param isCLIcmd (default: true) Whether the command array is a balena CLI command
|
||||
* (e.g. ['internal', 'osinit', ...]), in which case process.argv[0] and argv[1] are
|
||||
* added as necessary, depending on whether the CLI is running as a standalone zip
|
||||
* package (with Node built in).
|
||||
*/
|
||||
export async function executeWithPrivileges(
|
||||
command: string[],
|
||||
stderr?: NodeJS.WritableStream,
|
||||
): Promise<string> {
|
||||
const stdio: StdioOptions = [
|
||||
'inherit',
|
||||
'inherit',
|
||||
stderr ? 'pipe' : 'inherit',
|
||||
];
|
||||
const opts = {
|
||||
isCLIcmd = true,
|
||||
): Promise<void> {
|
||||
// whether the CLI is already running with admin / super user privileges
|
||||
const isElevated = await (await import('is-elevated'))();
|
||||
const { shellEscape } = await import('./helpers');
|
||||
const opts: SpawnOptions = {
|
||||
env: process.env,
|
||||
stdio,
|
||||
stdio: ['inherit', 'inherit', stderr ? 'pipe' : 'inherit'],
|
||||
};
|
||||
|
||||
const args = process.argv
|
||||
.slice(0, 2)
|
||||
.concat(['internal', 'sudo', command.join(' ')]);
|
||||
|
||||
const ps = spawn(args[0], args.slice(1), opts);
|
||||
|
||||
if (stderr) {
|
||||
ps.stderr.pipe(stderr);
|
||||
if (isElevated) {
|
||||
if (isCLIcmd) {
|
||||
// opts.shell is false, so preserve pkg's '/snapshot' at argv[1]
|
||||
command = [process.argv[0], process.argv[1], ...command];
|
||||
}
|
||||
// already running with privileges: simply spawn the command
|
||||
await spawnAndPipe(command[0], command.slice(1), opts, stderr);
|
||||
} else {
|
||||
if (isCLIcmd) {
|
||||
// In the case of a CLI standalone zip package (process.pkg is truthy),
|
||||
// the Node executable is bundled with the source code and node_modules
|
||||
// folder in a single file named in argv[0]. In this case, argv[1]
|
||||
// contains a "/snapshot" path that should be discarded when opts.shell
|
||||
// is true.
|
||||
command = (process as any).pkg
|
||||
? [process.argv[0], ...command]
|
||||
: [process.argv[0], process.argv[1], ...command];
|
||||
}
|
||||
opts.shell = true;
|
||||
const escapedCmd = shellEscape(command);
|
||||
// running as ordinary user: elevate privileges
|
||||
if (process.platform === 'win32') {
|
||||
await windosuExec(escapedCmd, stderr);
|
||||
} else {
|
||||
await spawnAndPipe('sudo', escapedCmd, opts, stderr);
|
||||
}
|
||||
}
|
||||
|
||||
return Bluebird.fromCallback<string>(callback => rindle.wait(ps, callback));
|
||||
}
|
||||
|
||||
async function spawnAndPipe(
|
||||
spawnCmd: string,
|
||||
spawnArgs: string[],
|
||||
spawnOpts: SpawnOptions,
|
||||
stderr?: NodeJS.WritableStream,
|
||||
) {
|
||||
await new Promise((resolve, reject) => {
|
||||
const ps: ChildProcess = spawn(spawnCmd, spawnArgs, spawnOpts);
|
||||
ps.on('error', reject);
|
||||
ps.on('exit', codeOrSignal => {
|
||||
if (codeOrSignal !== 0) {
|
||||
const errMsgCmd = `[${[spawnCmd, ...spawnArgs].join()}]`;
|
||||
reject(
|
||||
new Error(
|
||||
`Child process exited with error code "${codeOrSignal}" for command:\n${errMsgCmd}`,
|
||||
),
|
||||
);
|
||||
} else {
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
if (stderr) {
|
||||
ps.stderr.pipe(stderr);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
async function windosuExec(
|
||||
escapedArgs: string[],
|
||||
stderr?: NodeJS.WritableStream,
|
||||
): Promise<void> {
|
||||
if (stderr) {
|
||||
const msg = stripIndent`
|
||||
Error: unable to elevate privileges. Please run the command prompt as an Administrator:
|
||||
https://www.howtogeek.com/194041/how-to-open-the-command-prompt-as-administrator-in-windows-8.1/
|
||||
`;
|
||||
throw new Error(msg);
|
||||
}
|
||||
return require('windosu').exec(escapedArgs.join(' '));
|
||||
}
|
||||
|
68
npm-shrinkwrap.json
generated
68
npm-shrinkwrap.json
generated
@ -2704,6 +2704,20 @@
|
||||
"version": "1.5.2",
|
||||
"resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz",
|
||||
"integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo="
|
||||
},
|
||||
"is-elevated": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/is-elevated/-/is-elevated-1.0.0.tgz",
|
||||
"integrity": "sha1-+IThcowajY1ez2I/iHM8bm7h4u4=",
|
||||
"requires": {
|
||||
"is-admin": "^1.0.2",
|
||||
"is-root": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"is-root": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/is-root/-/is-root-1.0.0.tgz",
|
||||
"integrity": "sha1-B7bCM7w5TNnQK6FclmvWZg1jQtU="
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -7599,12 +7613,22 @@
|
||||
"integrity": "sha1-YTObbyR1/Hcv2cnYP1yFddwVSuE="
|
||||
},
|
||||
"is-elevated": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/is-elevated/-/is-elevated-1.0.0.tgz",
|
||||
"integrity": "sha1-+IThcowajY1ez2I/iHM8bm7h4u4=",
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/is-elevated/-/is-elevated-3.0.0.tgz",
|
||||
"integrity": "sha512-wjcp6RkouU9jpg55zERl+BglvV5j4jx5c/EMvQ+d12j/+nIEenNWPu+qc0tCg3JkLodbKZMg1qhJzEwG4qjclg==",
|
||||
"requires": {
|
||||
"is-admin": "^1.0.2",
|
||||
"is-root": "^1.0.0"
|
||||
"is-admin": "^3.0.0",
|
||||
"is-root": "^2.1.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"is-admin": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/is-admin/-/is-admin-3.0.0.tgz",
|
||||
"integrity": "sha512-wOa3CXFJAu8BZ2BDtG9xYOOrsq6oiSvc2jFPy4X/HINx5bmJUcW8e+apItVbU2E7GIfBVaFVO7Zit4oAWtTJcw==",
|
||||
"requires": {
|
||||
"execa": "^1.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"is-extendable": {
|
||||
@ -7741,9 +7765,9 @@
|
||||
"integrity": "sha1-EaBgVotnM5REAz0BJaYaINVk+zQ="
|
||||
},
|
||||
"is-root": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/is-root/-/is-root-1.0.0.tgz",
|
||||
"integrity": "sha1-B7bCM7w5TNnQK6FclmvWZg1jQtU="
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/is-root/-/is-root-2.1.0.tgz",
|
||||
"integrity": "sha512-AGOriNp96vNBd3HtU+RzFEc75FfR5ymiYv8E553I71SCeXBiMsVDUtdio1OEFvrPyLIQ9tVR5RxXIFe5PUFjMg=="
|
||||
},
|
||||
"is-scoped": {
|
||||
"version": "1.0.0",
|
||||
@ -14993,15 +15017,15 @@
|
||||
}
|
||||
},
|
||||
"resin-cli-visuals": {
|
||||
"version": "1.4.3",
|
||||
"resolved": "https://registry.npmjs.org/resin-cli-visuals/-/resin-cli-visuals-1.4.3.tgz",
|
||||
"integrity": "sha512-vzj6iTdWd0zq1pRXNJZmgMPL6cKS66lLOZlT4lr2kam/ohWFRQNZfmwigZRbrtUOOtBwdVujqSqYAP9USjX9NQ==",
|
||||
"version": "1.4.4",
|
||||
"resolved": "https://registry.npmjs.org/resin-cli-visuals/-/resin-cli-visuals-1.4.4.tgz",
|
||||
"integrity": "sha512-EchgufKC2loXoxB4xjnFtR2bJZbR5xNtJ/pVLc8G2But45TwgkORC5RDbWNe6fCdXJvgWFW1RgZ0Z0tc7Zd+Nw==",
|
||||
"requires": {
|
||||
"bluebird": "^3.5.1",
|
||||
"chalk": "^2.3.1",
|
||||
"cli-spinner": "0.2.7",
|
||||
"columnify": "^1.5.1",
|
||||
"drivelist": "^8.0.6",
|
||||
"drivelist": "^8.0.7",
|
||||
"inquirer": "^0.11.0",
|
||||
"inquirer-dynamic-list": "^1.0.0",
|
||||
"is-promise": "^2.1.0",
|
||||
@ -15041,14 +15065,14 @@
|
||||
}
|
||||
},
|
||||
"drivelist": {
|
||||
"version": "8.0.6",
|
||||
"resolved": "https://registry.npmjs.org/drivelist/-/drivelist-8.0.6.tgz",
|
||||
"integrity": "sha512-KkXaGslqZP7Y13rofyFZBUl9dQrs0wqT5aXq5PAr67uPE2IDXEUYH+LNGTv69xpd7cUImjQvvB9H4bkziLIs1w==",
|
||||
"version": "8.0.7",
|
||||
"resolved": "https://registry.npmjs.org/drivelist/-/drivelist-8.0.7.tgz",
|
||||
"integrity": "sha512-KgFVzXux+rdRjzt1b1Vv4btqCmB/XC0wOfodtUev9MkJcL8VyxjTsopt+lE3GlSv4M+XPgS9dqf9fBowJ8I/2w==",
|
||||
"requires": {
|
||||
"bindings": "^1.3.0",
|
||||
"debug": "^3.1.0",
|
||||
"mz": "^2.7.0",
|
||||
"nan": "^2.10.0",
|
||||
"nan": "^2.14.0",
|
||||
"prebuild-install": "^5.2.4"
|
||||
}
|
||||
},
|
||||
@ -15099,6 +15123,11 @@
|
||||
"resolved": "https://registry.npmjs.org/lodash/-/lodash-3.10.1.tgz",
|
||||
"integrity": "sha1-W/Rejkm6QYnhfUgnid/RW9FAt7Y="
|
||||
},
|
||||
"nan": {
|
||||
"version": "2.14.0",
|
||||
"resolved": "https://registry.npmjs.org/nan/-/nan-2.14.0.tgz",
|
||||
"integrity": "sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg=="
|
||||
},
|
||||
"run-async": {
|
||||
"version": "0.1.0",
|
||||
"resolved": "https://registry.npmjs.org/run-async/-/run-async-0.1.0.tgz",
|
||||
@ -17839,13 +17868,14 @@
|
||||
}
|
||||
},
|
||||
"windosu": {
|
||||
"version": "0.2.0",
|
||||
"resolved": "https://registry.npmjs.org/windosu/-/windosu-0.2.0.tgz",
|
||||
"integrity": "sha1-oqGqymWHczDqCxtoXvPACQIKY4k=",
|
||||
"version": "0.3.0",
|
||||
"resolved": "https://registry.npmjs.org/windosu/-/windosu-0.3.0.tgz",
|
||||
"integrity": "sha1-Bhx/5KgRikrZ9P420/kA0ivApHk=",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"cli-width": "^1.1.0",
|
||||
"q": "~0.9.7",
|
||||
"rimraf": "^2.5.2",
|
||||
"tail": "~0.3.1",
|
||||
"temp": "~0.6.0"
|
||||
},
|
||||
|
13
package.json
13
package.json
@ -33,7 +33,9 @@
|
||||
"build/actions-oclif",
|
||||
"build/auth/pages/*.ejs",
|
||||
"build/hooks",
|
||||
"node_modules/resin-discoverable-services/services/**/*"
|
||||
"node_modules/resin-discoverable-services/services/**/*",
|
||||
"node_modules/windosu/*.bat",
|
||||
"node_modules/windosu/*.cmd"
|
||||
]
|
||||
},
|
||||
"scripts": {
|
||||
@ -135,7 +137,6 @@
|
||||
"publish-release": "^1.6.0",
|
||||
"resin-lint": "^3.0.1",
|
||||
"rewire": "^3.0.2",
|
||||
"shell-escape": "^0.2.0",
|
||||
"sinon": "^7.4.1",
|
||||
"ts-node": "^8.1.0",
|
||||
"typescript": "^3.4.5"
|
||||
@ -184,7 +185,8 @@
|
||||
"humanize": "0.0.9",
|
||||
"ignore": "^5.1.1",
|
||||
"inquirer": "^3.1.1",
|
||||
"is-root": "^1.0.0",
|
||||
"is-elevated": "^3.0.0",
|
||||
"is-root": "^2.1.0",
|
||||
"js-yaml": "^3.13.1",
|
||||
"klaw": "^3.0.0",
|
||||
"livepush": "^2.0.1",
|
||||
@ -205,7 +207,7 @@
|
||||
"reconfix": "^0.1.0",
|
||||
"request": "^2.81.0",
|
||||
"resin-cli-form": "^2.0.1",
|
||||
"resin-cli-visuals": "^1.4.0",
|
||||
"resin-cli-visuals": "^1.4.4",
|
||||
"resin-compose-parse": "^2.1.0",
|
||||
"resin-doodles": "0.0.1",
|
||||
"resin-image-fs": "^5.0.8",
|
||||
@ -216,6 +218,7 @@
|
||||
"rimraf": "^2.4.3",
|
||||
"rindle": "^1.3.4",
|
||||
"semver": "^5.7.0",
|
||||
"shell-escape": "^0.2.0",
|
||||
"split": "^1.0.1",
|
||||
"string-width": "^2.1.1",
|
||||
"strip-ansi-stream": "^1.0.0",
|
||||
@ -231,6 +234,6 @@
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"net-keepalive": "^1.2.1",
|
||||
"windosu": "^0.2.0"
|
||||
"windosu": "^0.3.0"
|
||||
}
|
||||
}
|
||||
|
38
patches/windosu+0.3.0.patch
Normal file
38
patches/windosu+0.3.0.patch
Normal file
@ -0,0 +1,38 @@
|
||||
diff --git a/node_modules/windosu/lib/pipe.js b/node_modules/windosu/lib/pipe.js
|
||||
index dc81fa5..a381cc7 100644
|
||||
--- a/node_modules/windosu/lib/pipe.js
|
||||
+++ b/node_modules/windosu/lib/pipe.js
|
||||
@@ -42,7 +42,8 @@ function pipe(path, options) {
|
||||
return d.promise;
|
||||
}
|
||||
module.exports = pipe;
|
||||
-if (module === require.main) {
|
||||
+
|
||||
+function main() {
|
||||
if (!process.argv[4]) {
|
||||
console.error('Incorrect arguments!');
|
||||
process.exit(-1);
|
||||
@@ -52,3 +53,8 @@ if (module === require.main) {
|
||||
serve: process.argv[3] == 'server'
|
||||
});
|
||||
}
|
||||
+module.exports.main = main;
|
||||
+
|
||||
+if (module === require.main) {
|
||||
+ main();
|
||||
+}
|
||||
diff --git a/node_modules/windosu/lib/windosu.js b/node_modules/windosu/lib/windosu.js
|
||||
index 6502812..dd0391a 100644
|
||||
--- a/node_modules/windosu/lib/windosu.js
|
||||
+++ b/node_modules/windosu/lib/windosu.js
|
||||
@@ -16,7 +16,9 @@ module.exports.exec = function (command, options, callback) {
|
||||
temp: temp,
|
||||
command: command,
|
||||
cliWidth: cliWidth(),
|
||||
- pipe: '"' + process.execPath + '" "' + path.join(__dirname, 'pipe.js') + '"',
|
||||
+ pipe: process.pkg
|
||||
+ ? '"' + process.execPath + '" pkgExec "' + path.join(__dirname, 'pipe.js') + '::main"'
|
||||
+ : '"' + process.execPath + '" "' + path.join(__dirname, 'pipe.js') + '"',
|
||||
input: inputName = id + '-in',
|
||||
output: outputName = id + '-out',
|
||||
stderr_redir: process.stdout.isTTY ? '2>&1' : '2> %ERROR%'
|
2
typings/balena-device-init/index.d.ts
vendored
2
typings/balena-device-init/index.d.ts
vendored
@ -75,6 +75,8 @@ declare module 'balena-device-init' {
|
||||
on(event: 'stdout' | 'stderr', callback: (msg: string) => void): void;
|
||||
on(event: 'state', callback: (state: OperationState) => void): void;
|
||||
on(event: 'burn', callback: (state: BurnProgress) => void): void;
|
||||
on(event: 'end', callback: () => void): void;
|
||||
on(event: 'error', callback: (error: Error) => void): void;
|
||||
}
|
||||
|
||||
export function configure(
|
||||
|
Loading…
Reference in New Issue
Block a user