1- import { default as dockerComposeV1 , default as v1 , v2 as dockerComposeV2 , v2 } from "docker-compose" ;
1+ import { default as v1 , v2 } from "docker-compose" ;
22import { log , pullLog } from "../../../common" ;
33import { ComposeInfo } from "../types" ;
44import { defaultComposeOptions } from "./default-compose-options" ;
55import { ComposeDownOptions , ComposeOptions } from "./types" ;
66
77export interface ComposeClient {
8- info : ComposeInfo ;
8+ getInfo ( ) : Promise < ComposeInfo > ;
99 up ( options : ComposeOptions , services ?: Array < string > ) : Promise < void > ;
1010 pull ( options : ComposeOptions , services ?: Array < string > ) : Promise < void > ;
1111 stop ( options : ComposeOptions ) : Promise < void > ;
1212 down ( options : ComposeOptions , downOptions : ComposeDownOptions ) : Promise < void > ;
1313}
1414
15- export async function getComposeClient ( environment : NodeJS . ProcessEnv ) : Promise < ComposeClient > {
16- const info = await getComposeInfo ( ) ;
17-
18- switch ( info ?. compatability ) {
19- case undefined :
20- return new MissingComposeClient ( ) ;
21- case "v1" :
22- return new ComposeV1Client ( info , environment ) ;
23- case "v2" :
24- return new ComposeV2Client ( info , environment ) ;
25- }
26- }
27-
28- async function getComposeInfo ( ) : Promise < ComposeInfo | undefined > {
29- try {
30- return {
31- version : ( await dockerComposeV2 . version ( ) ) . data . version ,
32- compatability : "v2" ,
33- } ;
34- } catch ( err ) {
35- try {
36- return {
37- version : ( await dockerComposeV1 . version ( ) ) . data . version ,
38- compatability : "v1" ,
39- } ;
40- } catch {
41- return undefined ;
42- }
43- }
15+ export function getComposeClient ( environment : NodeJS . ProcessEnv ) : ComposeClient {
16+ return new LazyComposeClient ( environment ) ;
4417}
4518
46- class ComposeV1Client implements ComposeClient {
47- constructor (
48- public readonly info : ComposeInfo ,
49- private readonly environment : NodeJS . ProcessEnv
50- ) { }
19+ class LazyComposeClient implements ComposeClient {
20+ private info : ComposeInfo | undefined = undefined ;
21+ private client : typeof v1 | typeof v2 | undefined = undefined ;
22+ constructor ( private readonly environment : NodeJS . ProcessEnv ) { }
5123
52- async up ( options : ComposeOptions , services : Array < string > | undefined ) : Promise < void > {
53- try {
54- if ( services ) {
55- log . info ( `Upping Compose environment services ${ services . join ( ", " ) } ...` ) ;
56- await v1 . upMany ( services , await defaultComposeOptions ( this . environment , options ) ) ;
57- } else {
58- log . info ( `Upping Compose environment...` ) ;
59- await v1 . upAll ( await defaultComposeOptions ( this . environment , options ) ) ;
60- }
61- log . info ( `Upped Compose environment` ) ;
62- } catch ( err ) {
63- await handleAndRethrow ( err , async ( error : Error ) => {
64- try {
65- log . error ( `Failed to up Compose environment: ${ error . message } ` ) ;
66- await this . down ( options , { removeVolumes : true , timeout : 0 } ) ;
67- } catch {
68- log . error ( `Failed to down Compose environment after failed up` ) ;
69- }
70- } ) ;
24+ async getInfo ( ) : Promise < ComposeInfo | undefined > {
25+ if ( this . info !== undefined ) {
26+ return this . info ;
7127 }
72- }
7328
74- async pull ( options : ComposeOptions , services : Array < string > | undefined ) : Promise < void > {
7529 try {
76- if ( services ) {
77- log . info ( `Pulling Compose environment images "${ services . join ( '", "' ) } "...` ) ;
78- await v1 . pullMany ( services , await defaultComposeOptions ( this . environment , { ...options , logger : pullLog } ) ) ;
79- } else {
80- log . info ( `Pulling Compose environment images...` ) ;
81- await v1 . pullAll ( await defaultComposeOptions ( this . environment , { ...options , logger : pullLog } ) ) ;
82- }
83- log . info ( `Pulled Compose environment` ) ;
30+ this . info = {
31+ version : ( await v2 . version ( ) ) . data . version ,
32+ compatibility : "v2" ,
33+ } ;
8434 } catch ( err ) {
85- await handleAndRethrow ( err , async ( error : Error ) =>
86- log . error ( `Failed to pull Compose environment images: ${ error . message } ` )
87- ) ;
35+ try {
36+ this . info = {
37+ version : ( await v1 . version ( ) ) . data . version ,
38+ compatibility : "v1" ,
39+ } ;
40+ } catch {
41+ return undefined ;
42+ }
8843 }
44+
45+ return this . info ;
8946 }
9047
91- async stop ( options : ComposeOptions ) : Promise < void > {
92- try {
93- log . info ( `Stopping Compose environment...` ) ;
94- await v1 . stop ( await defaultComposeOptions ( this . environment , options ) ) ;
95- log . info ( `Stopped Compose environment` ) ;
96- } catch ( err ) {
97- await handleAndRethrow ( err , async ( error : Error ) =>
98- log . error ( `Failed to stop Compose environment: ${ error . message } ` )
99- ) ;
48+ private async getClient ( ) : Promise < typeof v1 | typeof v2 > {
49+ if ( this . client !== undefined ) {
50+ return this . client ;
10051 }
101- }
10252
103- async down ( options : ComposeOptions , downOptions : ComposeDownOptions ) : Promise < void > {
104- try {
105- log . info ( `Downing Compose environment...` ) ;
106- await v1 . down ( {
107- ...( await defaultComposeOptions ( this . environment , options ) ) ,
108- commandOptions : composeDownCommandOptions ( downOptions ) ,
109- } ) ;
110- log . info ( `Downed Compose environment` ) ;
111- } catch ( err ) {
112- await handleAndRethrow ( err , async ( error : Error ) =>
113- log . error ( `Failed to down Compose environment: ${ error . message } ` )
114- ) ;
53+ const info = await this . getInfo ( ) ;
54+ switch ( info ?. compatibility ) {
55+ case undefined :
56+ throw new Error ( "Compose is not installed" ) ;
57+ case "v1" :
58+ this . client = v1 ;
59+ return v1 ;
60+ case "v2" :
61+ this . client = v2 ;
62+ return v2 ;
11563 }
11664 }
117- }
118-
119- class ComposeV2Client implements ComposeClient {
120- constructor (
121- public readonly info : ComposeInfo ,
122- private readonly environment : NodeJS . ProcessEnv
123- ) { }
12465
12566 async up ( options : ComposeOptions , services : Array < string > | undefined ) : Promise < void > {
67+ const client = await this . getClient ( ) ;
68+
12669 try {
12770 if ( services ) {
12871 log . info ( `Upping Compose environment services ${ services . join ( ", " ) } ...` ) ;
129- await v2 . upMany ( services , await defaultComposeOptions ( this . environment , options ) ) ;
72+ await client . upMany ( services , await defaultComposeOptions ( this . environment , options ) ) ;
13073 } else {
13174 log . info ( `Upping Compose environment...` ) ;
132- await v2 . upAll ( await defaultComposeOptions ( this . environment , options ) ) ;
75+ await client . upAll ( await defaultComposeOptions ( this . environment , options ) ) ;
13376 }
13477 log . info ( `Upped Compose environment` ) ;
13578 } catch ( err ) {
@@ -145,13 +88,15 @@ class ComposeV2Client implements ComposeClient {
14588 }
14689
14790 async pull ( options : ComposeOptions , services : Array < string > | undefined ) : Promise < void > {
91+ const client = await this . getClient ( ) ;
92+
14893 try {
14994 if ( services ) {
15095 log . info ( `Pulling Compose environment images "${ services . join ( '", "' ) } "...` ) ;
151- await v2 . pullMany ( services , await defaultComposeOptions ( this . environment , { ...options , logger : pullLog } ) ) ;
96+ await client . pullMany ( services , await defaultComposeOptions ( this . environment , { ...options , logger : pullLog } ) ) ;
15297 } else {
15398 log . info ( `Pulling Compose environment images...` ) ;
154- await v2 . pullAll ( await defaultComposeOptions ( this . environment , { ...options , logger : pullLog } ) ) ;
99+ await client . pullAll ( await defaultComposeOptions ( this . environment , { ...options , logger : pullLog } ) ) ;
155100 }
156101 log . info ( `Pulled Compose environment` ) ;
157102 } catch ( err ) {
@@ -162,9 +107,11 @@ class ComposeV2Client implements ComposeClient {
162107 }
163108
164109 async stop ( options : ComposeOptions ) : Promise < void > {
110+ const client = await this . getClient ( ) ;
111+
165112 try {
166113 log . info ( `Stopping Compose environment...` ) ;
167- await v2 . stop ( await defaultComposeOptions ( this . environment , options ) ) ;
114+ await client . stop ( await defaultComposeOptions ( this . environment , options ) ) ;
168115 log . info ( `Stopped Compose environment` ) ;
169116 } catch ( err ) {
170117 await handleAndRethrow ( err , async ( error : Error ) =>
@@ -174,9 +121,10 @@ class ComposeV2Client implements ComposeClient {
174121 }
175122
176123 async down ( options : ComposeOptions , downOptions : ComposeDownOptions ) : Promise < void > {
124+ const client = await this . getClient ( ) ;
177125 try {
178126 log . info ( `Downing Compose environment...` ) ;
179- await v2 . down ( {
127+ await client . down ( {
180128 ...( await defaultComposeOptions ( this . environment , options ) ) ,
181129 commandOptions : composeDownCommandOptions ( downOptions ) ,
182130 } ) ;
@@ -189,26 +137,6 @@ class ComposeV2Client implements ComposeClient {
189137 }
190138}
191139
192- class MissingComposeClient implements ComposeClient {
193- public readonly info = undefined ;
194-
195- up ( ) : Promise < void > {
196- throw new Error ( "Compose is not installed" ) ;
197- }
198-
199- pull ( ) : Promise < void > {
200- throw new Error ( "Compose is not installed" ) ;
201- }
202-
203- stop ( ) : Promise < void > {
204- throw new Error ( "Compose is not installed" ) ;
205- }
206-
207- down ( ) : Promise < void > {
208- throw new Error ( "Compose is not installed" ) ;
209- }
210- }
211-
212140// eslint-disable-next-line @typescript-eslint/no-explicit-any
213141async function handleAndRethrow ( err : any , handle : ( error : Error ) => Promise < void > ) : Promise < never > {
214142 const error = err instanceof Error ? err : new Error ( err . err . trim ( ) ) ;
0 commit comments