Skip to content

Commit 697fca1

Browse files
committed
[Console] Restore SHELL_VERBOSITY after a command is ran
1 parent d30c951 commit 697fca1

File tree

3 files changed

+125
-30
lines changed

3 files changed

+125
-30
lines changed

src/Symfony/Component/Console/Application.php

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,8 @@ public function run(?InputInterface $input = null, ?OutputInterface $output = nu
186186
}
187187
}
188188

189+
$prevShellVerbosity = getenv('SHELL_VERBOSITY');
190+
189191
try {
190192
$this->configureIO($input, $output);
191193

@@ -223,6 +225,22 @@ public function run(?InputInterface $input = null, ?OutputInterface $output = nu
223225
$phpHandler[0]->setExceptionHandler($finalHandler);
224226
}
225227
}
228+
229+
// SHELL_VERBOSITY is set by Application::configureIO so we need to unset/reset it
230+
// to its previous value to avoid one command verbosity to spread to other commands
231+
if (false === $prevShellVerbosity) {
232+
if (\function_exists('putenv')) {
233+
@putenv('SHELL_VERBOSITY');
234+
}
235+
unset($_ENV['SHELL_VERBOSITY']);
236+
unset($_SERVER['SHELL_VERBOSITY']);
237+
} else {
238+
if (\function_exists('putenv')) {
239+
@putenv('SHELL_VERBOSITY='.$prevShellVerbosity);
240+
}
241+
$_ENV['SHELL_VERBOSITY'] = $prevShellVerbosity;
242+
$_SERVER['SHELL_VERBOSITY'] = $prevShellVerbosity;
243+
}
226244
}
227245

