Files
ClashForAndroid/buildSrc/src/main/java/GolangBindTask.kt
T
2019-12-14 14:42:00 +08:00

138 lines
4.2 KiB
Kotlin

import org.apache.tools.ant.taskdefs.condition.Os
import org.gradle.api.DefaultTask
import org.gradle.api.GradleException
import org.gradle.api.tasks.TaskAction
import java.io.File
import java.io.FileReader
import java.io.FileWriter
import java.util.*
import kotlin.concurrent.thread
open class GolangBindTask : DefaultTask() {
companion object {
private val STUB_GO_MOD_CONTENT = """
module github.com/kr328/cfa-bind
require (
github.com/kr328/cfa v0.0.0 // redirect
github.com/Dreamacro/clash v0.0.0 // redirect
)
replace github.com/kr328/cfa v0.0.0 => {SOURCE_PATH}
replace github.com/Dreamacro/clash v0.0.0 => {SOURCE_PATH}/clash
""".trimIndent()
private val STUB_GO_FILE_CONTENT = """
package main
import "github.com/kr328/cfa/bridge"
func main() {}
""".trimIndent()
}
val javaOutput: File
get() {
return project.buildDir.resolve("intermediates/go_output/generate_java")
}
val nativeOutput: File
get() {
return project.buildDir.resolve("intermediates/go_output/native_library")
}
private val goBuildPath: File
get() {
return project.buildDir.resolve("intermediates/go_build")
}
private val goPath: File
get() {
return goBuildPath.resolve("go_path")
}
private val goBindPath: File
get() {
return goBuildPath.resolve("go_bind_path")
}
private val sourcePath: File
get() {
return project.file("src/main/golang")
}
private val properties by lazy {
FileReader(project.rootProject.file("local.properties")).use {
Properties().apply { load(it) }
}
}
private val environment = mutableMapOf<String, String>()
init {
}
@TaskAction
fun process() {
environment.put("GOPATH", goPath.absolutePath)
environment.put("ANDROID_HOME", findAndroidSdkPath().absolutePath)
environment.put("ANDROID_NDK_HOME", findAndroidNdkPath().absolutePath)
if ( Os.isFamily(Os.FAMILY_WINDOWS) )
environment.put("Path", System.getenv("Path") + ";" + goPath.resolve("bin"))
else
environment.put("PATH", System.getenv("PATH") + ":" + goPath.resolve("bin"))
goBindPath.deleteRecursively()
goBindPath.mkdirs()
"go get golang.org/x/mobile/cmd/gomobile".exec()
FileWriter(goBindPath.resolve("go.mod")).use {
it.write(STUB_GO_MOD_CONTENT.replace("{SOURCE_PATH}", sourcePath.absolutePath))
}
FileWriter(goBindPath.resolve("main.go")).use {
it.write(STUB_GO_FILE_CONTENT)
}
"go mod vendor".exec(goBindPath)
goBindPath.resolve("vendor")
.copyRecursively(goPath.resolve("src"), overwrite = true)
"gomobile init".exec(goBuildPath)
"gomobile bind -target=android github.com/kr328/cfa/bridge".exec(goBuildPath)
}
private fun findAndroidNdkPath(): File {
return properties.getProperty("ndk.dir")?.let { File(it) }?.takeIf { it.exists() }
?: throw GradleException("Android NDK not found.")
}
private fun findAndroidSdkPath(): File {
return properties.getProperty("sdk.dir")?.let { File(it) }?.takeIf { it.exists() }
?: throw GradleException("Android SDK not found.")
}
private fun String.exec(pwd: File = File(".")) {
val process = with (ProcessBuilder()) {
if ( Os.isFamily(Os.FAMILY_WINDOWS) )
command("cmd.exe", "/c", this@exec)
else
command("bash", "-c", this@exec)
environment().putAll(environment)
directory(pwd)
redirectErrorStream(true)
start()
}
process.inputStream.copyTo(System.out)
println()
if ( process.waitFor() != 0 )
throw GradleException("Run command $this failure")
}
private fun String.exe(): String {
return if ( Os.isFamily(Os.FAMILY_WINDOWS) )
"$this.exe"
else
this
}
}