Skip to content

Commit 338221c

Browse files
committed
Support cancelling the activity on Ctrl+C (non-Windows)
1 parent 2a893f5 commit 338221c

File tree

1 file changed

+63
-4
lines changed

1 file changed

+63
-4
lines changed

src/Service/ActivityMonitor.php

Lines changed: 63 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
namespace Platformsh\Cli\Service;
44

5+
use GuzzleHttp\Exception\BadResponseException;
56
use Platformsh\Client\Model\Activity;
67
use Platformsh\Client\Model\ActivityLog\LogItem;
78
use Platformsh\Client\Model\Project;
@@ -99,6 +100,29 @@ public function waitAndLog(Activity $activity, $pollInterval = 3, $timestamps =
99100
return Helper::formatTime(time() - $startTime);
100101
});
101102
$bar->setFormat('[%bar%] %elapsed:6s% (%state%)');
103+
104+
// Set up cancellation for the activity on Ctrl+C.
105+
if (\function_exists('\\pcntl_signal') && $activity->operationAvailable('cancel')) {
106+
declare(ticks = 1);
107+
$sigintReceived = false;
108+
/** @noinspection PhpComposerExtensionStubsInspection */
109+
\pcntl_signal(SIGINT, function () use ($activity, $stdErr, $bar, &$sigintReceived) {
110+
if ($sigintReceived) {
111+
exit(1);
112+
}
113+
$bar->clear();
114+
$stdErr->write($stdErr->isDecorated() ? "\n\033[1A" : "\n");
115+
$result = $this->cancel($activity, $stdErr);
116+
if ($result) {
117+
exit(1);
118+
}
119+
$sigintReceived = true;
120+
$stdErr->writeln('');
121+
$bar->advance();
122+
});
123+
$stdErr->writeln('Enter Ctrl+C once to cancel the activity (or twice to quit this command).');
124+
}
125+
102126
$bar->start();
103127

104128
$logStream = $this->getLogStream($activity, $bar);
@@ -166,6 +190,40 @@ public function waitAndLog(Activity $activity, $pollInterval = 3, $timestamps =
166190
return false;
167191
}
168192

193+
/**
194+
* Attempts to cancel the activity, catching and printing errors.
195+
*
196+
* @param Activity $activity
197+
* @param OutputInterface $stdErr
198+
*
199+
* @return bool
200+
*/
201+
private function cancel(Activity $activity, OutputInterface $stdErr)
202+
{
203+
if (!$activity->operationAvailable('cancel')) {
204+
$stdErr->writeln('The activity cannot be cancelled.');
205+
return false;
206+
}
207+
$stdErr->writeln('Cancelling the activity...');
208+
try {
209+
try {
210+
$activity->cancel();
211+
} catch (BadResponseException $e) {
212+
if ($e->getResponse() && $e->getResponse()->getStatusCode() === 400 && \strpos($e->getMessage(), 'cannot be cancelled in its current state')) {
213+
$activity->refresh();
214+
$stdErr->writeln(\sprintf('The activity cannot be cancelled in its current state (<error>%s</error>).', $activity->state));
215+
return false;
216+
}
217+
throw $e;
218+
}
219+
} catch (\Exception $e) {
220+
$stdErr->writeln(\sprintf('Failed to cancel the activity: <error>%s</error>', $e->getMessage()));
221+
return false;
222+
}
223+
$stdErr->writeln('The activity was successfully cancelled.');
224+
return true;
225+
}
226+
169227
/**
170228
* Reads the log stream and returns LogItem objects.
171229
*
@@ -435,11 +493,11 @@ private function getStart(Activity $activity) {
435493
private function getLogStream(Activity $activity, ProgressBar $bar) {
436494
$url = $activity->getLink('log');
437495

438-
// Try fetching the stream with a 10 second timeout per call, and a .5
439-
// second interval between calls, for up to 2 minutes.
440-
$readTimeout = 10;
441-
$interval = .5;
496+
// Try fetching the stream with an up to 10 second timeout per call,
497+
// and a .5 second interval between calls, for up to 2 minutes.
498+
$readTimeout = .5;
442499
$stream = \fopen($url, 'r', false, $this->api->getStreamContext($readTimeout));
500+
$interval = .5;
443501
$start = \microtime(true);
444502
while ($stream === false) {
445503
if (\microtime(true) - $start > 120) {
@@ -448,6 +506,7 @@ private function getLogStream(Activity $activity, ProgressBar $bar) {
448506
$bar->advance();
449507
\usleep($interval * 1000000);
450508
$bar->advance();
509+
$readTimeout = $readTimeout >= 10 ? $readTimeout : $readTimeout + .5;
451510
$stream = \fopen($url, 'r', false, $this->api->getStreamContext($readTimeout));
452511
}
453512
\stream_set_blocking($stream, 0);

0 commit comments

Comments
 (0)