@@ -88,35 +88,13 @@ export class ConnectionManager implements IConnectionManager {
8888 this . setConnectionStatus ( "Starting Puppet..." , ConnectionStatus . Starting ) ;
8989
9090 if ( this . connectionConfiguration . type == ConnectionType . Local ) {
91- this . languageServerProcess = this . createLanguageServerProcess ( contextPath ) ;
92- if ( this . languageServerProcess == undefined ) {
93- if ( this . connectionStatus == ConnectionStatus . Failed ) {
94- // We've already handled this state. Just return
95- return
96- }
97- throw new Error ( 'Unable to start the Language Server Process' ) ;
98- }
99-
100- this . languageServerProcess . stdout . on ( 'data' , ( data ) => {
101- this . logger . debug ( "OUTPUT: " + data . toString ( ) ) ;
102-
103- // If the language client isn't already running and it's sent the trigger text, start up a client
104- if ( ( this . languageServerClient == undefined ) && ( data . toString ( ) . match ( "LANGUAGE SERVER RUNNING" ) != null ) ) {
105- this . languageServerClient = this . startLangClientTCP ( ) ;
106- this . extensionContext . subscriptions . push ( this . languageServerClient . start ( ) ) ;
107- }
108- } ) ;
109-
110- this . languageServerProcess . on ( 'close' , ( exitCode ) => {
111- this . logger . debug ( "SERVER terminated with exit code: " + exitCode ) ;
112- } ) ;
91+ this . createLanguageServerProcess ( contextPath , this . onLanguageServerStart . bind ( this ) ) ;
11392 }
11493 else {
11594 this . languageServerClient = this . startLangClientTCP ( ) ;
11695 this . extensionContext . subscriptions . push ( this . languageServerClient . start ( ) ) ;
96+ this . logStart ( ) ;
11797 }
118-
119- this . logger . debug ( 'Congratulations, your extension "vscode-puppet" is now active!' ) ;
12098 }
12199
122100 public stop ( ) {
@@ -159,12 +137,64 @@ export class ConnectionManager implements IConnectionManager {
159137 this . extensionContext . subscriptions . clear ( ) ;
160138 }
161139
162- private createLanguageServerProcess ( serverExe : string ) {
140+ private logStart ( ) {
141+ this . logger . debug ( 'Congratulations, your extension "vscode-puppet" is now active!' ) ;
142+ }
143+
144+ private onLanguageServerStart ( proc : cp . ChildProcess ) {
145+ this . logger . debug ( 'LanguageServer Process Started: ' + proc )
146+ this . languageServerProcess = proc
147+ if ( this . languageServerProcess == undefined ) {
148+ if ( this . connectionStatus == ConnectionStatus . Failed ) {
149+ // We've already handled this state. Just return
150+ return
151+ }
152+ throw new Error ( 'Unable to start the Language Server Process' ) ;
153+ }
154+
155+ this . languageServerProcess . stdout . on ( 'data' , ( data ) => {
156+ this . logger . debug ( "OUTPUT: " + data . toString ( ) ) ;
157+
158+ // If the language client isn't already running and it's sent the trigger text, start up a client
159+ if ( ( this . languageServerClient == undefined ) && ( data . toString ( ) . match ( "LANGUAGE SERVER RUNNING" ) != null ) ) {
160+ this . languageServerClient = this . startLangClientTCP ( ) ;
161+ this . extensionContext . subscriptions . push ( this . languageServerClient . start ( ) ) ;
162+ }
163+ } ) ;
164+
165+ this . languageServerProcess . on ( 'close' , ( exitCode ) => {
166+ this . logger . debug ( "SERVER terminated with exit code: " + exitCode ) ;
167+ } ) ;
168+
169+ this . logStart ( ) ;
170+ }
171+
172+ public startLanguageServerProcess ( cmd : string , args : Array < string > , options : cp . SpawnOptions , callback : Function ) {
173+ if ( ( this . connectionConfiguration . host == undefined ) || ( this . connectionConfiguration . host == '' ) ) {
174+ args . push ( '--ip=127.0.0.1' ) ;
175+ } else {
176+ args . push ( '--ip=' + this . connectionConfiguration . host ) ;
177+ }
178+ args . push ( '--port=' + this . connectionConfiguration . port ) ;
179+ args . push ( '--timeout=' + this . connectionConfiguration . timeout ) ;
180+ if ( this . connectionConfiguration . preLoadPuppet == false ) { args . push ( '--no-preload' ) ; }
181+ if ( ( this . connectionConfiguration . debugFilePath != undefined ) && ( this . connectionConfiguration . debugFilePath != '' ) ) {
182+ args . push ( '--debug=' + this . connectionConfiguration . debugFilePath ) ;
183+ }
184+
185+ this . logger . debug ( "Starting the language server with " + cmd + " " + args . join ( " " ) ) ;
186+ var proc = cp . spawn ( cmd , args , options )
187+ this . logger . debug ( 'Language server PID:' + proc . pid )
188+
189+ callback ( proc ) ;
190+ }
191+
192+ private createLanguageServerProcess ( serverExe : string , callback : Function ) {
163193 this . logger . debug ( 'Language server found at: ' + serverExe )
164194
165195 let cmd : string = undefined ;
166196 let args = [ serverExe ] ;
167- let options = { } ;
197+ let options : cp . SpawnOptions = { } ;
168198
169199 // type Platform = 'aix'
170200 // | 'android'
@@ -204,7 +234,7 @@ export class ConnectionManager implements IConnectionManager {
204234 this . logger . debug ( 'Starting language server' )
205235
206236 // Try and find the puppet-agent ruby
207- let rubyPath : string = '/opt/puppetlabs/puppet/bin/ruby' ;
237+ let rubyPath : string = '/opt/puppetlabs/puppet/bin/ruby' ;
208238 if ( fs . existsSync ( rubyPath ) ) { cmd = rubyPath }
209239
210240 // Default to ruby on the path
@@ -222,30 +252,30 @@ export class ConnectionManager implements IConnectionManager {
222252 return ;
223253 }
224254
225- if ( ( this . connectionConfiguration . host == undefined ) || ( this . connectionConfiguration . host == '' ) ) {
226- args . push ( '--ip=127.0.0.1' ) ;
227- args . push ( '--local-workspace=' + vscode . workspace . textDocuments [ 0 ] ) ;
228- } else {
229- args . push ( '--ip=' + this . connectionConfiguration . host ) ;
230- }
231- args . push ( '--port=' + this . connectionConfiguration . port ) ;
232- args . push ( '--timeout=' + this . connectionConfiguration . timeout ) ;
233- if ( this . connectionConfiguration . preLoadPuppet == false ) { args . push ( '--no-preload' ) ; }
234- if ( ( this . connectionConfiguration . debugFilePath != undefined ) && ( this . connectionConfiguration . debugFilePath != '' ) ) {
235- args . push ( '--debug=' + this . connectionConfiguration . debugFilePath ) ;
236- }
237-
238- this . logger . debug ( "Starting the language server with " + cmd + " " + args . join ( " " ) ) ;
239- var proc = cp . spawn ( cmd , args , options )
240- this . logger . debug ( 'Language server PID:' + proc . pid )
255+ let connMgr : ConnectionManager = this ;
256+ let logger = this . logger ;
257+ // Start a server to get a random port
258+ this . logger . debug ( 'Creating server process to identify random port' )
259+ const server = net . createServer ( )
260+ . on ( 'close' , ( ) => {
261+ logger . debug ( 'Server process to identify random port disconnected' ) ;
262+ connMgr . startLanguageServerProcess ( cmd , args , options , callback ) ;
263+ } )
264+ . on ( 'error' , ( err ) => {
265+ throw err ;
266+ } ) ;
241267
242- return proc ;
268+ // Listen on random port
269+ server . listen ( 0 ) ;
270+ this . logger . debug ( 'Selected port for local language server: ' + server . address ( ) . port ) ;
271+ connMgr . connectionConfiguration . port = server . address ( ) . port ;
272+ server . close ( ) ;
243273 }
244274
245275 private startLangClientTCP ( ) : LanguageClient {
246276 this . logger . debug ( 'Configuring language server options' )
247277
248- var connMgr :ConnectionManager = this ;
278+ let connMgr :ConnectionManager = this ;
249279 let serverOptions : ServerOptions = function ( ) {
250280 return new Promise ( ( resolve , reject ) => {
251281 var client = new net . Socket ( ) ;
0 commit comments