Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commitfd64a13

Browse files
committed
[Console] Fix issue with signal handling
1 parent9b30b94 commitfd64a13

File tree

5 files changed

+119
-9
lines changed

5 files changed

+119
-9
lines changed

‎src/Symfony/Component/Console/Application.php‎

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1012,25 +1012,42 @@ protected function doRunCommand(Command $command, InputInterface $input, OutputI
10121012
$sttyMode =shell_exec('stty -g');
10131013

10141014
foreach ([\SIGINT, \SIGTERM]as$signal) {
1015-
$this->signalRegistry->register($signal,staticfunction ()use ($sttyMode) {
1016-
shell_exec('stty'.$sttyMode);
1017-
});
1015+
$this->signalRegistry->register($signal,staticfn () =>shell_exec('stty'.$sttyMode));
10181016
}
10191017
}
10201018
}
10211019

1022-
if (null !==$this->dispatcher) {
1020+
if ($this->dispatcher) {
1021+
// We register application signal, so that we can dispatch the event
10231022
foreach ($this->signalsToDispatchEventas$signal) {
1024-
$event =newConsoleSignalEvent($command,$input,$output,$signal);
1023+
$event =newConsoleSignalEvent($command,$input,$output,$signal,0);
10251024

1026-
$this->signalRegistry->register($signal,function ()use ($event) {
1025+
$this->signalRegistry->register($signal,function ($signal)use ($event,$command,$commandSignals) {
10271026
$this->dispatcher->dispatch($event, ConsoleEvents::SIGNAL);
1027+
$exitCode =$event->getExitCode();
1028+
1029+
if (\in_array($signal,$commandSignals,true)) {
1030+
$command->handleSignal($signal);
1031+
$exitCode =$command->getExitCode($signal,$exitCode);
1032+
}
1033+
if (null !==$exitCode) {
1034+
exit($exitCode);
1035+
}
10281036
});
10291037
}
1038+
1039+
// then we register command signal, but not if already handled by the dispatcher
1040+
$commandSignals =array_diff($commandSignals,$this->signalsToDispatchEvent);
10301041
}
10311042

10321043
foreach ($commandSignalsas$signal) {
1033-
$this->signalRegistry->register($signal, [$command,'handleSignal']);
1044+
$this->signalRegistry->register($signal,function (int$signal)use ($command):void {
1045+
$command->handleSignal($signal);
1046+
$exitCode =$command->getExitCode($signal,0);
1047+
if (null !==$exitCode) {
1048+
exit($exitCode);
1049+
}
1050+
});
10341051
}
10351052
}
10361053

‎src/Symfony/Component/Console/Command/SignalableCommandInterface.php‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515
* Interface for command reacting to signal.
1616
*
1717
* @author Grégoire Pineau <lyrixx@lyrix.info>
18+
*
19+
* @method ?int getExitCode(int $signal, ?int $previousExitCode) Returns whether to automatically exit with $exitCode after command handling, or not with null.
1820
*/
1921
interface SignalableCommandInterface
2022
{

‎src/Symfony/Component/Console/Event/ConsoleSignalEvent.php‎

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,15 +21,34 @@
2121
finalclass ConsoleSignalEventextends ConsoleEvent
2222
{
2323
privateint$handlingSignal;
24+
private ?int$exitCode;
2425

25-
publicfunction__construct(Command$command,InputInterface$input,OutputInterface$output,int$handlingSignal)
26+
publicfunction__construct(Command$command,InputInterface$input,OutputInterface$output,int$handlingSignal, ?int$exitCode =0)
2627
{
2728
parent::__construct($command,$input,$output);
2829
$this->handlingSignal =$handlingSignal;
30+
$this->exitCode =$exitCode;
2931
}
3032

3133
publicfunctiongetHandlingSignal():int
3234
{
3335
return$this->handlingSignal;
3436
}
37+
38+
/**
39+
* Sets whether to automatically exit with $exitCode after command handling, or not with null.
40+
*/
41+
publicfunctionsetExitCode(?int$exitCode):void
42+
{
43+
if (null !==$exitCode && ($exitCode <0 ||$exitCode >255)) {
44+
thrownew \InvalidArgumentException('Exit code must be between 0 and 255 or null.');
45+
}
46+
47+
$this->exitCode =$exitCode;
48+
}
49+
50+
publicfunctiongetExitCode(): ?int
51+
{
52+
return$this->exitCode;
53+
}
3554
}

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

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1929,7 +1929,8 @@ public function testSignalListener()
19291929

19301930
$dispatcherCalled =false;
19311931
$dispatcher =newEventDispatcher();
1932-
$dispatcher->addListener('console.signal',function ()use (&$dispatcherCalled) {
1932+
$dispatcher->addListener('console.signal',function ($e)use (&$dispatcherCalled) {
1933+
$e->setExitCode(null);
19331934
$dispatcherCalled =true;
19341935
});
19351936

@@ -2222,6 +2223,11 @@ public function handleSignal(int $signal): void
22222223
$this->signaled =true;
22232224
$this->signalHandlers[] =__CLASS__;
22242225
}
2226+
2227+
publicfunctiongetExitCode(int$signal, ?int$previousExitCode): ?int
2228+
{
2229+
returnnull;
2230+
}
22252231
}
22262232

22272233
#[AsCommand(name:'signal')]
@@ -2237,6 +2243,11 @@ public function handleSignal(int $signal): void
22372243
$this->signaled =true;
22382244
$this->signalHandlers[] =__CLASS__;
22392245
}
2246+
2247+
publicfunctiongetExitCode(int$signal, ?int$previousExitCode): ?int
2248+
{
2249+
returnnull;
2250+
}
22402251
}
22412252

22422253
class SignalEventSubscriberimplements EventSubscriberInterface
@@ -2248,6 +2259,8 @@ public function onSignal(ConsoleSignalEvent $event): void
22482259
$this->signaled =true;
22492260
$event->getCommand()->signaled =true;
22502261
$event->getCommand()->signalHandlers[] =__CLASS__;
2262+
2263+
$event->setExitCode(null);
22512264
}
22522265

