@@ -57,6 +57,7 @@ import org.gradle.util.GradleVersion
5757import java.nio.charset.StandardCharsets
5858import java.time.ZoneOffset
5959import java.time.ZonedDateTime
60+ import java.util.regex.Matcher
6061
6162/**
6263 * Encapsulates build configuration for elasticsearch projects.
@@ -265,56 +266,68 @@ class BuildPlugin implements Plugin<Project> {
265266 rootProject. rootProject. ext. buildDocker = buildDocker
266267 rootProject. rootProject. ext. requiresDocker = []
267268 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- }
287269 final List<String > tasks =
288270 ((List<Task > )rootProject. requiresDocker). findAll { taskGraph. hasTask(it) }. collect { " ${ it.path} " . toString()}
289271 if (tasks. isEmpty() == false ) {
290272 /*
291273 * There are tasks in the task graph that require Docker. Now we are failing because either the Docker binary does not
292274 * exist or because execution of a privileged Docker command failed.
293275 */
294- String message
295276 if (dockerBinary == null ) {
296- message = String . format(
277+ final String message = String . format(
297278 Locale . ROOT ,
298279 " Docker (checked [%s]) is required to run the following task%s: \n %s" ,
299280 maybeDockerBinaries. join(" ," ),
300281 tasks. size() > 1 ? " s" : " " ,
301282 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(
305320 Locale . ROOT ,
306321 " a problem occurred running Docker from [%s] yet it is required to run the following task%s: \n %s\n " +
307322 " the problem is that Docker exited with exit code [%d] with standard error output [%s]" ,
308323 dockerBinary,
309324 tasks. size() > 1 ? " s" : " " ,
310325 tasks. join(' \n ' ),
311- exitCode,
312- dockerErrorOutput. trim())
326+ dockerImagesResult. exitValue,
327+ dockerImagesErrorOutput. toString(). trim())
328+ throwDockerRequiredException(message)
313329 }
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+
318331 }
319332 }
320333 }
@@ -325,6 +338,13 @@ class BuildPlugin implements Plugin<Project> {
325338 }
326339 }
327340
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+
328348 private static String findCompilerJavaHome () {
329349 String compilerJavaHome = System . getenv(' JAVA_HOME' )
330350 final String compilerJavaProperty = System . getProperty(' compiler.java' )
0 commit comments