Skip to content

Commit

Permalink
参考 TransformClassesWithAsmTask 实现对 Jars 的增量构建, 以保证远程构建缓存稳定
Browse files Browse the repository at this point in the history
  • Loading branch information
b7woreo committed Nov 18, 2023
1 parent 143694e commit df5510e
Show file tree
Hide file tree
Showing 2 changed files with 103 additions and 50 deletions.
41 changes: 41 additions & 0 deletions gradle-plugin/src/main/java/tracex/JarsIdentity.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package tracex

import org.gradle.api.file.ConfigurableFileCollection
import org.gradle.work.ChangeType
import org.gradle.work.InputChanges
import java.io.File

class JarsIdentity(
private val inputJars: ConfigurableFileCollection,
private val inputChanges: InputChanges,
) {

fun compute(): JarChanges {
val (changed, addedOrRemoved) = inputChanges
.getFileChanges(inputJars)
.partition { it.changeType == ChangeType.MODIFIED }

val reprocessAll = !inputChanges.isIncremental || addedOrRemoved.isNotEmpty()
val changedFiles = changed.map { it.file }.toSet()
val hasChanged = { file: File -> reprocessAll || (file in changedFiles) }
val jarsInfo = inputJars.files.mapIndexedNotNull { index: Int, file: File ->
if (!hasChanged(file)) null
else FileInfo(
identity = index.toString(),
file = file,
)
}

return JarChanges(jarsInfo, reprocessAll)
}

data class JarChanges(
val jarsInfo: List<FileInfo>,
val reprocessAll: Boolean,
)

data class FileInfo(
val identity: String,
val file: File,
)
}
112 changes: 62 additions & 50 deletions gradle-plugin/src/main/java/tracex/TraceTransformTask.kt
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,14 @@ import org.gradle.work.Incremental
import org.gradle.work.InputChanges
import org.gradle.workers.WorkAction
import org.gradle.workers.WorkParameters
import org.gradle.workers.WorkQueue
import org.gradle.workers.WorkerExecutor
import org.objectweb.asm.ClassReader
import org.objectweb.asm.ClassWriter
import org.objectweb.asm.Opcodes
import java.io.File
import java.io.InputStream
import java.io.OutputStream
import java.security.MessageDigest
import java.util.Locale
import java.util.jar.JarEntry
import java.util.jar.JarInputStream
Expand Down Expand Up @@ -71,50 +71,74 @@ abstract class TraceTransformTask : DefaultTask() {
@TaskAction
fun transform(inputChanges: InputChanges) {
val workQueue = workerExecutor.noIsolation()

val changedJars = inputChanges.getFileChanges(allJarsFileCollection)
val changedClasses = inputChanges.getFileChanges(allDirectoriesFileCollection)
val intermediate = intermediate.get().asFile

changedJars.forEach { changedJar ->
val intermediateJars = intermediate.resolve("jars")
val intermediateClasses = intermediate.resolve("classes")

transformJars(
inputChanges = inputChanges,
intermediate = intermediateJars,
workQueue = workQueue
)

transformClasses(
inputChanges = inputChanges,
intermediate = intermediateClasses,
workQueue = workQueue
)

workQueue.await()

mergeClasses(
outputJar.get().asFile,
intermediateClasses,
*(intermediateJars.listFiles() ?: emptyArray())
)
}

private fun transformJars(inputChanges: InputChanges, intermediate: File, workQueue: WorkQueue) {
val (jarChanges, reprocessAll) = JarsIdentity(
inputJars = allJarsFileCollection,
inputChanges = inputChanges
).compute()

if (reprocessAll) {
intermediate.deleteRecursively()
}

jarChanges.forEach { changedJar ->
workQueue.submit(TransformJar::class.java) {
it.rootDir.set(project.rootDir)
it.identity.set(changedJar.identity)
it.source.set(changedJar.file)
it.normalizedPath.set(changedJar.normalizedPath)
it.changeType.set(changedJar.changeType)
it.changeType.set(ChangeType.MODIFIED)
it.intermediate.set(intermediate)
}
}
}

changedClasses.forEach { changedClass ->
private fun transformClasses(inputChanges: InputChanges, intermediate: File, workQueue: WorkQueue) {
val classChanges = inputChanges.getFileChanges(allDirectoriesFileCollection)
classChanges.forEach { changedClass ->
workQueue.submit(TransformClass::class.java) {
it.rootDir.set(project.rootDir)
it.source.set(changedClass.file)
it.normalizedPath.set(changedClass.normalizedPath)
it.source.set(changedClass.file)
it.changeType.set(changedClass.changeType)
it.intermediate.set(intermediate)
}
}

workQueue.await()

mergeClasses(
intermediate,
outputJar.get().asFile,
)
}

private fun mergeClasses(
intermediate: File,
outputJar: File,
vararg classpath: File,
) {
JarOutputStream(
outputJar.outputStream()
.buffered()
).use { jar ->
jar.setLevel(Deflater.NO_COMPRESSION)

intermediate.listFiles()?.forEach { rootDir ->
classpath.forEach { rootDir ->
rootDir.allFiles { child ->
val name = child.toRelativeString(rootDir)
val entry = JarEntry(name)
Expand All @@ -126,17 +150,11 @@ abstract class TraceTransformTask : DefaultTask() {
}
}

abstract class Transform : WorkAction<Transform.Parameters> {

protected val rootDir: File
get() = parameters.rootDir.get().asFile
abstract class Transform<T : Transform.Parameters> : WorkAction<T> {

protected val source: File
get() = parameters.source.get().asFile

protected val normalizedPath: String
get() = parameters.normalizedPath.get()

protected val changeType: ChangeType
get() = parameters.changeType.get()

Expand All @@ -148,7 +166,7 @@ abstract class TraceTransformTask : DefaultTask() {
protected abstract fun transform()

final override fun execute() {
println("[$changeType] $source($normalizedPath) -> $destination")
println("[$changeType] $source -> $destination")

when (changeType) {
ChangeType.ADDED -> {
Expand Down Expand Up @@ -199,18 +217,18 @@ abstract class TraceTransformTask : DefaultTask() {
}

interface Parameters : WorkParameters {
val rootDir: DirectoryProperty
val source: RegularFileProperty
val normalizedPath: Property<String>
val changeType: Property<ChangeType>
val intermediate: DirectoryProperty
}
}

abstract class TransformJar : Transform() {
abstract class TransformJar : Transform<TransformJar.Parameters>() {
val identity: String
get() = parameters.identity.get()

override val destination: File
get() = File(intermediate, source.identify())
get() = File(intermediate, identity)

override fun transform() {
JarInputStream(
Expand All @@ -234,28 +252,18 @@ abstract class TraceTransformTask : DefaultTask() {
}
}

private fun File.identify(): String {
var current: File? = this
while (current != null) {
if (rootDir == current) {
return toRelativeString(rootDir).toSha256()
}
current = current.parentFile
}
return name.toSha256()
}

private fun String.toSha256(): String {
val md = MessageDigest.getInstance("SHA-256")
val bytes = md.digest(this.toByteArray())
return bytes.joinToString("") { "%02x".format(it) }
interface Parameters : Transform.Parameters {
val identity: Property<String>
}
}

abstract class TransformClass : Transform() {
abstract class TransformClass : Transform<TransformClass.Parameters>() {

protected val normalizedPath: String
get() = parameters.normalizedPath.get()

override val destination: File
get() = File(intermediate.resolve("classes"), normalizedPath)
get() = File(intermediate, normalizedPath)

override fun transform() {
if (!includeFileInTransform(normalizedPath)) return
Expand All @@ -272,6 +280,10 @@ abstract class TraceTransformTask : DefaultTask() {
}
}
}

interface Parameters : Transform.Parameters {
val normalizedPath: Property<String>
}
}

private fun File.allFiles(block: (File) -> Unit) {
Expand Down

0 comments on commit df5510e

Please sign in to comment.