228246
if ($this->autoExit) {

src/Symfony/Component/Console/Tester/ApplicationTester.php

Lines changed: 9 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -47,37 +47,17 @@ public function __construct(
4747
*/
4848
public function run(array $input, array $options = []): int
4949
{
50-
$prevShellVerbosity = getenv('SHELL_VERBOSITY');
51-
52-
try {
53-
$this->input = new ArrayInput($input);
54-
if (isset($options['interactive'])) {
55-
$this->input->setInteractive($options['interactive']);
56-
}
50+
$this->input = new ArrayInput($input);
51+
if (isset($options['interactive'])) {
52+
$this->input->setInteractive($options['interactive']);
53+
}
5754

58-
if ($this->inputs) {
59-
$this->input->setStream(self::createStream($this->inputs));
60-
}
55+
if ($this->inputs) {
56+
$this->input->setStream(self::createStream($this->inputs));
57+
}
6158

62-
$this->initOutput($options);
59+
$this->initOutput($options);
6360

64-
return $this->statusCode = $this->application->run($this->input, $this->output);
65-
} finally {
66-
// SHELL_VERBOSITY is set by Application::configureIO so we need to unset/reset it
67-
// to its previous value to avoid one test's verbosity to spread to the following tests
68-
if (false === $prevShellVerbosity) {
69-
if (\function_exists('putenv')) {
70-
@putenv('SHELL_VERBOSITY');
71-
}
72-
unset($_ENV['SHELL_VERBOSITY']);
73-
unset($_SERVER['SHELL_VERBOSITY']);
74-
} else {
75-
if (\function_exists('putenv')) {
76-
@putenv('SHELL_VERBOSITY='.$prevShellVerbosity);
77-
}
78-
$_ENV['SHELL_VERBOSITY'] = $prevShellVerbosity;
79-
$_SERVER['SHELL_VERBOSITY'] = $prevShellVerbosity;
80-
}
81-
}
61+
return $this->statusCode = $this->application->run($this->input, $this->output);
8262
}
8363
}

src/Symfony/Component/Console/Tests/ApplicationTest.php

Lines changed: 98 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
use Symfony\Component\Console\Input\InputDefinition;
3838
use Symfony\Component\Console\Input\InputInterface;
3939
use Symfony\Component\Console\Input\InputOption;
40+
use Symfony\Component\Console\Output\BufferedOutput;
4041
use Symfony\Component\Console\Output\ConsoleOutput;
4142
use Symfony\Component\Console\Output\NullOutput;
4243
use Symfony\Component\Console\Output\Output;
@@ -831,7 +832,7 @@ public function testSetCatchErrors(bool $catchExceptions)
831832

832833
try {
833834
$tester->run(['command' => 'boom']);
834-
$this->fail('The exception is not catched.');
835+
$this->fail('The exception is not caught.');
835836
} catch (\Throwable $e) {
836837
$this->assertInstanceOf(\Error::class, $e);
837838
$this->assertSame('This is an error.', $e->getMessage());
@@ -2463,6 +2464,102 @@ private function createSignalableApplication(Command $command, ?EventDispatcherI
24632464

24642465
return $application;
24652466
}
2467+
2468+
public function testShellVerbosityIsRestoredAfterCommandExecutionWithInitialValue()
2469+
{
2470+
// Set initial SHELL_VERBOSITY
2471+
putenv('SHELL_VERBOSITY=-2');
2472+
$_ENV['SHELL_VERBOSITY'] = '-2';
2473+
$_SERVER['SHELL_VERBOSITY'] = '-2';
2474+
2475+
$application = new Application();
2476+
$application->setAutoExit(false);
2477+
$application->register('foo')
2478+
->setCode(function (InputInterface $input, OutputInterface $output): int {
2479+
$output->write('SHELL_VERBOSITY: '.$_SERVER['SHELL_VERBOSITY']);
2480+
2481+
return 0;
2482+
});
2483+
2484+
$input = new ArrayInput(['command' => 'foo', '--verbose' => 3]);
2485+
$output = new BufferedOutput();
2486+
2487+
$application->run($input, $output);
2488+
2489+
$this->assertSame('SHELL_VERBOSITY: 3', $output->fetch());
2490+
$this->assertSame('-2', getenv('SHELL_VERBOSITY'));
2491+
$this->assertSame('-2', $_ENV['SHELL_VERBOSITY']);
2492+
$this->assertSame('-2', $_SERVER['SHELL_VERBOSITY']);
2493+
2494+
// Clean up for other tests
2495+
putenv('SHELL_VERBOSITY');
2496+
unset($_ENV['SHELL_VERBOSITY']);
2497+
unset($_SERVER['SHELL_VERBOSITY']);
2498+
}
2499+
2500+
public function testShellVerbosityIsRemovedAfterCommandExecutionWhenNotSetInitially()
2501+
{
2502+
// Ensure SHELL_VERBOSITY is not set initially
2503+
putenv('SHELL_VERBOSITY');
2504+
unset($_ENV['SHELL_VERBOSITY']);
2505+
unset($_SERVER['SHELL_VERBOSITY']);
2506+
2507+
$application = new Application();
2508+
$application->setAutoExit(false);
2509+
$application->register('foo')
2510+
->setCode(function (InputInterface $input, OutputInterface $output): int {
2511+
$output->write('SHELL_VERBOSITY: '.$_SERVER['SHELL_VERBOSITY']);
2512+
2513+
return 0;
2514+
});
2515+
2516+
$input = new ArrayInput(['command' => 'foo', '--verbose' => 3]);
2517+
$output = new BufferedOutput();
2518+
2519+
$application->run($input, $output);
2520+
2521+
$this->assertSame('SHELL_VERBOSITY: 3', $output->fetch());
2522+
$this->assertFalse(getenv('SHELL_VERBOSITY'));
2523+
$this->assertArrayNotHasKey('SHELL_VERBOSITY', $_ENV);
2524+
$this->assertArrayNotHasKey('SHELL_VERBOSITY', $_SERVER);
2525+
}
2526+
2527+
public function testShellVerbosityDoesNotLeakBetweenCommandExecutions()
2528+
{
2529+
// Ensure no initial SHELL_VERBOSITY
2530+
putenv('SHELL_VERBOSITY');
2531+
unset($_ENV['SHELL_VERBOSITY']);
2532+
unset($_SERVER['SHELL_VERBOSITY']);
2533+
2534+
$application = new Application();
2535+
$application->setAutoExit(false);
2536+
$application->register('verbose-cmd')
2537+
->setCode(function (InputInterface $input, OutputInterface $output): int {
2538+
$output->write('SHELL_VERBOSITY: '.$_SERVER['SHELL_VERBOSITY']);
2539+
2540+
return 0;
2541+
});
2542+
$application->register('normal-cmd')
2543+
->setCode(function (InputInterface $input, OutputInterface $output): int {
2544+
$output->write('SHELL_VERBOSITY: '.$_SERVER['SHELL_VERBOSITY']);
2545+
2546+
return 0;
2547+
});
2548+
2549+
$output = new BufferedOutput();
2550+
2551+
$application->run(new ArrayInput(['command' => 'verbose-cmd', '--verbose' => true]), $output);
2552+
2553+
$this->assertSame('SHELL_VERBOSITY: 1', $output->fetch(), 'SHELL_VERBOSITY should be set to 1 for verbose command');
2554+
$this->assertFalse(getenv('SHELL_VERBOSITY'), 'SHELL_VERBOSITY should not be set after first command');
2555+
2556+
$application->run(new ArrayInput(['command' => 'normal-cmd']), $output);
2557+
2558+
$this->assertSame('SHELL_VERBOSITY: 0', $output->fetch(), 'SHELL_VERBOSITY should not leak to second command');
2559+
$this->assertFalse(getenv('SHELL_VERBOSITY'), 'SHELL_VERBOSITY should not leak to second command');
2560+
$this->assertArrayNotHasKey('SHELL_VERBOSITY', $_ENV);
2561+
$this->assertArrayNotHasKey('SHELL_VERBOSITY', $_SERVER);
2562+
}
24662563
}
24672564

24682565
class CustomApplication extends Application

0 commit comments

Comments
 (0)