@@ -105,16 +105,15 @@ public DockerAvailability getDockerAvailability() {
105
105
Result lastResult = null ;
106
106
Version version = null ;
107
107
boolean isVersionHighEnough = false ;
108
- boolean isComposeAvailable = false ;
109
- boolean isComposeV2Available = false ;
108
+ DockerComposeAvailability dockerComposeAvailability = null ;
110
109
111
110
// Check if the Docker binary exists
112
111
final Optional <String > dockerBinary = getDockerPath ();
113
112
if (isExcludedOs () == false && dockerBinary .isPresent ()) {
114
113
dockerPath = dockerBinary .get ();
115
114
116
115
// Since we use a multi-stage Docker build, check the Docker version meets minimum requirement
117
- lastResult = runCommand (dockerPath , "version" , "--format" , "{{.Server.Version}}" );
116
+ lastResult = runCommand (execOperations , dockerPath , "version" , "--format" , "{{.Server.Version}}" );
118
117
119
118
if (lastResult .isSuccess ()) {
120
119
version = Version .fromString (lastResult .stdout .trim (), Version .Mode .RELAXED );
@@ -123,15 +122,11 @@ public DockerAvailability getDockerAvailability() {
123
122
124
123
if (isVersionHighEnough ) {
125
124
// Check that we can execute a privileged command
126
- lastResult = runCommand (dockerPath , "images" );
127
-
125
+ lastResult = runCommand (execOperations , dockerPath , "images" );
128
126
// If docker all checks out, see if docker-compose is available and working
129
- Optional <String > composePath = getDockerComposePath ();
130
- if (lastResult .isSuccess () && composePath .isPresent ()) {
131
- isComposeAvailable = runCommand (composePath .get (), "version" ).isSuccess ();
127
+ if (lastResult .isSuccess ()) {
128
+ dockerComposeAvailability = DockerComposeAvailability .detect (execOperations , dockerPath ).orElse (null );
132
129
}
133
-
134
- isComposeV2Available = runCommand (dockerPath , "compose" , "version" ).isSuccess ();
135
130
}
136
131
}
137
132
}
@@ -140,8 +135,7 @@ public DockerAvailability getDockerAvailability() {
140
135
141
136
this .dockerAvailability = new DockerAvailability (
142
137
isAvailable ,
143
- isComposeAvailable ,
144
- isComposeV2Available ,
138
+ dockerComposeAvailability ,
145
139
isVersionHighEnough ,
146
140
dockerPath ,
147
141
version ,
@@ -291,17 +285,6 @@ private Optional<String> getDockerPath() {
291
285
return Arrays .asList (DOCKER_BINARIES ).stream ().filter (path -> new File (path ).exists ()).findFirst ();
292
286
}
293
287
294
- /**
295
- * Searches the entries in {@link #DOCKER_COMPOSE_BINARIES} for the Docker Compose CLI. This method does
296
- * not check whether the installation appears usable, see {@link #getDockerAvailability()} instead.
297
- *
298
- * @return the path to a CLI, if available.
299
- */
300
- private Optional <String > getDockerComposePath () {
301
- // Check if the Docker binary exists
302
- return Arrays .asList (DOCKER_COMPOSE_BINARIES ).stream ().filter (path -> new File (path ).exists ()).findFirst ();
303
- }
304
-
305
288
private void throwDockerRequiredException (final String message ) {
306
289
throwDockerRequiredException (message , null );
307
290
}
@@ -321,7 +304,7 @@ private void throwDockerRequiredException(final String message, Exception e) {
321
304
* while running the command, or the process was killed after reaching the 10s timeout,
322
305
* then the exit code will be -1.
323
306
*/
324
- private Result runCommand (String ... args ) {
307
+ private static Result runCommand (ExecOperations execOperations , String ... args ) {
325
308
if (args .length == 0 ) {
326
309
throw new IllegalArgumentException ("Cannot execute with no command" );
327
310
}
@@ -356,14 +339,9 @@ public static class DockerAvailability {
356
339
public final boolean isAvailable ;
357
340
358
341
/**
359
- * True if docker-compose is available.
342
+ * Non-null if docker-compose v1 or v2 is available.
360
343
*/
361
- public final boolean isComposeAvailable ;
362
-
363
- /**
364
- * True if docker compose is available.
365
- */
366
- public final boolean isComposeV2Available ;
344
+ public final DockerComposeAvailability dockerComposeAvailability ;
367
345
368
346
/**
369
347
* True if the installed Docker version is >= 17.05
@@ -387,23 +365,70 @@ public static class DockerAvailability {
387
365
388
366
DockerAvailability (
389
367
boolean isAvailable ,
390
- boolean isComposeAvailable ,
391
- boolean isComposeV2Available ,
368
+ DockerComposeAvailability dockerComposeAvailability ,
392
369
boolean isVersionHighEnough ,
393
370
String path ,
394
371
Version version ,
395
372
Result lastCommand
396
373
) {
397
374
this .isAvailable = isAvailable ;
398
- this .isComposeAvailable = isComposeAvailable ;
399
- this .isComposeV2Available = isComposeV2Available ;
375
+ this .dockerComposeAvailability = dockerComposeAvailability ;
400
376
this .isVersionHighEnough = isVersionHighEnough ;
401
377
this .path = path ;
402
378
this .version = version ;
403
379
this .lastCommand = lastCommand ;
404
380
}
381
+
382
+ public boolean isDockerComposeAvailable () {
383
+ return dockerComposeAvailability != null ;
384
+ }
385
+ }
386
+
387
+ /**
388
+ * Marker interface for Docker Compose availability
389
+ */
390
+ private interface DockerComposeAvailability {
391
+ /**
392
+ * Detects Docker Compose V1/V2 availability
393
+ */
394
+ private static Optional <DockerComposeAvailability > detect (ExecOperations execOperations , String dockerPath ) {
395
+ Optional <String > composePath = getDockerComposePath ();
396
+ if (composePath .isPresent ()) {
397
+ if (runCommand (execOperations , composePath .get (), "version" ).isSuccess ()) {
398
+ return Optional .of (new DockerComposeV1Availability ());
399
+ }
400
+ }
401
+
402
+ if (runCommand (execOperations , dockerPath , "compose" , "version" ).isSuccess ()) {
403
+ return Optional .of (new DockerComposeV2Availability ());
404
+ }
405
+
406
+ return Optional .empty ();
407
+ }
408
+
409
+ /**
410
+ * Searches the entries in {@link #DOCKER_COMPOSE_BINARIES} for the Docker Compose CLI. This method does
411
+ * not check whether the installation appears usable, see {@link #getDockerAvailability()} instead.
412
+ *
413
+ * @return the path to a CLI, if available.
414
+ */
415
+ private static Optional <String > getDockerComposePath () {
416
+ // Check if the Docker binary exists
417
+ return Arrays .asList (DOCKER_COMPOSE_BINARIES ).stream ().filter (path -> new File (path ).exists ()).findFirst ();
418
+ }
419
+
405
420
}
406
421
422
+ /**
423
+ * Docker Compose V1 availability
424
+ */
425
+ public static class DockerComposeV1Availability implements DockerComposeAvailability {}
426
+
427
+ /**
428
+ * Docker Compose V2 availability
429
+ */
430
+ public static class DockerComposeV2Availability implements DockerComposeAvailability {}
431
+
407
432
/**
408
433
* This class models the result of running a command. It captures the exit code, standard output and standard error.
409
434
*/
0 commit comments