@karmaniverous/get-dotenv 4.4.2 → 4.4.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/getdotenv.cli.mjs +1866 -679
- package/dist/index.cjs +1862 -675
- package/dist/index.mjs +1866 -679
- package/package.json +17 -13
package/dist/index.cjs
CHANGED
|
@@ -14,6 +14,7 @@ var require$$0$2 = require('path');
|
|
|
14
14
|
var require$$0$1 = require('fs');
|
|
15
15
|
var promises = require('node:timers/promises');
|
|
16
16
|
var node_os = require('node:os');
|
|
17
|
+
var node_v8 = require('node:v8');
|
|
17
18
|
var node_stream = require('node:stream');
|
|
18
19
|
var node_buffer = require('node:buffer');
|
|
19
20
|
var promises$1 = require('node:stream/promises');
|
|
@@ -4463,64 +4464,6 @@ const fallbackSymbols = {...common$7, ...specialFallbackSymbols};
|
|
|
4463
4464
|
const shouldUseMain = isUnicodeSupported();
|
|
4464
4465
|
const figures = shouldUseMain ? mainSymbols : fallbackSymbols;
|
|
4465
4466
|
|
|
4466
|
-
// Write synchronously to ensure lines are properly ordered and not interleaved with `stdout`
|
|
4467
|
-
const verboseLog = (string, verboseId, icon, color) => {
|
|
4468
|
-
const prefixedLines = addPrefix(string, verboseId, icon, color);
|
|
4469
|
-
fs$v.writeFileSync(STDERR_FD, `${prefixedLines}\n`);
|
|
4470
|
-
};
|
|
4471
|
-
|
|
4472
|
-
const STDERR_FD = 2;
|
|
4473
|
-
|
|
4474
|
-
const addPrefix = (string, verboseId, icon, color) => string.includes('\n')
|
|
4475
|
-
? string
|
|
4476
|
-
.split('\n')
|
|
4477
|
-
.map(line => addPrefixToLine(line, verboseId, icon, color))
|
|
4478
|
-
.join('\n')
|
|
4479
|
-
: addPrefixToLine(string, verboseId, icon, color);
|
|
4480
|
-
|
|
4481
|
-
const addPrefixToLine = (line, verboseId, icon, color = identity$1) => [
|
|
4482
|
-
gray(`[${getTimestamp()}]`),
|
|
4483
|
-
gray(`[${verboseId}]`),
|
|
4484
|
-
color(ICONS[icon]),
|
|
4485
|
-
color(line),
|
|
4486
|
-
].join(' ');
|
|
4487
|
-
|
|
4488
|
-
const identity$1 = string => string;
|
|
4489
|
-
|
|
4490
|
-
// Prepending the timestamp allows debugging the slow paths of a subprocess
|
|
4491
|
-
const getTimestamp = () => {
|
|
4492
|
-
const date = new Date();
|
|
4493
|
-
return `${padField(date.getHours(), 2)}:${padField(date.getMinutes(), 2)}:${padField(date.getSeconds(), 2)}.${padField(date.getMilliseconds(), 3)}`;
|
|
4494
|
-
};
|
|
4495
|
-
|
|
4496
|
-
const padField = (field, padding) => String(field).padStart(padding, '0');
|
|
4497
|
-
|
|
4498
|
-
const ICONS = {
|
|
4499
|
-
command: '$',
|
|
4500
|
-
pipedCommand: '|',
|
|
4501
|
-
output: ' ',
|
|
4502
|
-
error: figures.cross,
|
|
4503
|
-
warning: figures.warning,
|
|
4504
|
-
success: figures.tick,
|
|
4505
|
-
};
|
|
4506
|
-
|
|
4507
|
-
// When `verbose` is `short|full`, print each command
|
|
4508
|
-
const logCommand = (escapedCommand, {verbose, verboseId}, {piped = false}) => {
|
|
4509
|
-
if (!isVerbose(verbose)) {
|
|
4510
|
-
return;
|
|
4511
|
-
}
|
|
4512
|
-
|
|
4513
|
-
const icon = piped ? 'pipedCommand' : 'command';
|
|
4514
|
-
verboseLog(escapedCommand, verboseId, icon, bold);
|
|
4515
|
-
};
|
|
4516
|
-
|
|
4517
|
-
// Start counting time before spawning the subprocess
|
|
4518
|
-
const getStartTime = () => process$3.hrtime.bigint();
|
|
4519
|
-
|
|
4520
|
-
// Compute duration after the subprocess ended.
|
|
4521
|
-
// Printed by the `verbose` option.
|
|
4522
|
-
const getDurationMs = startTime => Number(process$3.hrtime.bigint() - startTime) / 1e6;
|
|
4523
|
-
|
|
4524
4467
|
// Compute `result.command` and `result.escapedCommand`
|
|
4525
4468
|
const joinCommand = (filePath, rawArguments) => {
|
|
4526
4469
|
const fileAndArguments = [filePath, ...rawArguments];
|
|
@@ -4591,6 +4534,75 @@ const quoteString = escapedArgument => {
|
|
|
4591
4534
|
|
|
4592
4535
|
const NO_ESCAPE_REGEXP = /^[\w./-]+$/;
|
|
4593
4536
|
|
|
4537
|
+
// Write synchronously to ensure lines are properly ordered and not interleaved with `stdout`
|
|
4538
|
+
const verboseLog = (string, verboseId, icon, color) => {
|
|
4539
|
+
const prefixedLines = addPrefix(string, verboseId, icon, color);
|
|
4540
|
+
fs$v.writeFileSync(STDERR_FD, `${prefixedLines}\n`);
|
|
4541
|
+
};
|
|
4542
|
+
|
|
4543
|
+
const STDERR_FD = 2;
|
|
4544
|
+
|
|
4545
|
+
const addPrefix = (string, verboseId, icon, color) => string.includes('\n')
|
|
4546
|
+
? string
|
|
4547
|
+
.split('\n')
|
|
4548
|
+
.map(line => addPrefixToLine(line, verboseId, icon, color))
|
|
4549
|
+
.join('\n')
|
|
4550
|
+
: addPrefixToLine(string, verboseId, icon, color);
|
|
4551
|
+
|
|
4552
|
+
const addPrefixToLine = (line, verboseId, icon, color = identity$1) => [
|
|
4553
|
+
gray(`[${getTimestamp()}]`),
|
|
4554
|
+
gray(`[${verboseId}]`),
|
|
4555
|
+
color(ICONS[icon]),
|
|
4556
|
+
color(line),
|
|
4557
|
+
].join(' ');
|
|
4558
|
+
|
|
4559
|
+
const identity$1 = string => string;
|
|
4560
|
+
|
|
4561
|
+
// Prepending the timestamp allows debugging the slow paths of a subprocess
|
|
4562
|
+
const getTimestamp = () => {
|
|
4563
|
+
const date = new Date();
|
|
4564
|
+
return `${padField(date.getHours(), 2)}:${padField(date.getMinutes(), 2)}:${padField(date.getSeconds(), 2)}.${padField(date.getMilliseconds(), 3)}`;
|
|
4565
|
+
};
|
|
4566
|
+
|
|
4567
|
+
const padField = (field, padding) => String(field).padStart(padding, '0');
|
|
4568
|
+
|
|
4569
|
+
const ICONS = {
|
|
4570
|
+
command: '$',
|
|
4571
|
+
pipedCommand: '|',
|
|
4572
|
+
output: ' ',
|
|
4573
|
+
ipc: '*',
|
|
4574
|
+
error: figures.cross,
|
|
4575
|
+
warning: figures.warning,
|
|
4576
|
+
success: figures.tick,
|
|
4577
|
+
};
|
|
4578
|
+
|
|
4579
|
+
// Serialize any type to a line string, for logging
|
|
4580
|
+
const serializeLogMessage = message => {
|
|
4581
|
+
const messageString = typeof message === 'string' ? message : node_util.inspect(message);
|
|
4582
|
+
const escapedMessage = escapeLines(messageString);
|
|
4583
|
+
return escapedMessage.replaceAll('\t', ' '.repeat(TAB_SIZE));
|
|
4584
|
+
};
|
|
4585
|
+
|
|
4586
|
+
// Same as `util.inspect()`
|
|
4587
|
+
const TAB_SIZE = 2;
|
|
4588
|
+
|
|
4589
|
+
// When `verbose` is `short|full`, print each command
|
|
4590
|
+
const logCommand = (escapedCommand, {verbose, verboseId}, {piped = false}) => {
|
|
4591
|
+
if (!isVerbose(verbose)) {
|
|
4592
|
+
return;
|
|
4593
|
+
}
|
|
4594
|
+
|
|
4595
|
+
const icon = piped ? 'pipedCommand' : 'command';
|
|
4596
|
+
verboseLog(escapedCommand, verboseId, icon, bold);
|
|
4597
|
+
};
|
|
4598
|
+
|
|
4599
|
+
// Start counting time before spawning the subprocess
|
|
4600
|
+
const getStartTime = () => process$3.hrtime.bigint();
|
|
4601
|
+
|
|
4602
|
+
// Compute duration after the subprocess ended.
|
|
4603
|
+
// Printed by the `verbose` option.
|
|
4604
|
+
const getDurationMs = startTime => Number(process$3.hrtime.bigint() - startTime) / 1e6;
|
|
4605
|
+
|
|
4594
4606
|
const isStandardStream = stream => STANDARD_STREAMS.includes(stream);
|
|
4595
4607
|
const STANDARD_STREAMS = [process$3.stdin, process$3.stdout, process$3.stderr];
|
|
4596
4608
|
const STANDARD_STREAMS_ALIASES = ['stdin', 'stdout', 'stderr'];
|
|
@@ -4610,7 +4622,7 @@ const normalizeFdSpecificOptions = options => {
|
|
|
4610
4622
|
};
|
|
4611
4623
|
|
|
4612
4624
|
const normalizeFdSpecificOption = (options, optionName) => {
|
|
4613
|
-
const optionBaseArray = Array.from({length: getStdioLength(options)});
|
|
4625
|
+
const optionBaseArray = Array.from({length: getStdioLength(options) + 1});
|
|
4614
4626
|
const optionArray = normalizeFdSpecificValue(options[optionName], optionBaseArray, optionName);
|
|
4615
4627
|
return addDefaultValue$1(optionArray, optionName);
|
|
4616
4628
|
};
|
|
@@ -4645,10 +4657,14 @@ const getFdNameOrder = fdName => {
|
|
|
4645
4657
|
};
|
|
4646
4658
|
|
|
4647
4659
|
const parseFdName = (fdName, optionName, optionArray) => {
|
|
4660
|
+
if (fdName === 'ipc') {
|
|
4661
|
+
return [optionArray.length - 1];
|
|
4662
|
+
}
|
|
4663
|
+
|
|
4648
4664
|
const fdNumber = parseFd(fdName);
|
|
4649
4665
|
if (fdNumber === undefined || fdNumber === 0) {
|
|
4650
4666
|
throw new TypeError(`"${optionName}.${fdName}" is invalid.
|
|
4651
|
-
It must be "${optionName}.stdout", "${optionName}.stderr", "${optionName}.all", or "${optionName}.fd3", "${optionName}.fd4" (and so on).`);
|
|
4667
|
+
It must be "${optionName}.stdout", "${optionName}.stderr", "${optionName}.all", "${optionName}.ipc", or "${optionName}.fd3", "${optionName}.fd4" (and so on).`);
|
|
4652
4668
|
}
|
|
4653
4669
|
|
|
4654
4670
|
if (fdNumber >= optionArray.length) {
|
|
@@ -5442,6 +5458,386 @@ setErrorName(ExecaError, ExecaError.name);
|
|
|
5442
5458
|
class ExecaSyncError extends Error {}
|
|
5443
5459
|
setErrorName(ExecaSyncError, ExecaSyncError.name);
|
|
5444
5460
|
|
|
5461
|
+
const getRealtimeSignals=()=>{
|
|
5462
|
+
const length=SIGRTMAX-SIGRTMIN+1;
|
|
5463
|
+
return Array.from({length},getRealtimeSignal)
|
|
5464
|
+
};
|
|
5465
|
+
|
|
5466
|
+
const getRealtimeSignal=(value,index)=>({
|
|
5467
|
+
name:`SIGRT${index+1}`,
|
|
5468
|
+
number:SIGRTMIN+index,
|
|
5469
|
+
action:"terminate",
|
|
5470
|
+
description:"Application-specific signal (realtime)",
|
|
5471
|
+
standard:"posix"
|
|
5472
|
+
});
|
|
5473
|
+
|
|
5474
|
+
const SIGRTMIN=34;
|
|
5475
|
+
const SIGRTMAX=64;
|
|
5476
|
+
|
|
5477
|
+
const SIGNALS=[
|
|
5478
|
+
{
|
|
5479
|
+
name:"SIGHUP",
|
|
5480
|
+
number:1,
|
|
5481
|
+
action:"terminate",
|
|
5482
|
+
description:"Terminal closed",
|
|
5483
|
+
standard:"posix"
|
|
5484
|
+
},
|
|
5485
|
+
{
|
|
5486
|
+
name:"SIGINT",
|
|
5487
|
+
number:2,
|
|
5488
|
+
action:"terminate",
|
|
5489
|
+
description:"User interruption with CTRL-C",
|
|
5490
|
+
standard:"ansi"
|
|
5491
|
+
},
|
|
5492
|
+
{
|
|
5493
|
+
name:"SIGQUIT",
|
|
5494
|
+
number:3,
|
|
5495
|
+
action:"core",
|
|
5496
|
+
description:"User interruption with CTRL-\\",
|
|
5497
|
+
standard:"posix"
|
|
5498
|
+
},
|
|
5499
|
+
{
|
|
5500
|
+
name:"SIGILL",
|
|
5501
|
+
number:4,
|
|
5502
|
+
action:"core",
|
|
5503
|
+
description:"Invalid machine instruction",
|
|
5504
|
+
standard:"ansi"
|
|
5505
|
+
},
|
|
5506
|
+
{
|
|
5507
|
+
name:"SIGTRAP",
|
|
5508
|
+
number:5,
|
|
5509
|
+
action:"core",
|
|
5510
|
+
description:"Debugger breakpoint",
|
|
5511
|
+
standard:"posix"
|
|
5512
|
+
},
|
|
5513
|
+
{
|
|
5514
|
+
name:"SIGABRT",
|
|
5515
|
+
number:6,
|
|
5516
|
+
action:"core",
|
|
5517
|
+
description:"Aborted",
|
|
5518
|
+
standard:"ansi"
|
|
5519
|
+
},
|
|
5520
|
+
{
|
|
5521
|
+
name:"SIGIOT",
|
|
5522
|
+
number:6,
|
|
5523
|
+
action:"core",
|
|
5524
|
+
description:"Aborted",
|
|
5525
|
+
standard:"bsd"
|
|
5526
|
+
},
|
|
5527
|
+
{
|
|
5528
|
+
name:"SIGBUS",
|
|
5529
|
+
number:7,
|
|
5530
|
+
action:"core",
|
|
5531
|
+
description:
|
|
5532
|
+
"Bus error due to misaligned, non-existing address or paging error",
|
|
5533
|
+
standard:"bsd"
|
|
5534
|
+
},
|
|
5535
|
+
{
|
|
5536
|
+
name:"SIGEMT",
|
|
5537
|
+
number:7,
|
|
5538
|
+
action:"terminate",
|
|
5539
|
+
description:"Command should be emulated but is not implemented",
|
|
5540
|
+
standard:"other"
|
|
5541
|
+
},
|
|
5542
|
+
{
|
|
5543
|
+
name:"SIGFPE",
|
|
5544
|
+
number:8,
|
|
5545
|
+
action:"core",
|
|
5546
|
+
description:"Floating point arithmetic error",
|
|
5547
|
+
standard:"ansi"
|
|
5548
|
+
},
|
|
5549
|
+
{
|
|
5550
|
+
name:"SIGKILL",
|
|
5551
|
+
number:9,
|
|
5552
|
+
action:"terminate",
|
|
5553
|
+
description:"Forced termination",
|
|
5554
|
+
standard:"posix",
|
|
5555
|
+
forced:true
|
|
5556
|
+
},
|
|
5557
|
+
{
|
|
5558
|
+
name:"SIGUSR1",
|
|
5559
|
+
number:10,
|
|
5560
|
+
action:"terminate",
|
|
5561
|
+
description:"Application-specific signal",
|
|
5562
|
+
standard:"posix"
|
|
5563
|
+
},
|
|
5564
|
+
{
|
|
5565
|
+
name:"SIGSEGV",
|
|
5566
|
+
number:11,
|
|
5567
|
+
action:"core",
|
|
5568
|
+
description:"Segmentation fault",
|
|
5569
|
+
standard:"ansi"
|
|
5570
|
+
},
|
|
5571
|
+
{
|
|
5572
|
+
name:"SIGUSR2",
|
|
5573
|
+
number:12,
|
|
5574
|
+
action:"terminate",
|
|
5575
|
+
description:"Application-specific signal",
|
|
5576
|
+
standard:"posix"
|
|
5577
|
+
},
|
|
5578
|
+
{
|
|
5579
|
+
name:"SIGPIPE",
|
|
5580
|
+
number:13,
|
|
5581
|
+
action:"terminate",
|
|
5582
|
+
description:"Broken pipe or socket",
|
|
5583
|
+
standard:"posix"
|
|
5584
|
+
},
|
|
5585
|
+
{
|
|
5586
|
+
name:"SIGALRM",
|
|
5587
|
+
number:14,
|
|
5588
|
+
action:"terminate",
|
|
5589
|
+
description:"Timeout or timer",
|
|
5590
|
+
standard:"posix"
|
|
5591
|
+
},
|
|
5592
|
+
{
|
|
5593
|
+
name:"SIGTERM",
|
|
5594
|
+
number:15,
|
|
5595
|
+
action:"terminate",
|
|
5596
|
+
description:"Termination",
|
|
5597
|
+
standard:"ansi"
|
|
5598
|
+
},
|
|
5599
|
+
{
|
|
5600
|
+
name:"SIGSTKFLT",
|
|
5601
|
+
number:16,
|
|
5602
|
+
action:"terminate",
|
|
5603
|
+
description:"Stack is empty or overflowed",
|
|
5604
|
+
standard:"other"
|
|
5605
|
+
},
|
|
5606
|
+
{
|
|
5607
|
+
name:"SIGCHLD",
|
|
5608
|
+
number:17,
|
|
5609
|
+
action:"ignore",
|
|
5610
|
+
description:"Child process terminated, paused or unpaused",
|
|
5611
|
+
standard:"posix"
|
|
5612
|
+
},
|
|
5613
|
+
{
|
|
5614
|
+
name:"SIGCLD",
|
|
5615
|
+
number:17,
|
|
5616
|
+
action:"ignore",
|
|
5617
|
+
description:"Child process terminated, paused or unpaused",
|
|
5618
|
+
standard:"other"
|
|
5619
|
+
},
|
|
5620
|
+
{
|
|
5621
|
+
name:"SIGCONT",
|
|
5622
|
+
number:18,
|
|
5623
|
+
action:"unpause",
|
|
5624
|
+
description:"Unpaused",
|
|
5625
|
+
standard:"posix",
|
|
5626
|
+
forced:true
|
|
5627
|
+
},
|
|
5628
|
+
{
|
|
5629
|
+
name:"SIGSTOP",
|
|
5630
|
+
number:19,
|
|
5631
|
+
action:"pause",
|
|
5632
|
+
description:"Paused",
|
|
5633
|
+
standard:"posix",
|
|
5634
|
+
forced:true
|
|
5635
|
+
},
|
|
5636
|
+
{
|
|
5637
|
+
name:"SIGTSTP",
|
|
5638
|
+
number:20,
|
|
5639
|
+
action:"pause",
|
|
5640
|
+
description:"Paused using CTRL-Z or \"suspend\"",
|
|
5641
|
+
standard:"posix"
|
|
5642
|
+
},
|
|
5643
|
+
{
|
|
5644
|
+
name:"SIGTTIN",
|
|
5645
|
+
number:21,
|
|
5646
|
+
action:"pause",
|
|
5647
|
+
description:"Background process cannot read terminal input",
|
|
5648
|
+
standard:"posix"
|
|
5649
|
+
},
|
|
5650
|
+
{
|
|
5651
|
+
name:"SIGBREAK",
|
|
5652
|
+
number:21,
|
|
5653
|
+
action:"terminate",
|
|
5654
|
+
description:"User interruption with CTRL-BREAK",
|
|
5655
|
+
standard:"other"
|
|
5656
|
+
},
|
|
5657
|
+
{
|
|
5658
|
+
name:"SIGTTOU",
|
|
5659
|
+
number:22,
|
|
5660
|
+
action:"pause",
|
|
5661
|
+
description:"Background process cannot write to terminal output",
|
|
5662
|
+
standard:"posix"
|
|
5663
|
+
},
|
|
5664
|
+
{
|
|
5665
|
+
name:"SIGURG",
|
|
5666
|
+
number:23,
|
|
5667
|
+
action:"ignore",
|
|
5668
|
+
description:"Socket received out-of-band data",
|
|
5669
|
+
standard:"bsd"
|
|
5670
|
+
},
|
|
5671
|
+
{
|
|
5672
|
+
name:"SIGXCPU",
|
|
5673
|
+
number:24,
|
|
5674
|
+
action:"core",
|
|
5675
|
+
description:"Process timed out",
|
|
5676
|
+
standard:"bsd"
|
|
5677
|
+
},
|
|
5678
|
+
{
|
|
5679
|
+
name:"SIGXFSZ",
|
|
5680
|
+
number:25,
|
|
5681
|
+
action:"core",
|
|
5682
|
+
description:"File too big",
|
|
5683
|
+
standard:"bsd"
|
|
5684
|
+
},
|
|
5685
|
+
{
|
|
5686
|
+
name:"SIGVTALRM",
|
|
5687
|
+
number:26,
|
|
5688
|
+
action:"terminate",
|
|
5689
|
+
description:"Timeout or timer",
|
|
5690
|
+
standard:"bsd"
|
|
5691
|
+
},
|
|
5692
|
+
{
|
|
5693
|
+
name:"SIGPROF",
|
|
5694
|
+
number:27,
|
|
5695
|
+
action:"terminate",
|
|
5696
|
+
description:"Timeout or timer",
|
|
5697
|
+
standard:"bsd"
|
|
5698
|
+
},
|
|
5699
|
+
{
|
|
5700
|
+
name:"SIGWINCH",
|
|
5701
|
+
number:28,
|
|
5702
|
+
action:"ignore",
|
|
5703
|
+
description:"Terminal window size changed",
|
|
5704
|
+
standard:"bsd"
|
|
5705
|
+
},
|
|
5706
|
+
{
|
|
5707
|
+
name:"SIGIO",
|
|
5708
|
+
number:29,
|
|
5709
|
+
action:"terminate",
|
|
5710
|
+
description:"I/O is available",
|
|
5711
|
+
standard:"other"
|
|
5712
|
+
},
|
|
5713
|
+
{
|
|
5714
|
+
name:"SIGPOLL",
|
|
5715
|
+
number:29,
|
|
5716
|
+
action:"terminate",
|
|
5717
|
+
description:"Watched event",
|
|
5718
|
+
standard:"other"
|
|
5719
|
+
},
|
|
5720
|
+
{
|
|
5721
|
+
name:"SIGINFO",
|
|
5722
|
+
number:29,
|
|
5723
|
+
action:"ignore",
|
|
5724
|
+
description:"Request for process information",
|
|
5725
|
+
standard:"other"
|
|
5726
|
+
},
|
|
5727
|
+
{
|
|
5728
|
+
name:"SIGPWR",
|
|
5729
|
+
number:30,
|
|
5730
|
+
action:"terminate",
|
|
5731
|
+
description:"Device running out of power",
|
|
5732
|
+
standard:"systemv"
|
|
5733
|
+
},
|
|
5734
|
+
{
|
|
5735
|
+
name:"SIGSYS",
|
|
5736
|
+
number:31,
|
|
5737
|
+
action:"core",
|
|
5738
|
+
description:"Invalid system call",
|
|
5739
|
+
standard:"other"
|
|
5740
|
+
},
|
|
5741
|
+
{
|
|
5742
|
+
name:"SIGUNUSED",
|
|
5743
|
+
number:31,
|
|
5744
|
+
action:"terminate",
|
|
5745
|
+
description:"Invalid system call",
|
|
5746
|
+
standard:"other"
|
|
5747
|
+
}];
|
|
5748
|
+
|
|
5749
|
+
const getSignals=()=>{
|
|
5750
|
+
const realtimeSignals=getRealtimeSignals();
|
|
5751
|
+
const signals=[...SIGNALS,...realtimeSignals].map(normalizeSignal$1);
|
|
5752
|
+
return signals
|
|
5753
|
+
};
|
|
5754
|
+
|
|
5755
|
+
|
|
5756
|
+
|
|
5757
|
+
|
|
5758
|
+
|
|
5759
|
+
|
|
5760
|
+
|
|
5761
|
+
const normalizeSignal$1=({
|
|
5762
|
+
name,
|
|
5763
|
+
number:defaultNumber,
|
|
5764
|
+
description,
|
|
5765
|
+
action,
|
|
5766
|
+
forced=false,
|
|
5767
|
+
standard
|
|
5768
|
+
})=>{
|
|
5769
|
+
const{
|
|
5770
|
+
signals:{[name]:constantSignal}
|
|
5771
|
+
}=node_os.constants;
|
|
5772
|
+
const supported=constantSignal!==undefined;
|
|
5773
|
+
const number=supported?constantSignal:defaultNumber;
|
|
5774
|
+
return {name,number,description,supported,action,forced,standard}
|
|
5775
|
+
};
|
|
5776
|
+
|
|
5777
|
+
const getSignalsByName=()=>{
|
|
5778
|
+
const signals=getSignals();
|
|
5779
|
+
return Object.fromEntries(signals.map(getSignalByName))
|
|
5780
|
+
};
|
|
5781
|
+
|
|
5782
|
+
const getSignalByName=({
|
|
5783
|
+
name,
|
|
5784
|
+
number,
|
|
5785
|
+
description,
|
|
5786
|
+
supported,
|
|
5787
|
+
action,
|
|
5788
|
+
forced,
|
|
5789
|
+
standard
|
|
5790
|
+
})=>[name,{name,number,description,supported,action,forced,standard}];
|
|
5791
|
+
|
|
5792
|
+
const signalsByName=getSignalsByName();
|
|
5793
|
+
|
|
5794
|
+
|
|
5795
|
+
|
|
5796
|
+
|
|
5797
|
+
const getSignalsByNumber=()=>{
|
|
5798
|
+
const signals=getSignals();
|
|
5799
|
+
const length=SIGRTMAX+1;
|
|
5800
|
+
const signalsA=Array.from({length},(value,number)=>
|
|
5801
|
+
getSignalByNumber(number,signals)
|
|
5802
|
+
);
|
|
5803
|
+
return Object.assign({},...signalsA)
|
|
5804
|
+
};
|
|
5805
|
+
|
|
5806
|
+
const getSignalByNumber=(number,signals)=>{
|
|
5807
|
+
const signal=findSignalByNumber(number,signals);
|
|
5808
|
+
|
|
5809
|
+
if(signal===undefined){
|
|
5810
|
+
return {}
|
|
5811
|
+
}
|
|
5812
|
+
|
|
5813
|
+
const{name,description,supported,action,forced,standard}=signal;
|
|
5814
|
+
return {
|
|
5815
|
+
[number]:{
|
|
5816
|
+
name,
|
|
5817
|
+
number,
|
|
5818
|
+
description,
|
|
5819
|
+
supported,
|
|
5820
|
+
action,
|
|
5821
|
+
forced,
|
|
5822
|
+
standard
|
|
5823
|
+
}
|
|
5824
|
+
}
|
|
5825
|
+
};
|
|
5826
|
+
|
|
5827
|
+
|
|
5828
|
+
|
|
5829
|
+
const findSignalByNumber=(number,signals)=>{
|
|
5830
|
+
const signal=signals.find(({name})=>node_os.constants.signals[name]===number);
|
|
5831
|
+
|
|
5832
|
+
if(signal!==undefined){
|
|
5833
|
+
return signal
|
|
5834
|
+
}
|
|
5835
|
+
|
|
5836
|
+
return signals.find((signalA)=>signalA.number===number)
|
|
5837
|
+
};
|
|
5838
|
+
|
|
5839
|
+
getSignalsByNumber();
|
|
5840
|
+
|
|
5445
5841
|
// Normalize signals for comparison purpose.
|
|
5446
5842
|
// Also validate the signal exists.
|
|
5447
5843
|
const normalizeKillSignal = killSignal => {
|
|
@@ -5450,14 +5846,14 @@ const normalizeKillSignal = killSignal => {
|
|
|
5450
5846
|
throw new TypeError(`Invalid ${optionName}: 0 cannot be used.`);
|
|
5451
5847
|
}
|
|
5452
5848
|
|
|
5453
|
-
return normalizeSignal
|
|
5849
|
+
return normalizeSignal(killSignal, optionName);
|
|
5454
5850
|
};
|
|
5455
5851
|
|
|
5456
5852
|
const normalizeSignalArgument = signal => signal === 0
|
|
5457
5853
|
? signal
|
|
5458
|
-
: normalizeSignal
|
|
5854
|
+
: normalizeSignal(signal, '`subprocess.kill()`\'s argument');
|
|
5459
5855
|
|
|
5460
|
-
const normalizeSignal
|
|
5856
|
+
const normalizeSignal = (signalNameOrInteger, optionName) => {
|
|
5461
5857
|
if (Number.isInteger(signalNameOrInteger)) {
|
|
5462
5858
|
return normalizeSignalInteger(signalNameOrInteger, optionName);
|
|
5463
5859
|
}
|
|
@@ -5507,6 +5903,9 @@ const getAvailableSignalIntegers = () => [...new Set(Object.values(node_os.const
|
|
|
5507
5903
|
.sort((signalInteger, signalIntegerTwo) => signalInteger - signalIntegerTwo))]
|
|
5508
5904
|
.join(', ');
|
|
5509
5905
|
|
|
5906
|
+
// Human-friendly description of a signal
|
|
5907
|
+
const getSignalDescription = signal => signalsByName[signal].description;
|
|
5908
|
+
|
|
5510
5909
|
// Normalize the `forceKillAfterDelay` option
|
|
5511
5910
|
const normalizeForceKillAfterDelay = forceKillAfterDelay => {
|
|
5512
5911
|
if (forceKillAfterDelay === false) {
|
|
@@ -5528,7 +5927,7 @@ const DEFAULT_FORCE_KILL_TIMEOUT = 1000 * 5;
|
|
|
5528
5927
|
|
|
5529
5928
|
// Monkey-patches `subprocess.kill()` to add `forceKillAfterDelay` behavior and `.kill(error)`
|
|
5530
5929
|
const subprocessKill = (
|
|
5531
|
-
{kill, options: {forceKillAfterDelay, killSignal}, onInternalError, controller},
|
|
5930
|
+
{kill, options: {forceKillAfterDelay, killSignal}, onInternalError, context, controller},
|
|
5532
5931
|
signalOrError,
|
|
5533
5932
|
errorArgument,
|
|
5534
5933
|
) => {
|
|
@@ -5541,6 +5940,7 @@ const subprocessKill = (
|
|
|
5541
5940
|
forceKillAfterDelay,
|
|
5542
5941
|
killSignal,
|
|
5543
5942
|
killResult,
|
|
5943
|
+
context,
|
|
5544
5944
|
controller,
|
|
5545
5945
|
});
|
|
5546
5946
|
return killResult;
|
|
@@ -5571,20 +5971,834 @@ const emitKillError = (error, onInternalError) => {
|
|
|
5571
5971
|
}
|
|
5572
5972
|
};
|
|
5573
5973
|
|
|
5574
|
-
const setKillTimeout = async ({kill, signal, forceKillAfterDelay, killSignal, killResult, controller}) => {
|
|
5575
|
-
if (
|
|
5974
|
+
const setKillTimeout = async ({kill, signal, forceKillAfterDelay, killSignal, killResult, context, controller}) => {
|
|
5975
|
+
if (signal === killSignal && killResult) {
|
|
5976
|
+
killOnTimeout({
|
|
5977
|
+
kill,
|
|
5978
|
+
forceKillAfterDelay,
|
|
5979
|
+
context,
|
|
5980
|
+
controllerSignal: controller.signal,
|
|
5981
|
+
});
|
|
5982
|
+
}
|
|
5983
|
+
};
|
|
5984
|
+
|
|
5985
|
+
// Forcefully terminate a subprocess after a timeout
|
|
5986
|
+
const killOnTimeout = async ({kill, forceKillAfterDelay, context, controllerSignal}) => {
|
|
5987
|
+
if (forceKillAfterDelay === false) {
|
|
5576
5988
|
return;
|
|
5577
5989
|
}
|
|
5578
5990
|
|
|
5579
5991
|
try {
|
|
5580
|
-
await promises.setTimeout(forceKillAfterDelay, undefined, {signal:
|
|
5581
|
-
kill('SIGKILL')
|
|
5992
|
+
await promises.setTimeout(forceKillAfterDelay, undefined, {signal: controllerSignal});
|
|
5993
|
+
if (kill('SIGKILL')) {
|
|
5994
|
+
context.isForcefullyTerminated ??= true;
|
|
5995
|
+
}
|
|
5582
5996
|
} catch {}
|
|
5583
5997
|
};
|
|
5584
5998
|
|
|
5585
|
-
|
|
5586
|
-
|
|
5587
|
-
|
|
5999
|
+
// Combines `util.aborted()` and `events.addAbortListener()`: promise-based and cleaned up with a stop signal
|
|
6000
|
+
const onAbortedSignal = async (mainSignal, stopSignal) => {
|
|
6001
|
+
if (!mainSignal.aborted) {
|
|
6002
|
+
await require$$0.once(mainSignal, 'abort', {signal: stopSignal});
|
|
6003
|
+
}
|
|
6004
|
+
};
|
|
6005
|
+
|
|
6006
|
+
// Validate the `cancelSignal` option
|
|
6007
|
+
const validateCancelSignal = ({cancelSignal}) => {
|
|
6008
|
+
if (cancelSignal !== undefined && Object.prototype.toString.call(cancelSignal) !== '[object AbortSignal]') {
|
|
6009
|
+
throw new Error(`The \`cancelSignal\` option must be an AbortSignal: ${String(cancelSignal)}`);
|
|
6010
|
+
}
|
|
6011
|
+
};
|
|
6012
|
+
|
|
6013
|
+
// Terminate the subprocess when aborting the `cancelSignal` option and `gracefulSignal` is `false`
|
|
6014
|
+
const throwOnCancel = ({subprocess, cancelSignal, gracefulCancel, context, controller}) => cancelSignal === undefined || gracefulCancel
|
|
6015
|
+
? []
|
|
6016
|
+
: [terminateOnCancel(subprocess, cancelSignal, context, controller)];
|
|
6017
|
+
|
|
6018
|
+
const terminateOnCancel = async (subprocess, cancelSignal, context, {signal}) => {
|
|
6019
|
+
await onAbortedSignal(cancelSignal, signal);
|
|
6020
|
+
context.terminationReason ??= 'cancel';
|
|
6021
|
+
subprocess.kill();
|
|
6022
|
+
throw cancelSignal.reason;
|
|
6023
|
+
};
|
|
6024
|
+
|
|
6025
|
+
// Validate the IPC channel is connected before receiving/sending messages
|
|
6026
|
+
const validateIpcMethod = ({methodName, isSubprocess, ipc, isConnected}) => {
|
|
6027
|
+
validateIpcOption(methodName, isSubprocess, ipc);
|
|
6028
|
+
validateConnection(methodName, isSubprocess, isConnected);
|
|
6029
|
+
};
|
|
6030
|
+
|
|
6031
|
+
// Better error message when forgetting to set `ipc: true` and using the IPC methods
|
|
6032
|
+
const validateIpcOption = (methodName, isSubprocess, ipc) => {
|
|
6033
|
+
if (!ipc) {
|
|
6034
|
+
throw new Error(`${getMethodName(methodName, isSubprocess)} can only be used if the \`ipc\` option is \`true\`.`);
|
|
6035
|
+
}
|
|
6036
|
+
};
|
|
6037
|
+
|
|
6038
|
+
// Better error message when one process does not send/receive messages once the other process has disconnected.
|
|
6039
|
+
// This also makes it clear that any buffered messages are lost once either process has disconnected.
|
|
6040
|
+
// Also when aborting `cancelSignal` after disconnecting the IPC.
|
|
6041
|
+
const validateConnection = (methodName, isSubprocess, isConnected) => {
|
|
6042
|
+
if (!isConnected) {
|
|
6043
|
+
throw new Error(`${getMethodName(methodName, isSubprocess)} cannot be used: the ${getOtherProcessName(isSubprocess)} has already exited or disconnected.`);
|
|
6044
|
+
}
|
|
6045
|
+
};
|
|
6046
|
+
|
|
6047
|
+
// When `getOneMessage()` could not complete due to an early disconnection
|
|
6048
|
+
const throwOnEarlyDisconnect = isSubprocess => {
|
|
6049
|
+
throw new Error(`${getMethodName('getOneMessage', isSubprocess)} could not complete: the ${getOtherProcessName(isSubprocess)} exited or disconnected.`);
|
|
6050
|
+
};
|
|
6051
|
+
|
|
6052
|
+
// When both processes use `sendMessage()` with `strict` at the same time
|
|
6053
|
+
const throwOnStrictDeadlockError = isSubprocess => {
|
|
6054
|
+
throw new Error(`${getMethodName('sendMessage', isSubprocess)} failed: the ${getOtherProcessName(isSubprocess)} is sending a message too, instead of listening to incoming messages.
|
|
6055
|
+
This can be fixed by both sending a message and listening to incoming messages at the same time:
|
|
6056
|
+
|
|
6057
|
+
const [receivedMessage] = await Promise.all([
|
|
6058
|
+
${getMethodName('getOneMessage', isSubprocess)},
|
|
6059
|
+
${getMethodName('sendMessage', isSubprocess, 'message, {strict: true}')},
|
|
6060
|
+
]);`);
|
|
6061
|
+
};
|
|
6062
|
+
|
|
6063
|
+
// When the other process used `strict` but the current process had I/O error calling `sendMessage()` for the response
|
|
6064
|
+
const getStrictResponseError = (error, isSubprocess) => new Error(`${getMethodName('sendMessage', isSubprocess)} failed when sending an acknowledgment response to the ${getOtherProcessName(isSubprocess)}.`, {cause: error});
|
|
6065
|
+
|
|
6066
|
+
// When using `strict` but the other process was not listening for messages
|
|
6067
|
+
const throwOnMissingStrict = isSubprocess => {
|
|
6068
|
+
throw new Error(`${getMethodName('sendMessage', isSubprocess)} failed: the ${getOtherProcessName(isSubprocess)} is not listening to incoming messages.`);
|
|
6069
|
+
};
|
|
6070
|
+
|
|
6071
|
+
// When using `strict` but the other process disconnected before receiving the message
|
|
6072
|
+
const throwOnStrictDisconnect = isSubprocess => {
|
|
6073
|
+
throw new Error(`${getMethodName('sendMessage', isSubprocess)} failed: the ${getOtherProcessName(isSubprocess)} exited without listening to incoming messages.`);
|
|
6074
|
+
};
|
|
6075
|
+
|
|
6076
|
+
// When the current process disconnects while the subprocess is listening to `cancelSignal`
|
|
6077
|
+
const getAbortDisconnectError = () => new Error(`\`cancelSignal\` aborted: the ${getOtherProcessName(true)} disconnected.`);
|
|
6078
|
+
|
|
6079
|
+
// When the subprocess uses `cancelSignal` but not the current process
|
|
6080
|
+
const throwOnMissingParent = () => {
|
|
6081
|
+
throw new Error('`getCancelSignal()` cannot be used without setting the `cancelSignal` subprocess option.');
|
|
6082
|
+
};
|
|
6083
|
+
|
|
6084
|
+
// EPIPE can happen when sending a message to a subprocess that is closing but has not disconnected yet
|
|
6085
|
+
const handleEpipeError = ({error, methodName, isSubprocess}) => {
|
|
6086
|
+
if (error.code === 'EPIPE') {
|
|
6087
|
+
throw new Error(`${getMethodName(methodName, isSubprocess)} cannot be used: the ${getOtherProcessName(isSubprocess)} is disconnecting.`, {cause: error});
|
|
6088
|
+
}
|
|
6089
|
+
};
|
|
6090
|
+
|
|
6091
|
+
// Better error message when sending messages which cannot be serialized.
|
|
6092
|
+
// Works with both `serialization: 'advanced'` and `serialization: 'json'`.
|
|
6093
|
+
const handleSerializationError = ({error, methodName, isSubprocess, message}) => {
|
|
6094
|
+
if (isSerializationError(error)) {
|
|
6095
|
+
throw new Error(`${getMethodName(methodName, isSubprocess)}'s argument type is invalid: the message cannot be serialized: ${String(message)}.`, {cause: error});
|
|
6096
|
+
}
|
|
6097
|
+
};
|
|
6098
|
+
|
|
6099
|
+
const isSerializationError = ({code, message}) => SERIALIZATION_ERROR_CODES.has(code)
|
|
6100
|
+
|| SERIALIZATION_ERROR_MESSAGES.some(serializationErrorMessage => message.includes(serializationErrorMessage));
|
|
6101
|
+
|
|
6102
|
+
// `error.code` set by Node.js when it failed to serialize the message
|
|
6103
|
+
const SERIALIZATION_ERROR_CODES = new Set([
|
|
6104
|
+
// Message is `undefined`
|
|
6105
|
+
'ERR_MISSING_ARGS',
|
|
6106
|
+
// Message is a function, a bigint, a symbol
|
|
6107
|
+
'ERR_INVALID_ARG_TYPE',
|
|
6108
|
+
]);
|
|
6109
|
+
|
|
6110
|
+
// `error.message` set by Node.js when it failed to serialize the message
|
|
6111
|
+
const SERIALIZATION_ERROR_MESSAGES = [
|
|
6112
|
+
// Message is a promise or a proxy, with `serialization: 'advanced'`
|
|
6113
|
+
'could not be cloned',
|
|
6114
|
+
// Message has cycles, with `serialization: 'json'`
|
|
6115
|
+
'circular structure',
|
|
6116
|
+
// Message has cycles inside toJSON(), with `serialization: 'json'`
|
|
6117
|
+
'call stack size exceeded',
|
|
6118
|
+
];
|
|
6119
|
+
|
|
6120
|
+
const getMethodName = (methodName, isSubprocess, parameters = '') => methodName === 'cancelSignal'
|
|
6121
|
+
? '`cancelSignal`\'s `controller.abort()`'
|
|
6122
|
+
: `${getNamespaceName(isSubprocess)}${methodName}(${parameters})`;
|
|
6123
|
+
|
|
6124
|
+
const getNamespaceName = isSubprocess => isSubprocess ? '' : 'subprocess.';
|
|
6125
|
+
|
|
6126
|
+
const getOtherProcessName = isSubprocess => isSubprocess ? 'parent process' : 'subprocess';
|
|
6127
|
+
|
|
6128
|
+
// When any error arises, we disconnect the IPC.
|
|
6129
|
+
// Otherwise, it is likely that one of the processes will stop sending/receiving messages.
|
|
6130
|
+
// This would leave the other process hanging.
|
|
6131
|
+
const disconnect = anyProcess => {
|
|
6132
|
+
if (anyProcess.connected) {
|
|
6133
|
+
anyProcess.disconnect();
|
|
6134
|
+
}
|
|
6135
|
+
};
|
|
6136
|
+
|
|
6137
|
+
const createDeferred = () => {
|
|
6138
|
+
const methods = {};
|
|
6139
|
+
const promise = new Promise((resolve, reject) => {
|
|
6140
|
+
Object.assign(methods, {resolve, reject});
|
|
6141
|
+
});
|
|
6142
|
+
return Object.assign(promise, methods);
|
|
6143
|
+
};
|
|
6144
|
+
|
|
6145
|
+
// Retrieve stream targeted by the `to` option
|
|
6146
|
+
const getToStream = (destination, to = 'stdin') => {
|
|
6147
|
+
const isWritable = true;
|
|
6148
|
+
const {options, fileDescriptors} = SUBPROCESS_OPTIONS.get(destination);
|
|
6149
|
+
const fdNumber = getFdNumber(fileDescriptors, to, isWritable);
|
|
6150
|
+
const destinationStream = destination.stdio[fdNumber];
|
|
6151
|
+
|
|
6152
|
+
if (destinationStream === null) {
|
|
6153
|
+
throw new TypeError(getInvalidStdioOptionMessage(fdNumber, to, options, isWritable));
|
|
6154
|
+
}
|
|
6155
|
+
|
|
6156
|
+
return destinationStream;
|
|
6157
|
+
};
|
|
6158
|
+
|
|
6159
|
+
// Retrieve stream targeted by the `from` option
|
|
6160
|
+
const getFromStream = (source, from = 'stdout') => {
|
|
6161
|
+
const isWritable = false;
|
|
6162
|
+
const {options, fileDescriptors} = SUBPROCESS_OPTIONS.get(source);
|
|
6163
|
+
const fdNumber = getFdNumber(fileDescriptors, from, isWritable);
|
|
6164
|
+
const sourceStream = fdNumber === 'all' ? source.all : source.stdio[fdNumber];
|
|
6165
|
+
|
|
6166
|
+
if (sourceStream === null || sourceStream === undefined) {
|
|
6167
|
+
throw new TypeError(getInvalidStdioOptionMessage(fdNumber, from, options, isWritable));
|
|
6168
|
+
}
|
|
6169
|
+
|
|
6170
|
+
return sourceStream;
|
|
6171
|
+
};
|
|
6172
|
+
|
|
6173
|
+
// Keeps track of the options passed to each Execa call
|
|
6174
|
+
const SUBPROCESS_OPTIONS = new WeakMap();
|
|
6175
|
+
|
|
6176
|
+
const getFdNumber = (fileDescriptors, fdName, isWritable) => {
|
|
6177
|
+
const fdNumber = parseFdNumber(fdName, isWritable);
|
|
6178
|
+
validateFdNumber(fdNumber, fdName, isWritable, fileDescriptors);
|
|
6179
|
+
return fdNumber;
|
|
6180
|
+
};
|
|
6181
|
+
|
|
6182
|
+
const parseFdNumber = (fdName, isWritable) => {
|
|
6183
|
+
const fdNumber = parseFd(fdName);
|
|
6184
|
+
if (fdNumber !== undefined) {
|
|
6185
|
+
return fdNumber;
|
|
6186
|
+
}
|
|
6187
|
+
|
|
6188
|
+
const {validOptions, defaultValue} = isWritable
|
|
6189
|
+
? {validOptions: '"stdin"', defaultValue: 'stdin'}
|
|
6190
|
+
: {validOptions: '"stdout", "stderr", "all"', defaultValue: 'stdout'};
|
|
6191
|
+
throw new TypeError(`"${getOptionName(isWritable)}" must not be "${fdName}".
|
|
6192
|
+
It must be ${validOptions} or "fd3", "fd4" (and so on).
|
|
6193
|
+
It is optional and defaults to "${defaultValue}".`);
|
|
6194
|
+
};
|
|
6195
|
+
|
|
6196
|
+
const validateFdNumber = (fdNumber, fdName, isWritable, fileDescriptors) => {
|
|
6197
|
+
const fileDescriptor = fileDescriptors[getUsedDescriptor(fdNumber)];
|
|
6198
|
+
if (fileDescriptor === undefined) {
|
|
6199
|
+
throw new TypeError(`"${getOptionName(isWritable)}" must not be ${fdName}. That file descriptor does not exist.
|
|
6200
|
+
Please set the "stdio" option to ensure that file descriptor exists.`);
|
|
6201
|
+
}
|
|
6202
|
+
|
|
6203
|
+
if (fileDescriptor.direction === 'input' && !isWritable) {
|
|
6204
|
+
throw new TypeError(`"${getOptionName(isWritable)}" must not be ${fdName}. It must be a readable stream, not writable.`);
|
|
6205
|
+
}
|
|
6206
|
+
|
|
6207
|
+
if (fileDescriptor.direction !== 'input' && isWritable) {
|
|
6208
|
+
throw new TypeError(`"${getOptionName(isWritable)}" must not be ${fdName}. It must be a writable stream, not readable.`);
|
|
6209
|
+
}
|
|
6210
|
+
};
|
|
6211
|
+
|
|
6212
|
+
const getInvalidStdioOptionMessage = (fdNumber, fdName, options, isWritable) => {
|
|
6213
|
+
if (fdNumber === 'all' && !options.all) {
|
|
6214
|
+
return 'The "all" option must be true to use "from: \'all\'".';
|
|
6215
|
+
}
|
|
6216
|
+
|
|
6217
|
+
const {optionName, optionValue} = getInvalidStdioOption(fdNumber, options);
|
|
6218
|
+
return `The "${optionName}: ${serializeOptionValue(optionValue)}" option is incompatible with using "${getOptionName(isWritable)}: ${serializeOptionValue(fdName)}".
|
|
6219
|
+
Please set this option with "pipe" instead.`;
|
|
6220
|
+
};
|
|
6221
|
+
|
|
6222
|
+
const getInvalidStdioOption = (fdNumber, {stdin, stdout, stderr, stdio}) => {
|
|
6223
|
+
const usedDescriptor = getUsedDescriptor(fdNumber);
|
|
6224
|
+
|
|
6225
|
+
if (usedDescriptor === 0 && stdin !== undefined) {
|
|
6226
|
+
return {optionName: 'stdin', optionValue: stdin};
|
|
6227
|
+
}
|
|
6228
|
+
|
|
6229
|
+
if (usedDescriptor === 1 && stdout !== undefined) {
|
|
6230
|
+
return {optionName: 'stdout', optionValue: stdout};
|
|
6231
|
+
}
|
|
6232
|
+
|
|
6233
|
+
if (usedDescriptor === 2 && stderr !== undefined) {
|
|
6234
|
+
return {optionName: 'stderr', optionValue: stderr};
|
|
6235
|
+
}
|
|
6236
|
+
|
|
6237
|
+
return {optionName: `stdio[${usedDescriptor}]`, optionValue: stdio[usedDescriptor]};
|
|
6238
|
+
};
|
|
6239
|
+
|
|
6240
|
+
const getUsedDescriptor = fdNumber => fdNumber === 'all' ? 1 : fdNumber;
|
|
6241
|
+
|
|
6242
|
+
const getOptionName = isWritable => isWritable ? 'to' : 'from';
|
|
6243
|
+
|
|
6244
|
+
const serializeOptionValue = value => {
|
|
6245
|
+
if (typeof value === 'string') {
|
|
6246
|
+
return `'${value}'`;
|
|
6247
|
+
}
|
|
6248
|
+
|
|
6249
|
+
return typeof value === 'number' ? `${value}` : 'Stream';
|
|
6250
|
+
};
|
|
6251
|
+
|
|
6252
|
+
// Temporarily increase the maximum number of listeners on an eventEmitter
|
|
6253
|
+
const incrementMaxListeners = (eventEmitter, maxListenersIncrement, signal) => {
|
|
6254
|
+
const maxListeners = eventEmitter.getMaxListeners();
|
|
6255
|
+
if (maxListeners === 0 || maxListeners === Number.POSITIVE_INFINITY) {
|
|
6256
|
+
return;
|
|
6257
|
+
}
|
|
6258
|
+
|
|
6259
|
+
eventEmitter.setMaxListeners(maxListeners + maxListenersIncrement);
|
|
6260
|
+
require$$0.addAbortListener(signal, () => {
|
|
6261
|
+
eventEmitter.setMaxListeners(eventEmitter.getMaxListeners() - maxListenersIncrement);
|
|
6262
|
+
});
|
|
6263
|
+
};
|
|
6264
|
+
|
|
6265
|
+
// By default, Node.js keeps the subprocess alive while it has a `message` or `disconnect` listener.
|
|
6266
|
+
// We replicate the same logic for the events that we proxy.
|
|
6267
|
+
// This ensures the subprocess is kept alive while `getOneMessage()` and `getEachMessage()` are ongoing.
|
|
6268
|
+
// This is not a problem with `sendMessage()` since Node.js handles that method automatically.
|
|
6269
|
+
// We do not use `anyProcess.channel.ref()` since this would prevent the automatic `.channel.refCounted()` Node.js is doing.
|
|
6270
|
+
// We keep a reference to `anyProcess.channel` since it might be `null` while `getOneMessage()` or `getEachMessage()` is still processing debounced messages.
|
|
6271
|
+
// See https://github.com/nodejs/node/blob/2aaeaa863c35befa2ebaa98fb7737ec84df4d8e9/lib/internal/child_process.js#L547
|
|
6272
|
+
const addReference = (channel, reference) => {
|
|
6273
|
+
if (reference) {
|
|
6274
|
+
addReferenceCount(channel);
|
|
6275
|
+
}
|
|
6276
|
+
};
|
|
6277
|
+
|
|
6278
|
+
const addReferenceCount = channel => {
|
|
6279
|
+
channel.refCounted();
|
|
6280
|
+
};
|
|
6281
|
+
|
|
6282
|
+
const removeReference = (channel, reference) => {
|
|
6283
|
+
if (reference) {
|
|
6284
|
+
removeReferenceCount(channel);
|
|
6285
|
+
}
|
|
6286
|
+
};
|
|
6287
|
+
|
|
6288
|
+
const removeReferenceCount = channel => {
|
|
6289
|
+
channel.unrefCounted();
|
|
6290
|
+
};
|
|
6291
|
+
|
|
6292
|
+
// To proxy events, we setup some global listeners on the `message` and `disconnect` events.
|
|
6293
|
+
// Those should not keep the subprocess alive, so we remove the automatic counting that Node.js is doing.
|
|
6294
|
+
// See https://github.com/nodejs/node/blob/1b965270a9c273d4cf70e8808e9d28b9ada7844f/lib/child_process.js#L180
|
|
6295
|
+
const undoAddedReferences = (channel, isSubprocess) => {
|
|
6296
|
+
if (isSubprocess) {
|
|
6297
|
+
removeReferenceCount(channel);
|
|
6298
|
+
removeReferenceCount(channel);
|
|
6299
|
+
}
|
|
6300
|
+
};
|
|
6301
|
+
|
|
6302
|
+
// Reverse it during `disconnect`
|
|
6303
|
+
const redoAddedReferences = (channel, isSubprocess) => {
|
|
6304
|
+
if (isSubprocess) {
|
|
6305
|
+
addReferenceCount(channel);
|
|
6306
|
+
addReferenceCount(channel);
|
|
6307
|
+
}
|
|
6308
|
+
};
|
|
6309
|
+
|
|
6310
|
+
// By default, Node.js buffers `message` events.
|
|
6311
|
+
// - Buffering happens when there is a `message` event is emitted but there is no handler.
|
|
6312
|
+
// - As soon as a `message` event handler is set, all buffered `message` events are emitted, emptying the buffer.
|
|
6313
|
+
// - This happens both in the current process and the subprocess.
|
|
6314
|
+
// - See https://github.com/nodejs/node/blob/501546e8f37059cd577041e23941b640d0d4d406/lib/internal/child_process.js#L719
|
|
6315
|
+
// This is helpful. Notably, this allows sending messages to a subprocess that's still initializing.
|
|
6316
|
+
// However, it has several problems.
|
|
6317
|
+
// - This works with `events.on()` but not `events.once()` since all buffered messages are emitted at once.
|
|
6318
|
+
// For example, users cannot call `await getOneMessage()`/`getEachMessage()` multiple times in a row.
|
|
6319
|
+
// - When a user intentionally starts listening to `message` at a specific point in time, past `message` events are replayed, which might be unexpected.
|
|
6320
|
+
// - Buffering is unlimited, which might lead to an out-of-memory crash.
|
|
6321
|
+
// - This does not work well with multiple consumers.
|
|
6322
|
+
// For example, Execa consumes events with both `result.ipcOutput` and manual IPC calls like `getOneMessage()`.
|
|
6323
|
+
// Since `result.ipcOutput` reads all incoming messages, no buffering happens for manual IPC calls.
|
|
6324
|
+
// - Forgetting to setup a `message` listener, or setting it up too late, is a programming mistake.
|
|
6325
|
+
// The default behavior does not allow users to realize they made that mistake.
|
|
6326
|
+
// To solve those problems, instead of buffering messages, we debounce them.
|
|
6327
|
+
// The `message` event so it is emitted at most once per macrotask.
|
|
6328
|
+
const onMessage = async ({anyProcess, channel, isSubprocess, ipcEmitter}, wrappedMessage) => {
|
|
6329
|
+
if (handleStrictResponse(wrappedMessage) || handleAbort(wrappedMessage)) {
|
|
6330
|
+
return;
|
|
6331
|
+
}
|
|
6332
|
+
|
|
6333
|
+
if (!INCOMING_MESSAGES.has(anyProcess)) {
|
|
6334
|
+
INCOMING_MESSAGES.set(anyProcess, []);
|
|
6335
|
+
}
|
|
6336
|
+
|
|
6337
|
+
const incomingMessages = INCOMING_MESSAGES.get(anyProcess);
|
|
6338
|
+
incomingMessages.push(wrappedMessage);
|
|
6339
|
+
|
|
6340
|
+
if (incomingMessages.length > 1) {
|
|
6341
|
+
return;
|
|
6342
|
+
}
|
|
6343
|
+
|
|
6344
|
+
while (incomingMessages.length > 0) {
|
|
6345
|
+
// eslint-disable-next-line no-await-in-loop
|
|
6346
|
+
await waitForOutgoingMessages(anyProcess, ipcEmitter, wrappedMessage);
|
|
6347
|
+
// eslint-disable-next-line no-await-in-loop
|
|
6348
|
+
await promises.scheduler.yield();
|
|
6349
|
+
|
|
6350
|
+
// eslint-disable-next-line no-await-in-loop
|
|
6351
|
+
const message = await handleStrictRequest({
|
|
6352
|
+
wrappedMessage: incomingMessages[0],
|
|
6353
|
+
anyProcess,
|
|
6354
|
+
channel,
|
|
6355
|
+
isSubprocess,
|
|
6356
|
+
ipcEmitter,
|
|
6357
|
+
});
|
|
6358
|
+
|
|
6359
|
+
incomingMessages.shift();
|
|
6360
|
+
ipcEmitter.emit('message', message);
|
|
6361
|
+
ipcEmitter.emit('message:done');
|
|
6362
|
+
}
|
|
6363
|
+
};
|
|
6364
|
+
|
|
6365
|
+
// If the `message` event is currently debounced, the `disconnect` event must wait for it
|
|
6366
|
+
const onDisconnect = async ({anyProcess, channel, isSubprocess, ipcEmitter, boundOnMessage}) => {
|
|
6367
|
+
abortOnDisconnect();
|
|
6368
|
+
|
|
6369
|
+
const incomingMessages = INCOMING_MESSAGES.get(anyProcess);
|
|
6370
|
+
while (incomingMessages?.length > 0) {
|
|
6371
|
+
// eslint-disable-next-line no-await-in-loop
|
|
6372
|
+
await require$$0.once(ipcEmitter, 'message:done');
|
|
6373
|
+
}
|
|
6374
|
+
|
|
6375
|
+
anyProcess.removeListener('message', boundOnMessage);
|
|
6376
|
+
redoAddedReferences(channel, isSubprocess);
|
|
6377
|
+
ipcEmitter.connected = false;
|
|
6378
|
+
ipcEmitter.emit('disconnect');
|
|
6379
|
+
};
|
|
6380
|
+
|
|
6381
|
+
const INCOMING_MESSAGES = new WeakMap();
|
|
6382
|
+
|
|
6383
|
+
// Forward the `message` and `disconnect` events from the process and subprocess to a proxy emitter.
|
|
6384
|
+
// This prevents the `error` event from stopping IPC.
|
|
6385
|
+
// This also allows debouncing the `message` event.
|
|
6386
|
+
const getIpcEmitter = (anyProcess, channel, isSubprocess) => {
|
|
6387
|
+
if (IPC_EMITTERS.has(anyProcess)) {
|
|
6388
|
+
return IPC_EMITTERS.get(anyProcess);
|
|
6389
|
+
}
|
|
6390
|
+
|
|
6391
|
+
// Use an `EventEmitter`, like the `process` that is being proxied
|
|
6392
|
+
// eslint-disable-next-line unicorn/prefer-event-target
|
|
6393
|
+
const ipcEmitter = new require$$0.EventEmitter();
|
|
6394
|
+
ipcEmitter.connected = true;
|
|
6395
|
+
IPC_EMITTERS.set(anyProcess, ipcEmitter);
|
|
6396
|
+
forwardEvents({
|
|
6397
|
+
ipcEmitter,
|
|
6398
|
+
anyProcess,
|
|
6399
|
+
channel,
|
|
6400
|
+
isSubprocess,
|
|
6401
|
+
});
|
|
6402
|
+
return ipcEmitter;
|
|
6403
|
+
};
|
|
6404
|
+
|
|
6405
|
+
const IPC_EMITTERS = new WeakMap();
|
|
6406
|
+
|
|
6407
|
+
// The `message` and `disconnect` events are buffered in the subprocess until the first listener is setup.
|
|
6408
|
+
// However, unbuffering happens after one tick, so this give enough time for the caller to setup the listener on the proxy emitter first.
|
|
6409
|
+
// See https://github.com/nodejs/node/blob/2aaeaa863c35befa2ebaa98fb7737ec84df4d8e9/lib/internal/child_process.js#L721
|
|
6410
|
+
const forwardEvents = ({ipcEmitter, anyProcess, channel, isSubprocess}) => {
|
|
6411
|
+
const boundOnMessage = onMessage.bind(undefined, {
|
|
6412
|
+
anyProcess,
|
|
6413
|
+
channel,
|
|
6414
|
+
isSubprocess,
|
|
6415
|
+
ipcEmitter,
|
|
6416
|
+
});
|
|
6417
|
+
anyProcess.on('message', boundOnMessage);
|
|
6418
|
+
anyProcess.once('disconnect', onDisconnect.bind(undefined, {
|
|
6419
|
+
anyProcess,
|
|
6420
|
+
channel,
|
|
6421
|
+
isSubprocess,
|
|
6422
|
+
ipcEmitter,
|
|
6423
|
+
boundOnMessage,
|
|
6424
|
+
}));
|
|
6425
|
+
undoAddedReferences(channel, isSubprocess);
|
|
6426
|
+
};
|
|
6427
|
+
|
|
6428
|
+
// Check whether there might still be some `message` events to receive
|
|
6429
|
+
const isConnected = anyProcess => {
|
|
6430
|
+
const ipcEmitter = IPC_EMITTERS.get(anyProcess);
|
|
6431
|
+
return ipcEmitter === undefined
|
|
6432
|
+
? anyProcess.channel !== null
|
|
6433
|
+
: ipcEmitter.connected;
|
|
6434
|
+
};
|
|
6435
|
+
|
|
6436
|
+
// When using the `strict` option, wrap the message with metadata during `sendMessage()`
|
|
6437
|
+
const handleSendStrict = ({anyProcess, channel, isSubprocess, message, strict}) => {
|
|
6438
|
+
if (!strict) {
|
|
6439
|
+
return message;
|
|
6440
|
+
}
|
|
6441
|
+
|
|
6442
|
+
const ipcEmitter = getIpcEmitter(anyProcess, channel, isSubprocess);
|
|
6443
|
+
const hasListeners = hasMessageListeners(anyProcess, ipcEmitter);
|
|
6444
|
+
return {
|
|
6445
|
+
id: count++,
|
|
6446
|
+
type: REQUEST_TYPE,
|
|
6447
|
+
message,
|
|
6448
|
+
hasListeners,
|
|
6449
|
+
};
|
|
6450
|
+
};
|
|
6451
|
+
|
|
6452
|
+
let count = 0n;
|
|
6453
|
+
|
|
6454
|
+
// Handles when both processes are calling `sendMessage()` with `strict` at the same time.
|
|
6455
|
+
// If neither process is listening, this would create a deadlock. We detect it and throw.
|
|
6456
|
+
const validateStrictDeadlock = (outgoingMessages, wrappedMessage) => {
|
|
6457
|
+
if (wrappedMessage?.type !== REQUEST_TYPE || wrappedMessage.hasListeners) {
|
|
6458
|
+
return;
|
|
6459
|
+
}
|
|
6460
|
+
|
|
6461
|
+
for (const {id} of outgoingMessages) {
|
|
6462
|
+
if (id !== undefined) {
|
|
6463
|
+
STRICT_RESPONSES[id].resolve({isDeadlock: true, hasListeners: false});
|
|
6464
|
+
}
|
|
6465
|
+
}
|
|
6466
|
+
};
|
|
6467
|
+
|
|
6468
|
+
// The other process then sends the acknowledgment back as a response
|
|
6469
|
+
const handleStrictRequest = async ({wrappedMessage, anyProcess, channel, isSubprocess, ipcEmitter}) => {
|
|
6470
|
+
if (wrappedMessage?.type !== REQUEST_TYPE || !anyProcess.connected) {
|
|
6471
|
+
return wrappedMessage;
|
|
6472
|
+
}
|
|
6473
|
+
|
|
6474
|
+
const {id, message} = wrappedMessage;
|
|
6475
|
+
const response = {id, type: RESPONSE_TYPE, message: hasMessageListeners(anyProcess, ipcEmitter)};
|
|
6476
|
+
|
|
6477
|
+
try {
|
|
6478
|
+
await sendMessage({
|
|
6479
|
+
anyProcess,
|
|
6480
|
+
channel,
|
|
6481
|
+
isSubprocess,
|
|
6482
|
+
ipc: true,
|
|
6483
|
+
}, response);
|
|
6484
|
+
} catch (error) {
|
|
6485
|
+
ipcEmitter.emit('strict:error', error);
|
|
6486
|
+
}
|
|
6487
|
+
|
|
6488
|
+
return message;
|
|
6489
|
+
};
|
|
6490
|
+
|
|
6491
|
+
// Reception of the acknowledgment response
|
|
6492
|
+
const handleStrictResponse = wrappedMessage => {
|
|
6493
|
+
if (wrappedMessage?.type !== RESPONSE_TYPE) {
|
|
6494
|
+
return false;
|
|
6495
|
+
}
|
|
6496
|
+
|
|
6497
|
+
const {id, message: hasListeners} = wrappedMessage;
|
|
6498
|
+
STRICT_RESPONSES[id]?.resolve({isDeadlock: false, hasListeners});
|
|
6499
|
+
return true;
|
|
6500
|
+
};
|
|
6501
|
+
|
|
6502
|
+
// Wait for the other process to receive the message from `sendMessage()`
|
|
6503
|
+
const waitForStrictResponse = async (wrappedMessage, anyProcess, isSubprocess) => {
|
|
6504
|
+
if (wrappedMessage?.type !== REQUEST_TYPE) {
|
|
6505
|
+
return;
|
|
6506
|
+
}
|
|
6507
|
+
|
|
6508
|
+
const deferred = createDeferred();
|
|
6509
|
+
STRICT_RESPONSES[wrappedMessage.id] = deferred;
|
|
6510
|
+
const controller = new AbortController();
|
|
6511
|
+
|
|
6512
|
+
try {
|
|
6513
|
+
const {isDeadlock, hasListeners} = await Promise.race([
|
|
6514
|
+
deferred,
|
|
6515
|
+
throwOnDisconnect$1(anyProcess, isSubprocess, controller),
|
|
6516
|
+
]);
|
|
6517
|
+
|
|
6518
|
+
if (isDeadlock) {
|
|
6519
|
+
throwOnStrictDeadlockError(isSubprocess);
|
|
6520
|
+
}
|
|
6521
|
+
|
|
6522
|
+
if (!hasListeners) {
|
|
6523
|
+
throwOnMissingStrict(isSubprocess);
|
|
6524
|
+
}
|
|
6525
|
+
} finally {
|
|
6526
|
+
controller.abort();
|
|
6527
|
+
delete STRICT_RESPONSES[wrappedMessage.id];
|
|
6528
|
+
}
|
|
6529
|
+
};
|
|
6530
|
+
|
|
6531
|
+
const STRICT_RESPONSES = {};
|
|
6532
|
+
|
|
6533
|
+
const throwOnDisconnect$1 = async (anyProcess, isSubprocess, {signal}) => {
|
|
6534
|
+
incrementMaxListeners(anyProcess, 1, signal);
|
|
6535
|
+
await require$$0.once(anyProcess, 'disconnect', {signal});
|
|
6536
|
+
throwOnStrictDisconnect(isSubprocess);
|
|
6537
|
+
};
|
|
6538
|
+
|
|
6539
|
+
const REQUEST_TYPE = 'execa:ipc:request';
|
|
6540
|
+
const RESPONSE_TYPE = 'execa:ipc:response';
|
|
6541
|
+
|
|
6542
|
+
// When `sendMessage()` is ongoing, any `message` being received waits before being emitted.
|
|
6543
|
+
// This allows calling one or multiple `await sendMessage()` followed by `await getOneMessage()`/`await getEachMessage()`.
|
|
6544
|
+
// Without running into a race condition when the other process sends a response too fast, before the current process set up a listener.
|
|
6545
|
+
const startSendMessage = (anyProcess, wrappedMessage, strict) => {
|
|
6546
|
+
if (!OUTGOING_MESSAGES.has(anyProcess)) {
|
|
6547
|
+
OUTGOING_MESSAGES.set(anyProcess, new Set());
|
|
6548
|
+
}
|
|
6549
|
+
|
|
6550
|
+
const outgoingMessages = OUTGOING_MESSAGES.get(anyProcess);
|
|
6551
|
+
const onMessageSent = createDeferred();
|
|
6552
|
+
const id = strict ? wrappedMessage.id : undefined;
|
|
6553
|
+
const outgoingMessage = {onMessageSent, id};
|
|
6554
|
+
outgoingMessages.add(outgoingMessage);
|
|
6555
|
+
return {outgoingMessages, outgoingMessage};
|
|
6556
|
+
};
|
|
6557
|
+
|
|
6558
|
+
const endSendMessage = ({outgoingMessages, outgoingMessage}) => {
|
|
6559
|
+
outgoingMessages.delete(outgoingMessage);
|
|
6560
|
+
outgoingMessage.onMessageSent.resolve();
|
|
6561
|
+
};
|
|
6562
|
+
|
|
6563
|
+
// Await while `sendMessage()` is ongoing, unless there is already a `message` listener
|
|
6564
|
+
const waitForOutgoingMessages = async (anyProcess, ipcEmitter, wrappedMessage) => {
|
|
6565
|
+
while (!hasMessageListeners(anyProcess, ipcEmitter) && OUTGOING_MESSAGES.get(anyProcess)?.size > 0) {
|
|
6566
|
+
const outgoingMessages = [...OUTGOING_MESSAGES.get(anyProcess)];
|
|
6567
|
+
validateStrictDeadlock(outgoingMessages, wrappedMessage);
|
|
6568
|
+
// eslint-disable-next-line no-await-in-loop
|
|
6569
|
+
await Promise.all(outgoingMessages.map(({onMessageSent}) => onMessageSent));
|
|
6570
|
+
}
|
|
6571
|
+
};
|
|
6572
|
+
|
|
6573
|
+
const OUTGOING_MESSAGES = new WeakMap();
|
|
6574
|
+
|
|
6575
|
+
// Whether any `message` listener is setup
|
|
6576
|
+
const hasMessageListeners = (anyProcess, ipcEmitter) => ipcEmitter.listenerCount('message') > getMinListenerCount(anyProcess);
|
|
6577
|
+
|
|
6578
|
+
// When `buffer` is `false`, we set up a `message` listener that should be ignored.
|
|
6579
|
+
// That listener is only meant to intercept `strict` acknowledgement responses.
|
|
6580
|
+
const getMinListenerCount = anyProcess => SUBPROCESS_OPTIONS.has(anyProcess)
|
|
6581
|
+
&& !SUBPROCESS_OPTIONS.get(anyProcess).options.buffer.at(-1)
|
|
6582
|
+
? 1
|
|
6583
|
+
: 0;
|
|
6584
|
+
|
|
6585
|
+
// Like `[sub]process.send()` but promise-based.
|
|
6586
|
+
// We do not `await subprocess` during `.sendMessage()` nor `.getOneMessage()` since those methods are transient.
|
|
6587
|
+
// Users would still need to `await subprocess` after the method is done.
|
|
6588
|
+
// Also, this would prevent `unhandledRejection` event from being emitted, making it silent.
|
|
6589
|
+
const sendMessage = ({anyProcess, channel, isSubprocess, ipc}, message, {strict = false} = {}) => {
|
|
6590
|
+
const methodName = 'sendMessage';
|
|
6591
|
+
validateIpcMethod({
|
|
6592
|
+
methodName,
|
|
6593
|
+
isSubprocess,
|
|
6594
|
+
ipc,
|
|
6595
|
+
isConnected: anyProcess.connected,
|
|
6596
|
+
});
|
|
6597
|
+
|
|
6598
|
+
return sendMessageAsync({
|
|
6599
|
+
anyProcess,
|
|
6600
|
+
channel,
|
|
6601
|
+
methodName,
|
|
6602
|
+
isSubprocess,
|
|
6603
|
+
message,
|
|
6604
|
+
strict,
|
|
6605
|
+
});
|
|
6606
|
+
};
|
|
6607
|
+
|
|
6608
|
+
const sendMessageAsync = async ({anyProcess, channel, methodName, isSubprocess, message, strict}) => {
|
|
6609
|
+
const wrappedMessage = handleSendStrict({
|
|
6610
|
+
anyProcess,
|
|
6611
|
+
channel,
|
|
6612
|
+
isSubprocess,
|
|
6613
|
+
message,
|
|
6614
|
+
strict,
|
|
6615
|
+
});
|
|
6616
|
+
const outgoingMessagesState = startSendMessage(anyProcess, wrappedMessage, strict);
|
|
6617
|
+
try {
|
|
6618
|
+
await sendOneMessage({
|
|
6619
|
+
anyProcess,
|
|
6620
|
+
methodName,
|
|
6621
|
+
isSubprocess,
|
|
6622
|
+
wrappedMessage,
|
|
6623
|
+
message,
|
|
6624
|
+
});
|
|
6625
|
+
} catch (error) {
|
|
6626
|
+
disconnect(anyProcess);
|
|
6627
|
+
throw error;
|
|
6628
|
+
} finally {
|
|
6629
|
+
endSendMessage(outgoingMessagesState);
|
|
6630
|
+
}
|
|
6631
|
+
};
|
|
6632
|
+
|
|
6633
|
+
// Used internally by `cancelSignal`
|
|
6634
|
+
const sendOneMessage = async ({anyProcess, methodName, isSubprocess, wrappedMessage, message}) => {
|
|
6635
|
+
const sendMethod = getSendMethod(anyProcess);
|
|
6636
|
+
|
|
6637
|
+
try {
|
|
6638
|
+
await Promise.all([
|
|
6639
|
+
waitForStrictResponse(wrappedMessage, anyProcess, isSubprocess),
|
|
6640
|
+
sendMethod(wrappedMessage),
|
|
6641
|
+
]);
|
|
6642
|
+
} catch (error) {
|
|
6643
|
+
handleEpipeError({error, methodName, isSubprocess});
|
|
6644
|
+
handleSerializationError({
|
|
6645
|
+
error,
|
|
6646
|
+
methodName,
|
|
6647
|
+
isSubprocess,
|
|
6648
|
+
message,
|
|
6649
|
+
});
|
|
6650
|
+
throw error;
|
|
6651
|
+
}
|
|
6652
|
+
};
|
|
6653
|
+
|
|
6654
|
+
// [sub]process.send() promisified, memoized
|
|
6655
|
+
const getSendMethod = anyProcess => {
|
|
6656
|
+
if (PROCESS_SEND_METHODS.has(anyProcess)) {
|
|
6657
|
+
return PROCESS_SEND_METHODS.get(anyProcess);
|
|
6658
|
+
}
|
|
6659
|
+
|
|
6660
|
+
const sendMethod = node_util.promisify(anyProcess.send.bind(anyProcess));
|
|
6661
|
+
PROCESS_SEND_METHODS.set(anyProcess, sendMethod);
|
|
6662
|
+
return sendMethod;
|
|
6663
|
+
};
|
|
6664
|
+
|
|
6665
|
+
const PROCESS_SEND_METHODS = new WeakMap();
|
|
6666
|
+
|
|
6667
|
+
// Send an IPC message so the subprocess performs a graceful termination
|
|
6668
|
+
const sendAbort = (subprocess, message) => {
|
|
6669
|
+
const methodName = 'cancelSignal';
|
|
6670
|
+
validateConnection(methodName, false, subprocess.connected);
|
|
6671
|
+
return sendOneMessage({
|
|
6672
|
+
anyProcess: subprocess,
|
|
6673
|
+
methodName,
|
|
6674
|
+
isSubprocess: false,
|
|
6675
|
+
wrappedMessage: {type: GRACEFUL_CANCEL_TYPE, message},
|
|
6676
|
+
message,
|
|
6677
|
+
});
|
|
6678
|
+
};
|
|
6679
|
+
|
|
6680
|
+
// When the signal is being used, start listening for incoming messages.
|
|
6681
|
+
// Unbuffering messages takes one microtask to complete, so this must be async.
|
|
6682
|
+
const getCancelSignal = async ({anyProcess, channel, isSubprocess, ipc}) => {
|
|
6683
|
+
await startIpc({
|
|
6684
|
+
anyProcess,
|
|
6685
|
+
channel,
|
|
6686
|
+
isSubprocess,
|
|
6687
|
+
ipc,
|
|
6688
|
+
});
|
|
6689
|
+
return cancelController.signal;
|
|
6690
|
+
};
|
|
6691
|
+
|
|
6692
|
+
const startIpc = async ({anyProcess, channel, isSubprocess, ipc}) => {
|
|
6693
|
+
if (cancelListening) {
|
|
6694
|
+
return;
|
|
6695
|
+
}
|
|
6696
|
+
|
|
6697
|
+
cancelListening = true;
|
|
6698
|
+
|
|
6699
|
+
if (!ipc) {
|
|
6700
|
+
throwOnMissingParent();
|
|
6701
|
+
return;
|
|
6702
|
+
}
|
|
6703
|
+
|
|
6704
|
+
if (channel === null) {
|
|
6705
|
+
abortOnDisconnect();
|
|
6706
|
+
return;
|
|
6707
|
+
}
|
|
6708
|
+
|
|
6709
|
+
getIpcEmitter(anyProcess, channel, isSubprocess);
|
|
6710
|
+
await promises.scheduler.yield();
|
|
6711
|
+
};
|
|
6712
|
+
|
|
6713
|
+
let cancelListening = false;
|
|
6714
|
+
|
|
6715
|
+
// Reception of IPC message to perform a graceful termination
|
|
6716
|
+
const handleAbort = wrappedMessage => {
|
|
6717
|
+
if (wrappedMessage?.type !== GRACEFUL_CANCEL_TYPE) {
|
|
6718
|
+
return false;
|
|
6719
|
+
}
|
|
6720
|
+
|
|
6721
|
+
cancelController.abort(wrappedMessage.message);
|
|
6722
|
+
return true;
|
|
6723
|
+
};
|
|
6724
|
+
|
|
6725
|
+
const GRACEFUL_CANCEL_TYPE = 'execa:ipc:cancel';
|
|
6726
|
+
|
|
6727
|
+
// When the current process disconnects early, the subprocess `cancelSignal` is aborted.
|
|
6728
|
+
// Otherwise, the signal would never be able to be aborted later on.
|
|
6729
|
+
const abortOnDisconnect = () => {
|
|
6730
|
+
cancelController.abort(getAbortDisconnectError());
|
|
6731
|
+
};
|
|
6732
|
+
|
|
6733
|
+
const cancelController = new AbortController();
|
|
6734
|
+
|
|
6735
|
+
// Validate the `gracefulCancel` option
|
|
6736
|
+
const validateGracefulCancel = ({gracefulCancel, cancelSignal, ipc, serialization}) => {
|
|
6737
|
+
if (!gracefulCancel) {
|
|
6738
|
+
return;
|
|
6739
|
+
}
|
|
6740
|
+
|
|
6741
|
+
if (cancelSignal === undefined) {
|
|
6742
|
+
throw new Error('The `cancelSignal` option must be defined when setting the `gracefulCancel` option.');
|
|
6743
|
+
}
|
|
6744
|
+
|
|
6745
|
+
if (!ipc) {
|
|
6746
|
+
throw new Error('The `ipc` option cannot be false when setting the `gracefulCancel` option.');
|
|
6747
|
+
}
|
|
6748
|
+
|
|
6749
|
+
if (serialization === 'json') {
|
|
6750
|
+
throw new Error('The `serialization` option cannot be \'json\' when setting the `gracefulCancel` option.');
|
|
6751
|
+
}
|
|
6752
|
+
};
|
|
6753
|
+
|
|
6754
|
+
// Send abort reason to the subprocess when aborting the `cancelSignal` option and `gracefulCancel` is `true`
|
|
6755
|
+
const throwOnGracefulCancel = ({
|
|
6756
|
+
subprocess,
|
|
6757
|
+
cancelSignal,
|
|
6758
|
+
gracefulCancel,
|
|
6759
|
+
forceKillAfterDelay,
|
|
6760
|
+
context,
|
|
6761
|
+
controller,
|
|
6762
|
+
}) => gracefulCancel
|
|
6763
|
+
? [sendOnAbort({
|
|
6764
|
+
subprocess,
|
|
6765
|
+
cancelSignal,
|
|
6766
|
+
forceKillAfterDelay,
|
|
6767
|
+
context,
|
|
6768
|
+
controller,
|
|
6769
|
+
})]
|
|
6770
|
+
: [];
|
|
6771
|
+
|
|
6772
|
+
const sendOnAbort = async ({subprocess, cancelSignal, forceKillAfterDelay, context, controller: {signal}}) => {
|
|
6773
|
+
await onAbortedSignal(cancelSignal, signal);
|
|
6774
|
+
const reason = getReason(cancelSignal);
|
|
6775
|
+
await sendAbort(subprocess, reason);
|
|
6776
|
+
killOnTimeout({
|
|
6777
|
+
kill: subprocess.kill,
|
|
6778
|
+
forceKillAfterDelay,
|
|
6779
|
+
context,
|
|
6780
|
+
controllerSignal: signal,
|
|
6781
|
+
});
|
|
6782
|
+
context.terminationReason ??= 'gracefulCancel';
|
|
6783
|
+
throw cancelSignal.reason;
|
|
6784
|
+
};
|
|
6785
|
+
|
|
6786
|
+
// The default `reason` is a DOMException, which is not serializable with V8
|
|
6787
|
+
// See https://github.com/nodejs/node/issues/53225
|
|
6788
|
+
const getReason = ({reason}) => {
|
|
6789
|
+
if (!(reason instanceof DOMException)) {
|
|
6790
|
+
return reason;
|
|
6791
|
+
}
|
|
6792
|
+
|
|
6793
|
+
const error = new Error(reason.message);
|
|
6794
|
+
Object.defineProperty(error, 'stack', {
|
|
6795
|
+
value: reason.stack,
|
|
6796
|
+
enumerable: false,
|
|
6797
|
+
configurable: true,
|
|
6798
|
+
writable: true,
|
|
6799
|
+
});
|
|
6800
|
+
return error;
|
|
6801
|
+
};
|
|
5588
6802
|
|
|
5589
6803
|
// Validate `timeout` option
|
|
5590
6804
|
const validateTimeout = ({timeout}) => {
|
|
@@ -5600,7 +6814,7 @@ const throwOnTimeout = (subprocess, timeout, context, controller) => timeout ===
|
|
|
5600
6814
|
|
|
5601
6815
|
const killAfterTimeout = async (subprocess, timeout, context, {signal}) => {
|
|
5602
6816
|
await promises.setTimeout(timeout, undefined, {signal});
|
|
5603
|
-
context.
|
|
6817
|
+
context.terminationReason ??= 'timeout';
|
|
5604
6818
|
subprocess.kill();
|
|
5605
6819
|
throw new DiscardedError();
|
|
5606
6820
|
};
|
|
@@ -5653,6 +6867,49 @@ const handleNodeOption = (file, commandArguments, {
|
|
|
5653
6867
|
];
|
|
5654
6868
|
};
|
|
5655
6869
|
|
|
6870
|
+
// Validate the `ipcInput` option
|
|
6871
|
+
const validateIpcInputOption = ({ipcInput, ipc, serialization}) => {
|
|
6872
|
+
if (ipcInput === undefined) {
|
|
6873
|
+
return;
|
|
6874
|
+
}
|
|
6875
|
+
|
|
6876
|
+
if (!ipc) {
|
|
6877
|
+
throw new Error('The `ipcInput` option cannot be set unless the `ipc` option is `true`.');
|
|
6878
|
+
}
|
|
6879
|
+
|
|
6880
|
+
validateIpcInput[serialization](ipcInput);
|
|
6881
|
+
};
|
|
6882
|
+
|
|
6883
|
+
const validateAdvancedInput = ipcInput => {
|
|
6884
|
+
try {
|
|
6885
|
+
node_v8.serialize(ipcInput);
|
|
6886
|
+
} catch (error) {
|
|
6887
|
+
throw new Error('The `ipcInput` option is not serializable with a structured clone.', {cause: error});
|
|
6888
|
+
}
|
|
6889
|
+
};
|
|
6890
|
+
|
|
6891
|
+
const validateJsonInput = ipcInput => {
|
|
6892
|
+
try {
|
|
6893
|
+
JSON.stringify(ipcInput);
|
|
6894
|
+
} catch (error) {
|
|
6895
|
+
throw new Error('The `ipcInput` option is not serializable with JSON.', {cause: error});
|
|
6896
|
+
}
|
|
6897
|
+
};
|
|
6898
|
+
|
|
6899
|
+
const validateIpcInput = {
|
|
6900
|
+
advanced: validateAdvancedInput,
|
|
6901
|
+
json: validateJsonInput,
|
|
6902
|
+
};
|
|
6903
|
+
|
|
6904
|
+
// When the `ipcInput` option is set, it is sent as an initial IPC message to the subprocess
|
|
6905
|
+
const sendIpcInput = async (subprocess, ipcInput) => {
|
|
6906
|
+
if (ipcInput === undefined) {
|
|
6907
|
+
return;
|
|
6908
|
+
}
|
|
6909
|
+
|
|
6910
|
+
await subprocess.sendMessage(ipcInput);
|
|
6911
|
+
};
|
|
6912
|
+
|
|
5656
6913
|
// Validate `encoding` option
|
|
5657
6914
|
const validateEncoding = ({encoding}) => {
|
|
5658
6915
|
if (ENCODINGS.has(encoding)) {
|
|
@@ -5751,6 +7008,9 @@ const normalizeOptions$2 = (filePath, rawArguments, rawOptions) => {
|
|
|
5751
7008
|
const options = addDefaultOptions(fdOptions);
|
|
5752
7009
|
validateTimeout(options);
|
|
5753
7010
|
validateEncoding(options);
|
|
7011
|
+
validateIpcInputOption(options);
|
|
7012
|
+
validateCancelSignal(options);
|
|
7013
|
+
validateGracefulCancel(options);
|
|
5754
7014
|
options.shell = normalizeFileUrl(options.shell);
|
|
5755
7015
|
options.env = getEnv(options);
|
|
5756
7016
|
options.killSignal = normalizeKillSignal(options.killSignal);
|
|
@@ -5777,7 +7037,9 @@ const addDefaultOptions = ({
|
|
|
5777
7037
|
windowsHide = true,
|
|
5778
7038
|
killSignal = 'SIGTERM',
|
|
5779
7039
|
forceKillAfterDelay = true,
|
|
5780
|
-
|
|
7040
|
+
gracefulCancel = false,
|
|
7041
|
+
ipcInput,
|
|
7042
|
+
ipc = ipcInput !== undefined || gracefulCancel,
|
|
5781
7043
|
serialization = 'advanced',
|
|
5782
7044
|
...options
|
|
5783
7045
|
}) => ({
|
|
@@ -5793,6 +7055,8 @@ const addDefaultOptions = ({
|
|
|
5793
7055
|
windowsHide,
|
|
5794
7056
|
killSignal,
|
|
5795
7057
|
forceKillAfterDelay,
|
|
7058
|
+
gracefulCancel,
|
|
7059
|
+
ipcInput,
|
|
5796
7060
|
ipc,
|
|
5797
7061
|
serialization,
|
|
5798
7062
|
});
|
|
@@ -5813,386 +7077,6 @@ const getEnv = ({env: envOption, extendEnv, preferLocal, node, localDirectory, n
|
|
|
5813
7077
|
return env;
|
|
5814
7078
|
};
|
|
5815
7079
|
|
|
5816
|
-
const getRealtimeSignals=()=>{
|
|
5817
|
-
const length=SIGRTMAX-SIGRTMIN+1;
|
|
5818
|
-
return Array.from({length},getRealtimeSignal)
|
|
5819
|
-
};
|
|
5820
|
-
|
|
5821
|
-
const getRealtimeSignal=(value,index)=>({
|
|
5822
|
-
name:`SIGRT${index+1}`,
|
|
5823
|
-
number:SIGRTMIN+index,
|
|
5824
|
-
action:"terminate",
|
|
5825
|
-
description:"Application-specific signal (realtime)",
|
|
5826
|
-
standard:"posix"
|
|
5827
|
-
});
|
|
5828
|
-
|
|
5829
|
-
const SIGRTMIN=34;
|
|
5830
|
-
const SIGRTMAX=64;
|
|
5831
|
-
|
|
5832
|
-
const SIGNALS=[
|
|
5833
|
-
{
|
|
5834
|
-
name:"SIGHUP",
|
|
5835
|
-
number:1,
|
|
5836
|
-
action:"terminate",
|
|
5837
|
-
description:"Terminal closed",
|
|
5838
|
-
standard:"posix"
|
|
5839
|
-
},
|
|
5840
|
-
{
|
|
5841
|
-
name:"SIGINT",
|
|
5842
|
-
number:2,
|
|
5843
|
-
action:"terminate",
|
|
5844
|
-
description:"User interruption with CTRL-C",
|
|
5845
|
-
standard:"ansi"
|
|
5846
|
-
},
|
|
5847
|
-
{
|
|
5848
|
-
name:"SIGQUIT",
|
|
5849
|
-
number:3,
|
|
5850
|
-
action:"core",
|
|
5851
|
-
description:"User interruption with CTRL-\\",
|
|
5852
|
-
standard:"posix"
|
|
5853
|
-
},
|
|
5854
|
-
{
|
|
5855
|
-
name:"SIGILL",
|
|
5856
|
-
number:4,
|
|
5857
|
-
action:"core",
|
|
5858
|
-
description:"Invalid machine instruction",
|
|
5859
|
-
standard:"ansi"
|
|
5860
|
-
},
|
|
5861
|
-
{
|
|
5862
|
-
name:"SIGTRAP",
|
|
5863
|
-
number:5,
|
|
5864
|
-
action:"core",
|
|
5865
|
-
description:"Debugger breakpoint",
|
|
5866
|
-
standard:"posix"
|
|
5867
|
-
},
|
|
5868
|
-
{
|
|
5869
|
-
name:"SIGABRT",
|
|
5870
|
-
number:6,
|
|
5871
|
-
action:"core",
|
|
5872
|
-
description:"Aborted",
|
|
5873
|
-
standard:"ansi"
|
|
5874
|
-
},
|
|
5875
|
-
{
|
|
5876
|
-
name:"SIGIOT",
|
|
5877
|
-
number:6,
|
|
5878
|
-
action:"core",
|
|
5879
|
-
description:"Aborted",
|
|
5880
|
-
standard:"bsd"
|
|
5881
|
-
},
|
|
5882
|
-
{
|
|
5883
|
-
name:"SIGBUS",
|
|
5884
|
-
number:7,
|
|
5885
|
-
action:"core",
|
|
5886
|
-
description:
|
|
5887
|
-
"Bus error due to misaligned, non-existing address or paging error",
|
|
5888
|
-
standard:"bsd"
|
|
5889
|
-
},
|
|
5890
|
-
{
|
|
5891
|
-
name:"SIGEMT",
|
|
5892
|
-
number:7,
|
|
5893
|
-
action:"terminate",
|
|
5894
|
-
description:"Command should be emulated but is not implemented",
|
|
5895
|
-
standard:"other"
|
|
5896
|
-
},
|
|
5897
|
-
{
|
|
5898
|
-
name:"SIGFPE",
|
|
5899
|
-
number:8,
|
|
5900
|
-
action:"core",
|
|
5901
|
-
description:"Floating point arithmetic error",
|
|
5902
|
-
standard:"ansi"
|
|
5903
|
-
},
|
|
5904
|
-
{
|
|
5905
|
-
name:"SIGKILL",
|
|
5906
|
-
number:9,
|
|
5907
|
-
action:"terminate",
|
|
5908
|
-
description:"Forced termination",
|
|
5909
|
-
standard:"posix",
|
|
5910
|
-
forced:true
|
|
5911
|
-
},
|
|
5912
|
-
{
|
|
5913
|
-
name:"SIGUSR1",
|
|
5914
|
-
number:10,
|
|
5915
|
-
action:"terminate",
|
|
5916
|
-
description:"Application-specific signal",
|
|
5917
|
-
standard:"posix"
|
|
5918
|
-
},
|
|
5919
|
-
{
|
|
5920
|
-
name:"SIGSEGV",
|
|
5921
|
-
number:11,
|
|
5922
|
-
action:"core",
|
|
5923
|
-
description:"Segmentation fault",
|
|
5924
|
-
standard:"ansi"
|
|
5925
|
-
},
|
|
5926
|
-
{
|
|
5927
|
-
name:"SIGUSR2",
|
|
5928
|
-
number:12,
|
|
5929
|
-
action:"terminate",
|
|
5930
|
-
description:"Application-specific signal",
|
|
5931
|
-
standard:"posix"
|
|
5932
|
-
},
|
|
5933
|
-
{
|
|
5934
|
-
name:"SIGPIPE",
|
|
5935
|
-
number:13,
|
|
5936
|
-
action:"terminate",
|
|
5937
|
-
description:"Broken pipe or socket",
|
|
5938
|
-
standard:"posix"
|
|
5939
|
-
},
|
|
5940
|
-
{
|
|
5941
|
-
name:"SIGALRM",
|
|
5942
|
-
number:14,
|
|
5943
|
-
action:"terminate",
|
|
5944
|
-
description:"Timeout or timer",
|
|
5945
|
-
standard:"posix"
|
|
5946
|
-
},
|
|
5947
|
-
{
|
|
5948
|
-
name:"SIGTERM",
|
|
5949
|
-
number:15,
|
|
5950
|
-
action:"terminate",
|
|
5951
|
-
description:"Termination",
|
|
5952
|
-
standard:"ansi"
|
|
5953
|
-
},
|
|
5954
|
-
{
|
|
5955
|
-
name:"SIGSTKFLT",
|
|
5956
|
-
number:16,
|
|
5957
|
-
action:"terminate",
|
|
5958
|
-
description:"Stack is empty or overflowed",
|
|
5959
|
-
standard:"other"
|
|
5960
|
-
},
|
|
5961
|
-
{
|
|
5962
|
-
name:"SIGCHLD",
|
|
5963
|
-
number:17,
|
|
5964
|
-
action:"ignore",
|
|
5965
|
-
description:"Child process terminated, paused or unpaused",
|
|
5966
|
-
standard:"posix"
|
|
5967
|
-
},
|
|
5968
|
-
{
|
|
5969
|
-
name:"SIGCLD",
|
|
5970
|
-
number:17,
|
|
5971
|
-
action:"ignore",
|
|
5972
|
-
description:"Child process terminated, paused or unpaused",
|
|
5973
|
-
standard:"other"
|
|
5974
|
-
},
|
|
5975
|
-
{
|
|
5976
|
-
name:"SIGCONT",
|
|
5977
|
-
number:18,
|
|
5978
|
-
action:"unpause",
|
|
5979
|
-
description:"Unpaused",
|
|
5980
|
-
standard:"posix",
|
|
5981
|
-
forced:true
|
|
5982
|
-
},
|
|
5983
|
-
{
|
|
5984
|
-
name:"SIGSTOP",
|
|
5985
|
-
number:19,
|
|
5986
|
-
action:"pause",
|
|
5987
|
-
description:"Paused",
|
|
5988
|
-
standard:"posix",
|
|
5989
|
-
forced:true
|
|
5990
|
-
},
|
|
5991
|
-
{
|
|
5992
|
-
name:"SIGTSTP",
|
|
5993
|
-
number:20,
|
|
5994
|
-
action:"pause",
|
|
5995
|
-
description:"Paused using CTRL-Z or \"suspend\"",
|
|
5996
|
-
standard:"posix"
|
|
5997
|
-
},
|
|
5998
|
-
{
|
|
5999
|
-
name:"SIGTTIN",
|
|
6000
|
-
number:21,
|
|
6001
|
-
action:"pause",
|
|
6002
|
-
description:"Background process cannot read terminal input",
|
|
6003
|
-
standard:"posix"
|
|
6004
|
-
},
|
|
6005
|
-
{
|
|
6006
|
-
name:"SIGBREAK",
|
|
6007
|
-
number:21,
|
|
6008
|
-
action:"terminate",
|
|
6009
|
-
description:"User interruption with CTRL-BREAK",
|
|
6010
|
-
standard:"other"
|
|
6011
|
-
},
|
|
6012
|
-
{
|
|
6013
|
-
name:"SIGTTOU",
|
|
6014
|
-
number:22,
|
|
6015
|
-
action:"pause",
|
|
6016
|
-
description:"Background process cannot write to terminal output",
|
|
6017
|
-
standard:"posix"
|
|
6018
|
-
},
|
|
6019
|
-
{
|
|
6020
|
-
name:"SIGURG",
|
|
6021
|
-
number:23,
|
|
6022
|
-
action:"ignore",
|
|
6023
|
-
description:"Socket received out-of-band data",
|
|
6024
|
-
standard:"bsd"
|
|
6025
|
-
},
|
|
6026
|
-
{
|
|
6027
|
-
name:"SIGXCPU",
|
|
6028
|
-
number:24,
|
|
6029
|
-
action:"core",
|
|
6030
|
-
description:"Process timed out",
|
|
6031
|
-
standard:"bsd"
|
|
6032
|
-
},
|
|
6033
|
-
{
|
|
6034
|
-
name:"SIGXFSZ",
|
|
6035
|
-
number:25,
|
|
6036
|
-
action:"core",
|
|
6037
|
-
description:"File too big",
|
|
6038
|
-
standard:"bsd"
|
|
6039
|
-
},
|
|
6040
|
-
{
|
|
6041
|
-
name:"SIGVTALRM",
|
|
6042
|
-
number:26,
|
|
6043
|
-
action:"terminate",
|
|
6044
|
-
description:"Timeout or timer",
|
|
6045
|
-
standard:"bsd"
|
|
6046
|
-
},
|
|
6047
|
-
{
|
|
6048
|
-
name:"SIGPROF",
|
|
6049
|
-
number:27,
|
|
6050
|
-
action:"terminate",
|
|
6051
|
-
description:"Timeout or timer",
|
|
6052
|
-
standard:"bsd"
|
|
6053
|
-
},
|
|
6054
|
-
{
|
|
6055
|
-
name:"SIGWINCH",
|
|
6056
|
-
number:28,
|
|
6057
|
-
action:"ignore",
|
|
6058
|
-
description:"Terminal window size changed",
|
|
6059
|
-
standard:"bsd"
|
|
6060
|
-
},
|
|
6061
|
-
{
|
|
6062
|
-
name:"SIGIO",
|
|
6063
|
-
number:29,
|
|
6064
|
-
action:"terminate",
|
|
6065
|
-
description:"I/O is available",
|
|
6066
|
-
standard:"other"
|
|
6067
|
-
},
|
|
6068
|
-
{
|
|
6069
|
-
name:"SIGPOLL",
|
|
6070
|
-
number:29,
|
|
6071
|
-
action:"terminate",
|
|
6072
|
-
description:"Watched event",
|
|
6073
|
-
standard:"other"
|
|
6074
|
-
},
|
|
6075
|
-
{
|
|
6076
|
-
name:"SIGINFO",
|
|
6077
|
-
number:29,
|
|
6078
|
-
action:"ignore",
|
|
6079
|
-
description:"Request for process information",
|
|
6080
|
-
standard:"other"
|
|
6081
|
-
},
|
|
6082
|
-
{
|
|
6083
|
-
name:"SIGPWR",
|
|
6084
|
-
number:30,
|
|
6085
|
-
action:"terminate",
|
|
6086
|
-
description:"Device running out of power",
|
|
6087
|
-
standard:"systemv"
|
|
6088
|
-
},
|
|
6089
|
-
{
|
|
6090
|
-
name:"SIGSYS",
|
|
6091
|
-
number:31,
|
|
6092
|
-
action:"core",
|
|
6093
|
-
description:"Invalid system call",
|
|
6094
|
-
standard:"other"
|
|
6095
|
-
},
|
|
6096
|
-
{
|
|
6097
|
-
name:"SIGUNUSED",
|
|
6098
|
-
number:31,
|
|
6099
|
-
action:"terminate",
|
|
6100
|
-
description:"Invalid system call",
|
|
6101
|
-
standard:"other"
|
|
6102
|
-
}];
|
|
6103
|
-
|
|
6104
|
-
const getSignals=()=>{
|
|
6105
|
-
const realtimeSignals=getRealtimeSignals();
|
|
6106
|
-
const signals=[...SIGNALS,...realtimeSignals].map(normalizeSignal);
|
|
6107
|
-
return signals
|
|
6108
|
-
};
|
|
6109
|
-
|
|
6110
|
-
|
|
6111
|
-
|
|
6112
|
-
|
|
6113
|
-
|
|
6114
|
-
|
|
6115
|
-
|
|
6116
|
-
const normalizeSignal=({
|
|
6117
|
-
name,
|
|
6118
|
-
number:defaultNumber,
|
|
6119
|
-
description,
|
|
6120
|
-
action,
|
|
6121
|
-
forced=false,
|
|
6122
|
-
standard
|
|
6123
|
-
})=>{
|
|
6124
|
-
const{
|
|
6125
|
-
signals:{[name]:constantSignal}
|
|
6126
|
-
}=node_os.constants;
|
|
6127
|
-
const supported=constantSignal!==undefined;
|
|
6128
|
-
const number=supported?constantSignal:defaultNumber;
|
|
6129
|
-
return {name,number,description,supported,action,forced,standard}
|
|
6130
|
-
};
|
|
6131
|
-
|
|
6132
|
-
const getSignalsByName=()=>{
|
|
6133
|
-
const signals=getSignals();
|
|
6134
|
-
return Object.fromEntries(signals.map(getSignalByName))
|
|
6135
|
-
};
|
|
6136
|
-
|
|
6137
|
-
const getSignalByName=({
|
|
6138
|
-
name,
|
|
6139
|
-
number,
|
|
6140
|
-
description,
|
|
6141
|
-
supported,
|
|
6142
|
-
action,
|
|
6143
|
-
forced,
|
|
6144
|
-
standard
|
|
6145
|
-
})=>[name,{name,number,description,supported,action,forced,standard}];
|
|
6146
|
-
|
|
6147
|
-
const signalsByName=getSignalsByName();
|
|
6148
|
-
|
|
6149
|
-
|
|
6150
|
-
|
|
6151
|
-
|
|
6152
|
-
const getSignalsByNumber=()=>{
|
|
6153
|
-
const signals=getSignals();
|
|
6154
|
-
const length=SIGRTMAX+1;
|
|
6155
|
-
const signalsA=Array.from({length},(value,number)=>
|
|
6156
|
-
getSignalByNumber(number,signals)
|
|
6157
|
-
);
|
|
6158
|
-
return Object.assign({},...signalsA)
|
|
6159
|
-
};
|
|
6160
|
-
|
|
6161
|
-
const getSignalByNumber=(number,signals)=>{
|
|
6162
|
-
const signal=findSignalByNumber(number,signals);
|
|
6163
|
-
|
|
6164
|
-
if(signal===undefined){
|
|
6165
|
-
return {}
|
|
6166
|
-
}
|
|
6167
|
-
|
|
6168
|
-
const{name,description,supported,action,forced,standard}=signal;
|
|
6169
|
-
return {
|
|
6170
|
-
[number]:{
|
|
6171
|
-
name,
|
|
6172
|
-
number,
|
|
6173
|
-
description,
|
|
6174
|
-
supported,
|
|
6175
|
-
action,
|
|
6176
|
-
forced,
|
|
6177
|
-
standard
|
|
6178
|
-
}
|
|
6179
|
-
}
|
|
6180
|
-
};
|
|
6181
|
-
|
|
6182
|
-
|
|
6183
|
-
|
|
6184
|
-
const findSignalByNumber=(number,signals)=>{
|
|
6185
|
-
const signal=signals.find(({name})=>node_os.constants.signals[name]===number);
|
|
6186
|
-
|
|
6187
|
-
if(signal!==undefined){
|
|
6188
|
-
return signal
|
|
6189
|
-
}
|
|
6190
|
-
|
|
6191
|
-
return signals.find((signalA)=>signalA.number===number)
|
|
6192
|
-
};
|
|
6193
|
-
|
|
6194
|
-
getSignalsByNumber();
|
|
6195
|
-
|
|
6196
7080
|
function stripFinalNewline(input) {
|
|
6197
7081
|
if (typeof input === 'string') {
|
|
6198
7082
|
return stripFinalNewlineString(input);
|
|
@@ -6714,6 +7598,17 @@ const getMaxBufferUnit = (readableObjectMode, lines, encoding) => {
|
|
|
6714
7598
|
return 'characters';
|
|
6715
7599
|
};
|
|
6716
7600
|
|
|
7601
|
+
// Check the `maxBuffer` option with `result.ipcOutput`
|
|
7602
|
+
const checkIpcMaxBuffer = (subprocess, ipcOutput, maxBuffer) => {
|
|
7603
|
+
if (ipcOutput.length !== maxBuffer) {
|
|
7604
|
+
return;
|
|
7605
|
+
}
|
|
7606
|
+
|
|
7607
|
+
const error = new MaxBufferError();
|
|
7608
|
+
error.maxBufferInfo = {fdNumber: 'ipc'};
|
|
7609
|
+
throw error;
|
|
7610
|
+
};
|
|
7611
|
+
|
|
6717
7612
|
// Error message when `maxBuffer` is hit
|
|
6718
7613
|
const getMaxBufferMessage = (error, maxBuffer) => {
|
|
6719
7614
|
const {streamName, threshold, unit} = getMaxBufferInfo(error, maxBuffer);
|
|
@@ -6727,6 +7622,11 @@ const getMaxBufferInfo = (error, maxBuffer) => {
|
|
|
6727
7622
|
|
|
6728
7623
|
const {maxBufferInfo: {fdNumber, unit}} = error;
|
|
6729
7624
|
delete error.maxBufferInfo;
|
|
7625
|
+
|
|
7626
|
+
if (fdNumber === 'ipc') {
|
|
7627
|
+
return {streamName: 'IPC output', threshold: maxBuffer.at(-1), unit: 'messages'};
|
|
7628
|
+
}
|
|
7629
|
+
|
|
6730
7630
|
return {streamName: getStreamName(fdNumber), threshold: maxBuffer[fdNumber], unit};
|
|
6731
7631
|
};
|
|
6732
7632
|
|
|
@@ -6754,6 +7654,7 @@ const getMaxBufferSync = ([, stdoutMaxBuffer]) => stdoutMaxBuffer;
|
|
|
6754
7654
|
const createMessages = ({
|
|
6755
7655
|
stdio,
|
|
6756
7656
|
all,
|
|
7657
|
+
ipcOutput,
|
|
6757
7658
|
originalError,
|
|
6758
7659
|
signal,
|
|
6759
7660
|
signalDescription,
|
|
@@ -6761,7 +7662,11 @@ const createMessages = ({
|
|
|
6761
7662
|
escapedCommand,
|
|
6762
7663
|
timedOut,
|
|
6763
7664
|
isCanceled,
|
|
7665
|
+
isGracefullyCanceled,
|
|
6764
7666
|
isMaxBuffer,
|
|
7667
|
+
isForcefullyTerminated,
|
|
7668
|
+
forceKillAfterDelay,
|
|
7669
|
+
killSignal,
|
|
6765
7670
|
maxBuffer,
|
|
6766
7671
|
timeout,
|
|
6767
7672
|
cwd,
|
|
@@ -6778,33 +7683,73 @@ const createMessages = ({
|
|
|
6778
7683
|
signalDescription,
|
|
6779
7684
|
exitCode,
|
|
6780
7685
|
isCanceled,
|
|
7686
|
+
isGracefullyCanceled,
|
|
7687
|
+
isForcefullyTerminated,
|
|
7688
|
+
forceKillAfterDelay,
|
|
7689
|
+
killSignal,
|
|
6781
7690
|
});
|
|
6782
7691
|
const originalMessage = getOriginalMessage(originalError, cwd);
|
|
6783
7692
|
const suffix = originalMessage === undefined ? '' : `\n${originalMessage}`;
|
|
6784
7693
|
const shortMessage = `${prefix}: ${escapedCommand}${suffix}`;
|
|
6785
7694
|
const messageStdio = all === undefined ? [stdio[2], stdio[1]] : [all];
|
|
6786
|
-
const message = [
|
|
7695
|
+
const message = [
|
|
7696
|
+
shortMessage,
|
|
7697
|
+
...messageStdio,
|
|
7698
|
+
...stdio.slice(3),
|
|
7699
|
+
ipcOutput.map(ipcMessage => serializeIpcMessage(ipcMessage)).join('\n'),
|
|
7700
|
+
]
|
|
6787
7701
|
.map(messagePart => escapeLines(stripFinalNewline(serializeMessagePart(messagePart))))
|
|
6788
7702
|
.filter(Boolean)
|
|
6789
7703
|
.join('\n\n');
|
|
6790
7704
|
return {originalMessage, shortMessage, message};
|
|
6791
7705
|
};
|
|
6792
7706
|
|
|
6793
|
-
const getErrorPrefix = ({
|
|
7707
|
+
const getErrorPrefix = ({
|
|
7708
|
+
originalError,
|
|
7709
|
+
timedOut,
|
|
7710
|
+
timeout,
|
|
7711
|
+
isMaxBuffer,
|
|
7712
|
+
maxBuffer,
|
|
7713
|
+
errorCode,
|
|
7714
|
+
signal,
|
|
7715
|
+
signalDescription,
|
|
7716
|
+
exitCode,
|
|
7717
|
+
isCanceled,
|
|
7718
|
+
isGracefullyCanceled,
|
|
7719
|
+
isForcefullyTerminated,
|
|
7720
|
+
forceKillAfterDelay,
|
|
7721
|
+
killSignal,
|
|
7722
|
+
}) => {
|
|
7723
|
+
const forcefulSuffix = getForcefulSuffix(isForcefullyTerminated, forceKillAfterDelay);
|
|
7724
|
+
|
|
6794
7725
|
if (timedOut) {
|
|
6795
|
-
return `Command timed out after ${timeout} milliseconds`;
|
|
7726
|
+
return `Command timed out after ${timeout} milliseconds${forcefulSuffix}`;
|
|
7727
|
+
}
|
|
7728
|
+
|
|
7729
|
+
if (isGracefullyCanceled) {
|
|
7730
|
+
if (signal === undefined) {
|
|
7731
|
+
return `Command was gracefully canceled with exit code ${exitCode}`;
|
|
7732
|
+
}
|
|
7733
|
+
|
|
7734
|
+
return isForcefullyTerminated
|
|
7735
|
+
? `Command was gracefully canceled${forcefulSuffix}`
|
|
7736
|
+
: `Command was gracefully canceled with ${signal} (${signalDescription})`;
|
|
6796
7737
|
}
|
|
6797
7738
|
|
|
6798
7739
|
if (isCanceled) {
|
|
6799
|
-
return
|
|
7740
|
+
return `Command was canceled${forcefulSuffix}`;
|
|
6800
7741
|
}
|
|
6801
7742
|
|
|
6802
7743
|
if (isMaxBuffer) {
|
|
6803
|
-
return getMaxBufferMessage(originalError, maxBuffer)
|
|
7744
|
+
return `${getMaxBufferMessage(originalError, maxBuffer)}${forcefulSuffix}`;
|
|
6804
7745
|
}
|
|
6805
7746
|
|
|
6806
7747
|
if (errorCode !== undefined) {
|
|
6807
|
-
return `Command failed with ${errorCode}`;
|
|
7748
|
+
return `Command failed with ${errorCode}${forcefulSuffix}`;
|
|
7749
|
+
}
|
|
7750
|
+
|
|
7751
|
+
if (isForcefullyTerminated) {
|
|
7752
|
+
return `Command was killed with ${killSignal} (${getSignalDescription(killSignal)})${forcefulSuffix}`;
|
|
6808
7753
|
}
|
|
6809
7754
|
|
|
6810
7755
|
if (signal !== undefined) {
|
|
@@ -6818,6 +7763,10 @@ const getErrorPrefix = ({originalError, timedOut, timeout, isMaxBuffer, maxBuffe
|
|
|
6818
7763
|
return 'Command failed';
|
|
6819
7764
|
};
|
|
6820
7765
|
|
|
7766
|
+
const getForcefulSuffix = (isForcefullyTerminated, forceKillAfterDelay) => isForcefullyTerminated
|
|
7767
|
+
? ` and was forcefully terminated after ${forceKillAfterDelay} milliseconds`
|
|
7768
|
+
: '';
|
|
7769
|
+
|
|
6821
7770
|
const getOriginalMessage = (originalError, cwd) => {
|
|
6822
7771
|
if (originalError instanceof DiscardedError) {
|
|
6823
7772
|
return;
|
|
@@ -6830,6 +7779,10 @@ const getOriginalMessage = (originalError, cwd) => {
|
|
|
6830
7779
|
return escapedOriginalMessage === '' ? undefined : escapedOriginalMessage;
|
|
6831
7780
|
};
|
|
6832
7781
|
|
|
7782
|
+
const serializeIpcMessage = ipcMessage => typeof ipcMessage === 'string'
|
|
7783
|
+
? ipcMessage
|
|
7784
|
+
: node_util.inspect(ipcMessage);
|
|
7785
|
+
|
|
6833
7786
|
const serializeMessagePart = messagePart => Array.isArray(messagePart)
|
|
6834
7787
|
? messagePart.map(messageItem => stripFinalNewline(serializeMessageItem(messageItem))).filter(Boolean).join('\n')
|
|
6835
7788
|
: serializeMessageItem(messagePart);
|
|
@@ -6852,6 +7805,7 @@ const makeSuccessResult = ({
|
|
|
6852
7805
|
escapedCommand,
|
|
6853
7806
|
stdio,
|
|
6854
7807
|
all,
|
|
7808
|
+
ipcOutput,
|
|
6855
7809
|
options: {cwd},
|
|
6856
7810
|
startTime,
|
|
6857
7811
|
}) => omitUndefinedProperties({
|
|
@@ -6862,13 +7816,16 @@ const makeSuccessResult = ({
|
|
|
6862
7816
|
failed: false,
|
|
6863
7817
|
timedOut: false,
|
|
6864
7818
|
isCanceled: false,
|
|
7819
|
+
isGracefullyCanceled: false,
|
|
6865
7820
|
isTerminated: false,
|
|
6866
7821
|
isMaxBuffer: false,
|
|
7822
|
+
isForcefullyTerminated: false,
|
|
6867
7823
|
exitCode: 0,
|
|
6868
7824
|
stdout: stdio[1],
|
|
6869
7825
|
stderr: stdio[2],
|
|
6870
7826
|
all,
|
|
6871
7827
|
stdio,
|
|
7828
|
+
ipcOutput,
|
|
6872
7829
|
pipedFrom: [],
|
|
6873
7830
|
});
|
|
6874
7831
|
|
|
@@ -6888,8 +7845,11 @@ const makeEarlyError = ({
|
|
|
6888
7845
|
startTime,
|
|
6889
7846
|
timedOut: false,
|
|
6890
7847
|
isCanceled: false,
|
|
7848
|
+
isGracefullyCanceled: false,
|
|
6891
7849
|
isMaxBuffer: false,
|
|
7850
|
+
isForcefullyTerminated: false,
|
|
6892
7851
|
stdio: Array.from({length: fileDescriptors.length}),
|
|
7852
|
+
ipcOutput: [],
|
|
6893
7853
|
options,
|
|
6894
7854
|
isSync,
|
|
6895
7855
|
});
|
|
@@ -6902,18 +7862,29 @@ const makeError = ({
|
|
|
6902
7862
|
startTime,
|
|
6903
7863
|
timedOut,
|
|
6904
7864
|
isCanceled,
|
|
7865
|
+
isGracefullyCanceled,
|
|
6905
7866
|
isMaxBuffer,
|
|
7867
|
+
isForcefullyTerminated,
|
|
6906
7868
|
exitCode: rawExitCode,
|
|
6907
7869
|
signal: rawSignal,
|
|
6908
7870
|
stdio,
|
|
6909
7871
|
all,
|
|
6910
|
-
|
|
7872
|
+
ipcOutput,
|
|
7873
|
+
options: {
|
|
7874
|
+
timeoutDuration,
|
|
7875
|
+
timeout = timeoutDuration,
|
|
7876
|
+
forceKillAfterDelay,
|
|
7877
|
+
killSignal,
|
|
7878
|
+
cwd,
|
|
7879
|
+
maxBuffer,
|
|
7880
|
+
},
|
|
6911
7881
|
isSync,
|
|
6912
7882
|
}) => {
|
|
6913
7883
|
const {exitCode, signal, signalDescription} = normalizeExitPayload(rawExitCode, rawSignal);
|
|
6914
7884
|
const {originalMessage, shortMessage, message} = createMessages({
|
|
6915
7885
|
stdio,
|
|
6916
7886
|
all,
|
|
7887
|
+
ipcOutput,
|
|
6917
7888
|
originalError,
|
|
6918
7889
|
signal,
|
|
6919
7890
|
signalDescription,
|
|
@@ -6921,7 +7892,11 @@ const makeError = ({
|
|
|
6921
7892
|
escapedCommand,
|
|
6922
7893
|
timedOut,
|
|
6923
7894
|
isCanceled,
|
|
7895
|
+
isGracefullyCanceled,
|
|
6924
7896
|
isMaxBuffer,
|
|
7897
|
+
isForcefullyTerminated,
|
|
7898
|
+
forceKillAfterDelay,
|
|
7899
|
+
killSignal,
|
|
6925
7900
|
maxBuffer,
|
|
6926
7901
|
timeout,
|
|
6927
7902
|
cwd,
|
|
@@ -6934,12 +7909,15 @@ const makeError = ({
|
|
|
6934
7909
|
startTime,
|
|
6935
7910
|
timedOut,
|
|
6936
7911
|
isCanceled,
|
|
7912
|
+
isGracefullyCanceled,
|
|
6937
7913
|
isMaxBuffer,
|
|
7914
|
+
isForcefullyTerminated,
|
|
6938
7915
|
exitCode,
|
|
6939
7916
|
signal,
|
|
6940
7917
|
signalDescription,
|
|
6941
7918
|
stdio,
|
|
6942
7919
|
all,
|
|
7920
|
+
ipcOutput,
|
|
6943
7921
|
cwd,
|
|
6944
7922
|
originalMessage,
|
|
6945
7923
|
shortMessage,
|
|
@@ -6954,12 +7932,15 @@ const getErrorProperties = ({
|
|
|
6954
7932
|
startTime,
|
|
6955
7933
|
timedOut,
|
|
6956
7934
|
isCanceled,
|
|
7935
|
+
isGracefullyCanceled,
|
|
6957
7936
|
isMaxBuffer,
|
|
7937
|
+
isForcefullyTerminated,
|
|
6958
7938
|
exitCode,
|
|
6959
7939
|
signal,
|
|
6960
7940
|
signalDescription,
|
|
6961
7941
|
stdio,
|
|
6962
7942
|
all,
|
|
7943
|
+
ipcOutput,
|
|
6963
7944
|
cwd,
|
|
6964
7945
|
originalMessage,
|
|
6965
7946
|
shortMessage,
|
|
@@ -6973,8 +7954,10 @@ const getErrorProperties = ({
|
|
|
6973
7954
|
failed: true,
|
|
6974
7955
|
timedOut,
|
|
6975
7956
|
isCanceled,
|
|
7957
|
+
isGracefullyCanceled,
|
|
6976
7958
|
isTerminated: signal !== undefined,
|
|
6977
7959
|
isMaxBuffer,
|
|
7960
|
+
isForcefullyTerminated,
|
|
6978
7961
|
exitCode,
|
|
6979
7962
|
signal,
|
|
6980
7963
|
signalDescription,
|
|
@@ -6983,6 +7966,7 @@ const getErrorProperties = ({
|
|
|
6983
7966
|
stderr: stdio[2],
|
|
6984
7967
|
all,
|
|
6985
7968
|
stdio,
|
|
7969
|
+
ipcOutput,
|
|
6986
7970
|
pipedFrom: [],
|
|
6987
7971
|
});
|
|
6988
7972
|
|
|
@@ -6993,7 +7977,7 @@ const omitUndefinedProperties = result => Object.fromEntries(Object.entries(resu
|
|
|
6993
7977
|
const normalizeExitPayload = (rawExitCode, rawSignal) => {
|
|
6994
7978
|
const exitCode = rawExitCode === null ? undefined : rawExitCode;
|
|
6995
7979
|
const signal = rawSignal === null ? undefined : rawSignal;
|
|
6996
|
-
const signalDescription = signal === undefined ? undefined :
|
|
7980
|
+
const signalDescription = signal === undefined ? undefined : getSignalDescription(rawSignal);
|
|
6997
7981
|
return {exitCode, signal, signalDescription};
|
|
6998
7982
|
};
|
|
6999
7983
|
|
|
@@ -7633,11 +8617,18 @@ const getStandardStreamDirection = value => {
|
|
|
7633
8617
|
// When the ambiguity remains, we default to `output` since it is the most common use case for additional file descriptors.
|
|
7634
8618
|
const DEFAULT_DIRECTION = 'output';
|
|
7635
8619
|
|
|
8620
|
+
// The `ipc` option adds an `ipc` item to the `stdio` option
|
|
8621
|
+
const normalizeIpcStdioArray = (stdioArray, ipc) => ipc && !stdioArray.includes('ipc')
|
|
8622
|
+
? [...stdioArray, 'ipc']
|
|
8623
|
+
: stdioArray;
|
|
8624
|
+
|
|
7636
8625
|
// Add support for `stdin`/`stdout`/`stderr` as an alias for `stdio`.
|
|
7637
8626
|
// Also normalize the `stdio` option.
|
|
7638
8627
|
const normalizeStdioOption = ({stdio, ipc, buffer, verbose, ...options}, isSync) => {
|
|
7639
8628
|
const stdioArray = getStdioArray(stdio, options).map((stdioOption, fdNumber) => addDefaultValue(stdioOption, fdNumber));
|
|
7640
|
-
return isSync
|
|
8629
|
+
return isSync
|
|
8630
|
+
? normalizeStdioSync(stdioArray, buffer, verbose)
|
|
8631
|
+
: normalizeIpcStdioArray(stdioArray, ipc);
|
|
7641
8632
|
};
|
|
7642
8633
|
|
|
7643
8634
|
const getStdioArray = (stdio, options) => {
|
|
@@ -7688,118 +8679,6 @@ const normalizeStdioSync = (stdioArray, buffer, verbose) => stdioArray.map((stdi
|
|
|
7688
8679
|
const isOutputPipeOnly = stdioOption => stdioOption === 'pipe'
|
|
7689
8680
|
|| (Array.isArray(stdioOption) && stdioOption.every(item => item === 'pipe'));
|
|
7690
8681
|
|
|
7691
|
-
// The `ipc` option adds an `ipc` item to the `stdio` option
|
|
7692
|
-
const normalizeStdioAsync = (stdioArray, ipc) => ipc && !stdioArray.includes('ipc')
|
|
7693
|
-
? [...stdioArray, 'ipc']
|
|
7694
|
-
: stdioArray;
|
|
7695
|
-
|
|
7696
|
-
// Retrieve stream targeted by the `to` option
|
|
7697
|
-
const getToStream = (destination, to = 'stdin') => {
|
|
7698
|
-
const isWritable = true;
|
|
7699
|
-
const {options, fileDescriptors} = SUBPROCESS_OPTIONS.get(destination);
|
|
7700
|
-
const fdNumber = getFdNumber(fileDescriptors, to, isWritable);
|
|
7701
|
-
const destinationStream = destination.stdio[fdNumber];
|
|
7702
|
-
|
|
7703
|
-
if (destinationStream === null) {
|
|
7704
|
-
throw new TypeError(getInvalidStdioOptionMessage(fdNumber, to, options, isWritable));
|
|
7705
|
-
}
|
|
7706
|
-
|
|
7707
|
-
return destinationStream;
|
|
7708
|
-
};
|
|
7709
|
-
|
|
7710
|
-
// Retrieve stream targeted by the `from` option
|
|
7711
|
-
const getFromStream = (source, from = 'stdout') => {
|
|
7712
|
-
const isWritable = false;
|
|
7713
|
-
const {options, fileDescriptors} = SUBPROCESS_OPTIONS.get(source);
|
|
7714
|
-
const fdNumber = getFdNumber(fileDescriptors, from, isWritable);
|
|
7715
|
-
const sourceStream = fdNumber === 'all' ? source.all : source.stdio[fdNumber];
|
|
7716
|
-
|
|
7717
|
-
if (sourceStream === null || sourceStream === undefined) {
|
|
7718
|
-
throw new TypeError(getInvalidStdioOptionMessage(fdNumber, from, options, isWritable));
|
|
7719
|
-
}
|
|
7720
|
-
|
|
7721
|
-
return sourceStream;
|
|
7722
|
-
};
|
|
7723
|
-
|
|
7724
|
-
// Keeps track of the options passed to each Execa call
|
|
7725
|
-
const SUBPROCESS_OPTIONS = new WeakMap();
|
|
7726
|
-
|
|
7727
|
-
const getFdNumber = (fileDescriptors, fdName, isWritable) => {
|
|
7728
|
-
const fdNumber = parseFdNumber(fdName, isWritable);
|
|
7729
|
-
validateFdNumber(fdNumber, fdName, isWritable, fileDescriptors);
|
|
7730
|
-
return fdNumber;
|
|
7731
|
-
};
|
|
7732
|
-
|
|
7733
|
-
const parseFdNumber = (fdName, isWritable) => {
|
|
7734
|
-
const fdNumber = parseFd(fdName);
|
|
7735
|
-
if (fdNumber !== undefined) {
|
|
7736
|
-
return fdNumber;
|
|
7737
|
-
}
|
|
7738
|
-
|
|
7739
|
-
const {validOptions, defaultValue} = isWritable
|
|
7740
|
-
? {validOptions: '"stdin"', defaultValue: 'stdin'}
|
|
7741
|
-
: {validOptions: '"stdout", "stderr", "all"', defaultValue: 'stdout'};
|
|
7742
|
-
throw new TypeError(`"${getOptionName(isWritable)}" must not be "${fdName}".
|
|
7743
|
-
It must be ${validOptions} or "fd3", "fd4" (and so on).
|
|
7744
|
-
It is optional and defaults to "${defaultValue}".`);
|
|
7745
|
-
};
|
|
7746
|
-
|
|
7747
|
-
const validateFdNumber = (fdNumber, fdName, isWritable, fileDescriptors) => {
|
|
7748
|
-
const fileDescriptor = fileDescriptors[getUsedDescriptor(fdNumber)];
|
|
7749
|
-
if (fileDescriptor === undefined) {
|
|
7750
|
-
throw new TypeError(`"${getOptionName(isWritable)}" must not be ${fdName}. That file descriptor does not exist.
|
|
7751
|
-
Please set the "stdio" option to ensure that file descriptor exists.`);
|
|
7752
|
-
}
|
|
7753
|
-
|
|
7754
|
-
if (fileDescriptor.direction === 'input' && !isWritable) {
|
|
7755
|
-
throw new TypeError(`"${getOptionName(isWritable)}" must not be ${fdName}. It must be a readable stream, not writable.`);
|
|
7756
|
-
}
|
|
7757
|
-
|
|
7758
|
-
if (fileDescriptor.direction !== 'input' && isWritable) {
|
|
7759
|
-
throw new TypeError(`"${getOptionName(isWritable)}" must not be ${fdName}. It must be a writable stream, not readable.`);
|
|
7760
|
-
}
|
|
7761
|
-
};
|
|
7762
|
-
|
|
7763
|
-
const getInvalidStdioOptionMessage = (fdNumber, fdName, options, isWritable) => {
|
|
7764
|
-
if (fdNumber === 'all' && !options.all) {
|
|
7765
|
-
return 'The "all" option must be true to use "from: \'all\'".';
|
|
7766
|
-
}
|
|
7767
|
-
|
|
7768
|
-
const {optionName, optionValue} = getInvalidStdioOption(fdNumber, options);
|
|
7769
|
-
return `The "${optionName}: ${serializeOptionValue(optionValue)}" option is incompatible with using "${getOptionName(isWritable)}: ${serializeOptionValue(fdName)}".
|
|
7770
|
-
Please set this option with "pipe" instead.`;
|
|
7771
|
-
};
|
|
7772
|
-
|
|
7773
|
-
const getInvalidStdioOption = (fdNumber, {stdin, stdout, stderr, stdio}) => {
|
|
7774
|
-
const usedDescriptor = getUsedDescriptor(fdNumber);
|
|
7775
|
-
|
|
7776
|
-
if (usedDescriptor === 0 && stdin !== undefined) {
|
|
7777
|
-
return {optionName: 'stdin', optionValue: stdin};
|
|
7778
|
-
}
|
|
7779
|
-
|
|
7780
|
-
if (usedDescriptor === 1 && stdout !== undefined) {
|
|
7781
|
-
return {optionName: 'stdout', optionValue: stdout};
|
|
7782
|
-
}
|
|
7783
|
-
|
|
7784
|
-
if (usedDescriptor === 2 && stderr !== undefined) {
|
|
7785
|
-
return {optionName: 'stderr', optionValue: stderr};
|
|
7786
|
-
}
|
|
7787
|
-
|
|
7788
|
-
return {optionName: `stdio[${usedDescriptor}]`, optionValue: stdio[usedDescriptor]};
|
|
7789
|
-
};
|
|
7790
|
-
|
|
7791
|
-
const getUsedDescriptor = fdNumber => fdNumber === 'all' ? 1 : fdNumber;
|
|
7792
|
-
|
|
7793
|
-
const getOptionName = isWritable => isWritable ? 'to' : 'from';
|
|
7794
|
-
|
|
7795
|
-
const serializeOptionValue = value => {
|
|
7796
|
-
if (typeof value === 'string') {
|
|
7797
|
-
return `'${value}'`;
|
|
7798
|
-
}
|
|
7799
|
-
|
|
7800
|
-
return typeof value === 'number' ? `${value}` : 'Stream';
|
|
7801
|
-
};
|
|
7802
|
-
|
|
7803
8682
|
// When we use multiple `stdio` values for the same streams, we pass 'pipe' to `child_process.spawn()`.
|
|
7804
8683
|
// We then emulate the piping done by core Node.js.
|
|
7805
8684
|
// To do so, we transform the following values:
|
|
@@ -8032,7 +8911,7 @@ const getDuplicateStreamInstance = ({otherStdioItems, type, value, optionName, d
|
|
|
8032
8911
|
|
|
8033
8912
|
const hasSameValue = ({type, value}, secondValue) => {
|
|
8034
8913
|
if (type === 'filePath') {
|
|
8035
|
-
return value.
|
|
8914
|
+
return value.file === secondValue.file;
|
|
8036
8915
|
}
|
|
8037
8916
|
|
|
8038
8917
|
if (type === 'fileUrl') {
|
|
@@ -8782,7 +9661,7 @@ const fdUsesVerbose = fdNumber => fdNumber === 1 || fdNumber === 2;
|
|
|
8782
9661
|
|
|
8783
9662
|
const PIPED_STDIO_VALUES = new Set(['pipe', 'overlapped']);
|
|
8784
9663
|
|
|
8785
|
-
// `verbose` printing logic with async methods
|
|
9664
|
+
// `verbose: 'full'` printing logic with async methods
|
|
8786
9665
|
const logLines = async (linesIterable, stream, verboseInfo) => {
|
|
8787
9666
|
for await (const line of linesIterable) {
|
|
8788
9667
|
if (!isPipingStream(stream)) {
|
|
@@ -8791,7 +9670,7 @@ const logLines = async (linesIterable, stream, verboseInfo) => {
|
|
|
8791
9670
|
}
|
|
8792
9671
|
};
|
|
8793
9672
|
|
|
8794
|
-
// `verbose` printing logic with sync methods
|
|
9673
|
+
// `verbose: 'full'` printing logic with sync methods
|
|
8795
9674
|
const logLinesSync = (linesArray, verboseInfo) => {
|
|
8796
9675
|
for (const line of linesArray) {
|
|
8797
9676
|
logLine(line, verboseInfo);
|
|
@@ -8809,15 +9688,9 @@ const isPipingStream = stream => stream._readableState.pipes.length > 0;
|
|
|
8809
9688
|
|
|
8810
9689
|
// When `verbose` is `full`, print stdout|stderr
|
|
8811
9690
|
const logLine = (line, {verboseId}) => {
|
|
8812
|
-
|
|
8813
|
-
const escapedLines = escapeLines(lines);
|
|
8814
|
-
const spacedLines = escapedLines.replaceAll('\t', ' '.repeat(TAB_SIZE));
|
|
8815
|
-
verboseLog(spacedLines, verboseId, 'output');
|
|
9691
|
+
verboseLog(serializeLogMessage(line), verboseId, 'output');
|
|
8816
9692
|
};
|
|
8817
9693
|
|
|
8818
|
-
// Same as `util.inspect()`
|
|
8819
|
-
const TAB_SIZE = 2;
|
|
8820
|
-
|
|
8821
9694
|
// Apply `stdout`/`stderr` options, after spawning, in sync mode
|
|
8822
9695
|
const transformOutputSync = ({fileDescriptors, syncResult: {output}, options, isMaxBuffer, verboseInfo}) => {
|
|
8823
9696
|
if (output === null) {
|
|
@@ -8959,13 +9832,19 @@ const getAllSync = ([, stdout, stderr], options) => {
|
|
|
8959
9832
|
};
|
|
8960
9833
|
|
|
8961
9834
|
// If `error` is emitted before `spawn`, `exit` will never be emitted.
|
|
8962
|
-
// However, `error` might be emitted after `spawn
|
|
9835
|
+
// However, `error` might be emitted after `spawn`.
|
|
8963
9836
|
// In that case, `exit` will still be emitted.
|
|
8964
9837
|
// Since the `exit` event contains the signal name, we want to make sure we are listening for it.
|
|
8965
9838
|
// This function also takes into account the following unlikely cases:
|
|
8966
9839
|
// - `exit` being emitted in the same microtask as `spawn`
|
|
8967
9840
|
// - `error` being emitted multiple times
|
|
8968
|
-
const waitForExit = async subprocess => {
|
|
9841
|
+
const waitForExit = async (subprocess, context) => {
|
|
9842
|
+
const [exitCode, signal] = await waitForExitOrError(subprocess);
|
|
9843
|
+
context.isForcefullyTerminated ??= false;
|
|
9844
|
+
return [exitCode, signal];
|
|
9845
|
+
};
|
|
9846
|
+
|
|
9847
|
+
const waitForExitOrError = async subprocess => {
|
|
8969
9848
|
const [spawnPayload, exitPayload] = await Promise.allSettled([
|
|
8970
9849
|
require$$0.once(subprocess, 'spawn'),
|
|
8971
9850
|
require$$0.once(subprocess, 'exit'),
|
|
@@ -9026,7 +9905,7 @@ const getResultError = (error, exitCode, signal) => {
|
|
|
9026
9905
|
return isFailedExit(exitCode, signal) ? new DiscardedError() : undefined;
|
|
9027
9906
|
};
|
|
9028
9907
|
|
|
9029
|
-
// Main shared logic for all sync methods: `execaSync()`,
|
|
9908
|
+
// Main shared logic for all sync methods: `execaSync()`, `$.sync()`
|
|
9030
9909
|
const execaCoreSync = (rawFile, rawArguments, rawOptions) => {
|
|
9031
9910
|
const {file, commandArguments, command, escapedCommand, startTime, verboseInfo, options, fileDescriptors} = handleSyncArguments(rawFile, rawArguments, rawOptions);
|
|
9032
9911
|
const result = spawnSubprocessSync({
|
|
@@ -9071,7 +9950,11 @@ const handleSyncArguments = (rawFile, rawArguments, rawOptions) => {
|
|
|
9071
9950
|
const normalizeSyncOptions = options => options.node && !options.ipc ? {...options, ipc: false} : options;
|
|
9072
9951
|
|
|
9073
9952
|
// Options validation logic specific to sync methods
|
|
9074
|
-
const validateSyncOptions = ({ipc, detached, cancelSignal}) => {
|
|
9953
|
+
const validateSyncOptions = ({ipc, ipcInput, detached, cancelSignal}) => {
|
|
9954
|
+
if (ipcInput) {
|
|
9955
|
+
throwInvalidSyncOption('ipcInput');
|
|
9956
|
+
}
|
|
9957
|
+
|
|
9075
9958
|
if (ipc) {
|
|
9076
9959
|
throwInvalidSyncOption('ipc: true');
|
|
9077
9960
|
}
|
|
@@ -9155,6 +10038,7 @@ const getSyncResult = ({error, exitCode, signal, timedOut, isMaxBuffer, stdio, a
|
|
|
9155
10038
|
escapedCommand,
|
|
9156
10039
|
stdio,
|
|
9157
10040
|
all,
|
|
10041
|
+
ipcOutput: [],
|
|
9158
10042
|
options,
|
|
9159
10043
|
startTime,
|
|
9160
10044
|
})
|
|
@@ -9164,16 +10048,208 @@ const getSyncResult = ({error, exitCode, signal, timedOut, isMaxBuffer, stdio, a
|
|
|
9164
10048
|
escapedCommand,
|
|
9165
10049
|
timedOut,
|
|
9166
10050
|
isCanceled: false,
|
|
10051
|
+
isGracefullyCanceled: false,
|
|
9167
10052
|
isMaxBuffer,
|
|
10053
|
+
isForcefullyTerminated: false,
|
|
9168
10054
|
exitCode,
|
|
9169
10055
|
signal,
|
|
9170
10056
|
stdio,
|
|
9171
10057
|
all,
|
|
10058
|
+
ipcOutput: [],
|
|
9172
10059
|
options,
|
|
9173
10060
|
startTime,
|
|
9174
10061
|
isSync: true,
|
|
9175
10062
|
});
|
|
9176
10063
|
|
|
10064
|
+
// Like `[sub]process.once('message')` but promise-based
|
|
10065
|
+
const getOneMessage = ({anyProcess, channel, isSubprocess, ipc}, {reference = true, filter} = {}) => {
|
|
10066
|
+
validateIpcMethod({
|
|
10067
|
+
methodName: 'getOneMessage',
|
|
10068
|
+
isSubprocess,
|
|
10069
|
+
ipc,
|
|
10070
|
+
isConnected: isConnected(anyProcess),
|
|
10071
|
+
});
|
|
10072
|
+
|
|
10073
|
+
return getOneMessageAsync({
|
|
10074
|
+
anyProcess,
|
|
10075
|
+
channel,
|
|
10076
|
+
isSubprocess,
|
|
10077
|
+
filter,
|
|
10078
|
+
reference,
|
|
10079
|
+
});
|
|
10080
|
+
};
|
|
10081
|
+
|
|
10082
|
+
const getOneMessageAsync = async ({anyProcess, channel, isSubprocess, filter, reference}) => {
|
|
10083
|
+
addReference(channel, reference);
|
|
10084
|
+
const ipcEmitter = getIpcEmitter(anyProcess, channel, isSubprocess);
|
|
10085
|
+
const controller = new AbortController();
|
|
10086
|
+
try {
|
|
10087
|
+
return await Promise.race([
|
|
10088
|
+
getMessage(ipcEmitter, filter, controller),
|
|
10089
|
+
throwOnDisconnect(ipcEmitter, isSubprocess, controller),
|
|
10090
|
+
throwOnStrictError(ipcEmitter, isSubprocess, controller),
|
|
10091
|
+
]);
|
|
10092
|
+
} catch (error) {
|
|
10093
|
+
disconnect(anyProcess);
|
|
10094
|
+
throw error;
|
|
10095
|
+
} finally {
|
|
10096
|
+
controller.abort();
|
|
10097
|
+
removeReference(channel, reference);
|
|
10098
|
+
}
|
|
10099
|
+
};
|
|
10100
|
+
|
|
10101
|
+
const getMessage = async (ipcEmitter, filter, {signal}) => {
|
|
10102
|
+
if (filter === undefined) {
|
|
10103
|
+
const [message] = await require$$0.once(ipcEmitter, 'message', {signal});
|
|
10104
|
+
return message;
|
|
10105
|
+
}
|
|
10106
|
+
|
|
10107
|
+
for await (const [message] of require$$0.on(ipcEmitter, 'message', {signal})) {
|
|
10108
|
+
if (filter(message)) {
|
|
10109
|
+
return message;
|
|
10110
|
+
}
|
|
10111
|
+
}
|
|
10112
|
+
};
|
|
10113
|
+
|
|
10114
|
+
const throwOnDisconnect = async (ipcEmitter, isSubprocess, {signal}) => {
|
|
10115
|
+
await require$$0.once(ipcEmitter, 'disconnect', {signal});
|
|
10116
|
+
throwOnEarlyDisconnect(isSubprocess);
|
|
10117
|
+
};
|
|
10118
|
+
|
|
10119
|
+
const throwOnStrictError = async (ipcEmitter, isSubprocess, {signal}) => {
|
|
10120
|
+
const [error] = await require$$0.once(ipcEmitter, 'strict:error', {signal});
|
|
10121
|
+
throw getStrictResponseError(error, isSubprocess);
|
|
10122
|
+
};
|
|
10123
|
+
|
|
10124
|
+
// Like `[sub]process.on('message')` but promise-based
|
|
10125
|
+
const getEachMessage = ({anyProcess, channel, isSubprocess, ipc}, {reference = true} = {}) => loopOnMessages({
|
|
10126
|
+
anyProcess,
|
|
10127
|
+
channel,
|
|
10128
|
+
isSubprocess,
|
|
10129
|
+
ipc,
|
|
10130
|
+
shouldAwait: !isSubprocess,
|
|
10131
|
+
reference,
|
|
10132
|
+
});
|
|
10133
|
+
|
|
10134
|
+
// Same but used internally
|
|
10135
|
+
const loopOnMessages = ({anyProcess, channel, isSubprocess, ipc, shouldAwait, reference}) => {
|
|
10136
|
+
validateIpcMethod({
|
|
10137
|
+
methodName: 'getEachMessage',
|
|
10138
|
+
isSubprocess,
|
|
10139
|
+
ipc,
|
|
10140
|
+
isConnected: isConnected(anyProcess),
|
|
10141
|
+
});
|
|
10142
|
+
|
|
10143
|
+
addReference(channel, reference);
|
|
10144
|
+
const ipcEmitter = getIpcEmitter(anyProcess, channel, isSubprocess);
|
|
10145
|
+
const controller = new AbortController();
|
|
10146
|
+
const state = {};
|
|
10147
|
+
stopOnDisconnect(anyProcess, ipcEmitter, controller);
|
|
10148
|
+
abortOnStrictError({
|
|
10149
|
+
ipcEmitter,
|
|
10150
|
+
isSubprocess,
|
|
10151
|
+
controller,
|
|
10152
|
+
state,
|
|
10153
|
+
});
|
|
10154
|
+
return iterateOnMessages({
|
|
10155
|
+
anyProcess,
|
|
10156
|
+
channel,
|
|
10157
|
+
ipcEmitter,
|
|
10158
|
+
isSubprocess,
|
|
10159
|
+
shouldAwait,
|
|
10160
|
+
controller,
|
|
10161
|
+
state,
|
|
10162
|
+
reference,
|
|
10163
|
+
});
|
|
10164
|
+
};
|
|
10165
|
+
|
|
10166
|
+
const stopOnDisconnect = async (anyProcess, ipcEmitter, controller) => {
|
|
10167
|
+
try {
|
|
10168
|
+
await require$$0.once(ipcEmitter, 'disconnect', {signal: controller.signal});
|
|
10169
|
+
controller.abort();
|
|
10170
|
+
} catch {}
|
|
10171
|
+
};
|
|
10172
|
+
|
|
10173
|
+
const abortOnStrictError = async ({ipcEmitter, isSubprocess, controller, state}) => {
|
|
10174
|
+
try {
|
|
10175
|
+
const [error] = await require$$0.once(ipcEmitter, 'strict:error', {signal: controller.signal});
|
|
10176
|
+
state.error = getStrictResponseError(error, isSubprocess);
|
|
10177
|
+
controller.abort();
|
|
10178
|
+
} catch {}
|
|
10179
|
+
};
|
|
10180
|
+
|
|
10181
|
+
const iterateOnMessages = async function * ({anyProcess, channel, ipcEmitter, isSubprocess, shouldAwait, controller, state, reference}) {
|
|
10182
|
+
try {
|
|
10183
|
+
for await (const [message] of require$$0.on(ipcEmitter, 'message', {signal: controller.signal})) {
|
|
10184
|
+
throwIfStrictError(state);
|
|
10185
|
+
yield message;
|
|
10186
|
+
}
|
|
10187
|
+
} catch {
|
|
10188
|
+
throwIfStrictError(state);
|
|
10189
|
+
} finally {
|
|
10190
|
+
controller.abort();
|
|
10191
|
+
removeReference(channel, reference);
|
|
10192
|
+
|
|
10193
|
+
if (!isSubprocess) {
|
|
10194
|
+
disconnect(anyProcess);
|
|
10195
|
+
}
|
|
10196
|
+
|
|
10197
|
+
if (shouldAwait) {
|
|
10198
|
+
await anyProcess;
|
|
10199
|
+
}
|
|
10200
|
+
}
|
|
10201
|
+
};
|
|
10202
|
+
|
|
10203
|
+
const throwIfStrictError = ({error}) => {
|
|
10204
|
+
if (error) {
|
|
10205
|
+
throw error;
|
|
10206
|
+
}
|
|
10207
|
+
};
|
|
10208
|
+
|
|
10209
|
+
// Add promise-based IPC methods in current process
|
|
10210
|
+
const addIpcMethods = (subprocess, {ipc}) => {
|
|
10211
|
+
Object.assign(subprocess, getIpcMethods(subprocess, false, ipc));
|
|
10212
|
+
};
|
|
10213
|
+
|
|
10214
|
+
// Get promise-based IPC in the subprocess
|
|
10215
|
+
const getIpcExport = () => {
|
|
10216
|
+
const anyProcess = process$3;
|
|
10217
|
+
const isSubprocess = true;
|
|
10218
|
+
const ipc = process$3.channel !== undefined;
|
|
10219
|
+
|
|
10220
|
+
return {
|
|
10221
|
+
...getIpcMethods(anyProcess, isSubprocess, ipc),
|
|
10222
|
+
getCancelSignal: getCancelSignal.bind(undefined, {
|
|
10223
|
+
anyProcess,
|
|
10224
|
+
channel: anyProcess.channel,
|
|
10225
|
+
isSubprocess,
|
|
10226
|
+
ipc,
|
|
10227
|
+
}),
|
|
10228
|
+
};
|
|
10229
|
+
};
|
|
10230
|
+
|
|
10231
|
+
// Retrieve the `ipc` shared by both the current process and the subprocess
|
|
10232
|
+
const getIpcMethods = (anyProcess, isSubprocess, ipc) => ({
|
|
10233
|
+
sendMessage: sendMessage.bind(undefined, {
|
|
10234
|
+
anyProcess,
|
|
10235
|
+
channel: anyProcess.channel,
|
|
10236
|
+
isSubprocess,
|
|
10237
|
+
ipc,
|
|
10238
|
+
}),
|
|
10239
|
+
getOneMessage: getOneMessage.bind(undefined, {
|
|
10240
|
+
anyProcess,
|
|
10241
|
+
channel: anyProcess.channel,
|
|
10242
|
+
isSubprocess,
|
|
10243
|
+
ipc,
|
|
10244
|
+
}),
|
|
10245
|
+
getEachMessage: getEachMessage.bind(undefined, {
|
|
10246
|
+
anyProcess,
|
|
10247
|
+
channel: anyProcess.channel,
|
|
10248
|
+
isSubprocess,
|
|
10249
|
+
ipc,
|
|
10250
|
+
}),
|
|
10251
|
+
});
|
|
10252
|
+
|
|
9177
10253
|
// When the subprocess fails to spawn.
|
|
9178
10254
|
// We ensure the returned error is always both a promise and a subprocess.
|
|
9179
10255
|
const handleEarlyError = ({error, command, escapedCommand, fileDescriptors, options, startTime, verboseInfo}) => {
|
|
@@ -9532,19 +10608,6 @@ const PASSTHROUGH_LISTENERS_COUNT = 2;
|
|
|
9532
10608
|
// - once due to `stream.pipe(passThroughStream)`
|
|
9533
10609
|
const PASSTHROUGH_LISTENERS_PER_STREAM = 1;
|
|
9534
10610
|
|
|
9535
|
-
// Temporarily increase the maximum number of listeners on an eventEmitter
|
|
9536
|
-
const incrementMaxListeners = (eventEmitter, maxListenersIncrement, signal) => {
|
|
9537
|
-
const maxListeners = eventEmitter.getMaxListeners();
|
|
9538
|
-
if (maxListeners === 0 || maxListeners === Number.POSITIVE_INFINITY) {
|
|
9539
|
-
return;
|
|
9540
|
-
}
|
|
9541
|
-
|
|
9542
|
-
eventEmitter.setMaxListeners(maxListeners + maxListenersIncrement);
|
|
9543
|
-
require$$0.addAbortListener(signal, () => {
|
|
9544
|
-
eventEmitter.setMaxListeners(eventEmitter.getMaxListeners() - maxListenersIncrement);
|
|
9545
|
-
});
|
|
9546
|
-
};
|
|
9547
|
-
|
|
9548
10611
|
// Similar to `Stream.pipeline(source, destination)`, but does not destroy standard streams
|
|
9549
10612
|
const pipeStreams = (source, destination) => {
|
|
9550
10613
|
source.pipe(destination);
|
|
@@ -10671,10 +11734,72 @@ const getAllMixed = ({all, stdout, stderr}) => all
|
|
|
10671
11734
|
&& stderr
|
|
10672
11735
|
&& stdout.readableObjectMode !== stderr.readableObjectMode;
|
|
10673
11736
|
|
|
11737
|
+
// When `verbose` is `'full'`, print IPC messages from the subprocess
|
|
11738
|
+
const shouldLogIpc = ({verbose}) => verbose.at(-1) === 'full';
|
|
11739
|
+
|
|
11740
|
+
const logIpcOutput = (message, {verboseId}) => {
|
|
11741
|
+
verboseLog(serializeLogMessage(message), verboseId, 'ipc');
|
|
11742
|
+
};
|
|
11743
|
+
|
|
11744
|
+
// Iterate through IPC messages sent by the subprocess
|
|
11745
|
+
const waitForIpcOutput = async ({
|
|
11746
|
+
subprocess,
|
|
11747
|
+
buffer: bufferArray,
|
|
11748
|
+
maxBuffer: maxBufferArray,
|
|
11749
|
+
ipc,
|
|
11750
|
+
ipcOutput,
|
|
11751
|
+
verboseInfo,
|
|
11752
|
+
}) => {
|
|
11753
|
+
if (!ipc) {
|
|
11754
|
+
return ipcOutput;
|
|
11755
|
+
}
|
|
11756
|
+
|
|
11757
|
+
const isVerbose = shouldLogIpc(verboseInfo);
|
|
11758
|
+
const buffer = bufferArray.at(-1);
|
|
11759
|
+
const maxBuffer = maxBufferArray.at(-1);
|
|
11760
|
+
|
|
11761
|
+
for await (const message of loopOnMessages({
|
|
11762
|
+
anyProcess: subprocess,
|
|
11763
|
+
channel: subprocess.channel,
|
|
11764
|
+
isSubprocess: false,
|
|
11765
|
+
ipc,
|
|
11766
|
+
shouldAwait: false,
|
|
11767
|
+
reference: true,
|
|
11768
|
+
})) {
|
|
11769
|
+
if (buffer) {
|
|
11770
|
+
checkIpcMaxBuffer(subprocess, ipcOutput, maxBuffer);
|
|
11771
|
+
ipcOutput.push(message);
|
|
11772
|
+
}
|
|
11773
|
+
|
|
11774
|
+
if (isVerbose) {
|
|
11775
|
+
logIpcOutput(message, verboseInfo);
|
|
11776
|
+
}
|
|
11777
|
+
}
|
|
11778
|
+
|
|
11779
|
+
return ipcOutput;
|
|
11780
|
+
};
|
|
11781
|
+
|
|
11782
|
+
const getBufferedIpcOutput = async (ipcOutputPromise, ipcOutput) => {
|
|
11783
|
+
await Promise.allSettled([ipcOutputPromise]);
|
|
11784
|
+
return ipcOutput;
|
|
11785
|
+
};
|
|
11786
|
+
|
|
10674
11787
|
// Retrieve result of subprocess: exit code, signal, error, streams (stdout/stderr/all)
|
|
10675
11788
|
const waitForSubprocessResult = async ({
|
|
10676
11789
|
subprocess,
|
|
10677
|
-
options: {
|
|
11790
|
+
options: {
|
|
11791
|
+
encoding,
|
|
11792
|
+
buffer,
|
|
11793
|
+
maxBuffer,
|
|
11794
|
+
lines,
|
|
11795
|
+
timeoutDuration: timeout,
|
|
11796
|
+
cancelSignal,
|
|
11797
|
+
gracefulCancel,
|
|
11798
|
+
forceKillAfterDelay,
|
|
11799
|
+
stripFinalNewline,
|
|
11800
|
+
ipc,
|
|
11801
|
+
ipcInput,
|
|
11802
|
+
},
|
|
10678
11803
|
context,
|
|
10679
11804
|
verboseInfo,
|
|
10680
11805
|
fileDescriptors,
|
|
@@ -10682,7 +11807,7 @@ const waitForSubprocessResult = async ({
|
|
|
10682
11807
|
onInternalError,
|
|
10683
11808
|
controller,
|
|
10684
11809
|
}) => {
|
|
10685
|
-
const exitPromise = waitForExit(subprocess);
|
|
11810
|
+
const exitPromise = waitForExit(subprocess, context);
|
|
10686
11811
|
const streamInfo = {
|
|
10687
11812
|
originalStreams,
|
|
10688
11813
|
fileDescriptors,
|
|
@@ -10711,6 +11836,15 @@ const waitForSubprocessResult = async ({
|
|
|
10711
11836
|
verboseInfo,
|
|
10712
11837
|
streamInfo,
|
|
10713
11838
|
});
|
|
11839
|
+
const ipcOutput = [];
|
|
11840
|
+
const ipcOutputPromise = waitForIpcOutput({
|
|
11841
|
+
subprocess,
|
|
11842
|
+
buffer,
|
|
11843
|
+
maxBuffer,
|
|
11844
|
+
ipc,
|
|
11845
|
+
ipcOutput,
|
|
11846
|
+
verboseInfo,
|
|
11847
|
+
});
|
|
10714
11848
|
const originalPromises = waitForOriginalStreams(originalStreams, subprocess, streamInfo);
|
|
10715
11849
|
const customStreamsEndPromises = waitForCustomStreamsEnd(fileDescriptors, streamInfo);
|
|
10716
11850
|
|
|
@@ -10721,19 +11855,38 @@ const waitForSubprocessResult = async ({
|
|
|
10721
11855
|
waitForSuccessfulExit(exitPromise),
|
|
10722
11856
|
Promise.all(stdioPromises),
|
|
10723
11857
|
allPromise,
|
|
11858
|
+
ipcOutputPromise,
|
|
11859
|
+
sendIpcInput(subprocess, ipcInput),
|
|
10724
11860
|
...originalPromises,
|
|
10725
11861
|
...customStreamsEndPromises,
|
|
10726
11862
|
]),
|
|
10727
11863
|
onInternalError,
|
|
10728
11864
|
throwOnSubprocessError(subprocess, controller),
|
|
10729
11865
|
...throwOnTimeout(subprocess, timeout, context, controller),
|
|
11866
|
+
...throwOnCancel({
|
|
11867
|
+
subprocess,
|
|
11868
|
+
cancelSignal,
|
|
11869
|
+
gracefulCancel,
|
|
11870
|
+
context,
|
|
11871
|
+
controller,
|
|
11872
|
+
}),
|
|
11873
|
+
...throwOnGracefulCancel({
|
|
11874
|
+
subprocess,
|
|
11875
|
+
cancelSignal,
|
|
11876
|
+
gracefulCancel,
|
|
11877
|
+
forceKillAfterDelay,
|
|
11878
|
+
context,
|
|
11879
|
+
controller,
|
|
11880
|
+
}),
|
|
10730
11881
|
]);
|
|
10731
11882
|
} catch (error) {
|
|
11883
|
+
context.terminationReason ??= 'other';
|
|
10732
11884
|
return Promise.all([
|
|
10733
11885
|
{error},
|
|
10734
11886
|
exitPromise,
|
|
10735
11887
|
Promise.all(stdioPromises.map(stdioPromise => getBufferedData(stdioPromise))),
|
|
10736
11888
|
getBufferedData(allPromise),
|
|
11889
|
+
getBufferedIpcOutput(ipcOutputPromise, ipcOutput),
|
|
10737
11890
|
Promise.allSettled(originalPromises),
|
|
10738
11891
|
Promise.allSettled(customStreamsEndPromises),
|
|
10739
11892
|
]);
|
|
@@ -10763,14 +11916,6 @@ const throwOnSubprocessError = async (subprocess, {signal}) => {
|
|
|
10763
11916
|
throw error;
|
|
10764
11917
|
};
|
|
10765
11918
|
|
|
10766
|
-
const createDeferred = () => {
|
|
10767
|
-
const methods = {};
|
|
10768
|
-
const promise = new Promise((resolve, reject) => {
|
|
10769
|
-
Object.assign(methods, {resolve, reject});
|
|
10770
|
-
});
|
|
10771
|
-
return Object.assign(promise, methods);
|
|
10772
|
-
};
|
|
10773
|
-
|
|
10774
11919
|
// When using multiple `.readable()`/`.writable()`/`.duplex()`, `final` and `destroy` should wait for other streams
|
|
10775
11920
|
const initializeConcurrentStreams = () => ({
|
|
10776
11921
|
readableDestroy: new WeakMap(),
|
|
@@ -11137,7 +12282,7 @@ const descriptors = ['then', 'catch', 'finally'].map(property => [
|
|
|
11137
12282
|
Reflect.getOwnPropertyDescriptor(nativePromisePrototype, property),
|
|
11138
12283
|
]);
|
|
11139
12284
|
|
|
11140
|
-
// Main shared logic for all async methods: `execa()`,
|
|
12285
|
+
// Main shared logic for all async methods: `execa()`, `$`, `execaNode()`
|
|
11141
12286
|
const execaCoreAsync = (rawFile, rawArguments, rawOptions, createNested) => {
|
|
11142
12287
|
const {file, commandArguments, command, escapedCommand, startTime, verboseInfo, options, fileDescriptors} = handleAsyncArguments(rawFile, rawArguments, rawOptions);
|
|
11143
12288
|
const {subprocess, promise} = spawnSubprocessAsync({
|
|
@@ -11187,12 +12332,12 @@ const handleAsyncArguments = (rawFile, rawArguments, rawOptions) => {
|
|
|
11187
12332
|
|
|
11188
12333
|
// Options normalization logic specific to async methods.
|
|
11189
12334
|
// Prevent passing the `timeout` option directly to `child_process.spawn()`.
|
|
11190
|
-
const handleAsyncOptions = ({timeout, signal,
|
|
12335
|
+
const handleAsyncOptions = ({timeout, signal, ...options}) => {
|
|
11191
12336
|
if (signal !== undefined) {
|
|
11192
12337
|
throw new TypeError('The "signal" option has been renamed to "cancelSignal" instead.');
|
|
11193
12338
|
}
|
|
11194
12339
|
|
|
11195
|
-
return {...options, timeoutDuration: timeout
|
|
12340
|
+
return {...options, timeoutDuration: timeout};
|
|
11196
12341
|
};
|
|
11197
12342
|
|
|
11198
12343
|
const spawnSubprocessAsync = ({file, commandArguments, options, startTime, verboseInfo, command, escapedCommand, fileDescriptors}) => {
|
|
@@ -11218,15 +12363,18 @@ const spawnSubprocessAsync = ({file, commandArguments, options, startTime, verbo
|
|
|
11218
12363
|
pipeOutputAsync(subprocess, fileDescriptors, controller);
|
|
11219
12364
|
cleanupOnExit(subprocess, options, controller);
|
|
11220
12365
|
|
|
12366
|
+
const context = {};
|
|
11221
12367
|
const onInternalError = createDeferred();
|
|
11222
12368
|
subprocess.kill = subprocessKill.bind(undefined, {
|
|
11223
12369
|
kill: subprocess.kill.bind(subprocess),
|
|
11224
12370
|
options,
|
|
11225
12371
|
onInternalError,
|
|
12372
|
+
context,
|
|
11226
12373
|
controller,
|
|
11227
12374
|
});
|
|
11228
12375
|
subprocess.all = makeAllStream(subprocess, options);
|
|
11229
12376
|
addConvertedStreams(subprocess, options);
|
|
12377
|
+
addIpcMethods(subprocess, options);
|
|
11230
12378
|
|
|
11231
12379
|
const promise = handlePromise({
|
|
11232
12380
|
subprocess,
|
|
@@ -11237,6 +12385,7 @@ const spawnSubprocessAsync = ({file, commandArguments, options, startTime, verbo
|
|
|
11237
12385
|
originalStreams,
|
|
11238
12386
|
command,
|
|
11239
12387
|
escapedCommand,
|
|
12388
|
+
context,
|
|
11240
12389
|
onInternalError,
|
|
11241
12390
|
controller,
|
|
11242
12391
|
});
|
|
@@ -11244,10 +12393,14 @@ const spawnSubprocessAsync = ({file, commandArguments, options, startTime, verbo
|
|
|
11244
12393
|
};
|
|
11245
12394
|
|
|
11246
12395
|
// Asynchronous logic, as opposed to the previous logic which can be run synchronously, i.e. can be returned to user right away
|
|
11247
|
-
const handlePromise = async ({subprocess, options, startTime, verboseInfo, fileDescriptors, originalStreams, command, escapedCommand, onInternalError, controller}) => {
|
|
11248
|
-
const
|
|
11249
|
-
|
|
11250
|
-
|
|
12396
|
+
const handlePromise = async ({subprocess, options, startTime, verboseInfo, fileDescriptors, originalStreams, command, escapedCommand, context, onInternalError, controller}) => {
|
|
12397
|
+
const [
|
|
12398
|
+
errorInfo,
|
|
12399
|
+
[exitCode, signal],
|
|
12400
|
+
stdioResults,
|
|
12401
|
+
allResult,
|
|
12402
|
+
ipcOutput,
|
|
12403
|
+
] = await waitForSubprocessResult({
|
|
11251
12404
|
subprocess,
|
|
11252
12405
|
options,
|
|
11253
12406
|
context,
|
|
@@ -11268,6 +12421,7 @@ const handlePromise = async ({subprocess, options, startTime, verboseInfo, fileD
|
|
|
11268
12421
|
signal,
|
|
11269
12422
|
stdio,
|
|
11270
12423
|
all,
|
|
12424
|
+
ipcOutput,
|
|
11271
12425
|
context,
|
|
11272
12426
|
options,
|
|
11273
12427
|
command,
|
|
@@ -11277,18 +12431,21 @@ const handlePromise = async ({subprocess, options, startTime, verboseInfo, fileD
|
|
|
11277
12431
|
return handleResult(result, verboseInfo, options);
|
|
11278
12432
|
};
|
|
11279
12433
|
|
|
11280
|
-
const getAsyncResult = ({errorInfo, exitCode, signal, stdio, all, context, options, command, escapedCommand, startTime}) => 'error' in errorInfo
|
|
12434
|
+
const getAsyncResult = ({errorInfo, exitCode, signal, stdio, all, ipcOutput, context, options, command, escapedCommand, startTime}) => 'error' in errorInfo
|
|
11281
12435
|
? makeError({
|
|
11282
12436
|
error: errorInfo.error,
|
|
11283
12437
|
command,
|
|
11284
12438
|
escapedCommand,
|
|
11285
|
-
timedOut: context.
|
|
11286
|
-
isCanceled:
|
|
12439
|
+
timedOut: context.terminationReason === 'timeout',
|
|
12440
|
+
isCanceled: context.terminationReason === 'cancel' || context.terminationReason === 'gracefulCancel',
|
|
12441
|
+
isGracefullyCanceled: context.terminationReason === 'gracefulCancel',
|
|
11287
12442
|
isMaxBuffer: errorInfo.error instanceof MaxBufferError,
|
|
12443
|
+
isForcefullyTerminated: context.isForcefullyTerminated,
|
|
11288
12444
|
exitCode,
|
|
11289
12445
|
signal,
|
|
11290
12446
|
stdio,
|
|
11291
12447
|
all,
|
|
12448
|
+
ipcOutput,
|
|
11292
12449
|
options,
|
|
11293
12450
|
startTime,
|
|
11294
12451
|
isSync: false,
|
|
@@ -11298,6 +12455,7 @@ const getAsyncResult = ({errorInfo, exitCode, signal, stdio, all, context, optio
|
|
|
11298
12455
|
escapedCommand,
|
|
11299
12456
|
stdio,
|
|
11300
12457
|
all,
|
|
12458
|
+
ipcOutput,
|
|
11301
12459
|
options,
|
|
11302
12460
|
startTime,
|
|
11303
12461
|
});
|
|
@@ -11394,8 +12552,23 @@ const parseCommand = (command, unusedArguments) => {
|
|
|
11394
12552
|
throw new TypeError(`The command and its arguments must be passed as a single string: ${command} ${unusedArguments}.`);
|
|
11395
12553
|
}
|
|
11396
12554
|
|
|
12555
|
+
const [file, ...commandArguments] = parseCommandString(command);
|
|
12556
|
+
return {file, commandArguments};
|
|
12557
|
+
};
|
|
12558
|
+
|
|
12559
|
+
// Convert `command` string into an array of file or arguments to pass to $`${...fileOrCommandArguments}`
|
|
12560
|
+
const parseCommandString = command => {
|
|
12561
|
+
if (typeof command !== 'string') {
|
|
12562
|
+
throw new TypeError(`The command must be a string: ${String(command)}.`);
|
|
12563
|
+
}
|
|
12564
|
+
|
|
12565
|
+
const trimmedCommand = command.trim();
|
|
12566
|
+
if (trimmedCommand === '') {
|
|
12567
|
+
return [];
|
|
12568
|
+
}
|
|
12569
|
+
|
|
11397
12570
|
const tokens = [];
|
|
11398
|
-
for (const token of
|
|
12571
|
+
for (const token of trimmedCommand.split(SPACES_REGEXP)) {
|
|
11399
12572
|
// Allow spaces to be escaped by a backslash if not meant as a delimiter
|
|
11400
12573
|
const previousToken = tokens.at(-1);
|
|
11401
12574
|
if (previousToken && previousToken.endsWith('\\')) {
|
|
@@ -11406,8 +12579,7 @@ const parseCommand = (command, unusedArguments) => {
|
|
|
11406
12579
|
}
|
|
11407
12580
|
}
|
|
11408
12581
|
|
|
11409
|
-
|
|
11410
|
-
return {file, commandArguments};
|
|
12582
|
+
return tokens;
|
|
11411
12583
|
};
|
|
11412
12584
|
|
|
11413
12585
|
const SPACES_REGEXP = / +/g;
|
|
@@ -11442,6 +12614,8 @@ createExeca(mapCommandSync);
|
|
|
11442
12614
|
createExeca(mapNode);
|
|
11443
12615
|
createExeca(mapScriptAsync, {}, deepScriptOptions, setScriptSync);
|
|
11444
12616
|
|
|
12617
|
+
getIpcExport();
|
|
12618
|
+
|
|
11445
12619
|
var lodash = {exports: {}};
|
|
11446
12620
|
|
|
11447
12621
|
/**
|
|
@@ -32272,7 +33446,7 @@ var utils$j = {};
|
|
|
32272
33446
|
*/
|
|
32273
33447
|
|
|
32274
33448
|
exports.escapeNode = (block, n = 0, type) => {
|
|
32275
|
-
|
|
33449
|
+
const node = block.nodes[n];
|
|
32276
33450
|
if (!node) return;
|
|
32277
33451
|
|
|
32278
33452
|
if ((type && node.type === type) || node.type === 'open' || node.type === 'close') {
|
|
@@ -32341,13 +33515,23 @@ var utils$j = {};
|
|
|
32341
33515
|
|
|
32342
33516
|
exports.flatten = (...args) => {
|
|
32343
33517
|
const result = [];
|
|
33518
|
+
|
|
32344
33519
|
const flat = arr => {
|
|
32345
33520
|
for (let i = 0; i < arr.length; i++) {
|
|
32346
|
-
|
|
32347
|
-
|
|
33521
|
+
const ele = arr[i];
|
|
33522
|
+
|
|
33523
|
+
if (Array.isArray(ele)) {
|
|
33524
|
+
flat(ele);
|
|
33525
|
+
continue;
|
|
33526
|
+
}
|
|
33527
|
+
|
|
33528
|
+
if (ele !== undefined) {
|
|
33529
|
+
result.push(ele);
|
|
33530
|
+
}
|
|
32348
33531
|
}
|
|
32349
33532
|
return result;
|
|
32350
33533
|
};
|
|
33534
|
+
|
|
32351
33535
|
flat(args);
|
|
32352
33536
|
return result;
|
|
32353
33537
|
};
|
|
@@ -32356,9 +33540,9 @@ var utils$j = {};
|
|
|
32356
33540
|
const utils$i = utils$j;
|
|
32357
33541
|
|
|
32358
33542
|
var stringify$4 = (ast, options = {}) => {
|
|
32359
|
-
|
|
32360
|
-
|
|
32361
|
-
|
|
33543
|
+
const stringify = (node, parent = {}) => {
|
|
33544
|
+
const invalidBlock = options.escapeInvalid && utils$i.isInvalidBrace(parent);
|
|
33545
|
+
const invalidNode = node.invalid === true && options.escapeInvalid === true;
|
|
32362
33546
|
let output = '';
|
|
32363
33547
|
|
|
32364
33548
|
if (node.value) {
|
|
@@ -32373,7 +33557,7 @@ var stringify$4 = (ast, options = {}) => {
|
|
|
32373
33557
|
}
|
|
32374
33558
|
|
|
32375
33559
|
if (node.nodes) {
|
|
32376
|
-
for (
|
|
33560
|
+
for (const child of node.nodes) {
|
|
32377
33561
|
output += stringify(child);
|
|
32378
33562
|
}
|
|
32379
33563
|
}
|
|
@@ -32747,7 +33931,7 @@ const toMaxLen = (input, maxLength) => {
|
|
|
32747
33931
|
return negative ? ('-' + input) : input;
|
|
32748
33932
|
};
|
|
32749
33933
|
|
|
32750
|
-
const toSequence = (parts, options) => {
|
|
33934
|
+
const toSequence = (parts, options, maxLen) => {
|
|
32751
33935
|
parts.negatives.sort((a, b) => a < b ? -1 : a > b ? 1 : 0);
|
|
32752
33936
|
parts.positives.sort((a, b) => a < b ? -1 : a > b ? 1 : 0);
|
|
32753
33937
|
|
|
@@ -32757,11 +33941,11 @@ const toSequence = (parts, options) => {
|
|
|
32757
33941
|
let result;
|
|
32758
33942
|
|
|
32759
33943
|
if (parts.positives.length) {
|
|
32760
|
-
positives = parts.positives.join('|');
|
|
33944
|
+
positives = parts.positives.map(v => toMaxLen(String(v), maxLen)).join('|');
|
|
32761
33945
|
}
|
|
32762
33946
|
|
|
32763
33947
|
if (parts.negatives.length) {
|
|
32764
|
-
negatives = `-(${prefix}${parts.negatives.join('|')})`;
|
|
33948
|
+
negatives = `-(${prefix}${parts.negatives.map(v => toMaxLen(String(v), maxLen)).join('|')})`;
|
|
32765
33949
|
}
|
|
32766
33950
|
|
|
32767
33951
|
if (positives && negatives) {
|
|
@@ -32859,7 +34043,7 @@ const fillNumbers = (start, end, step = 1, options = {}) => {
|
|
|
32859
34043
|
|
|
32860
34044
|
if (options.toRegex === true) {
|
|
32861
34045
|
return step > 1
|
|
32862
|
-
? toSequence(parts, options)
|
|
34046
|
+
? toSequence(parts, options, maxLen)
|
|
32863
34047
|
: toRegex(range, null, { wrap: false, ...options });
|
|
32864
34048
|
}
|
|
32865
34049
|
|
|
@@ -32871,7 +34055,6 @@ const fillLetters = (start, end, step = 1, options = {}) => {
|
|
|
32871
34055
|
return invalidRange(start, end, options);
|
|
32872
34056
|
}
|
|
32873
34057
|
|
|
32874
|
-
|
|
32875
34058
|
let format = options.transform || (val => String.fromCharCode(val));
|
|
32876
34059
|
let a = `${start}`.charCodeAt(0);
|
|
32877
34060
|
let b = `${end}`.charCodeAt(0);
|
|
@@ -32939,30 +34122,32 @@ const fill$1 = fillRange;
|
|
|
32939
34122
|
const utils$h = utils$j;
|
|
32940
34123
|
|
|
32941
34124
|
const compile$1 = (ast, options = {}) => {
|
|
32942
|
-
|
|
32943
|
-
|
|
32944
|
-
|
|
32945
|
-
|
|
32946
|
-
|
|
34125
|
+
const walk = (node, parent = {}) => {
|
|
34126
|
+
const invalidBlock = utils$h.isInvalidBrace(parent);
|
|
34127
|
+
const invalidNode = node.invalid === true && options.escapeInvalid === true;
|
|
34128
|
+
const invalid = invalidBlock === true || invalidNode === true;
|
|
34129
|
+
const prefix = options.escapeInvalid === true ? '\\' : '';
|
|
32947
34130
|
let output = '';
|
|
32948
34131
|
|
|
32949
34132
|
if (node.isOpen === true) {
|
|
32950
34133
|
return prefix + node.value;
|
|
32951
34134
|
}
|
|
34135
|
+
|
|
32952
34136
|
if (node.isClose === true) {
|
|
34137
|
+
console.log('node.isClose', prefix, node.value);
|
|
32953
34138
|
return prefix + node.value;
|
|
32954
34139
|
}
|
|
32955
34140
|
|
|
32956
34141
|
if (node.type === 'open') {
|
|
32957
|
-
return invalid ?
|
|
34142
|
+
return invalid ? prefix + node.value : '(';
|
|
32958
34143
|
}
|
|
32959
34144
|
|
|
32960
34145
|
if (node.type === 'close') {
|
|
32961
|
-
return invalid ?
|
|
34146
|
+
return invalid ? prefix + node.value : ')';
|
|
32962
34147
|
}
|
|
32963
34148
|
|
|
32964
34149
|
if (node.type === 'comma') {
|
|
32965
|
-
return node.prev.type === 'comma' ? '' :
|
|
34150
|
+
return node.prev.type === 'comma' ? '' : invalid ? node.value : '|';
|
|
32966
34151
|
}
|
|
32967
34152
|
|
|
32968
34153
|
if (node.value) {
|
|
@@ -32970,8 +34155,8 @@ const compile$1 = (ast, options = {}) => {
|
|
|
32970
34155
|
}
|
|
32971
34156
|
|
|
32972
34157
|
if (node.nodes && node.ranges > 0) {
|
|
32973
|
-
|
|
32974
|
-
|
|
34158
|
+
const args = utils$h.reduce(node.nodes);
|
|
34159
|
+
const range = fill$1(...args, { ...options, wrap: false, toRegex: true, strictZeros: true });
|
|
32975
34160
|
|
|
32976
34161
|
if (range.length !== 0) {
|
|
32977
34162
|
return args.length > 1 && range.length > 1 ? `(${range})` : range;
|
|
@@ -32979,10 +34164,11 @@ const compile$1 = (ast, options = {}) => {
|
|
|
32979
34164
|
}
|
|
32980
34165
|
|
|
32981
34166
|
if (node.nodes) {
|
|
32982
|
-
for (
|
|
34167
|
+
for (const child of node.nodes) {
|
|
32983
34168
|
output += walk(child, node);
|
|
32984
34169
|
}
|
|
32985
34170
|
}
|
|
34171
|
+
|
|
32986
34172
|
return output;
|
|
32987
34173
|
};
|
|
32988
34174
|
|
|
@@ -32996,7 +34182,7 @@ const stringify$2 = stringify$4;
|
|
|
32996
34182
|
const utils$g = utils$j;
|
|
32997
34183
|
|
|
32998
34184
|
const append = (queue = '', stash = '', enclose = false) => {
|
|
32999
|
-
|
|
34185
|
+
const result = [];
|
|
33000
34186
|
|
|
33001
34187
|
queue = [].concat(queue);
|
|
33002
34188
|
stash = [].concat(stash);
|
|
@@ -33006,15 +34192,15 @@ const append = (queue = '', stash = '', enclose = false) => {
|
|
|
33006
34192
|
return enclose ? utils$g.flatten(stash).map(ele => `{${ele}}`) : stash;
|
|
33007
34193
|
}
|
|
33008
34194
|
|
|
33009
|
-
for (
|
|
34195
|
+
for (const item of queue) {
|
|
33010
34196
|
if (Array.isArray(item)) {
|
|
33011
|
-
for (
|
|
34197
|
+
for (const value of item) {
|
|
33012
34198
|
result.push(append(value, stash, enclose));
|
|
33013
34199
|
}
|
|
33014
34200
|
} else {
|
|
33015
34201
|
for (let ele of stash) {
|
|
33016
34202
|
if (enclose === true && typeof ele === 'string') ele = `{${ele}}`;
|
|
33017
|
-
result.push(Array.isArray(ele) ? append(item, ele, enclose) :
|
|
34203
|
+
result.push(Array.isArray(ele) ? append(item, ele, enclose) : item + ele);
|
|
33018
34204
|
}
|
|
33019
34205
|
}
|
|
33020
34206
|
}
|
|
@@ -33022,9 +34208,9 @@ const append = (queue = '', stash = '', enclose = false) => {
|
|
|
33022
34208
|
};
|
|
33023
34209
|
|
|
33024
34210
|
const expand$1 = (ast, options = {}) => {
|
|
33025
|
-
|
|
34211
|
+
const rangeLimit = options.rangeLimit === undefined ? 1000 : options.rangeLimit;
|
|
33026
34212
|
|
|
33027
|
-
|
|
34213
|
+
const walk = (node, parent = {}) => {
|
|
33028
34214
|
node.queue = [];
|
|
33029
34215
|
|
|
33030
34216
|
let p = parent;
|
|
@@ -33046,7 +34232,7 @@ const expand$1 = (ast, options = {}) => {
|
|
|
33046
34232
|
}
|
|
33047
34233
|
|
|
33048
34234
|
if (node.nodes && node.ranges > 0) {
|
|
33049
|
-
|
|
34235
|
+
const args = utils$g.reduce(node.nodes);
|
|
33050
34236
|
|
|
33051
34237
|
if (utils$g.exceedsLimit(...args, options.step, rangeLimit)) {
|
|
33052
34238
|
throw new RangeError('expanded array length exceeds range limit. Use options.rangeLimit to increase or disable the limit.');
|
|
@@ -33062,7 +34248,7 @@ const expand$1 = (ast, options = {}) => {
|
|
|
33062
34248
|
return;
|
|
33063
34249
|
}
|
|
33064
34250
|
|
|
33065
|
-
|
|
34251
|
+
const enclose = utils$g.encloseBrace(node);
|
|
33066
34252
|
let queue = node.queue;
|
|
33067
34253
|
let block = node;
|
|
33068
34254
|
|
|
@@ -33072,7 +34258,7 @@ const expand$1 = (ast, options = {}) => {
|
|
|
33072
34258
|
}
|
|
33073
34259
|
|
|
33074
34260
|
for (let i = 0; i < node.nodes.length; i++) {
|
|
33075
|
-
|
|
34261
|
+
const child = node.nodes[i];
|
|
33076
34262
|
|
|
33077
34263
|
if (child.type === 'comma' && node.type === 'brace') {
|
|
33078
34264
|
if (i === 1) queue.push('');
|
|
@@ -33104,7 +34290,7 @@ const expand$1 = (ast, options = {}) => {
|
|
|
33104
34290
|
var expand_1 = expand$1;
|
|
33105
34291
|
|
|
33106
34292
|
var constants$4 = {
|
|
33107
|
-
MAX_LENGTH:
|
|
34293
|
+
MAX_LENGTH: 10000,
|
|
33108
34294
|
|
|
33109
34295
|
// Digits
|
|
33110
34296
|
CHAR_0: '0', /* 0 */
|
|
@@ -33192,18 +34378,18 @@ const parse$3 = (input, options = {}) => {
|
|
|
33192
34378
|
throw new TypeError('Expected a string');
|
|
33193
34379
|
}
|
|
33194
34380
|
|
|
33195
|
-
|
|
33196
|
-
|
|
34381
|
+
const opts = options || {};
|
|
34382
|
+
const max = typeof opts.maxLength === 'number' ? Math.min(MAX_LENGTH$1, opts.maxLength) : MAX_LENGTH$1;
|
|
33197
34383
|
if (input.length > max) {
|
|
33198
34384
|
throw new SyntaxError(`Input length (${input.length}), exceeds max characters (${max})`);
|
|
33199
34385
|
}
|
|
33200
34386
|
|
|
33201
|
-
|
|
33202
|
-
|
|
34387
|
+
const ast = { type: 'root', input, nodes: [] };
|
|
34388
|
+
const stack = [ast];
|
|
33203
34389
|
let block = ast;
|
|
33204
34390
|
let prev = ast;
|
|
33205
34391
|
let brackets = 0;
|
|
33206
|
-
|
|
34392
|
+
const length = input.length;
|
|
33207
34393
|
let index = 0;
|
|
33208
34394
|
let depth = 0;
|
|
33209
34395
|
let value;
|
|
@@ -33268,6 +34454,7 @@ const parse$3 = (input, options = {}) => {
|
|
|
33268
34454
|
|
|
33269
34455
|
if (value === CHAR_LEFT_SQUARE_BRACKET$1) {
|
|
33270
34456
|
brackets++;
|
|
34457
|
+
|
|
33271
34458
|
let next;
|
|
33272
34459
|
|
|
33273
34460
|
while (index < length && (next = advance())) {
|
|
@@ -33323,7 +34510,7 @@ const parse$3 = (input, options = {}) => {
|
|
|
33323
34510
|
*/
|
|
33324
34511
|
|
|
33325
34512
|
if (value === CHAR_DOUBLE_QUOTE || value === CHAR_SINGLE_QUOTE || value === CHAR_BACKTICK) {
|
|
33326
|
-
|
|
34513
|
+
const open = value;
|
|
33327
34514
|
let next;
|
|
33328
34515
|
|
|
33329
34516
|
if (options.keepQuotes !== true) {
|
|
@@ -33355,8 +34542,8 @@ const parse$3 = (input, options = {}) => {
|
|
|
33355
34542
|
if (value === CHAR_LEFT_CURLY_BRACE$1) {
|
|
33356
34543
|
depth++;
|
|
33357
34544
|
|
|
33358
|
-
|
|
33359
|
-
|
|
34545
|
+
const dollar = prev.value && prev.value.slice(-1) === '$' || block.dollar === true;
|
|
34546
|
+
const brace = {
|
|
33360
34547
|
type: 'brace',
|
|
33361
34548
|
open: true,
|
|
33362
34549
|
close: false,
|
|
@@ -33383,7 +34570,7 @@ const parse$3 = (input, options = {}) => {
|
|
|
33383
34570
|
continue;
|
|
33384
34571
|
}
|
|
33385
34572
|
|
|
33386
|
-
|
|
34573
|
+
const type = 'close';
|
|
33387
34574
|
block = stack.pop();
|
|
33388
34575
|
block.close = true;
|
|
33389
34576
|
|
|
@@ -33401,7 +34588,7 @@ const parse$3 = (input, options = {}) => {
|
|
|
33401
34588
|
if (value === CHAR_COMMA$1 && depth > 0) {
|
|
33402
34589
|
if (block.ranges > 0) {
|
|
33403
34590
|
block.ranges = 0;
|
|
33404
|
-
|
|
34591
|
+
const open = block.nodes.shift();
|
|
33405
34592
|
block.nodes = [open, { type: 'text', value: stringify$1(block) }];
|
|
33406
34593
|
}
|
|
33407
34594
|
|
|
@@ -33415,7 +34602,7 @@ const parse$3 = (input, options = {}) => {
|
|
|
33415
34602
|
*/
|
|
33416
34603
|
|
|
33417
34604
|
if (value === CHAR_DOT$1 && depth > 0 && block.commas === 0) {
|
|
33418
|
-
|
|
34605
|
+
const siblings = block.nodes;
|
|
33419
34606
|
|
|
33420
34607
|
if (depth === 0 || siblings.length === 0) {
|
|
33421
34608
|
push({ type: 'text', value });
|
|
@@ -33442,7 +34629,7 @@ const parse$3 = (input, options = {}) => {
|
|
|
33442
34629
|
if (prev.type === 'range') {
|
|
33443
34630
|
siblings.pop();
|
|
33444
34631
|
|
|
33445
|
-
|
|
34632
|
+
const before = siblings[siblings.length - 1];
|
|
33446
34633
|
before.value += prev.value + value;
|
|
33447
34634
|
prev = before;
|
|
33448
34635
|
block.ranges--;
|
|
@@ -33475,8 +34662,8 @@ const parse$3 = (input, options = {}) => {
|
|
|
33475
34662
|
});
|
|
33476
34663
|
|
|
33477
34664
|
// get the location of the block on parent.nodes (block's siblings)
|
|
33478
|
-
|
|
33479
|
-
|
|
34665
|
+
const parent = stack[stack.length - 1];
|
|
34666
|
+
const index = parent.nodes.indexOf(block);
|
|
33480
34667
|
// replace the (invalid) block with it's nodes
|
|
33481
34668
|
parent.nodes.splice(index, 1, ...block.nodes);
|
|
33482
34669
|
}
|
|
@@ -33511,8 +34698,8 @@ const braces$1 = (input, options = {}) => {
|
|
|
33511
34698
|
let output = [];
|
|
33512
34699
|
|
|
33513
34700
|
if (Array.isArray(input)) {
|
|
33514
|
-
for (
|
|
33515
|
-
|
|
34701
|
+
for (const pattern of input) {
|
|
34702
|
+
const result = braces$1.create(pattern, options);
|
|
33516
34703
|
if (Array.isArray(result)) {
|
|
33517
34704
|
output.push(...result);
|
|
33518
34705
|
} else {
|
|
@@ -33646,7 +34833,7 @@ braces$1.create = (input, options = {}) => {
|
|
|
33646
34833
|
return [input];
|
|
33647
34834
|
}
|
|
33648
34835
|
|
|
33649
|
-
|
|
34836
|
+
return options.expand !== true
|
|
33650
34837
|
? braces$1.compile(input, options)
|
|
33651
34838
|
: braces$1.expand(input, options);
|
|
33652
34839
|
};
|
|
@@ -39615,7 +40802,7 @@ const batchCommand = new Command()
|
|
|
39615
40802
|
|
|
39616
40803
|
const cmdCommand = new Command()
|
|
39617
40804
|
.name('cmd')
|
|
39618
|
-
.description('
|
|
40805
|
+
.description('Batch execute command according to the --shell option, conflicts with --command option (default subcommand)')
|
|
39619
40806
|
.configureHelp({ showGlobalOptions: true })
|
|
39620
40807
|
.enablePositionalOptions()
|
|
39621
40808
|
.passThroughOptions()
|