8000 [Console] Rework the signal integration · symfony/symfony@93c7e1f · GitHub
[go: up one dir, main page]

Skip to content

Commit 93c7e1f

Browse files
committed
[Console] Rework the signal integration
1 parent ae677cc commit 93c7e1f

File tree

4 files changed

+68
-29
lines changed

4 files changed

+68
-29
lines changed

src/Symfony/Component/Console/Application.php

Lines changed: 25 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
use Symfony\Component\Console\Command\Command;
1515
use Symfony\Component\Console\Command\HelpCommand;
1616
use Symfony\Component\Console\Command\ListCommand;
17+
use Symfony\Component\Console\Command\SignalableCommandInterface;
1718
use Symfony\Component\Console\CommandLoader\CommandLoaderInterface;
1819
use Symfony\Component\Console\Event\ConsoleCommandEvent;
1920
use Symfony\Component\Console\Event\ConsoleErrorEvent;
@@ -79,13 +80,18 @@ class Application implements ResetInterface
7980
private $singleCommand = false;
8081
private $initialized;
8182
private $signalRegistry;
83+
private $signalsToDispatchEvent = [];
8284

8385
public function __construct(string $name = 'UNKNOWN', string $version = 'UNKNOWN')
8486
{
8587
$this->name = $name;
8688
$this->version = $version;
8789
$this->terminal = new Terminal();
8890
$this->defaultCommand = 'list';
91+
$this->signalRegistry = new SignalRegistry();
92+
if (\defined('SIGINT')) {
93+
$this->signalsToDispatchEvent = [SIGINT, SIGTERM, SIGUSR1, SIGUSR2];
94+
}
8995
}
9096

9197
/**
@@ -101,9 +107,14 @@ public function setCommandLoader(CommandLoaderInterface $commandLoader)
101107
$this->commandLoader = $commandLoader;
102108
}
103109

104-
public function setSignalRegistry(SignalRegistry $signalRegistry)
110+
public function getSignalRegistry(): SignalRegistry
105111
{
106-
$this->signalRegistry = $signalRegistry;
112+
return $this->signalRegistry;
113+
}
114+
115+
public function setSignalsToDispatchEvent(int ...$signalsToDispatchEvent)
116+
{
117+
$this->signalsToDispatchEvent = $signalsToDispatchEvent;
107118
}
108119

109120
/**
@@ -268,14 +279,13 @@ public function doRun(InputInterface $input, OutputInterface $output)
268279
$command = $this->find($alternative);
269280
}
270281

271-
if ($this->signalRegistry) {
272-
foreach ($this->signalRegistry->getHandlingSignals() as $handlingSignal) {
273-
$event = new ConsoleSignalEvent($command, $input, $output, $handlingSignal);
274-
$onSignalHandler = function () use ($event) {
275-
$this->dispatcher->dispatch($event, ConsoleEvents::SIGNAL);
276-
};
282+
if ($this->dispatcher) {
283+
foreach ($this->signalsToDispatchEvent as $signal) {
284+
$event = new ConsoleSignalEvent($command, $input, $output, $signal);
277285

278-
$this->signalRegistry->register($handlingSignal, $onSignalHandler);
286+
$this->signalRegistry->register($signal, function () use ($event) {
287+
$this->dispatcher->dispatch($event, ConsoleEvents::SIGNAL);
288+
});
279289
}
280290
}
281291

@@ -926,6 +936,12 @@ protected function doRunCommand(Command $command, InputInterface $input, OutputI
926936
}
927937
}
928938

939+
if ($command instanceof SignalableCommandInterface) {
940+
foreach ($command->getSubscribedSignals() as $signal) {
941+
$this->signalRegistry->register($signal, [$command, 'handleSignal']);
942+
}
943+
}
944+
929945
if (null === $this->dispatcher) {
930946
return $command->run($input, $output);
931947
}

src/Symfony/Component/Console/CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,10 @@ CHANGELOG
77
* Added `SingleCommandApplication::setAutoExit()` to allow testing via `CommandTester`
88
* added support for multiline responses to questions through `Question::setMultiline()`
99
and `Question::isMultiline()`
10+
* Added `SignalRegistry` class to stack signals handlers
11+
* Added support for signals:
12+
* Added `Application::getSignalRegistry()` and `Application::setSignalsToDispatchEvent()` methods
13+
* Added `SignalableCommandInterface` interface
1014

1115
5.1.0
1216
-----
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\Console\Command;
13+
14+
/**
15+
* Interface for command reacting to signal.
16+
*
17+
* @author Grégoire Pineau <lyrixx@lyrix.info>
18+
*/
19+
interface SignalableCommandInterface
20+
{
21+
/**
22+
* Returns the list of signals to subscribe.
23+
*/
24+
public function getSubscribedSignals(): array;
25+
26+
/**
27+
* The method will be called when the application is signaled.
28+
*/
29+
public function handleSignal(int $signal): void;
30+
}

src/Symfony/Component/Console/SignalRegistry/SignalRegistry.php

Lines changed: 9 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -13,26 +13,27 @@
< F438 code>1313

1414
final class SignalRegistry
1515
{
16-
private $registeredSignals = [];
17-
18-
private $handlingSignals = [];
16+
private $signalHandlers = [];
1917

2018
public function __construct()
2119
{
22-
pcntl_async_signals(true);
20+
if (\function_exists('pcntl_async_signals')) {
21+
pcntl_async_signals(true);
22+
}
2323
}
2424

2525
public function register(int $signal, callable $signalHandler): void
2626
{
27-
if (!isset($this->registeredSignals[$signal])) {
27+
if (!isset($this->signalHandlers[$signal])) {
2828
$previousCallback = pcntl_signal_get_handler($signal);
2929

3030
if (\is_callable($previousCallback)) {
31-
$this->registeredSignals[$signal][] = $previousCallback;
31+
$this->signalHandlers[$signal][] = $previousCallback;
3232
}
3333
}
3434

35-
$this->registeredSignals[$signal][] = $signalHandler;
35+
$this->signalHandlers[$signal][] = $signalHandler;
36+
3637
pcntl_signal($signal, [$this, 'handle']);
3738
}
3839

@@ -41,20 +42,8 @@ public function register(int $signal, callable $signalHandler): void
4142
*/
4243
public function handle(int $signal): void
4344
{
44-
foreach ($this->registeredSignals[$signal] as $signalHandler) {
45+
foreach ($this->signalHandlers[$signal] as $signalHandler) {
4546
$signalHandler($signal);
4647
}
4748
}
48-
49-
public function addHandlingSignals(int ...$signals): void
50-
{
51-
foreach ($signals as $signal) {
52-
$this->handlingSignals[$signal] = true;
53-
}
54-
}
55-
56-
public function getHandlingSignals(): array
57-
{
58-
return array_keys($this->handlingSignals);
59-
}
6049
}

0 commit comments

Comments
 (0)
0