22532266
publicstaticfunctiongetSubscribedEvents():array
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
--TEST--
2+
Test command that exist
3+
--SKIPIF--
4+
<?phpif (!\defined('SIGINT'));
5+
--FILE--
6+
<?php
7+
8+
useSymfony\Component\Console\Application;
9+
useSymfony\Component\Console\Command\Command;
10+
useSymfony\Component\Console\Command\SignalableCommandInterface;
11+
useSymfony\Component\Console\Helper\QuestionHelper;
12+
useSymfony\Component\Console\Input\InputInterface;
13+
useSymfony\Component\Console\Output\OutputInterface;
14+
useSymfony\Component\Console\Question\Question;
15+
16+
$vendor =__DIR__;
17+
while (!file_exists($vendor.'/vendor')) {
18+
$vendor =\dirname($vendor);
19+
}
20+
require$vendor.'/vendor/autoload.php';
21+
22+
class MyCommandextends Commandimplements SignalableCommandInterface
23+
{
24+
protectedfunctionexecute(InputInterface$input,OutputInterface$output):int
25+
{
26+
posix_kill(posix_getpid(), \SIGINT);
27+
28+
$output->writeln('should not be displayed');
29+
30+
return0;
31+
}
32+
33+
34+
publicfunctiongetSubscribedSignals():array
35+
{
36+
return [\SIGINT];
37+
}
38+
39+
publicfunctionhandleSignal(int$signal):void
40+
{
41+
echo"Received signal!";
42+
}
43+
44+
publicfunctiongetExitCode(int$signal, ?int$previousExitCode): ?int
45+
{
46+
return12;
47+
}
48+
}
49+
50+
$app =newApplication();
51+
$app->setDispatcher(new \Symfony\Component\EventDispatcher\EventDispatcher());
52+
$app->add(newMyCommand('foo'));
53+
54+
$app
55+
->setDefaultCommand('foo',true)
56+
->run()
57+
;
58+
--EXPECT--
59+
Received signal!

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp