Skip to content

Commit

Permalink
child_process: refactor to use more primordials
Browse files Browse the repository at this point in the history
PR-URL: #36269
Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com>
  • Loading branch information
Lxxyx authored and nodejs-github-bot committed Dec 3, 2020
1 parent a897a25 commit f7dd330
Show file tree
Hide file tree
Showing 2 changed files with 81 additions and 54 deletions.
77 changes: 48 additions & 29 deletions lib/child_process.js
Expand Up @@ -23,13 +23,25 @@

const {
ArrayIsArray,
ArrayPrototypeFilter,
ArrayPrototypeIncludes,
ArrayPrototypeJoin,
ArrayPrototypeLastIndexOf,
ArrayPrototypePush,
ArrayPrototypeSlice,
ArrayPrototypeSort,
ArrayPrototypeSplice,
ArrayPrototypeUnshift,
Error,
NumberIsInteger,
ObjectAssign,
ObjectDefineProperty,
ObjectPrototypeHasOwnProperty,
Promise,
Set,
RegExpPrototypeTest,
SafeSet,
StringPrototypeSlice,
StringPrototypeToUpperCase,
} = primordials;

const {
Expand Down Expand Up @@ -94,15 +106,15 @@ function fork(modulePath /* , args, options */) {
execArgv = options.execArgv || process.execArgv;

if (execArgv === process.execArgv && process._eval != null) {
const index = execArgv.lastIndexOf(process._eval);
const index = ArrayPrototypeLastIndexOf(execArgv, process._eval);
if (index > 0) {
// Remove the -e switch to avoid fork bombing ourselves.
execArgv = execArgv.slice();
execArgv.splice(index - 1, 2);
execArgv = ArrayPrototypeSlice(execArgv);
ArrayPrototypeSplice(execArgv, index - 1, 2);
}
}

args = execArgv.concat([modulePath], args);
args = [...execArgv, modulePath, ...args];

if (typeof options.stdio === 'string') {
options.stdio = stdioStringToArray(options.stdio, 'ipc');
Expand All @@ -112,7 +124,7 @@ function fork(modulePath /* , args, options */) {
options.stdio = stdioStringToArray(
options.silent ? 'pipe' : 'inherit',
'ipc');
} else if (!options.stdio.includes('ipc')) {
} else if (!ArrayPrototypeIncludes(options.stdio, 'ipc')) {
throw new ERR_CHILD_PROCESS_IPC_REQUIRED('options.stdio');
}

Expand Down Expand Up @@ -282,7 +294,7 @@ function execFile(file /* , args, options, callback */) {
child.stdout &&
child.stdout.readableEncoding
)) {
stdout = _stdout.join('');
stdout = ArrayPrototypeJoin(_stdout, '');
} else {
stdout = Buffer.concat(_stdout);
}
Expand All @@ -291,7 +303,7 @@ function execFile(file /* , args, options, callback */) {
child.stderr &&
child.stderr.readableEncoding
)) {
stderr = _stderr.join('');
stderr = ArrayPrototypeJoin(_stderr, '');
} else {
stderr = Buffer.concat(_stderr);
}
Expand All @@ -302,7 +314,7 @@ function execFile(file /* , args, options, callback */) {
}

if (args.length !== 0)
cmd += ` ${args.join(' ')}`;
cmd += ` ${ArrayPrototypeJoin(args, ' ')}`;

if (!ex) {
// eslint-disable-next-line no-restricted-syntax
Expand Down Expand Up @@ -360,16 +372,18 @@ function execFile(file /* , args, options, callback */) {
const length = encoding ?
Buffer.byteLength(chunk, encoding) :
chunk.length;
const slice = encoding ? StringPrototypeSlice :
(buf, ...args) => buf.slice(...args);
stdoutLen += length;

if (stdoutLen > options.maxBuffer) {
const truncatedLen = options.maxBuffer - (stdoutLen - length);
_stdout.push(chunk.slice(0, truncatedLen));
ArrayPrototypePush(_stdout, slice(chunk, 0, truncatedLen));

ex = new ERR_CHILD_PROCESS_STDIO_MAXBUFFER('stdout');
kill();
} else {
_stdout.push(chunk);
ArrayPrototypePush(_stdout, chunk);
}
});
}
Expand All @@ -387,7 +401,8 @@ function execFile(file /* , args, options, callback */) {

if (stderrLen > options.maxBuffer) {
const truncatedLen = options.maxBuffer - (stderrLen - length);
_stderr.push(chunk.slice(0, truncatedLen));
ArrayPrototypePush(_stderr,
chunk.slice(0, truncatedLen));

ex = new ERR_CHILD_PROCESS_STDIO_MAXBUFFER('stderr');
kill();
Expand Down Expand Up @@ -415,7 +430,7 @@ function normalizeSpawnArguments(file, args, options) {
throw new ERR_INVALID_ARG_VALUE('file', file, 'cannot be empty');

if (ArrayIsArray(args)) {
args = args.slice(0);
args = ArrayPrototypeSlice(args);
} else if (args == null) {
args = [];
} else if (typeof args !== 'object') {
Expand Down Expand Up @@ -484,15 +499,15 @@ function normalizeSpawnArguments(file, args, options) {
}

if (options.shell) {
const command = [file].concat(args).join(' ');
const command = ArrayPrototypeJoin([file, ...args], ' ');
// Set the shell, switches, and commands.
if (process.platform === 'win32') {
if (typeof options.shell === 'string')
file = options.shell;
else
file = process.env.comspec || 'cmd.exe';
// '/d /s /c' is used only for cmd.exe.
if (/^(?:.*\\)?cmd(?:\.exe)?$/i.test(file)) {
if (RegExpPrototypeTest(/^(?:.*\\)?cmd(?:\.exe)?$/i, file)) {
args = ['/d', '/s', '/c', `"${command}"`];
windowsVerbatimArguments = true;
} else {
Expand All @@ -510,9 +525,9 @@ function normalizeSpawnArguments(file, args, options) {
}

if (typeof options.argv0 === 'string') {
args.unshift(options.argv0);
ArrayPrototypeUnshift(args, options.argv0);
} else {
args.unshift(file);
ArrayPrototypeUnshift(args, file);
}

const env = options.env || process.env;
Expand All @@ -528,27 +543,30 @@ function normalizeSpawnArguments(file, args, options) {
let envKeys = [];
// Prototype values are intentionally included.
for (const key in env) {
envKeys.push(key);
ArrayPrototypePush(envKeys, key);
}

if (process.platform === 'win32') {
// On Windows env keys are case insensitive. Filter out duplicates,
// keeping only the first one (in lexicographic order)
const sawKey = new Set();
envKeys = envKeys.sort().filter((key) => {
const uppercaseKey = key.toUpperCase();
if (sawKey.has(uppercaseKey)) {
return false;
const sawKey = new SafeSet();
envKeys = ArrayPrototypeFilter(
ArrayPrototypeSort(envKeys),
(key) => {
const uppercaseKey = StringPrototypeToUpperCase(key);
if (sawKey.has(uppercaseKey)) {
return false;
}
sawKey.add(uppercaseKey);
return true;
}
sawKey.add(uppercaseKey);
return true;
});
);
}

for (const key of envKeys) {
const value = env[key];
if (value !== undefined) {
envPairs.push(`${key}=${value}`);
ArrayPrototypePush(envPairs, `${key}=${value}`);
}
}

Expand Down Expand Up @@ -629,7 +647,7 @@ function checkExecSyncError(ret, args, cmd) {
err = ret.error;
} else if (ret.status !== 0) {
let msg = 'Command failed: ';
msg += cmd || args.join(' ');
msg += cmd || ArrayPrototypeJoin(args, ' ');
if (ret.stderr && ret.stderr.length > 0)
msg += `\n${ret.stderr.toString()}`;
// eslint-disable-next-line no-restricted-syntax
Expand All @@ -646,7 +664,8 @@ function execFileSync(command, args, options) {
options = normalizeSpawnArguments(command, args, options);

const inheritStderr = !options.stdio;
const ret = spawnSync(options.file, options.args.slice(1), options);
const ret = spawnSync(options.file,
ArrayPrototypeSlice(options.args, 1), options);

if (inheritStderr && ret.stderr)
process.stderr.write(ret.stderr);
Expand Down

0 comments on commit f7dd330

Please sign in to comment.