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- }
15+ export function getComposeClient ( environment : NodeJS . ProcessEnv ) : ComposeClient {
16+ return new LazyComposeClient ( environment ) ;
2617}
2718
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 ) {
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 ) { }
23+
24+ async getInfo ( ) : Promise < ComposeInfo | undefined > {
25+ if ( this . info !== undefined ) {
26+ return this . info ;
27+ }
28+
3529 try {
36- return {
37- version : ( await dockerComposeV1 . version ( ) ) . data . version ,
38- compatability : "v1 " ,
30+ this . info = {
31+ version : ( await v2 . version ( ) ) . data . version ,
32+ compatibility : "v2 " ,
3933 } ;
40- } catch {
41- return undefined ;
34+ } catch ( err ) {
35+ try {
36+ this . info = {
37+ version : ( await v1 . version ( ) ) . data . version ,
38+ compatibility : "v1" ,
39+ } ;
40+ } catch {
41+ return undefined ;
42+ }
4243 }
44+
45+ return this . info ;
4346 }
44- }
4547
46- class ComposeV1Client implements ComposeClient {
47- constructor (
48- public readonly info : ComposeInfo ,
49- private readonly environment : NodeJS . ProcessEnv
50- ) { }
48+ private async getClient ( ) : Promise < typeof v1 | typeof v2 > {
49+ if ( this . client !== undefined ) {
50+ return this . client ;
51+ }
5152
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- } ) ;
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 ;
7163 }
7264 }
7365
74- async pull ( options : ComposeOptions , services : Array < string > | undefined ) : Promise < void > {
66+ async up ( options : ComposeOptions , services : Array < string > | undefined ) : Promise < void > {
67+ const client = await this . getClient ( ) ;
68+
7569 try {
7670 if ( services ) {
7771 log . info ( `Pulling Compose environment images "${ services . join ( '", "' ) } "...` ) ;
78- await v1 . pullMany ( services , await defaultComposeOptions ( this . environment , { ...options , logger : pullLog } ) ) ;
72+ await client . pullMany ( services , await defaultComposeOptions ( this . environment , { ...options , logger : pullLog } ) ) ;
7973 } else {
8074 log . info ( `Pulling Compose environment images...` ) ;
81- await v1 . pullAll ( await defaultComposeOptions ( this . environment , { ...options , logger : pullLog } ) ) ;
75+ await client . pullAll ( await defaultComposeOptions ( this . environment , { ...options , logger : pullLog } ) ) ;
8276 }
8377 log . info ( `Pulled Compose environment` ) ;
8478 } catch ( err ) {
@@ -88,70 +82,16 @@ class ComposeV1Client implements ComposeClient {
8882 }
8983 }
9084
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- ) ;
100- }
101- }
102-
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- ) ;
115- }
116- }
117- }
118-
119- class ComposeV2Client implements ComposeClient {
120- constructor (
121- public readonly info : ComposeInfo ,
122- private readonly environment : NodeJS . ProcessEnv
123- ) { }
124-
125- async up ( options : ComposeOptions , services : Array < string > | undefined ) : Promise < void > {
126- try {
127- if ( services ) {
128- log . info ( `Upping Compose environment services ${ services . join ( ", " ) } ...` ) ;
129- await v2 . upMany ( services , await defaultComposeOptions ( this . environment , options ) ) ;
130- } else {
131- log . info ( `Upping Compose environment...` ) ;
132- await v2 . upAll ( await defaultComposeOptions ( this . environment , options ) ) ;
133- }
134- log . info ( `Upped Compose environment` ) ;
135- } catch ( err ) {
136- await handleAndRethrow ( err , async ( error : Error ) => {
137- try {
138- log . error ( `Failed to up Compose environment: ${ error . message } ` ) ;
139- await this . down ( options , { removeVolumes : true , timeout : 0 } ) ;
140- } catch {
141- log . error ( `Failed to down Compose environment after failed up` ) ;
142- }
143- } ) ;
144- }
145- }
146-
14785 async pull ( options : ComposeOptions , services : Array < string > | undefined ) : Promise < void > {
86+ const client = await this . getClient ( ) ;
87+
14888 try {
14989 if ( services ) {
15090 log . info ( `Pulling Compose environment images "${ services . join ( '", "' ) } "...` ) ;
151- await v2 . pullMany ( services , await defaultComposeOptions ( this . environment , { ...options , logger : pullLog } ) ) ;
91+ await client . pullMany ( services , await defaultComposeOptions ( this . environment , { ...options , logger : pullLog } ) ) ;
15292 } else {
15393 log . info ( `Pulling Compose environment images...` ) ;
154- await v2 . pullAll ( await defaultComposeOptions ( this . environment , { ...options , logger : pullLog } ) ) ;
94+ await client . pullAll ( await defaultComposeOptions ( this . environment , { ...options , logger : pullLog } ) ) ;
15595 }
15696 log . info ( `Pulled Compose environment` ) ;
15797 } catch ( err ) {
@@ -162,9 +102,11 @@ class ComposeV2Client implements ComposeClient {
162102 }
163103
164104 async stop ( options : ComposeOptions ) : Promise < void > {
105+ const client = await this . getClient ( ) ;
106+
165107 try {
166108 log . info ( `Stopping Compose environment...` ) ;
167- await v2 . stop ( await defaultComposeOptions ( this . environment , options ) ) ;
109+ await client . stop ( await defaultComposeOptions ( this . environment , options ) ) ;
168110 log . info ( `Stopped Compose environment` ) ;
169111 } catch ( err ) {
170112 await handleAndRethrow ( err , async ( error : Error ) =>
@@ -174,9 +116,10 @@ class ComposeV2Client implements ComposeClient {
174116 }
175117
176118 async down ( options : ComposeOptions , downOptions : ComposeDownOptions ) : Promise < void > {
119+ const client = await this . getClient ( ) ;
177120 try {
178121 log . info ( `Downing Compose environment...` ) ;
179- await v2 . down ( {
122+ await client . down ( {
180123 ...( await defaultComposeOptions ( this . environment , options ) ) ,
181124 commandOptions : composeDownCommandOptions ( downOptions ) ,
182125 } ) ;
@@ -189,26 +132,6 @@ class ComposeV2Client implements ComposeClient {
189132 }
190133}
191134
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-
212135// eslint-disable-next-line @typescript-eslint/no-explicit-any
213136async function handleAndRethrow ( err : any , handle : ( error : Error ) => Promise < void > ) : Promise < never > {
214137 const error = err instanceof Error ? err : new Error ( err . err . trim ( ) ) ;
0 commit comments