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,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