1
1
import fs = require( "fs" ) ;
2
2
import path = require( "path" ) ;
3
+ import { R_OK } from "constants" ;
3
4
import * as url from "url" ;
4
- import { execSync } from "child_process" ;
5
+ import { exec } from "child_process" ;
5
6
import * as vscode from "vscode" ;
6
7
import { config , schemas , workspaceState , terminals } from "../extension" ;
7
8
@@ -222,7 +223,7 @@ export function notNull(el: any): boolean {
222
223
return el !== null ;
223
224
}
224
225
225
- export function portFromDockerCompose ( ) : { port : number ; docker : boolean } {
226
+ export async function portFromDockerCompose ( ) : Promise < { port : number ; docker : boolean } > {
226
227
const { "docker-compose" : dockerCompose = { } } = config ( "conn" ) ;
227
228
const { service, file = "docker-compose.yml" , internalPort = 52773 , envFile } = dockerCompose ;
228
229
if ( ! internalPort || ! file || ! service || service === "" ) {
@@ -232,36 +233,50 @@ export function portFromDockerCompose(): { port: number; docker: boolean } {
232
233
const workspaceFolderPath = workspaceFolderUri ( ) . fsPath ;
233
234
const workspaceRootPath = vscode . workspace . workspaceFolders [ 0 ] . uri . fsPath ;
234
235
235
- const cwd = fs . existsSync ( path . join ( workspaceFolderPath , file ) )
236
- ? workspaceFolderPath
237
- : fs . existsSync ( path . join ( workspaceRootPath , file ) )
238
- ? workspaceRootPath
239
- : null ;
236
+ const cwd : string = await new Promise ( ( resolve , reject ) => {
237
+ fs . access ( path . join ( workspaceFolderPath , file ) , R_OK , ( error ) => {
238
+ if ( error ) {
239
+ fs . access ( path . join ( workspaceRootPath , file ) , R_OK , ( error ) => {
240
+ if ( error ) {
241
+ reject ( new Error ( `File '${ file } ' not found.` ) ) ;
242
+ } else {
243
+ resolve ( workspaceRootPath ) ;
244
+ }
245
+ } ) ;
246
+ } else {
247
+ resolve ( workspaceFolderPath ) ;
248
+ }
249
+ } ) ;
250
+ } ) ;
240
251
241
252
if ( ! cwd ) {
242
253
return result ;
243
254
}
244
255
245
256
const envFileParam = envFile ? `--env-file ${ envFile } ` : "" ;
246
- const cmd = `docker-compose -f ${ file } ${ envFileParam } port --protocol=tcp ${ service } ${ internalPort } ` ;
257
+ const cmd = `docker-compose -f ${ file } ${ envFileParam } ` ;
247
258
248
- try {
249
- const serviceLine = execSync ( cmd , {
250
- cwd,
251
- } )
252
- . toString ( )
253
- . replace ( "/r" , "" )
254
- . split ( "/n" )
255
- . pop ( ) ;
256
- const servicePortMatch = serviceLine . match ( new RegExp ( `:(\\d+)` ) ) ;
257
- if ( servicePortMatch ) {
258
- const [ , newPort ] = servicePortMatch ;
259
- return { port : parseInt ( newPort , 10 ) , docker : true } ;
260
- }
261
- } catch ( e ) {
262
- // nope
263
- }
264
- return result ;
259
+ return new Promise ( ( resolve , reject ) => {
260
+ exec ( `${ cmd } ps --services --filter 'status=running'` , { cwd } , ( error , stdout ) => {
261
+ if ( error ) {
262
+ reject ( error . message ) ;
263
+ }
264
+ if ( ! stdout . replace ( "\r" , "" ) . split ( "\n" ) . includes ( service ) ) {
265
+ reject ( `Service '${ service } ' not found in '${ file } ', or not running.` ) ;
266
+ }
267
+
268
+ exec ( `${ cmd } port --protocol=tcp ${ service } ${ internalPort } ` , { cwd } , ( error , stdout ) => {
269
+ if ( error ) {
270
+ reject ( error . message ) ;
271
+ }
272
+ const [ , port ] = stdout . match ( / : ( \d + ) / ) || [ ] ;
273
+ if ( ! port ) {
274
+ reject ( `Port ${ internalPort } not published for service '${ service } '.` ) ;
275
+ }
276
+ resolve ( { port : parseInt ( port , 10 ) , docker : true } ) ;
277
+ } ) ;
278
+ } ) ;
279
+ } ) ;
265
280
}
266
281
267
282
export async function terminalWithDocker ( ) : Promise < vscode . Terminal > {
0 commit comments