22
33namespace Platformsh \Cli \Service ;
44
5+ use GuzzleHttp \Exception \BadResponseException ;
56use Platformsh \Client \Model \Activity ;
67use Platformsh \Client \Model \ActivityLog \LogItem ;
78use Platformsh \Client \Model \Project ;
@@ -99,6 +100,27 @@ 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+ $ sigintReceived = true ;
114+ $ bar ->clear ();
115+ if ($ this ->cancel ($ activity , $ stdErr )) {
116+ exit (1 );
117+ }
118+ $ stdErr ->writeln ('' );
119+ $ bar ->advance ();
120+ });
121+ $ stdErr ->writeln ('Enter Ctrl+C once to cancel the activity (or twice to quit this command). ' );
122+ }
123+
102124 $ bar ->start ();
103125
104126 $ logStream = $ this ->getLogStream ($ activity , $ bar );
@@ -166,6 +188,40 @@ public function waitAndLog(Activity $activity, $pollInterval = 3, $timestamps =
166188 return false ;
167189 }
168190
191+ /**
192+ * Attempts to cancel the activity, catching and printing errors.
193+ *
194+ * @param Activity $activity
195+ * @param OutputInterface $stdErr
196+ *
197+ * @return bool
198+ */
199+ private function cancel (Activity $ activity , OutputInterface $ stdErr )
200+ {
201+ if (!$ activity ->operationAvailable ('cancel ' )) {
202+ $ stdErr ->writeln ('The activity cannot be cancelled. ' );
203+ return false ;
204+ }
205+ $ stdErr ->writeln ('Cancelling the activity... ' );
206+ try {
207+ try {
208+ $ activity ->cancel ();
209+ } catch (BadResponseException $ e ) {
210+ if ($ e ->getResponse () && $ e ->getResponse ()->getStatusCode () === 400 && \strpos ($ e ->getMessage (), 'cannot be cancelled in its current state ' )) {
211+ $ activity ->refresh ();
212+ $ stdErr ->writeln (\sprintf ('The activity cannot be cancelled in its current state (<error>%s</error>). ' , $ activity ->state ));
213+ return false ;
214+ }
215+ throw $ e ;
216+ }
217+ } catch (\Exception $ e ) {
218+ $ stdErr ->writeln (\sprintf ('Failed to cancel the activity: <error>%s</error> ' , $ e ->getMessage ()));
219+ return false ;
220+ }
221+ $ stdErr ->writeln ('The activity was successfully cancelled. ' );
222+ return true ;
223+ }
224+
169225 /**
170226 * Reads the log stream and returns LogItem objects.
171227 *
@@ -435,11 +491,11 @@ private function getStart(Activity $activity) {
435491 private function getLogStream (Activity $ activity , ProgressBar $ bar ) {
436492 $ url = $ activity ->getLink ('log ' );
437493
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 ;
494+ // Try fetching the stream with an up to 10 second timeout per call,
495+ // and a .5 second interval between calls, for up to 2 minutes.
496+ $ readTimeout = .5 ;
442497 $ stream = \fopen ($ url , 'r ' , false , $ this ->api ->getStreamContext ($ readTimeout ));
498+ $ interval = .5 ;
443499 $ start = \microtime (true );
444500 while ($ stream === false ) {
445501 if (\microtime (true ) - $ start > 120 ) {
@@ -448,6 +504,7 @@ private function getLogStream(Activity $activity, ProgressBar $bar) {
448504 $ bar ->advance ();
449505 \usleep ($ interval * 1000000 );
450506 $ bar ->advance ();
507+ $ readTimeout = $ readTimeout >= 10 ? $ readTimeout : $ readTimeout + .5 ;
451508 $ stream = \fopen ($ url , 'r ' , false , $ this ->api ->getStreamContext ($ readTimeout ));
452509 }
453510 \stream_set_blocking ($ stream , 0 );
0 commit comments