import { exec , spawn } from 'child_process' ; import * as os from 'os' ; import { detectAvailableProfiles as getProfiles , ITerminalProfile } from './profiles' ; export { getProfiles , ITerminalProfile } ; export function shell ( command , defShell ? ) { return new Promise ( ( resolve , reject ) => { exec ( command , { shell : defShell } , ( error , stdout , stderr ) => { if ( error instanceof Error ) { return reject ( error ) ; } if ( stderr . trim ( ) !== '' ) { return reject ( new Error ( `Finished deu error: ${ stderr }` ) ) ; } if ( typeof stdout !== 'string' || stdout . replace ( /[\n\r]/gi , '' ) . trim ( ) === '' ) { stdout = '' ; } resolve ( stdout ) ; } ) ; } ) ; } export enum EPlatforms { aix = 'aix' , darwin = 'darwin' , freebsd = 'freebsd' , linux = 'linux' , openbsd = 'openbsd' , sunos = 'sunos' , win32 = 'win32' , android = 'android' } export type TEnvVars = { [ key ] : string ; } ; export function printenv ( shellFullPath ? ) { if ( os . platform ( ) === EPlatforms . win32 ) { return Promise . reject ( new Error ( `This command doesn't supported by windows.` ) ) ; } return new Promise ( ( resolve , reject ) => { ( ( ) => { if ( shellFullPath === undefined ) { return getDefShell ( ) ; } else { return Promise . resolve ( shellFullPath ) ; } } ) ( ) . then ( ( defShell ) => { shell ( 'printenv' , defShell ) . then ( ( stdout ) => { const pairs = { } ; stdout . split ( /[\n\r]/gi ) . forEach ( ( row ) => { const pair = row . split ( '=' ) ; if ( pair . length <= 1 ) { return ; } pairs [ pair [ 0 ] ] = row . replace ( `${ pair [ 0 ] }=` , '' ) ; } ) ; if ( Object . keys ( pairs ) . length === 0 ) { return resolve ( Object . assign ( { } , process . env ) as TEnvVars ) ; } resolve ( pairs ) ; } ) . catch ( ( error ) => { reject ( error ) ; } ) ; } ) . catch ( ( defShellErr ) => { reject ( defShellErr ) ; } ) ; } ) ; } export function getElectronAppShellEnvVars ( electronPath , shellFullPath ? ) { return new Promise ( ( resolve , reject ) => { if ( os . platform ( ) !== EPlatforms . darwin ) { return resolve ( Object . assign ( { } , process . env ) as TEnvVars ) ; } ( ( ) => { if ( shellFullPath === undefined ) { return getDefShell ( ) ; } else { return Promise . resolve ( shellFullPath ) ; } } ) ( ) . then ( ( targetShell ) => { const env = { ... process . env , ELECTRON_RUN_AS_NODE : '1' , ELECTRON_NO_ATTACH_CONSOLE : '1' , } ; const marker = '__chipmunk_marker__' ; const child = spawn ( targetShell , [ ... [ '-ilc' ] , `'${ electronPath }' -p 'JSON.stringify(Object.assign({ ${ marker }: true }, process.env))'` , ] , { detached : true , stdio : [ 'ignore' , 'pipe' , 'pipe' ] , env , } ) ; child . on ( 'error' , ( err ) => { reject ( err ) ; } ) ; let stdout = '' ; child . stdout . on ( 'data' , ( out ) => ( stdout += out ) ) ; let stderr = '' ; child . stderr . on ( 'data' , ( out ) => ( stderr += out ) ) ; child . on ( 'close' , ( code , signal ) => { if ( code !== 0 ) { return reject ( new Error ( `Process has been finished with code ${ code }. Stderr: ${ stderr }` ) ) ; } try { const envvars = JSON . parse ( stdout ) ; if ( typeof envvars !== 'object' || envvars === null || ! envvars [ marker ] ) { return reject ( new Error ( `Invalid stdout` ) ) ; } resolve ( envvars ) ; } catch ( e ) { reject ( new Error ( `Fail to parse: ${ e . message }` ) ) ; } } ) ; } ) . catch ( ( defShellErr ) => { reject ( defShellErr ) ; } ) ; } ) ; } export function getEnvVar ( name ) { return new Promise ( ( resolve , reject ) => { const possible = process . env [ name ] ; if ( typeof possible === 'string' && possible . trim ( ) !== '' ) { return resolve ( possible ) ; } getDefShell ( ) . then ( ( defShell ) => { let cmd = '' ; switch ( os . platform ( ) ) { case EPlatforms . aix : case EPlatforms . android : case EPlatforms . darwin : case EPlatforms . freebsd : case EPlatforms . linux : case EPlatforms . openbsd : case EPlatforms . sunos : cmd = `echo $${ name }` ; break ; case EPlatforms . win32 : cmd = `echo %${ name }%` ; break ; } let output = '' ; shell ( cmd , defShell ) . then ( ( stdout ) => { output = stdout . replace ( /[\n\r]/gi , '' ) . trim ( ) ; if ( os . platform ( ) === EPlatforms . win32 && output === `%${ name }%` ) { cmd = `echo $${ name }` ; shell ( cmd ) . then ( ( stdoutUnixWay ) => { output = stdoutUnixWay . replace ( /[\n\r]/gi , '' ) . trim ( ) ; if ( os . platform ( ) === EPlatforms . win32 && output === `$${ name }` ) { output = '' ; } resolve ( output ) ; } ) . catch ( ( error ) => { reject ( error ) ; } ) ; } else { resolve ( output ) ; } } ) . catch ( ( error ) => { reject ( error ) ; } ) ; } ) . catch ( ( defShellErr ) => { reject ( defShellErr ) ; } ) ; } ) ; } export function getDefShell ( ignoreCache = false ) { return new Promise ( ( resolve , reject ) => { let shellPath ; let command = '' ; switch ( os . platform ( ) ) { case EPlatforms . aix : case EPlatforms . android : case EPlatforms . darwin : case EPlatforms . freebsd : case EPlatforms . linux : case EPlatforms . openbsd : case EPlatforms . sunos : shellPath = process . env . SHELL ; command = 'echo $SHELL' ; break ; case EPlatforms . win32 : shellPath = process . env . COMSPEC ; command = 'ECHO %COMSPEC%' ; break ; } if ( shellPath ) { return resolve ( shellPath ) ; } shell ( command ) . then ( ( stdout ) => { resolve ( stdout . trim ( ) ) ; } ) . catch ( ( error ) => { reject ( error ) ; } ) ; } ) ; } export function getShells ( ) { return new Promise ( ( resolve , reject ) => { getProfiles ( ) . then ( ( profiles ) => { const shells = [ ] ; profiles . forEach ( ( p ) => { if ( shells . indexOf ( p . path ) === - 1 ) { shells . push ( p . path ) ; } } ) ; resolve ( shells ) ; } ) . catch ( reject ) ; } ) ; }