<commit_before>/*
 * Licensed to Elasticsearch under one or more contributor
 * license agreements. See the NOTICE file distributed with
 * this work for additional information regarding copyright
 * ownership. Elasticsearch licenses this file to you under
 * the Apache License, Version 2.0 (the "License"); you may
 * not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */
package org.elasticsearch.gradle

import com.carrotsearch.gradle.junit4.RandomizedTestingTask
import com.github.jengelman.gradle.plugins.shadow.ShadowPlugin
import org.apache.commons.io.IOUtils
import org.apache.tools.ant.taskdefs.condition.Os
import org.eclipse.jgit.lib.Constants
import org.eclipse.jgit.lib.RepositoryBuilder
import org.elasticsearch.gradle.precommit.PrecommitTasks
import org.gradle.api.GradleException
import org.gradle.api.InvalidUserDataException
import org.gradle.api.JavaVersion
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.api.Task
import org.gradle.api.XmlProvider
import org.gradle.api.artifacts.Configuration
import org.gradle.api.artifacts.Dependency
import org.gradle.api.artifacts.ModuleDependency
import org.gradle.api.artifacts.ModuleVersionIdentifier
import org.gradle.api.artifacts.ProjectDependency
import org.gradle.api.artifacts.ResolvedArtifact
import org.gradle.api.artifacts.dsl.RepositoryHandler
import org.gradle.api.execution.TaskExecutionGraph
import org.gradle.api.plugins.JavaPlugin
import org.gradle.api.publish.maven.MavenPublication
import org.gradle.api.publish.maven.plugins.MavenPublishPlugin
import org.gradle.api.publish.maven.tasks.GenerateMavenPom
import org.gradle.api.tasks.SourceSet
import org.gradle.api.tasks.bundling.Jar
import org.gradle.api.tasks.compile.GroovyCompile
import org.gradle.api.tasks.compile.JavaCompile
import org.gradle.api.tasks.javadoc.Javadoc
import org.gradle.internal.jvm.Jvm
import org.gradle.process.ExecResult
import org.gradle.process.ExecSpec
import org.gradle.util.GradleVersion

import java.nio.charset.StandardCharsets
import java.time.ZoneOffset
import java.time.ZonedDateTime

/**
 * Encapsulates build configuration for elasticsearch projects.
 */
class BuildPlugin implements Plugin<Project> {

    @Override
    void apply(Project project) {
        if (project.pluginManager.hasPlugin('elasticsearch.standalone-rest-test')) {
              throw new InvalidUserDataException('elasticsearch.standalone-test, '
                + 'elasticsearch.standalone-rest-test, and elasticsearch.build '
                + 'are mutually exclusive')
        }
        String minimumGradleVersion = null
        InputStream is = getClass().getResourceAsStream("/minimumGradleVersion")
        try { minimumGradleVersion = IOUtils.toString(is, StandardCharsets.UTF_8.toString()) } finally { is.close() }
        if (GradleVersion.current() < GradleVersion.version(minimumGradleVersion.trim())) {
            throw new GradleException(
                    "Gradle ${minimumGradleVersion}+ is required to use elasticsearch.build plugin"
            )
        }
        project.pluginManager.apply('java')
        project.pluginManager.apply('carrotsearch.randomized-testing')
        configureConfigurations(project)
        configureJars(project) // jar config must be added before info broker
        // these plugins add lots of info to our jars
        project.pluginManager.apply('nebula.info-broker')
        project.pluginManager.apply('nebula.info-basic')
        project.pluginManager.apply('nebula.info-java')
        project.pluginManager.apply('nebula.info-scm')
        project.pluginManager.apply('nebula.info-jar')

        project.getTasks().create("buildResources", ExportElasticsearchBuildResourcesTask)

        globalBuildInfo(project)
        configureRepositories(project)
        project.ext.versions = VersionProperties.versions
        configureSourceSets(project)
        configureCompile(project)
        configureJavadoc(project)
        configureSourcesJar(project)
        configurePomGeneration(project)

        applyCommonTestConfig(project)
        configureTest(project)
        configurePrecommit(project)
        configureDependenciesInfo(project)
    }



