Skip to content

Commit 3531989

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

File tree

3 files changed

+117
-30
lines changed

3 files changed

+117
-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: 90 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,94 @@ 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) {
2479+
$output->write('SHELL_VERBOSITY: '.$_SERVER['SHELL_VERBOSITY']);
2480+
});
2481+
2482+
$input = new ArrayInput(['command' => 'foo', '--verbose' => 3]);
2483+
$output = new BufferedOutput();
2484+
2485+
$application->run($input, $output);
2486+
2487+
$this->assertSame('SHELL_VERBOSITY: 3', $output->fetch());
2488+
$this->assertSame('-2', getenv('SHELL_VERBOSITY'));
2489+
$this->assertSame('-2', $_ENV['SHELL_VERBOSITY']);
2490+
$this->assertSame('-2', $_SERVER['SHELL_VERBOSITY']);
2491+
2492+
// Clean up for other tests
2493+
putenv('SHELL_VERBOSITY');
2494+
unset($_ENV['SHELL_VERBOSITY']);
2495+
unset($_SERVER['SHELL_VERBOSITY']);
2496+
}
2497+
2498+
public function testShellVerbosityIsRemovedAfterCommandExecutionWhenNotSetInitially()
2499+
{
2500+
// Ensure SHELL_VERBOSITY is not set initially
2501+
putenv('SHELL_VERBOSITY');
2502+
unset($_ENV['SHELL_VERBOSITY']);
2503+
unset($_SERVER['SHELL_VERBOSITY']);
2504+
2505+
$application = new Application();
2506+
$application->setAutoExit(false);
2507+
$application->register('foo')
2508+
->setCode(function (InputInterface $input, OutputInterface $output) {
2509+
$output->write('SHELL_VERBOSITY: '.$_SERVER['SHELL_VERBOSITY']);
2510+
});
2511+
2512+
$input = new ArrayInput(['command' => 'foo', '--verbose' => 3]);
2513+
$output = new BufferedOutput();
2514+
2515+
$application->run($input, $output);
2516+
2517+
$this->assertSame('SHELL_VERBOSITY: 3', $output->fetch());
2518+
$this->assertFalse(getenv('SHELL_VERBOSITY'));
2519+
$this->assertArrayNotHasKey('SHELL_VERBOSITY', $_ENV);
2520+
$this->assertArrayNotHasKey('SHELL_VERBOSITY', $_SERVER);
2521+
}
2522+
2523+
public function testShellVerbosityDoesNotLeakBetweenCommandExecutions()
2524+
{
2525+
// Ensure no initial SHELL_VERBOSITY
2526+
putenv('SHELL_VERBOSITY');
2527+
unset($_ENV['SHELL_VERBOSITY']);
2528+
unset($_SERVER['SHELL_VERBOSITY']);
2529+
2530+
$application = new Application();
2531+
$application->setAutoExit(false);
2532+
$application->register('verbose-cmd')
2533+
->setCode(function (InputInterface $input, OutputInterface $output) {
2534+
$output->write('SHELL_VERBOSITY: '.$_SERVER['SHELL_VERBOSITY']);
2535+
});
2536+
$application->register('normal-cmd')
2537+
->setCode(function (InputInterface $input, OutputInterface $output) {
2538+
$output->write('SHELL_VERBOSITY: '.$_SERVER['SHELL_VERBOSITY']);
2539+
});
2540+
2541+
$output = new BufferedOutput();
2542+
2543+
$application->run(new ArrayInput(['command' => 'verbose-cmd', '--verbose' => true]), $output);
2544+
2545+
$this->assertSame('SHELL_VERBOSITY: 1', $output->fetch(), 'SHELL_VERBOSITY should be set to 1 for verbose command');
2546+
$this->assertFalse(getenv('SHELL_VERBOSITY'), 'SHELL_VERBOSITY should not be set after first command');
2547+
2548+
$application->run(new ArrayInput(['command' => 'normal-cmd']), $output);
2549+
2550+
$this->assertSame('SHELL_VERBOSITY: 0', $output->fetch(), 'SHELL_VERBOSITY should not leak to second command');
2551+
$this->assertFalse(getenv('SHELL_VERBOSITY'), 'SHELL_VERBOSITY should not leak to second command');
2552+
$this->assertArrayNotHasKey('SHELL_VERBOSITY', $_ENV);
2553+
$this->assertArrayNotHasKey('SHELL_VERBOSITY', $_SERVER);
2554+
}
24662555
}
24672556

24682557
class CustomApplication extends Application

0 commit comments

Comments
 (0)