19
19
import java .io .File ;
20
20
import java .util .ArrayList ;
21
21
import java .util .Collections ;
22
+ import java .util .HashMap ;
22
23
import java .util .List ;
24
+ import java .util .Map ;
23
25
import java .util .Set ;
24
26
import java .util .function .Consumer ;
25
27
39
41
*/
40
42
class DockerCli {
41
43
44
+ private static final Map <File , DockerCommands > dockerCommandsCache = new HashMap <>();
45
+
42
46
private static final Log logger = LogFactory .getLog (DockerCli .class );
43
47
44
48
private final ProcessRunner processRunner ;
45
49
46
- private final List <String > dockerCommand ;
47
-
48
- private final List <String > dockerComposeCommand ;
50
+ private final DockerCommands dockerCommands ;
49
51
50
52
private final DockerComposeFile composeFile ;
51
53
@@ -59,56 +61,12 @@ class DockerCli {
59
61
*/
60
62
DockerCli (File workingDirectory , DockerComposeFile composeFile , Set <String > activeProfiles ) {
61
63
this .processRunner = new ProcessRunner (workingDirectory );
62
- this .dockerCommand = getDockerCommand ( this . processRunner );
63
- this . dockerComposeCommand = getDockerComposeCommand (this .processRunner );
64
+ this .dockerCommands = dockerCommandsCache . computeIfAbsent ( workingDirectory ,
65
+ ( key ) -> new DockerCommands (this .processRunner ) );
64
66
this .composeFile = composeFile ;
65
67
this .activeProfiles = (activeProfiles != null ) ? activeProfiles : Collections .emptySet ();
66
68
}
67
69
68
- private List <String > getDockerCommand (ProcessRunner processRunner ) {
69
- try {
70
- String version = processRunner .run ("docker" , "version" , "--format" , "{{.Client.Version}}" );
71
- logger .trace (LogMessage .format ("Using docker %s" , version ));
72
- return List .of ("docker" );
73
- }
74
- catch (ProcessStartException ex ) {
75
- throw new DockerProcessStartException ("Unable to start docker process. Is docker correctly installed?" , ex );
76
- }
77
- catch (ProcessExitException ex ) {
78
- if (ex .getStdErr ().contains ("docker daemon is not running" )
79
- || ex .getStdErr ().contains ("Cannot connect to the Docker daemon" )) {
80
- throw new DockerNotRunningException (ex .getStdErr (), ex );
81
- }
82
- throw ex ;
83
-
84
- }
85
- }
86
-
87
- private List <String > getDockerComposeCommand (ProcessRunner processRunner ) {
88
- try {
89
- DockerCliComposeVersionResponse response = DockerJson .deserialize (
90
- processRunner .run ("docker" , "compose" , "version" , "--format" , "json" ),
91
- DockerCliComposeVersionResponse .class );
92
- logger .trace (LogMessage .format ("Using docker compose %s" , response .version ()));
93
- return List .of ("docker" , "compose" );
94
- }
95
- catch (ProcessExitException ex ) {
96
- // Ignore and try docker-compose
97
- }
98
- try {
99
- DockerCliComposeVersionResponse response = DockerJson .deserialize (
100
- processRunner .run ("docker-compose" , "version" , "--format" , "json" ),
101
- DockerCliComposeVersionResponse .class );
102
- logger .trace (LogMessage .format ("Using docker-compose %s" , response .version ()));
103
- return List .of ("docker-compose" );
104
- }
105
- catch (ProcessStartException ex ) {
106
- throw new DockerProcessStartException (
107
- "Unable to start 'docker-compose' process or use 'docker compose'. Is docker correctly installed?" ,
108
- ex );
109
- }
110
- }
111
-
112
70
/**
113
71
* Run the given {@link DockerCli} command and return the response.
114
72
* @param <R> the response type
@@ -132,9 +90,9 @@ private Consumer<String> createOutputConsumer(LogLevel logLevel) {
132
90
133
91
private List <String > createCommand (Type type ) {
134
92
return switch (type ) {
135
- case DOCKER -> new ArrayList <>(this .dockerCommand );
93
+ case DOCKER -> new ArrayList <>(this .dockerCommands . get ( type ) );
136
94
case DOCKER_COMPOSE -> {
137
- List <String > result = new ArrayList <>(this .dockerComposeCommand );
95
+ List <String > result = new ArrayList <>(this .dockerCommands . get ( type ) );
138
96
if (this .composeFile != null ) {
139
97
result .add ("--file" );
140
98
result .add (this .composeFile .toString ());
@@ -158,4 +116,71 @@ DockerComposeFile getDockerComposeFile() {
158
116
return this .composeFile ;
159
117
}
160
118
119
+ /**
120
+ * Holds details of the actual CLI commands to invoke.
121
+ */
122
+ private static class DockerCommands {
123
+
124
+ private final List <String > dockerCommand ;
125
+
126
+ private final List <String > dockerComposeCommand ;
127
+
128
+ DockerCommands (ProcessRunner processRunner ) {
129
+ this .dockerCommand = getDockerCommand (processRunner );
130
+ this .dockerComposeCommand = getDockerComposeCommand (processRunner );
131
+ }
132
+
133
+ private List <String > getDockerCommand (ProcessRunner processRunner ) {
134
+ try {
135
+ String version = processRunner .run ("docker" , "version" , "--format" , "{{.Client.Version}}" );
136
+ logger .trace (LogMessage .format ("Using docker %s" , version ));
137
+ return List .of ("docker" );
138
+ }
139
+ catch (ProcessStartException ex ) {
140
+ throw new DockerProcessStartException ("Unable to start docker process. Is docker correctly installed?" ,
141
+ ex );
142
+ }
143
+ catch (ProcessExitException ex ) {
144
+ if (ex .getStdErr ().contains ("docker daemon is not running" )
145
+ || ex .getStdErr ().contains ("Cannot connect to the Docker daemon" )) {
146
+ throw new DockerNotRunningException (ex .getStdErr (), ex );
147
+ }
148
+ throw ex ;
149
+ }
150
+ }
151
+
152
+ private List <String > getDockerComposeCommand (ProcessRunner processRunner ) {
153
+ try {
154
+ DockerCliComposeVersionResponse response = DockerJson .deserialize (
155
+ processRunner .run ("docker" , "compose" , "version" , "--format" , "json" ),
156
+ DockerCliComposeVersionResponse .class );
157
+ logger .trace (LogMessage .format ("Using docker compose %s" , response .version ()));
158
+ return List .of ("docker" , "compose" );
159
+ }
160
+ catch (ProcessExitException ex ) {
161
+ // Ignore and try docker-compose
162
+ }
163
+ try {
164
+ DockerCliComposeVersionResponse response = DockerJson .deserialize (
165
+ processRunner .run ("docker-compose" , "version" , "--format" , "json" ),
166
+ DockerCliComposeVersionResponse .class );
167
+ logger .trace (LogMessage .format ("Using docker-compose %s" , response .version ()));
168
+ return List .of ("docker-compose" );
169
+ }
170
+ catch (ProcessStartException ex ) {
171
+ throw new DockerProcessStartException (
172
+ "Unable to start 'docker-compose' process or use 'docker compose'. Is docker correctly installed?" ,
173
+ ex );
174
+ }
175
+ }
176
+
177
+ List <String > get (Type type ) {
178
+ return switch (type ) {
179
+ case DOCKER -> this .dockerCommand ;
180
+ case DOCKER_COMPOSE -> this .dockerComposeCommand ;
181
+ };
182
+ }
183
+
184
+ }
185
+
161
186
}
0 commit comments