    /** Performs checks on the build environment and prints information about the build environment. */
    static void globalBuildInfo(Project project) {
        if (project.rootProject.ext.has('buildChecksDone') == false) {
            JavaVersion minimumRuntimeVersion = JavaVersion.toVersion(
                    BuildPlugin.class.getClassLoader().getResourceAsStream("minimumRuntimeVersion").text.trim()
            )
            JavaVersion minimumCompilerVersion = JavaVersion.toVersion(
                    BuildPlugin.class.getClassLoader().getResourceAsStream("minimumCompilerVersion").text.trim()
            )
            String compilerJavaHome = findCompilerJavaHome()
            String runtimeJavaHome = findRuntimeJavaHome(compilerJavaHome)
            File gradleJavaHome = Jvm.current().javaHome

            final Map<Integer, String> javaVersions = [:]
            for (int version = 8; version <= Integer.parseInt(minimumCompilerVersion.majorVersion); version++) {
                if(System.getenv(getJavaHomeEnvVarName(version.toString())) != null) {
                    javaVersions.put(version, findJavaHome(version.toString()));
                }
            }

            String javaVendor = System.getProperty('java.vendor')
            String gradleJavaVersion = System.getProperty('java.version')
            String gradleJavaVersionDetails = "${javaVendor} ${gradleJavaVersion}" +
                " [${System.getProperty('java.vm.name')} ${System.getProperty('java.vm.version')}]"

            String compilerJavaVersionDetails = gradleJavaVersionDetails
            JavaVersion compilerJavaVersionEnum = JavaVersion.current()
            if (new File(compilerJavaHome).canonicalPath != gradleJavaHome.canonicalPath) {
                compilerJavaVersionDetails = findJavaVersionDetails(project, compilerJavaHome)
                compilerJavaVersionEnum = JavaVersion.toVersion(findJavaSpecificationVersion(project, compilerJavaHome))
            }

            String runtimeJavaVersionDetails = gradleJavaVersionDetails
            JavaVersion runtimeJavaVersionEnum = JavaVersion.current()
            if (new File(runtimeJavaHome).canonicalPath != gradleJavaHome.canonicalPath) {
                runtimeJavaVersionDetails = findJavaVersionDetails(project, runtimeJavaHome)
                runtimeJavaVersionEnum = JavaVersion.toVersion(findJavaSpecificationVersion(project, runtimeJavaHome))
            }

            String inFipsJvmScript = 'print(java.security.Security.getProviders()[0].name.toLowerCase().contains("fips"));'
            boolean inFipsJvm = Boolean.parseBoolean(runJavascript(project, runtimeJavaHome, inFipsJvmScript))

            // Build debugging info
            println '======================================='
            println 'Elasticsearch Build Hamster says Hello!'
            println "  Gradle Version        : ${project.gradle.gradleVersion}"
            println "  OS Info               : ${System.getProperty('os.name')} ${System.getProperty('os.version')} (${System.getProperty('os.arch')})"
            if (gradleJavaVersionDetails != compilerJavaVersionDetails || gradleJavaVersionDetails != runtimeJavaVersionDetails) {
                println "  Compiler JDK Version  : ${compilerJavaVersionEnum} (${compilerJavaVersionDetails})"
                println "  Compiler java.home    : ${compilerJavaHome}"
                println "  Runtime JDK Version   : ${runtimeJavaVersionEnum} (${runtimeJavaVersionDetails})"
                println "  Runtime java.home     : ${runtimeJavaHome}"
                println "  Gradle JDK Version    : ${JavaVersion.toVersion(gradleJavaVersion)} (${gradleJavaVersionDetails})"
                println "  Gradle java.home      : ${gradleJavaHome}"
            } else {
                println "  JDK Version           : ${JavaVersion.toVersion(gradleJavaVersion)} (${gradleJavaVersionDetails})"
                println "  JAVA_HOME             : ${gradleJavaHome}"
            }
            println "  Random Testing Seed   : ${project.testSeed}"
            println '======================================='

            // enforce Java version
            if (compilerJavaVersionEnum < minimumCompilerVersion) {
                final String message =
                        "the compiler java.home must be set to a JDK installation directory for Java ${minimumCompilerVersion}" +
                                " but is [${compilerJavaHome}] corresponding to [${compilerJavaVersionEnum}]"
                throw new GradleException(message)
            }

            if (runtimeJavaVersionEnum < minimumRuntimeVersion) {
                final String message =
                        "the runtime java.home must be set to a JDK installation directory for Java ${minimumRuntimeVersion}" +
                                " but is [${runtimeJavaHome}] corresponding to [${runtimeJavaVersionEnum}]"
                throw new GradleException(message)
            }

            for (final Map.Entry<Integer, String> javaVersionEntry : javaVersions.entrySet()) {
                final String javaHome = javaVersionEntry.getValue()
                if (javaHome == null) {
                    continue
                }
                JavaVersion javaVersionEnum = JavaVersion.toVersion(findJavaSpecificationVersion(project, javaHome))
                final JavaVersion expectedJavaVersionEnum
                final int version = javaVersionEntry.getKey()
                if (version < 9) {
                    expectedJavaVersionEnum = JavaVersion.toVersion("1." + version)
                } else {
                    expectedJavaVersionEnum = JavaVersion.toVersion(Integer.toString(version))
                }
                if (javaVersionEnum != expectedJavaVersionEnum) {
                    final String message =
                            "the environment variable JAVA" + version + "_HOME must be set to a JDK installation directory for Java" +
                                    " ${expectedJavaVersionEnum} but is [${javaHome}] corresponding to [${javaVersionEnum}]"
                    throw new GradleException(message)
                }
            }

            project.rootProject.ext.compilerJavaHome = compilerJavaHome
            project.rootProject.ext.runtimeJavaHome = runtimeJavaHome
            project.rootProject.ext.compilerJavaVersion = compilerJavaVersionEnum
            project.rootProject.ext.runtimeJavaVersion = runtimeJavaVersionEnum
            project.rootProject.ext.javaVersions = javaVersions
            project.rootProject.ext.buildChecksDone = true
            project.rootProject.ext.minimumCompilerVersion = minimumCompilerVersion
            project.rootProject.ext.minimumRuntimeVersion = minimumRuntimeVersion
            project.rootProject.ext.inFipsJvm = inFipsJvm
            project.rootProject.ext.gradleJavaVersion = JavaVersion.toVersion(gradleJavaVersion)
            project.rootProject.ext.java9Home = "${-> findJavaHome("9")}"
            project.rootProject.ext.defaultParallel = findDefaultParallel(project.rootProject)
        }

        project.targetCompatibility = project.rootProject.ext.minimumRuntimeVersion
        project.sourceCompatibility = project.rootProject.ext.minimumRuntimeVersion

        // set java home for each project, so they dont have to find it in the root project
        project.ext.compilerJavaHome = project.rootProject.ext.compilerJavaHome
        project.ext.runtimeJavaHome = project.rootProject.ext.runtimeJavaHome
        project.ext.compilerJavaVersion = project.rootProject.ext.compilerJavaVersion
        project.ext.runtimeJavaVersion = project.rootProject.ext.runtimeJavaVersion
        project.ext.javaVersions = project.rootProject.ext.javaVersions
        project.ext.inFipsJvm = project.rootProject.ext.inFipsJvm
        project.ext.gradleJavaVersion = project.rootProject.ext.gradleJavaVersion
        project.ext.java9Home = project.rootProject.ext.java9Home
    }

