// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements.  See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.  The ASF 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.

// This file contains tasks for the gradle wrapper generation.

// Ensure the wrapper script is generated based on the version defined in the project
// and not the version installed on the machine running the task.
// Read more about the wrapper here: https://docs.gradle.org/current/userguide/gradle_wrapper.html
wrapper {
  gradleVersion = versions.gradle
  distributionType = Wrapper.DistributionType.ALL
  distributionUrl = "${gradleDistUrlBase}/gradle-${versions.gradle}-all.zip"
}

// Custom task to inject support for downloading the gradle wrapper jar if it doesn't exist.
// This allows us to avoid checking in the jar to our repository.
// Additionally adds a license header to the wrapper while editing the file contents.
task bootstrapWrapper() {
  // In the doLast block so this runs when the task is called and not during project configuration.
  doLast {
    def wrapperBasePath = "\$APP_HOME/gradle/wrapper"
    def wrapperJarPath = wrapperBasePath + "/gradle-wrapper.jar"

    // Add a trailing zero to the version if needed.
    def fullVersion = versions.gradle.count(".") == 1 ? "${versions.gradle}.0" : versions.gradle
    def wrapperJarUrl = wrapperBaseUrl + "/gradle-wrapper.jar"

    def bootstrapString = """
      # Loop in case we encounter an error.
      for attempt in 1 2 3; do
        if [ ! -e $wrapperJarPath ]; then
          if ! curl -s -S --retry 3 -L -o "$wrapperJarPath" "$wrapperJarUrl"; then
            rm -f "$wrapperJarPath"
            # Pause for a bit before looping in case the server throttled us.
            sleep 5
            continue
          fi
        fi
      done
      """.stripIndent()

    def wrapperScript = wrapper.scriptFile
    def wrapperLines = wrapperScript.readLines()
    wrapperScript.withPrintWriter { out ->
      def bootstrapWritten = false
      wrapperLines.each { line ->
        // Print the wrapper bootstrap before the first usage of the wrapper jar.
        if (!bootstrapWritten && line.contains("gradle-wrapper.jar")) {
          out.println(bootstrapString)
          bootstrapWritten = true
        }
        out.println(line)
      }
    }
  }
}
wrapper.finalizedBy bootstrapWrapper

// Remove the generated batch file since we don't test building in the Windows environment.
task removeWindowScript(type: Delete) {
  delete "$rootDir/gradlew.bat"
}
wrapper.finalizedBy removeWindowScript
