Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions rector.php
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@
// Exclude test file because `is_cli()` is mocked and Rector might remove needed parameters.
RemoveExtraParametersRector::class => [
__DIR__ . '/tests/system/CLI/CLITest.php',
__DIR__ . '/tests/system/CLI/OutputTest.php',
__DIR__ . '/tests/system/Debug/ToolbarTest.php',
],

Expand Down
93 changes: 59 additions & 34 deletions system/CLI/AbstractCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -438,43 +438,60 @@ public function setInteractive(bool $interactive): static
*
* @param list<string> $arguments Parsed arguments from command line.
* @param array<string, list<string|null>|string|null> $options Parsed options from command line.
* @param Output|null $output The output to run against, or `null` for the current one.
*
* @throws ArgumentCountMismatchException
* @throws CommandNotAvailableException
* @throws LogicException
* @throws OptionValueMismatchException
* @throws UnknownOptionException
*/
final public function run(array $arguments, array $options): int
final public function run(array $arguments, array $options, ?Output $output = null): int
{
if (! $this->isAvailable()) {
throw new CommandNotAvailableException(lang('Commands.notAvailable', [$this->name]));
}
$previous = CLI::getOutput();

CLI::setOutput($output ?? $previous);

try {
if (! $this->isAvailable()) {
throw new CommandNotAvailableException(lang('Commands.notAvailable', [$this->name]));
}

// Reset per-run interactive state from the current options.
$this->runtimeInteractive = $this->hasUnboundOption('no-interaction', $options) ? false : null;

// Reset per-run interactive state from the current options.
$this->runtimeInteractive = $this->hasUnboundOption('no-interaction', $options) ? false : null;
$this->initialize($arguments, $options);

$this->initialize($arguments, $options);
if ($this->isInteractive()) {
if ($this instanceof PromptsForMissingInputInterface) {
$this->promptForMissingArguments($arguments, $options);
}

if ($this->isInteractive()) {
if ($this instanceof PromptsForMissingInputInterface) {
$this->promptForMissingArguments($arguments, $options);
$this->interact($arguments, $options);
}

$this->interact($arguments, $options);
}
$this->unboundArguments = $arguments;
$this->unboundOptions = $options;

$this->unboundArguments = $arguments;
$this->unboundOptions = $options;
[$boundArguments, $boundOptions] = $this->bind($arguments, $options);

[$boundArguments, $boundOptions] = $this->bind($arguments, $options);
$this->validate($boundArguments, $boundOptions);

$this->validate($boundArguments, $boundOptions);
$this->validatedArguments = $boundArguments;
$this->validatedOptions = $boundOptions;

$this->validatedArguments = $boundArguments;
$this->validatedOptions = $boundOptions;
return $this->execute($boundArguments, $boundOptions);
} finally {
CLI::setOutput($previous);
}
}

return $this->execute($boundArguments, $boundOptions);
/**
* Returns the output of the current run.
*/
final protected function getOutput(): Output
{
return CLI::getOutput();
Comment thread
paulbalandan marked this conversation as resolved.
}

/**
Expand Down Expand Up @@ -573,7 +590,7 @@ abstract protected function execute(array $arguments, array $options): int;
*/
protected function call(string $command, array $arguments = [], array $options = [], ?bool $noInteractionOverride = null): int
{
return $this->commands->runCommand($command, $arguments, $this->resolveChildInteractiveState($options, $noInteractionOverride));
return $this->runChild($command, $arguments, $options, $noInteractionOverride, $this->getOutput());
}

/**
Expand All @@ -585,19 +602,13 @@ protected function call(string $command, array $arguments = [], array $options =
*/
protected function callSilently(string $command, array $arguments = [], array $options = [], ?bool $noInteractionOverride = true): int
{
$priorInputOutput = CLI::getInputOutput();
$priorLastWrite = CLI::getLastWrite();

CLI::setInputOutput(new NullInputOutput());

try {
return $this->call($command, $arguments, $options, $noInteractionOverride);
} finally {
$priorInputOutput instanceof InputOutput
? CLI::setInputOutput($priorInputOutput)
: CLI::resetInputOutput();
CLI::setLastWrite($priorLastWrite);
}
return $this->runChild(
$command,
$arguments,
$options,
$noInteractionOverride,
new Output(new NullInputOutput(), $this->getOutput()->getTerminal()),
);
}

/**
Expand Down Expand Up @@ -782,7 +793,7 @@ protected function provideDefaultOptions(): void
private function promptForMissingArguments(array &$arguments, array &$options): void
{
// A null reader cannot satisfy a required prompt, so leave the missing arguments to validation.
if (CLI::getInputOutput() instanceof NullInputOutput) {
if ($this->getOutput()->getInputOutput() instanceof NullInputOutput) {
return;
}

Expand Down Expand Up @@ -1182,4 +1193,18 @@ private function createDefaultUsage(): void

array_unshift($this->usages, implode(' ', $usage));
}

/**
* @param list<string> $arguments
* @param array<string, list<string>|string|null> $options
*/
private function runChild(string $command, array $arguments, array $options, ?bool $noInteractionOverride, Output $output): int
{
return $this->commands->runCommand(
$command,
$arguments,
$this->resolveChildInteractiveState($options, $noInteractionOverride),
$output,
);
}
}
Loading
Loading