    static void requireDocker(final Task task) {
        final Project rootProject = task.project.rootProject
        if (rootProject.hasProperty('requiresDocker') == false) {
            /*
             * This is our first time encountering a task that requires Docker. We will add an extension that will let us track the tasks
             * that register as requiring Docker. We will add a delayed execution that when the task graph is ready if any such tasks are
             * in the task graph, then we check two things:
             *  - the Docker binary is available
             *  - we can execute a Docker command that requires privileges
             *
             *  If either of these fail, we fail the build.
             */

            // check if the Docker binary exists and record its path
            final List<String> maybeDockerBinaries = ['/usr/bin/docker', '/usr/local/bin/docker']
            final String dockerBinary = maybeDockerBinaries.find { it -> new File(it).exists() }

            final boolean buildDocker
            final String buildDockerProperty = System.getProperty("build.docker")
            if (buildDockerProperty == null) {
                buildDocker = dockerBinary != null
            } else if (buildDockerProperty == "true") {
                buildDocker = true
            } else if (buildDockerProperty == "false") {
                buildDocker = false
            } else {
                throw new IllegalArgumentException(
                        "expected build.docker to be unset or one of \"true\" or \"false\" but was [" + buildDockerProperty + "]")
            }
            rootProject.rootProject.ext.buildDocker = buildDocker
            rootProject.rootProject.ext.requiresDocker = []
            rootProject.gradle.taskGraph.whenReady { TaskExecutionGraph taskGraph ->
                int exitCode
                String dockerErrorOutput
                if (dockerBinary == null) {
                    exitCode = -1
                    dockerErrorOutput = null
                } else {
                    // the Docker binary executes, check that we can execute a privileged command
                    final ByteArrayOutputStream output = new ByteArrayOutputStream()
                    final ExecResult result = LoggedExec.exec(rootProject, { ExecSpec it ->
                        it.commandLine dockerBinary, "images"
                        it.errorOutput = output
                        it.ignoreExitValue = true
                    })
                    if (result.exitValue == 0) {
                        return
                    }
                    exitCode = result.exitValue
                    dockerErrorOutput = output.toString()
                }
                final List<String> tasks =
                        ((List<Task>)rootProject.requiresDocker).findAll { taskGraph.hasTask(it) }.collect { "  ${it.path}".toString()}
                if (tasks.isEmpty() == false) {
                    /*
                     * There are tasks in the task graph that require Docker. Now we are failing because either the Docker binary does not
                     * exist or because execution of a privileged Docker command failed.
                     */
                    String message
                    if (dockerBinary == null) {
                        message = String.format(
                                Locale.ROOT,
                                "Docker (checked [%s]) is required to run the following task%s: \n%s",
                                maybeDockerBinaries.join(","),
                                tasks.size() > 1 ? "s" : "",
                                tasks.join('\n'))
                    } else {
                        assert exitCode > 0 && dockerErrorOutput != null
                        message = String.format(
                                Locale.ROOT,
                                "a problem occurred running Docker from [%s] yet it is required to run the following task%s: \n%s\n" +
                                        "the problem is that Docker exited with exit code [%d] with standard error output [%s]",
                                dockerBinary,
                                tasks.size() > 1 ? "s" : "",
                                tasks.join('\n'),
                                exitCode,
                                dockerErrorOutput.trim())
                    }
                    throw new GradleException(
                            message + "\nyou can address this by attending to the reported issue, "
                                    + "removing the offending tasks from being executed, "
                                    + "or by passing -Dbuild.docker=false")
                }
            }
        }
        if (rootProject.buildDocker) {
            rootProject.requiresDocker.add(task)
        } else {
            task.enabled = false
        }
    }

