4
4
5
5
/// <reference path='../../../src/vs/vscode.d.ts'/>
6
6
7
- import * as grpc from '@grpc/grpc-js' ;
8
7
import * as cp from 'child_process' ;
9
- import * as shared from 'gitpod-shared/out/extension' ;
10
- import { GitpodExtensionContext } from 'gitpod-shared/out/features' ;
11
- import { TaskStatus , TasksStatusRequest , TasksStatusResponse , TaskState } from '@gitpod/supervisor-api-grpc/lib/status_pb' ;
12
- import { Terminal , ListTerminalsRequest , TerminalSize , SetTerminalSizeRequest , ListenTerminalRequest , ListenTerminalResponse , ShutdownTerminalRequest , WriteTerminalRequest } from '@gitpod/supervisor-api-grpc/lib/terminal_pb' ;
8
+ import { GitpodExtensionContext , setupGitpodContext } from 'gitpod-shared' ;
13
9
import * as http from 'http' ;
14
10
import * as path from 'path' ;
15
11
import * as util from 'util' ;
16
12
import * as vscode from 'vscode' ;
17
13
18
14
let gitpodContext : GitpodExtensionContext | undefined ;
19
15
export async function activate ( context : vscode . ExtensionContext ) {
20
- gitpodContext = await shared . createContext ( context ) ;
16
+ gitpodContext = await setupGitpodContext ( context ) ;
21
17
if ( ! gitpodContext ) {
22
18
return ;
23
19
}
@@ -36,7 +32,6 @@ export async function activate(context: vscode.ExtensionContext) {
36
32
37
33
installInitialExtensions ( gitpodContext ) ;
38
34
registerHearbeat ( gitpodContext ) ;
39
- registerTasks ( gitpodContext ) ;
40
35
registerCLI ( gitpodContext ) ;
41
36
42
37
// For port tunneling we rely on Remote SSH capabilities
@@ -254,233 +249,3 @@ export function registerHearbeat(context: GitpodExtensionContext): void {
254
249
vscode . workspace . onDidChangeConfiguration ( updateLastActivitiy )
255
250
) ;
256
251
}
257
-
258
- async function registerTasks ( context : GitpodExtensionContext ) : Promise < void > {
259
- const tokenSource = new vscode . CancellationTokenSource ( ) ;
260
- const token = tokenSource . token ;
261
- context . subscriptions . push ( {
262
- dispose : ( ) => tokenSource . cancel ( )
263
- } ) ;
264
-
265
- const tasks = new Map < string , TaskStatus > ( ) ;
266
- let synched = false ;
267
- while ( ! synched ) {
268
- let listener : vscode . Disposable | undefined ;
269
- try {
270
- const req = new TasksStatusRequest ( ) ;
271
- req . setObserve ( true ) ;
272
- const stream = context . supervisor . status . tasksStatus ( req , context . supervisor . metadata ) ;
273
- function done ( ) {
274
- synched = true ;
275
- stream . cancel ( ) ;
276
- }
277
- listener = token . onCancellationRequested ( ( ) => done ( ) ) ;
278
- await new Promise ( ( resolve , reject ) => {
279
- stream . on ( 'end' , resolve ) ;
280
- stream . on ( 'error' , reject ) ;
281
- stream . on ( 'data' , ( response : TasksStatusResponse ) => {
282
- if ( response . getTasksList ( ) . every ( status => {
283
- tasks . set ( status . getTerminal ( ) , status ) ;
284
- return status . getState ( ) !== TaskState . OPENING ;
285
- } ) ) {
286
- done ( ) ;
287
- }
288
- } ) ;
289
- } ) ;
290
- } catch ( err ) {
291
- if ( ! ( 'code' in err && err . code === grpc . status . CANCELLED ) ) {
292
- console . error ( 'code server: listening task updates failed:' , err ) ;
293
- }
294
- } finally {
295
- listener ?. dispose ( ) ;
296
- }
297
- if ( ! synched ) {
298
- await new Promise ( resolve => setTimeout ( resolve , 1000 ) ) ;
299
- }
300
- }
301
- if ( token . isCancellationRequested ) {
302
- return ;
303
- }
304
-
305
- const terminals = new Map < string , Terminal > ( ) ;
306
- try {
307
- const response = await util . promisify ( context . supervisor . terminal . list . bind ( context . supervisor . terminal , new ListTerminalsRequest ( ) , context . supervisor . metadata , {
308
- deadline : Date . now ( ) + context . supervisor . deadlines . long
309
- } ) ) ( ) ;
310
- for ( const terminal of response . getTerminalsList ( ) ) {
311
- terminals . set ( terminal . getAlias ( ) , terminal ) ;
312
- }
313
- } catch ( e ) {
314
- console . error ( 'failed to list terminals:' , e ) ;
315
- }
316
-
317
- for ( const alias of tasks . keys ( ) ) {
318
- const terminal = terminals . get ( alias ) ;
319
- if ( ! terminal ) {
320
- return ;
321
- }
322
- regsiterTask ( alias , terminal . getTitle ( ) , context , token ) ;
323
- }
324
- }
325
-
326
- function regsiterTask ( alias : string , initialTitle : string , context : GitpodExtensionContext , contextToken : vscode . CancellationToken ) : void {
327
- const tokenSource = new vscode . CancellationTokenSource ( ) ;
328
- contextToken . onCancellationRequested ( ( ) => tokenSource . cancel ( ) ) ;
329
- const token = tokenSource . token ;
330
-
331
- const onDidWriteEmitter = new vscode . EventEmitter < string > ( ) ;
332
- const onDidCloseEmitter = new vscode . EventEmitter < void | number > ( ) ;
333
- const onDidChangeNameEmitter = new vscode . EventEmitter < string > ( ) ;
334
- const toDispose = vscode . Disposable . from ( onDidWriteEmitter , onDidCloseEmitter , onDidChangeNameEmitter ) ;
335
- token . onCancellationRequested ( ( ) => toDispose . dispose ( ) ) ;
336
-
337
- let pendingWrite = Promise . resolve ( ) ;
338
- let pendinResize = Promise . resolve ( ) ;
339
- function setDimensions ( dimensions : vscode . TerminalDimensions ) : void {
340
- if ( token . isCancellationRequested ) {
341
- return ;
342
- }
343
- pendinResize = pendinResize . then ( async ( ) => {
344
- if ( token . isCancellationRequested ) {
345
- return ;
346
- }
347
- try {
348
- const size = new TerminalSize ( ) ;
349
- size . setCols ( dimensions . columns ) ;
350
- size . setRows ( dimensions . rows ) ;
351
-
352
- const request = new SetTerminalSizeRequest ( ) ;
353
- request . setAlias ( alias ) ;
354
- request . setSize ( size ) ;
355
- request . setForce ( true ) ;
356
- await util . promisify ( context . supervisor . terminal . setSize . bind ( context . supervisor . terminal , request , context . supervisor . metadata , {
357
- deadline : Date . now ( ) + context . supervisor . deadlines . short
358
- } ) ) ( ) ;
359
- } catch ( e ) {
360
- if ( e && e . code !== grpc . status . NOT_FOUND ) {
361
- console . error ( `${ alias } terminal: resize failed:` , e ) ;
362
- }
363
- }
364
- } ) ;
365
- }
366
- const terminal = vscode . window . createTerminal ( {
367
- name : initialTitle ,
368
- pty : {
369
- onDidWrite : onDidWriteEmitter . event ,
370
- onDidClose : onDidCloseEmitter . event ,
371
- onDidChangeName : onDidChangeNameEmitter . event ,
372
- open : async ( dimensions : vscode . TerminalDimensions | undefined ) => {
373
- if ( dimensions ) {
374
- setDimensions ( dimensions ) ;
375
- }
376
- while ( ! token . isCancellationRequested ) {
377
- let notFound = false ;
378
- let exitCode : number | undefined ;
379
- let listener : vscode . Disposable | undefined ;
380
- try {
381
- await new Promise ( ( resolve , reject ) => {
382
- const request = new ListenTerminalRequest ( ) ;
383
- request . setAlias ( alias ) ;
384
- const stream = context . supervisor . terminal . listen ( request , context . supervisor . metadata ) ;
385
- listener = token . onCancellationRequested ( ( ) => stream . cancel ( ) ) ;
386
- stream . on ( 'end' , resolve ) ;
387
- stream . on ( 'error' , reject ) ;
388
- stream . on ( 'data' , ( response : ListenTerminalResponse ) => {
389
- if ( response . hasTitle ( ) ) {
390
- const title = response . getTitle ( ) ;
391
- if ( title ) {
392
- onDidChangeNameEmitter . fire ( title ) ;
393
- }
394
- } else if ( response . hasData ( ) ) {
395
- let data = '' ;
396
- const buffer = response . getData ( ) ;
397
- if ( typeof buffer === 'string' ) {
398
- data += buffer ;
399
- } else {
400
- data += Buffer . from ( buffer ) . toString ( ) ;
401
- }
402
- if ( data !== '' ) {
403
- onDidWriteEmitter . fire ( data ) ;
404
- }
405
- } else if ( response . hasExitCode ( ) ) {
406
- exitCode = response . getExitCode ( ) ;
407
- }
408
- } ) ;
409
- } ) ;
410
- } catch ( e ) {
411
- notFound = 'code' in e && e . code === grpc . status . NOT_FOUND ;
412
- if ( ! token . isCancellationRequested && ! notFound && ! ( 'code' in e && e . code === grpc . status . CANCELLED ) ) {
413
- console . error ( `${ alias } terminal: listening failed:` , e ) ;
414
- }
415
- } finally {
416
- listener ?. dispose ( ) ;
417
- }
418
- if ( token . isCancellationRequested ) {
419
- return ;
420
- }
421
- if ( notFound ) {
422
- onDidCloseEmitter . fire ( ) ;
423
- } else if ( typeof exitCode === 'number' ) {
424
- onDidCloseEmitter . fire ( exitCode ) ;
425
- }
426
- await new Promise ( resolve => setTimeout ( resolve , 2000 ) ) ;
427
- }
428
- } ,
429
- close : async ( ) => {
430
- if ( token . isCancellationRequested ) {
431
- return ;
432
- }
433
- tokenSource . cancel ( ) ;
434
-
435
- // await to make sure that close is not cause by the extension host process termination
436
- // in such case we don't want to stop supervisor terminals
437
- setTimeout ( async ( ) => {
438
- if ( contextToken . isCancellationRequested ) {
439
- return ;
440
- }
441
- // Attempt to kill the pty, it may have already been killed at this
442
- // point but we want to make sure
443
- try {
444
- const request = new ShutdownTerminalRequest ( ) ;
445
- request . setAlias ( alias ) ;
446
- await util . promisify ( context . supervisor . terminal . shutdown . bind ( context . supervisor . terminal , request , context . supervisor . metadata , {
447
- deadline : Date . now ( ) + context . supervisor . deadlines . short
448
- } ) ) ( ) ;
449
- } catch ( e ) {
450
- if ( e && e . code === grpc . status . NOT_FOUND ) {
451
- // Swallow, the pty has already been killed
452
- } else {
453
- console . error ( `${ alias } terminal: shutdown failed:` , e ) ;
454
- }
455
- }
456
- } , 1000 ) ;
457
-
458
- } ,
459
- handleInput : async ( data : string ) => {
460
- if ( token . isCancellationRequested ) {
461
- return ;
462
- }
463
- pendingWrite = pendingWrite . then ( async ( ) => {
464
- if ( token . isCancellationRequested ) {
465
- return ;
466
- }
467
- try {
468
- const request = new WriteTerminalRequest ( ) ;
469
- request . setAlias ( alias ) ;
470
- request . setStdin ( Buffer . from ( data , 'utf8' ) ) ;
471
- await util . promisify ( context . supervisor . terminal . write . bind ( context . supervisor . terminal , request , context . supervisor . metadata , {
472
- deadline : Date . now ( ) + context . supervisor . deadlines . short
473
- } ) ) ( ) ;
474
- } catch ( e ) {
475
- if ( e && e . code !== grpc . status . NOT_FOUND ) {
476
- console . error ( `${ alias } terminal: write failed:` , e ) ;
477
- }
478
- }
479
- } ) ;
480
- } ,
481
- setDimensions : ( dimensions : vscode . TerminalDimensions ) => setDimensions ( dimensions )
482
- }
483
- } ) ;
484
- terminal . show ( ) ;
485
- }
486
-
0 commit comments