blob: 1204ba3685b29515be9b72ce310c1577163a37cf [file] [edit]
// Copyright (c) 2026, the R8 project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
import java.io.BufferedReader
import java.io.File
import java.io.IOException
import java.io.InputStreamReader
import java.nio.charset.StandardCharsets
import java.util.stream.Collectors
import javax.inject.Inject
import org.gradle.api.DefaultTask
import org.gradle.api.file.DirectoryProperty
import org.gradle.api.file.RegularFileProperty
import org.gradle.api.provider.Property
import org.gradle.api.tasks.Input
import org.gradle.api.tasks.InputFile
import org.gradle.api.tasks.Internal
import org.gradle.api.tasks.OutputDirectory
import org.gradle.api.tasks.OutputFile
import org.gradle.api.tasks.TaskAction
import org.gradle.internal.os.OperatingSystem
import org.gradle.workers.WorkAction
import org.gradle.workers.WorkParameters
import org.gradle.workers.WorkerExecutor
public interface DownloadWorkParameters : WorkParameters {
public val sha1File: RegularFileProperty
public val outputDir: DirectoryProperty
public val successFile: RegularFileProperty
public val dependencyType: Property<DependencyType>
public val rootDir: Property<File>
}
public abstract class DownloadWorkAction : WorkAction<DownloadWorkParameters> {
override fun execute() {
val sha1File = parameters.sha1File.asFile.get()
val outputDir = parameters.outputDir.asFile.get()
val successFile = parameters.successFile.asFile.get()
val root = parameters.rootDir.get()
if (successFile.exists()) {
successFile.delete()
}
if (outputDir.exists()) {
outputDir.deleteRecursively()
}
when (parameters.dependencyType.get()) {
DependencyType.GOOGLE_STORAGE -> {
downloadFromGoogleStorage(sha1File, root)
}
DependencyType.X20 -> {
downloadFromX20(sha1File, root)
}
}
successFile.createNewFile()
}
@Throws(IOException::class, InterruptedException::class)
private fun downloadFromGoogleStorage(sha1File: File, root: File) {
val args = listOf("-n", "-b", "r8-deps", "-s", "-u", sha1File.toString())
if (OperatingSystem.current().isWindows) {
val command: MutableList<String> = ArrayList()
command.add("download_from_google_storage.bat")
command.addAll(args)
runProcess(ProcessBuilder().command(command), root)
} else {
runProcess(
ProcessBuilder()
.command(
"bash",
"-c",
"download_from_google_storage " + java.lang.String.join(" ", args),
),
root,
)
}
}
@Throws(IOException::class, InterruptedException::class)
private fun downloadFromX20(sha1File: File, root: File) {
if (OperatingSystem.current().isWindows) {
throw RuntimeException("Downloading from x20 unsupported on windows")
}
runProcess(ProcessBuilder().command("bash", "-c", "tools/download_from_x20.py $sha1File"), root)
}
@Throws(IOException::class, InterruptedException::class)
private fun runProcess(builder: ProcessBuilder, root: File) {
builder.directory(root)
builder.redirectErrorStream(true)
val command = java.lang.String.join(" ", builder.command())
val p = builder.start()
val exit = p.waitFor()
if (exit != 0) {
throw IOException(
"Process failed for $command\n" +
BufferedReader(InputStreamReader(p.inputStream, StandardCharsets.UTF_8))
.lines()
.collect(Collectors.joining("\n"))
)
}
}
}
public abstract class DownloadDependency : DefaultTask() {
@get:InputFile public abstract val sha1File: RegularFileProperty
@get:OutputDirectory public abstract val outputDir: DirectoryProperty
@get:OutputFile public abstract val tarGzFile: RegularFileProperty
@get:OutputFile public abstract val successFile: RegularFileProperty
@get:Internal public val rootDir: File = project.rootDir
@get:Input public abstract val dependencyType: Property<DependencyType>
@get:Inject public abstract val workerExecutor: WorkerExecutor
@TaskAction
public fun execute() {
val sha1File = this.sha1File.asFile.get()
val outputDir = this.outputDir.asFile.get()
val tarGzFile = this.tarGzFile.asFile.get()
val successFile = this.successFile.asFile.get()
if (!sha1File.exists()) {
throw RuntimeException("Missing sha1 file: $sha1File")
}
if (!shouldExecute(outputDir, tarGzFile, sha1File, successFile)) {
return
}
workerExecutor.noIsolation().submit(DownloadWorkAction::class.java) {
this.sha1File.set(this@DownloadDependency.sha1File)
this.outputDir.set(this@DownloadDependency.outputDir)
this.successFile.set(this@DownloadDependency.successFile)
this.dependencyType.set(this@DownloadDependency.dependencyType)
this.rootDir.set(this@DownloadDependency.rootDir)
}
}
}
private fun shouldExecute(
outputDir: File,
tarGzFile: File,
sha1File: File,
successFile: File,
): Boolean {
if (
outputDir.exists() &&
tarGzFile.exists() &&
successFile.exists() &&
sha1File.lastModified() <= successFile.lastModified()
) {
return false
}
return true
}