@@ -57,6 +57,7 @@ import org.gradle.util.GradleVersion
57
57
import java.nio.charset.StandardCharsets
58
58
import java.time.ZoneOffset
59
59
import java.time.ZonedDateTime
60
+ import java.util.regex.Matcher
60
61
61
62
/**
62
63
* Encapsulates build configuration for elasticsearch projects.
@@ -265,56 +266,68 @@ class BuildPlugin implements Plugin<Project> {
265
266
rootProject. rootProject. ext. buildDocker = buildDocker
266
267
rootProject. rootProject. ext. requiresDocker = []
267
268
rootProject. gradle. taskGraph. whenReady { TaskExecutionGraph taskGraph ->
268
- int exitCode
269
- String dockerErrorOutput
270
- if (dockerBinary == null ) {
271
- exitCode = -1
272
- dockerErrorOutput = null
273
- } else {
274
- // the Docker binary executes, check that we can execute a privileged command
275
- final ByteArrayOutputStream output = new ByteArrayOutputStream ()
276
- final ExecResult result = LoggedExec . exec(rootProject, { ExecSpec it ->
277
- it. commandLine dockerBinary, " images"
278
- it. errorOutput = output
279
- it. ignoreExitValue = true
280
- })
281
- if (result. exitValue == 0 ) {
282
- return
283
- }
284
- exitCode = result. exitValue
285
- dockerErrorOutput = output. toString()
286
- }
287
269
final List<String > tasks =
288
270
((List<Task > )rootProject. requiresDocker). findAll { taskGraph. hasTask(it) }. collect { " ${ it.path} " . toString()}
289
271
if (tasks. isEmpty() == false ) {
290
272
/*
291
273
* There are tasks in the task graph that require Docker. Now we are failing because either the Docker binary does not
292
274
* exist or because execution of a privileged Docker command failed.
293
275
*/
294
- String message
295
276
if (dockerBinary == null ) {
296
- message = String . format(
277
+ final String message = String . format(
297
278
Locale . ROOT ,
298
279
" Docker (checked [%s]) is required to run the following task%s: \n %s" ,
299
280
maybeDockerBinaries. join(" ," ),
300
281
tasks. size() > 1 ? " s" : " " ,
301
282
tasks. join(' \n ' ))
302
- } else {
303
- assert exitCode > 0 && dockerErrorOutput != null
304
- message = String . format(
283
+ throwDockerRequiredException(message)
284
+ }
285
+
286
+ // we use a multi-stage Docker build, check the Docker version since 17.05
287
+ final ByteArrayOutputStream dockerVersionOutput = new ByteArrayOutputStream ()
288
+ LoggedExec . exec(
289
+ rootProject,
290
+ { ExecSpec it ->
291
+ it. commandLine = [dockerBinary, ' --version' ]
292
+ it. standardOutput = dockerVersionOutput
293
+ })
294
+ final String dockerVersion = dockerVersionOutput. toString(). trim()
295
+ final Matcher matcher = dockerVersion =~ / Docker version (\d +\.\d +)\.\d +(?:-ce)?, build [0-9a-f]{7}/
296
+ assert matcher. matches() : dockerVersion
297
+ final dockerMajorMinorVersion = matcher. group(1 )
298
+ final String [] majorMinor = dockerMajorMinorVersion. split(" \\ ." )
299
+ if (Integer . parseInt(majorMinor[0 ]) < 17
300
+ || (Integer . parseInt(majorMinor[0 ]) == 17 && Integer . parseInt(majorMinor[1 ]) < 5 )) {
301
+ final String message = String . format(
302
+ Locale . ROOT ,
303
+ " building Docker images requires Docker version 17.05+ due to use of multi-stage builds yet was [%s]" ,
304
+ dockerVersion)
305
+ throwDockerRequiredException(message)
306
+ }
307
+
308
+ final ByteArrayOutputStream dockerImagesErrorOutput = new ByteArrayOutputStream ()
309
+ // the Docker binary executes, check that we can execute a privileged command
310
+ final ExecResult dockerImagesResult = LoggedExec . exec(
311
+ rootProject,
312
+ { ExecSpec it ->
313
+ it. commandLine = [dockerBinary, " images" ]
314
+ it. errorOutput = dockerImagesErrorOutput
315
+ it. ignoreExitValue = true
316
+ })
317
+
318
+ if (dockerImagesResult. exitValue != 0 ) {
319
+ final String message = String . format(
305
320
Locale . ROOT ,
306
321
" a problem occurred running Docker from [%s] yet it is required to run the following task%s: \n %s\n " +
307
322
" the problem is that Docker exited with exit code [%d] with standard error output [%s]" ,
308
323
dockerBinary,
309
324
tasks. size() > 1 ? " s" : " " ,
310
325
tasks. join(' \n ' ),
311
- exitCode,
312
- dockerErrorOutput. trim())
326
+ dockerImagesResult. exitValue,
327
+ dockerImagesErrorOutput. toString(). trim())
328
+ throwDockerRequiredException(message)
313
329
}
314
- throw new GradleException (
315
- message + " \n you can address this by attending to the reported issue, "
316
- + " removing the offending tasks from being executed, "
317
- + " or by passing -Dbuild.docker=false" )
330
+
318
331
}
319
332
}
320
333
}
@@ -325,6 +338,13 @@ class BuildPlugin implements Plugin<Project> {
325
338
}
326
339
}
327
340
341
+ private static void throwDockerRequiredException (final String message ) {
342
+ throw new GradleException (
343
+ message + " \n you can address this by attending to the reported issue, "
344
+ + " removing the offending tasks from being executed, "
345
+ + " or by passing -Dbuild.docker=false" )
346
+ }
347
+
328
348
private static String findCompilerJavaHome () {
329
349
String compilerJavaHome = System . getenv(' JAVA_HOME' )
330
350
final String compilerJavaProperty = System . getProperty(' compiler.java' )
0 commit comments