    private static String findCompilerJavaHome() {
        String compilerJavaHome = System.getenv('JAVA_HOME')
        final String compilerJavaProperty = System.getProperty('compiler.java')
        if (compilerJavaProperty != null) {
            compilerJavaHome = findJavaHome(compilerJavaProperty)
        }
        if (compilerJavaHome == null) {
            if (System.getProperty("idea.executable") != null || System.getProperty("eclipse.launcher") != null) {
                // IntelliJ does not set JAVA_HOME, so we use the JDK that Gradle was run with
                return Jvm.current().javaHome
            } else {
                throw new GradleException(
                        " " + System.getProperties().toString() + " " +
                        "JAVA_HOME must be set to build Elasticsearch. " +
                                "Note that if the variable was just set you might have to run `./gradlew --stop` for " +
                                "it to be picked up. See https://github.com/elastic/elasticsearch/issues/31399 details."<commit_msg>Add check for minimum required Docker version (#36497)<commit_after>/*
 * Licensed to Elasticsearch under one or more contributor
 * license agreements. See the NOTICE file distributed with
 * this work for additional information regarding copyright
 * ownership. Elasticsearch licenses this file to you under
 * the Apache License, Version 2.0 (the "License"); you may
 * not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */
package org.elasticsearch.gradle

import com.carrotsearch.gradle.junit4.RandomizedTestingTask
import com.github.jengelman.gradle.plugins.shadow.ShadowPlugin
import org.apache.commons.io.IOUtils
import org.apache.tools.ant.taskdefs.condition.Os
import org.eclipse.jgit.lib.Constants
import org.eclipse.jgit.lib.RepositoryBuilder
import org.elasticsearch.gradle.precommit.PrecommitTasks
import org.gradle.api.GradleException
import org.gradle.api.InvalidUserDataException
import org.gradle.api.JavaVersion
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.api.Task
import org.gradle.api.XmlProvider
import org.gradle.api.artifacts.Configuration
import org.gradle.api.artifacts.Dependency
import org.gradle.api.artifacts.ModuleDependency
import org.gradle.api.artifacts.ModuleVersionIdentifier
import org.gradle.api.artifacts.ProjectDependency
import org.gradle.api.artifacts.ResolvedArtifact
import org.gradle.api.artifacts.dsl.RepositoryHandler
import org.gradle.api.execution.TaskExecutionGraph
import org.gradle.api.plugins.JavaPlugin
import org.gradle.api.publish.maven.MavenPublication
import org.gradle.api.publish.maven.plugins.MavenPublishPlugin
import org.gradle.api.publish.maven.tasks.GenerateMavenPom
import org.gradle.api.tasks.SourceSet
import org.gradle.api.tasks.bundling.Jar
import org.gradle.api.tasks.compile.GroovyCompile
import org.gradle.api.tasks.compile.JavaCompile
import org.gradle.api.tasks.javadoc.Javadoc
import org.gradle.internal.jvm.Jvm
import org.gradle.process.ExecResult
import org.gradle.process.ExecSpec
import org.gradle.util.GradleVersion

import java.nio.charset.StandardCharsets
import java.time.ZoneOffset
import java.time.ZonedDateTime
import java.util.regex.Matcher

/**
 * Encapsulates build configuration for elasticsearch projects.
 */
class BuildPlugin implements Plugin<Project> {

    @Override
    void apply(Project project) {
        if (project.pluginManager.hasPlugin('elasticsearch.standalone-rest-test')) {
              throw new InvalidUserDataException('elasticsearch.standalone-test, '
                + 'elasticsearch.standalone-rest-test, and elasticsearch.build '
                + 'are mutually exclusive')
        }
        String minimumGradleVersion = null
        InputStream is = getClass().getResourceAsStream("/minimumGradleVersion")
        try { minimumGradleVersion = IOUtils.toString(is, StandardCharsets.UTF_8.toString()) } finally { is.close() }
        if (GradleVersion.current() < GradleVersion.version(minimumGradleVersion.trim())) {
            throw new GradleException(
                    "Gradle ${minimumGradleVersion}+ is required to use elasticsearch.build plugin"
            )
        }
        project.pluginManager.apply('java')
        project.pluginManager.apply('carrotsearch.randomized-testing')
        configureConfigurations(project)
        configureJars(project) // jar config must be added before info broker
        // these plugins add lots of info to our jars
        project.pluginManager.apply('nebula.info-broker')
        project.pluginManager.apply('nebula.info-basic')
        project.pluginManager.apply('nebula.info-java')
        project.pluginManager.apply('nebula.info-scm')
        project.pluginManager.apply('nebula.info-jar')

        project.getTasks().create("buildResources", ExportElasticsearchBuildResourcesTask)

        globalBuildInfo(project)
        configureRepositories(project)
        project.ext.versions = VersionProperties.versions
        configureSourceSets(project)
        configureCompile(project)
        configureJavadoc(project)
        configureSourcesJar(project)
        configurePomGeneration(project)

        applyCommonTestConfig(project)
        configureTest(project)
        configurePrecommit(project)
        configureDependenciesInfo(project)
    }



    /** Performs checks on the build environment and prints information about the build environment. */
    static void globalBuildInfo(Project project) {
        if (project.rootProject.ext.has('buildChecksDone') == false) {
            JavaVersion minimumRuntimeVersion = JavaVersion.toVersion(
                    BuildPlugin.class.getClassLoader().getResourceAsStream("minimumRuntimeVersion").text.trim()
            )
            JavaVersion minimumCompilerVersion = JavaVersion.toVersion(
                    BuildPlugin.class.getClassLoader().getResourceAsStream("minimumCompilerVersion").text.trim()
            )
            String compilerJavaHome = findCompilerJavaHome()
            String runtimeJavaHome = findRuntimeJavaHome(compilerJavaHome)
            File gradleJavaHome = Jvm.current().javaHome

            final Map<Integer, String> javaVersions = [:]
            for (int version = 8; version <= Integer.parseInt(minimumCompilerVersion.majorVersion); version++) {
                if(System.getenv(getJavaHomeEnvVarName(version.toString())) != null) {
                    javaVersions.put(version, findJavaHome(version.toString()));
                }
            }

            String javaVendor = System.getProperty('java.vendor')
            String gradleJavaVersion = System.getProperty('java.version')
            String gradleJavaVersionDetails = "${javaVendor} ${gradleJavaVersion}" +
                " [${System.getProperty('java.vm.name')} ${System.getProperty('java.vm.version')}]"

            String compilerJavaVersionDetails = gradleJavaVersionDetails
            JavaVersion compilerJavaVersionEnum = JavaVersion.current()
            if (new File(compilerJavaHome).canonicalPath != gradleJavaHome.canonicalPath) {
                compilerJavaVersionDetails = findJavaVersionDetails(project, compilerJavaHome)
                compilerJavaVersionEnum = JavaVersion.toVersion(findJavaSpecificationVersion(project, compilerJavaHome))
            }

            String runtimeJavaVersionDetails = gradleJavaVersionDetails
            JavaVersion runtimeJavaVersionEnum = JavaVersion.current()
            if (new File(runtimeJavaHome).canonicalPath != gradleJavaHome.canonicalPath) {
                runtimeJavaVersionDetails = findJavaVersionDetails(project, runtimeJavaHome)
                runtimeJavaVersionEnum = JavaVersion.toVersion(findJavaSpecificationVersion(project, runtimeJavaHome))
            }

            String inFipsJvmScript = 'print(java.security.Security.getProviders()[0].name.toLowerCase().contains("fips"));'
            boolean inFipsJvm = Boolean.parseBoolean(runJavascript(project, runtimeJavaHome, inFipsJvmScript))

            // Build debugging info
            println '======================================='
            println 'Elasticsearch Build Hamster says Hello!'
            println "  Gradle Version        : ${project.gradle.gradleVersion}"
            println "  OS Info               : ${System.getProperty('os.name')} ${System.getProperty('os.version')} (${System.getProperty('os.arch')})"
            if (gradleJavaVersionDetails != compilerJavaVersionDetails || gradleJavaVersionDetails != runtimeJavaVersionDetails) {
                println "  Compiler JDK Version  : ${compilerJavaVersionEnum} (${compilerJavaVersionDetails})"
                println "  Compiler java.home    : ${compilerJavaHome}"
                println "  Runtime JDK Version   : ${runtimeJavaVersionEnum} (${runtimeJavaVersionDetails})"
                println "  Runtime java.home     : ${runtimeJavaHome}"
                println "  Gradle JDK Version    : ${JavaVersion.toVersion(gradleJavaVersion)} (${gradleJavaVersionDetails})"
                println "  Gradle java.home      : ${gradleJavaHome}"
            } else {
                println "  JDK Version           : ${JavaVersion.toVersion(gradleJavaVersion)} (${gradleJavaVersionDetails})"
                println "  JAVA_HOME             : ${gradleJavaHome}"
            }
            println "  Random Testing Seed   : ${project.testSeed}"
            println '======================================='

            // enforce Java version
            if (compilerJavaVersionEnum < minimumCompilerVersion) {
                final String message =
                        "the compiler java.home must be set to a JDK installation directory for Java ${minimumCompilerVersion}" +
                                " but is [${compilerJavaHome}] corresponding to [${compilerJavaVersionEnum}]"
                throw new GradleException(message)
            }

            if (runtimeJavaVersionEnum < minimumRuntimeVersion) {
                final String message =
                        "the runtime java.home must be set to a JDK installation directory for Java ${minimumRuntimeVersion}" +
                                " but is [${runtimeJavaHome}] corresponding to [${runtimeJavaVersionEnum}]"
                throw new GradleException(message)
            }

            for (final Map.Entry<Integer, String> javaVersionEntry : javaVersions.entrySet()) {
                final String javaHome = javaVersionEntry.getValue()
                if (javaHome == null) {
                    continue
                }
                JavaVersion javaVersionEnum = JavaVersion.toVersion(findJavaSpecificationVersion(project, javaHome))
                final JavaVersion expectedJavaVersionEnum
                final int version = javaVersionEntry.getKey()
                if (version < 9) {
                    expectedJavaVersionEnum = JavaVersion.toVersion("1." + version)
                } else {
                    expectedJavaVersionEnum = JavaVersion.toVersion(Integer.toString(version))
                }
                if (javaVersionEnum != expectedJavaVersionEnum) {
                    final String message =
                            "the environment variable JAVA" + version + "_HOME must be set to a JDK installation directory for Java" +
                                    " ${expectedJavaVersionEnum} but is [${javaHome}] corresponding to [${javaVersionEnum}]"
                    throw new GradleException(message)
                }
            }

            project.rootProject.ext.compilerJavaHome = compilerJavaHome
            project.rootProject.ext.runtimeJavaHome = runtimeJavaHome
            project.rootProject.ext.compilerJavaVersion = compilerJavaVersionEnum
            project.rootProject.ext.runtimeJavaVersion = runtimeJavaVersionEnum
            project.rootProject.ext.javaVersions = javaVersions
            project.rootProject.ext.buildChecksDone = true
            project.rootProject.ext.minimumCompilerVersion = minimumCompilerVersion
            project.rootProject.ext.minimumRuntimeVersion = minimumRuntimeVersion
            project.rootProject.ext.inFipsJvm = inFipsJvm
            project.rootProject.ext.gradleJavaVersion = JavaVersion.toVersion(gradleJavaVersion)
            project.rootProject.ext.java9Home = "${-> findJavaHome("9")}"
            project.rootProject.ext.defaultParallel = findDefaultParallel(project.rootProject)
        }

        project.targetCompatibility = project.rootProject.ext.minimumRuntimeVersion
        project.sourceCompatibility = project.rootProject.ext.minimumRuntimeVersion

        // set java home for each project, so they dont have to find it in the root project
        project.ext.compilerJavaHome = project.rootProject.ext.compilerJavaHome
        project.ext.runtimeJavaHome = project.rootProject.ext.runtimeJavaHome
        project.ext.compilerJavaVersion = project.rootProject.ext.compilerJavaVersion
        project.ext.runtimeJavaVersion = project.rootProject.ext.runtimeJavaVersion
        project.ext.javaVersions = project.rootProject.ext.javaVersions
        project.ext.inFipsJvm = project.rootProject.ext.inFipsJvm
        project.ext.gradleJavaVersion = project.rootProject.ext.gradleJavaVersion
        project.ext.java9Home = project.rootProject.ext.java9Home
    }

    static void requireDocker(final Task task) {
        final Project rootProject = task.project.rootProject
        if (rootProject.hasProperty('requiresDocker') == false) {
            /*
             * This is our first time encountering a task that requires Docker. We will add an extension that will let us track the tasks
             * that register as requiring Docker. We will add a delayed execution that when the task graph is ready if any such tasks are
             * in the task graph, then we check two things:
             *  - the Docker binary is available
             *  - we can execute a Docker command that requires privileges
             *
             *  If either of these fail, we fail the build.
             */

            // check if the Docker binary exists and record its path
            final List<String> maybeDockerBinaries = ['/usr/bin/docker', '/usr/local/bin/docker']
            final String dockerBinary = maybeDockerBinaries.find { it -> new File(it).exists() }

            final boolean buildDocker
            final String buildDockerProperty = System.getProperty("build.docker")
            if (buildDockerProperty == null) {
                buildDocker = dockerBinary != null
            } else if (buildDockerProperty == "true") {
                buildDocker = true
            } else if (buildDockerProperty == "false") {
                buildDocker = false
            } else {
                throw new IllegalArgumentException(
                        "expected build.docker to be unset or one of \"true\" or \"false\" but was [" + buildDockerProperty + "]")
            }
            rootProject.rootProject.ext.buildDocker = buildDocker
            rootProject.rootProject.ext.requiresDocker = []
            rootProject.gradle.taskGraph.whenReady { TaskExecutionGraph taskGraph ->
                final List<String> tasks =
                        ((List<Task>)rootProject.requiresDocker).findAll { taskGraph.hasTask(it) }.collect { "  ${it.path}".toString()}
                if (tasks.isEmpty() == false) {
                    /*
                     * There are tasks in the task graph that require Docker. Now we are failing because either the Docker binary does not
                     * exist or because execution of a privileged Docker command failed.
                     */
                    if (dockerBinary == null) {
                        final String message = String.format(
                                Locale.ROOT,
                                "Docker (checked [%s]) is required to run the following task%s: \n%s",
                                maybeDockerBinaries.join(","),
                                tasks.size() > 1 ? "s" : "",
                                tasks.join('\n'))
                        throwDockerRequiredException(message)
                    }

                    // we use a multi-stage Docker build, check the Docker version since 17.05
                    final ByteArrayOutputStream dockerVersionOutput = new ByteArrayOutputStream()
                    LoggedExec.exec(
                            rootProject,
                            { ExecSpec it ->
                                it.commandLine = [dockerBinary, '--version']
                                it.standardOutput = dockerVersionOutput
                            })
                    final String dockerVersion = dockerVersionOutput.toString().trim()
                    final Matcher matcher = dockerVersion =~ /Docker version (\d+\.\d+)\.\d+(?:-ce)?, build [0-9a-f]{7}/
                    assert matcher.matches() : dockerVersion
                    final dockerMajorMinorVersion = matcher.group(1)
                    final String[] majorMinor = dockerMajorMinorVersion.split("\\.")
                    if (Integer.parseInt(majorMinor[0]) < 17
                            || (Integer.parseInt(majorMinor[0]) == 17 && Integer.parseInt(majorMinor[1]) < 5)) {
                        final String message = String.format(
                                Locale.ROOT,
                                "building Docker images requires Docker version 17.05+ due to use of multi-stage builds yet was [%s]",
                                dockerVersion)
                        throwDockerRequiredException(message)
                    }

                    final ByteArrayOutputStream dockerImagesErrorOutput = new ByteArrayOutputStream()
                    // the Docker binary executes, check that we can execute a privileged command
                    final ExecResult dockerImagesResult = LoggedExec.exec(
                            rootProject,
                            { ExecSpec it ->
                                it.commandLine = [dockerBinary, "images"]
                                it.errorOutput = dockerImagesErrorOutput
                                it.ignoreExitValue = true
                            })

                    if (dockerImagesResult.exitValue != 0) {
                        final String message = String.format(
                                Locale.ROOT,
                                "a problem occurred running Docker from [%s] yet it is required to run the following task%s: \n%s\n" +
                                        "the problem is that Docker exited with exit code [%d] with standard error output [%s]",
                                dockerBinary,
                                tasks.size() > 1 ? "s" : "",
                                tasks.join('\n'),
                                dockerImagesResult.exitValue,
                                dockerImagesErrorOutput.toString().trim())
                        throwDockerRequiredException(message)
                    }

                }
            }
        }
        if (rootProject.buildDocker) {
            rootProject.requiresDocker.add(task)
        } else {
            task.enabled = false
        }
    }

    private static void throwDockerRequiredException(final String message) {
        throw new GradleException(
                message + "\nyou can address this by attending to the reported issue, "
                        + "removing the offending tasks from being executed, "
                        + "or by passing -Dbuild.docker=false")
    }

    private static String findCompilerJavaHome() {
        String compilerJavaHome = System.getenv('JAVA_HOME')
        final String compilerJavaProperty = System.getProperty('compiler.java')
        if (compilerJavaProperty != null) {
            compilerJavaHome = findJavaHome(compilerJavaProperty)
        }
        if (compilerJavaHome == null) {
            if (System.getProperty("idea.executable") != null || System.getProperty("eclipse.launcher") != null) {
                // IntelliJ does not set JAVA_HOME, so we use the JDK that Gradle was run with
                return Jvm.current().javaHome
            } else {
                throw new GradleException(
                        " " + System.getProperties().toString() + " " +
                        "JAVA_HOME must be set to build Elasticsearch. " +
                                "Note that if the variable was just set you might have to run `./gradlew --stop` for " +
                                "it to be picked up. See https://github.com/elastic/elasticsearch/issues/31399 details."
{'fraction_non_alphanumeric': 0.08570097810898929, 'fraction_numerical': 0.0018371888423122703, 'mean_word_length': 2.1737702225507105, 'pattern_counts': {'":': 0, '<': 27, '<?xml version=': 0, '>': 29, 'https://': 2, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 16, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6272818', 'n_tokens_mistral': 9428, 'n_tokens_neox': 8844, 'n_words': 2219}