@@ -51,6 +51,7 @@ import org.gradle.api.tasks.compile.JavaCompile
51
51
import org.gradle.api.tasks.javadoc.Javadoc
52
52
import org.gradle.internal.jvm.Jvm
53
53
import org.gradle.process.ExecResult
54
+ import org.gradle.process.ExecSpec
54
55
import org.gradle.util.GradleVersion
55
56
56
57
import java.nio.charset.StandardCharsets
@@ -232,6 +233,95 @@ class BuildPlugin implements Plugin<Project> {
232
233
project. ext. java9Home = project. rootProject. ext. java9Home
233
234
}
234
235
236
+ static void requireDocker (final Task task ) {
237
+ final Project rootProject = task. project. rootProject
238
+ if (rootProject. hasProperty(' requiresDocker' ) == false ) {
239
+ /*
240
+ * This is our first time encountering a task that requires Docker. We will add an extension that will let us track the tasks
241
+ * that register as requiring Docker. We will add a delayed execution that when the task graph is ready if any such tasks are
242
+ * in the task graph, then we check two things:
243
+ * - the Docker binary is available
244
+ * - we can execute a Docker command that requires privileges
245
+ *
246
+ * If either of these fail, we fail the build.
247
+ */
248
+ final boolean buildDocker
249
+ final String buildDockerProperty = System . getProperty(" build.docker" )
250
+ if (buildDockerProperty == null || buildDockerProperty == " true" ) {
251
+ buildDocker = true
252
+ } else if (buildDockerProperty == " false" ) {
253
+ buildDocker = false
254
+ } else {
255
+ throw new IllegalArgumentException (
256
+ " expected build.docker to be unset or one of \" true\" or \" false\" but was [" + buildDockerProperty + " ]" )
257
+ }
258
+ rootProject. rootProject. ext. buildDocker = buildDocker
259
+ rootProject. rootProject. ext. requiresDocker = []
260
+ rootProject. gradle. taskGraph. whenReady { TaskExecutionGraph taskGraph ->
261
+ // check if the Docker binary exists and record its path
262
+ final List<String > maybeDockerBinaries = [' /usr/bin/docker2' , ' /usr/local/bin/docker2' ]
263
+ final String dockerBinary = maybeDockerBinaries. find { it -> new File (it). exists() }
264
+
265
+ int exitCode
266
+ String dockerErrorOutput
267
+ if (dockerBinary == null ) {
268
+ exitCode = -1
269
+ dockerErrorOutput = null
270
+ } else {
271
+ // the Docker binary executes, check that we can execute a privileged command
272
+ final ByteArrayOutputStream output = new ByteArrayOutputStream ()
273
+ final ExecResult result = LoggedExec . exec(rootProject, { ExecSpec it ->
274
+ it. commandLine dockerBinary, " images"
275
+ it. errorOutput = output
276
+ it. ignoreExitValue = true
277
+ })
278
+ if (result. exitValue == 0 ) {
279
+ return
280
+ }
281
+ exitCode = result. exitValue
282
+ dockerErrorOutput = output. toString()
283
+ }
284
+ final List<String > tasks =
285
+ ((List<Task > )rootProject. requiresDocker). findAll { taskGraph. hasTask(it) }. collect { " ${ it.path} " . toString()}
286
+ if (tasks. isEmpty() == false ) {
287
+ /*
288
+ * There are tasks in the task graph that require Docker. Now we are failing because either the Docker binary does not
289
+ * exist or because execution of a privileged Docker command failed.
290
+ */
291
+ String message
292
+ if (dockerBinary == null ) {
293
+ message = String . format(
294
+ Locale . ROOT ,
295
+ " Docker (checked [%s]) is required to run the following task%s: \n %s" ,
296
+ maybeDockerBinaries. join(" ," ),
297
+ tasks. size() > 1 ? " s" : " " ,
298
+ tasks. join(' \n ' ))
299
+ } else {
300
+ assert exitCode > 0 && dockerErrorOutput != null
301
+ message = String . format(
302
+ Locale . ROOT ,
303
+ " a problem occurred running Docker from [%s] yet it is required to run the following task%s: \n %s\n " +
304
+ " the problem is that Docker exited with exit code [%d] with standard error output [%s]" ,
305
+ dockerBinary,
306
+ tasks. size() > 1 ? " s" : " " ,
307
+ tasks. join(' \n ' ),
308
+ exitCode,
309
+ dockerErrorOutput. trim())
310
+ }
311
+ throw new GradleException (
312
+ message + " \n you can address this by attending to the reported issue, "
313
+ + " removing the offending tasks from being executed, "
314
+ + " or by passing -Dbuild.docker=false" )
315
+ }
316
+ }
317
+ }
318
+ if (rootProject. buildDocker) {
319
+ rootProject. requiresDocker. add(task)
320
+ } else {
321
+ task. enabled = false
322
+ }
323
+ }
324
+
235
325
private static String findCompilerJavaHome () {
236
326
String compilerJavaHome = System . getenv(' JAVA_HOME' )
237
327
final String compilerJavaProperty = System . getProperty(' compiler.java' )
0 commit comments