summaryrefslogtreecommitdiff
path: root/build-logic/src/main/kotlin/DownloadArchiveFile.kt
blob: c7f549cd34b7042ffffaf5595a2342c60afeab58 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
import org.gradle.api.DefaultTask
import org.gradle.api.file.DirectoryProperty
import org.gradle.api.provider.Property
import org.gradle.api.tasks.Input
import org.gradle.api.tasks.OutputDirectory
import org.gradle.api.tasks.TaskAction
import java.io.InputStream
import java.net.URI

abstract class DownloadArchiveFile<T : InputStream> : DefaultTask() {
    @get:Input
    abstract val url: Property<URI>

    @get:Input
    abstract val stripRoot: Property<Boolean>

    @get:Input
    abstract val subDirectory: Property<String>

    @get:OutputDirectory
    abstract val outputDir: DirectoryProperty

    init {
        subDirectory.convention("")
        stripRoot.convention(false)
    }

    fun url(string: String) {
        url.set(URI.create(string))
    }

    abstract fun mapInputStream(inputStream: InputStream): T
    abstract fun nextEntry(stream: T): String?

    @TaskAction
    fun execute() {
        val baseFolder = outputDir.get().asFile
        baseFolder.deleteRecursively()
        baseFolder.mkdirs()
        val pathFilter = this.subDirectory.get()
        require(pathFilter.isEmpty() || pathFilter.endsWith("/")) {
            "subdirectory '$pathFilter' does not end with a /"
        }
        url.get().toURL().openStream().buffered().use { input ->
            val mappedStream = mapInputStream(input)
            while (true) {
                val entry = nextEntry(mappedStream) ?: break
                var name = entry
                if (name.endsWith("/")) continue
                if (stripRoot.get()) {
                    name = name.substringAfter("/")
                }
                if (pathFilter.isNotEmpty()) {
                    if (!name.startsWith(pathFilter)) {
                        continue
                    } else {
                        name = name.substring(pathFilter.length)
                    }
                }
                val fileLocation = baseFolder.resolve(name).absoluteFile
                if (baseFolder !in generateSequence(fileLocation) { it.parentFile }) {
                    error("File escaping output jail: $name")
                }
                fileLocation.parentFile.mkdirs()
                fileLocation.outputStream().use { output ->
                    mappedStream.copyTo(output)
                }
            }
        }
    }
}