11'use strict' ;
22
3- import { CommonSpawnOptions , spawn , spawnSync } from 'child_process' ;
3+ import { ChildProcess , CommonSpawnOptions , spawn , spawnSync , SpawnSyncReturns } from 'child_process' ;
44import { platform } from 'os' ;
55import { window } from 'vscode' ;
66import { GaugeCommands , GRADLE_COMMAND , MAVEN_COMMAND } from './constants' ;
@@ -10,11 +10,11 @@ export class CLI {
1010 private readonly _gaugeVersion : string ;
1111 private readonly _gaugeCommitHash : string ;
1212 private readonly _gaugePlugins : Array < any > ;
13- private readonly _gaugeCommand : string ;
14- private readonly _mvnCommand : string ;
15- private readonly _gradleCommand : string ;
13+ private readonly _gaugeCommand : Command ;
14+ private readonly _mvnCommand : Command ;
15+ private readonly _gradleCommand : Command ;
1616
17- public constructor ( cmd : string , manifest : any , mvnCommand : string , gradleCommand : string ) {
17+ public constructor ( cmd : Command , manifest : any , mvnCommand : Command , gradleCommand : Command ) {
1818 this . _gaugeCommand = cmd ;
1919 this . _mvnCommand = mvnCommand ;
2020 this . _gradleCommand = gradleCommand ;
@@ -23,18 +23,12 @@ export class CLI {
2323 this . _gaugePlugins = manifest . plugins ;
2424 }
2525
26- public static getDefaultSpawnOptions ( ) : CommonSpawnOptions {
27- // should only deal with platform specific options
28- return platform ( ) === "win32" ? { shell : true } : { } ;
29- }
30-
3126 public static instance ( ) : CLI {
3227 const gaugeCommand = this . getCommand ( GaugeCommands . Gauge ) ;
3328 const mvnCommand = this . getCommand ( MAVEN_COMMAND ) ;
34- let gradleCommand = this . getGradleCommand ( ) ;
35- if ( ! gaugeCommand || gaugeCommand === '' ) return new CLI ( gaugeCommand , { } , mvnCommand , gradleCommand ) ;
36- let options = this . getDefaultSpawnOptions ( ) ;
37- let gv = spawnSync ( gaugeCommand , [ GaugeCommands . Version , GaugeCommands . MachineReadable ] , options ) ;
29+ const gradleCommand = this . getGradleCommand ( ) ;
30+ if ( ! gaugeCommand ) return new CLI ( undefined , { } , mvnCommand , gradleCommand ) ;
31+ let gv = gaugeCommand . spawnSync ( [ GaugeCommands . Version , GaugeCommands . MachineReadable ] ) ;
3832 let gaugeVersionInfo ;
3933 try {
4034 gaugeVersionInfo = JSON . parse ( gv . stdout . toString ( ) ) ;
@@ -49,12 +43,12 @@ export class CLI {
4943 return this . _gaugePlugins . some ( ( p : any ) => p . name === pluginName ) ;
5044 }
5145
52- public gaugeCommand ( ) : string {
46+ public gaugeCommand ( ) : Command {
5347 return this . _gaugeCommand ;
5448 }
5549
5650 public isGaugeInstalled ( ) : boolean {
57- return ! ! this . _gaugeCommand && this . _gaugeCommand !== '' ;
51+ return ! ! this . _gaugeCommand ;
5852 }
5953
6054 public isGaugeVersionGreaterOrEqual ( version : string ) : boolean {
@@ -65,31 +59,21 @@ export class CLI {
6559 return this . _gaugePlugins . find ( ( p ) => p . name === language ) . version ;
6660 }
6761
68- public getGaugeVersion ( ) : string {
69- return this . _gaugeVersion ;
70- }
71-
7262 public async installGaugeRunner ( language : string ) : Promise < any > {
7363 let oc = window . createOutputChannel ( "Gauge Install" ) ;
7464 let chan = new OutputChannel ( oc , `Installing gauge ${ language } plugin ...\n` , "" ) ;
7565 return new Promise ( ( resolve , reject ) => {
76- let options = CLI . getDefaultSpawnOptions ( ) ;
77- let childProcess = spawn ( this . _gaugeCommand , [ GaugeCommands . Install , language ] , options ) ;
66+ let childProcess = this . _gaugeCommand . spawn ( [ GaugeCommands . Install , language ] ) ;
7867 childProcess . stdout . on ( 'data' , ( chunk ) => chan . appendOutBuf ( chunk . toString ( ) ) ) ;
7968 childProcess . stderr . on ( 'data' , ( chunk ) => chan . appendErrBuf ( chunk . toString ( ) ) ) ;
8069 childProcess . on ( 'exit' , ( code ) => {
81- let postFailureMessage = '\nRefer https://docs.gauge.org/plugin.html' +
82- ' to install manually' ;
70+ let postFailureMessage = '\nRefer to https://docs.gauge.org/plugin.html to install manually' ;
8371 chan . onFinish ( resolve , code , "" , postFailureMessage , false ) ;
8472 } ) ;
8573 } ) ;
8674 }
8775
88- public isMavenInstalled ( ) : boolean {
89- return ! ! this . _mvnCommand && this . _mvnCommand !== '' ;
90- }
91-
92- public mavenCommand ( ) : string {
76+ public mavenCommand ( ) : Command {
9377 return this . _mvnCommand ;
9478 }
9579
@@ -107,23 +91,55 @@ export class CLI {
10791 return `${ v } \n${ cm } \n\n${ plugins } ` ;
10892 }
10993
110- public static getCommandCandidates ( command : string ) : string [ ] {
111- return ( platform ( ) === 'win32' ? [ ".exe" , ".bat" , ".cmd" ] : [ "" ] )
112- . map ( ( ext ) => `${ command } ${ ext } ` ) ;
94+ public static getCommandCandidates ( command : string ) : Command [ ] {
95+ return platform ( ) === 'win32' ? [
96+ new Command ( command , ".exe" ) ,
97+ new Command ( command , ".bat" , true ) ,
98+ new Command ( command , ".cmd" , true ) ,
99+ ] : [
100+ new Command ( command )
101+ ]
113102 }
114103
115- public static checkSpawnable ( command : string ) : boolean {
116- const result = spawnSync ( command , [ ] , CLI . getDefaultSpawnOptions ( ) ) ;
104+ public static isSpawnable ( command : Command ) : boolean {
105+ const result = command . spawnSync ( ) ;
117106 return result . status === 0 && ! result . error ;
118107 }
119108
120- private static getCommand ( command : string ) : string {
109+ private static getCommand ( command : string ) : Command | undefined {
121110 for ( const candidate of this . getCommandCandidates ( command ) ) {
122- if ( this . checkSpawnable ( candidate ) ) return candidate ;
111+ if ( this . isSpawnable ( candidate ) ) return candidate ;
123112 }
124113 }
125114
126115 private static getGradleCommand ( ) {
127- return platform ( ) === 'win32' ? `${ GRADLE_COMMAND } .bat` : `./${ GRADLE_COMMAND } ` ;
116+ return platform ( ) === 'win32' ? new Command ( GRADLE_COMMAND , ".bat" , true ) : new Command ( `./${ GRADLE_COMMAND } ` ) ;
117+ }
118+ }
119+
120+ export type PlatformDependentSpawnOptions = {
121+ shell ?: boolean
122+ }
123+
124+ export class Command {
125+ public readonly command : string
126+ public readonly defaultSpawnOptions : PlatformDependentSpawnOptions
127+
128+ constructor ( public readonly cmdPrefix : string , public readonly cmdSuffix : string = "" , public readonly shellMode : boolean = false ) {
129+ this . command = this . cmdPrefix + this . cmdSuffix ;
130+ this . defaultSpawnOptions = this . shellMode ? { shell : true } : { } ;
131+ }
132+
133+ spawn ( args : string [ ] = [ ] , options : CommonSpawnOptions = { } ) : ChildProcess {
134+ return spawn ( this . command , this . argsForSpawnType ( args ) , { ...options , ...this . defaultSpawnOptions } ) ;
135+ }
136+
137+ spawnSync ( args : string [ ] = [ ] , options : CommonSpawnOptions = { } ) : SpawnSyncReturns < Buffer > {
138+ return spawnSync ( this . command , this . argsForSpawnType ( args ) , { ...options , ...this . defaultSpawnOptions } ) ;
139+ }
140+
141+ // See https://github.com/nodejs/node/issues/38490
142+ argsForSpawnType ( args : string [ ] ) : string [ ] {
143+ return this . shellMode ? args . map ( arg => arg . indexOf ( " " ) !== - 1 ? `"${ arg } "` : arg ) : args ;
128144 }
129145}
0 commit comments