import * as fs from 'fs' ; import * as path from 'path' ; import * as vscode from 'vscode' ; import * as utils from '../common/utilities' ; import { ChildProcess } from 'child_process' ; import { ILogger } from '../common/logger' ; import { AndroidProject } from '../project/androidProject' ; import { IosProject } from '../project/iosProject' ; import { NativeScriptCli } from '../project/nativeScriptCli' ; import { IDebugResult } from '../project/project' ; import { services } from './extensionHostServices' ; export class BuildService { private _tnsProcess : ChildProcess ; private _logger : ILogger ; constructor ( logger ) { this . _logger = logger ; } public async processRequest ( args ) { const tnsPath = services . workspaceConfigService . tnsPath ; this . _logger . log ( `[NSDebugAdapter] Using tns CLI on path '${ tnsPath }'\n` ) ; const tnsPathResolved = ( tnsPath !== 'tns' && ! path . isAbsolute ( tnsPath ) ) ? path . join ( args . appRoot , tnsPath ) : tnsPath ; const cli = new NativeScriptCli ( tnsPathResolved , this . _logger ) ; const project = args . platform === 'ios' ? new IosProject ( args . appRoot , cli ) : new AndroidProject ( args . appRoot , cli ) ; services . analyticsService . launchDebugger ( args . request , args . platform ) ; const version = project . cli . executeGetVersion ( ) ; this . _logger . log ( `[NSDebugAdapter] Using tns CLI v${ version } on path '${ project . cli . path }'\n` ) ; this . _logger . log ( '[NSDebugAdapter] Running tns command...\n' ) ; let cliCommand ; if ( args . request === 'launch' ) { let tnsArgs = args . tnsArgs ; if ( args . platform && args . platform . toLowerCase ( ) === 'ios' ) { const teamId = this . getTeamId ( path . join ( args . appRoot , 'app' ) , tnsArgs ) ; if ( ! teamId ) { const selectedTeam = await services . iOSTeamService . selectTeam ( ) ; if ( selectedTeam ) { tnsArgs = ( tnsArgs || [ ] ) . concat ( [ '--teamId' , selectedTeam . id ] ) ; this . _logger . log ( `[NSDebugAdapter] Using iOS Team ID '${ selectedTeam . id }', you can change this in the workspace settings.\n` ) ; } } } cliCommand = project . debug ( { stopOnEntry : args . stopOnEntry , watch : args . watch , launchTests : args . launchTests } , tnsArgs ) ; } else if ( args . request === 'attach' ) { cliCommand = project . attach ( args . tnsArgs ) ; } return new Promise < string | number > ( ( res , rej ) => { if ( cliCommand . tnsProcess ) { this . _tnsProcess = cliCommand . tnsProcess ; cliCommand . tnsProcess . stdout . on ( 'data' , ( data ) => { this . _logger . log ( data . toString ( ) ) ; } ) ; cliCommand . tnsProcess . stderr . on ( 'data' , ( data ) => { this . _logger . log ( data . toString ( ) ) ; } ) ; cliCommand . tnsProcess . on ( 'close' , ( code , signal ) => { this . _logger . log ( `[NSDebugAdapter] The tns command finished its execution with code ${ code }.\n` ) ; if ( code !== 0 ) { const errorMessage = `The tns command finished its execution with code ${ code }` ; this . _logger . log ( errorMessage ) ; } res ( ) ; } ) ; } this . _logger . log ( '[NSDebugAdapter] Watching the tns CLI output to receive a connection token\n' ) ; cliCommand . tnsOutputEventEmitter . on ( 'readyForConnection' , ( connectionToken ) => { this . _logger . log ( `[NSDebugAdapter] Ready to attach to application on ${ connectionToken }\n` ) ; args . port = connectionToken ; vscode . debug . activeDebugSession && vscode . debug . activeDebugSession . customRequest ( 'onPortReceived' , { port : connectionToken } ) ; res ( connectionToken ) ; } ) ; } ) ; } public disconnect ( ) { if ( this . _tnsProcess ) { this . _tnsProcess . stdout . removeAllListeners ( ) ; this . _tnsProcess . stderr . removeAllListeners ( ) ; this . _tnsProcess . removeAllListeners ( ) ; utils . killProcess ( this . _tnsProcess ) ; } } private getTeamId ( appRoot , tnsArgs ? ) { if ( tnsArgs ) { const teamIdArgIndex = tnsArgs . indexOf ( '--teamId' ) ; if ( teamIdArgIndex > 0 && teamIdArgIndex + 1 < tnsArgs . length ) { return tnsArgs [ teamIdArgIndex + 1 ] ; } } const teamIdFromConfig = this . readTeamId ( appRoot ) ; if ( teamIdFromConfig ) { return teamIdFromConfig ; } return null ; } private readXCConfig ( appRoot , flag ) { const xcconfigFile = path . join ( appRoot , 'App_Resources/iOS/build.xcconfig' ) ; if ( fs . existsSync ( xcconfigFile ) ) { const text = fs . readFileSync ( xcconfigFile , { encoding : 'utf8' } ) ; let teamId ; text . split ( /\r?\n/ ) . forEach ( ( line ) => { line = line . replace ( /\/(\/)[^\n]*$/ , '' ) ; if ( line . indexOf ( flag ) >= 0 ) { teamId = line . split ( '=' ) [ 1 ] . trim ( ) ; if ( teamId [ teamId . length - 1 ] === ';' ) { teamId = teamId . slice ( 0 , - 1 ) ; } } } ) ; if ( teamId ) { return teamId ; } } const fileName = path . join ( appRoot , 'teamid' ) ; if ( fs . existsSync ( fileName ) ) { return fs . readFileSync ( fileName , { encoding : 'utf8' } ) ; } return null ; } private readTeamId ( appRoot ) { return this . readXCConfig ( appRoot , 'DEVELOPMENT_TEAM' ) ; } }