mirror of
https://github.com/ethauvin/kobalt.git
synced 2025-04-26 16:28:12 -07:00
Make "assemble" incremental.
This commit is contained in:
parent
181a043047
commit
1ae9baa97d
6 changed files with 112 additions and 104 deletions
|
@ -1,5 +1,6 @@
|
||||||
package com.beust.kobalt
|
package com.beust.kobalt
|
||||||
|
|
||||||
|
import com.beust.kobalt.api.KobaltContext
|
||||||
import com.beust.kobalt.api.Project
|
import com.beust.kobalt.api.Project
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -7,10 +8,10 @@ import com.beust.kobalt.api.Project
|
||||||
* calculated by Kobalt. If they differ, the task gets run. If they are equal, outputChecksums are then compared.
|
* calculated by Kobalt. If they differ, the task gets run. If they are equal, outputChecksums are then compared.
|
||||||
* @param outputChecksum The checksum for the output of this task. If null, the output is absent
|
* @param outputChecksum The checksum for the output of this task. If null, the output is absent
|
||||||
* and the task will be run. If non null, it gets compared against the checksum of the previous run and
|
* and the task will be run. If non null, it gets compared against the checksum of the previous run and
|
||||||
* if they differ, the task gets run. Note that this parameter is a closure and not a direct value
|
* if they differ, the task gets run.
|
||||||
* because Kobalt needs to call it twice: once before the task and once after a successful execution (to store it).
|
|
||||||
* @param task The task to run.
|
* @param task The task to run.
|
||||||
*/
|
*/
|
||||||
class IncrementalTaskInfo(val inputChecksum: String?,
|
class IncrementalTaskInfo(val inputChecksum: () -> String?,
|
||||||
val outputChecksum: () -> String?,
|
val outputChecksum: () -> String?,
|
||||||
val task: (Project) -> TaskResult)
|
val task: (Project) -> TaskResult,
|
||||||
|
val context: KobaltContext)
|
||||||
|
|
|
@ -8,7 +8,7 @@ import com.beust.kobalt.internal.PluginInfo
|
||||||
import com.beust.kobalt.maven.DependencyManager
|
import com.beust.kobalt.maven.DependencyManager
|
||||||
import com.beust.kobalt.misc.KobaltExecutors
|
import com.beust.kobalt.misc.KobaltExecutors
|
||||||
|
|
||||||
public class KobaltContext(val args: Args) {
|
class KobaltContext(val args: Args) {
|
||||||
var variant: Variant = Variant()
|
var variant: Variant = Variant()
|
||||||
val profiles = arrayListOf<String>()
|
val profiles = arrayListOf<String>()
|
||||||
|
|
||||||
|
@ -20,6 +20,14 @@ public class KobaltContext(val args: Args) {
|
||||||
|
|
||||||
fun findPlugin(name: String) = Plugins.findPlugin(name)
|
fun findPlugin(name: String) = Plugins.findPlugin(name)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When an incremental task decides it's up to date, it sets this boolean to true so that subsequent
|
||||||
|
* tasks in that project can be skipped as well. This is an internal field that should only be set by Kobalt.
|
||||||
|
*/
|
||||||
|
private val incrementalSuccesses = hashSetOf<String>()
|
||||||
|
fun previousTaskWasIncrementalSuccess(projectName: String) = incrementalSuccesses.contains(projectName) ?: false
|
||||||
|
fun setIncrementalSuccess(projectName: String) = incrementalSuccesses.add(projectName)
|
||||||
|
|
||||||
//
|
//
|
||||||
// Injected
|
// Injected
|
||||||
//
|
//
|
||||||
|
|
|
@ -84,62 +84,72 @@ class IncrementalManager(val fileName: String = IncrementalManager.BUILD_INFO_FI
|
||||||
val taskName = project.name + ":" + shortTaskName
|
val taskName = project.name + ":" + shortTaskName
|
||||||
var upToDate = false
|
var upToDate = false
|
||||||
var taskOutputChecksum : String? = null
|
var taskOutputChecksum : String? = null
|
||||||
//
|
|
||||||
// First, compare the input checksums
|
|
||||||
//
|
|
||||||
inputChecksumFor(taskName)?.let { inputChecksum ->
|
|
||||||
val dependsOnDirtyProjects = project.projectExtra.dependsOnDirtyProjects(project)
|
|
||||||
if (inputChecksum == iti.inputChecksum && ! dependsOnDirtyProjects) {
|
|
||||||
//
|
|
||||||
// Input checksums are equal, compare the output checksums
|
|
||||||
//
|
|
||||||
outputChecksumFor(taskName)?.let { outputChecksum ->
|
|
||||||
taskOutputChecksum = iti.outputChecksum()
|
|
||||||
if (outputChecksum == taskOutputChecksum) {
|
|
||||||
upToDate = true
|
|
||||||
} else {
|
|
||||||
logIncremental(LEVEL, "Incremental task $taskName output is out of date, running it")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (dependsOnDirtyProjects) {
|
|
||||||
logIncremental(LEVEL, "Project ${project.name} depends on dirty project, running $taskName")
|
|
||||||
} else {
|
|
||||||
logIncremental(LEVEL, "Incremental task $taskName input is out of date, running it"
|
|
||||||
+ " old: $inputChecksum new: ${iti.inputChecksum}")
|
|
||||||
}
|
|
||||||
project.projectExtra.isDirty = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (! upToDate) {
|
if (iti.context.previousTaskWasIncrementalSuccess(project.name)) {
|
||||||
//
|
//
|
||||||
// The task is out of date, invoke the task on the IncrementalTaskInfo object
|
// If the previous task was an incremental success, no need to run
|
||||||
//
|
//
|
||||||
val result = iti.task(project)
|
logIncremental(LEVEL, "Previous incremental task was a success, not running $shortTaskName")
|
||||||
if (result.success) {
|
TaskResult()
|
||||||
logIncremental(LEVEL, "Incremental task $taskName done running, saving checksums")
|
|
||||||
iti.inputChecksum?.let {
|
|
||||||
saveInputChecksum(taskName, it)
|
|
||||||
logIncremental(LEVEL, " input checksum \"$it\" saved")
|
|
||||||
}
|
|
||||||
// Important to rerun the checksum here since the output of the task might have changed it
|
|
||||||
iti.outputChecksum()?.let {
|
|
||||||
saveOutputChecksum(taskName, it)
|
|
||||||
logIncremental(LEVEL, " output checksum \"$it\" saved")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
result
|
|
||||||
} else {
|
} else {
|
||||||
//
|
//
|
||||||
// Identical input and output checksums, don't run the task
|
// First, compare the input checksums
|
||||||
//
|
//
|
||||||
logIncremental(LEVEL, "Incremental task \"$taskName\" is up to date, not running it")
|
inputChecksumFor(taskName)?.let { inputChecksum ->
|
||||||
TaskResult()
|
val dependsOnDirtyProjects = project.projectExtra.dependsOnDirtyProjects(project)
|
||||||
|
if (inputChecksum == iti.inputChecksum() && !dependsOnDirtyProjects) {
|
||||||
|
//
|
||||||
|
// Input checksums are equal, compare the output checksums
|
||||||
|
//
|
||||||
|
outputChecksumFor(taskName)?.let { outputChecksum ->
|
||||||
|
taskOutputChecksum = iti.outputChecksum()
|
||||||
|
if (outputChecksum == taskOutputChecksum) {
|
||||||
|
upToDate = true
|
||||||
|
} else {
|
||||||
|
logIncremental(LEVEL, "Incremental task $taskName output is out of date, running it")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (dependsOnDirtyProjects) {
|
||||||
|
logIncremental(LEVEL, "Project ${project.name} depends on dirty project, running $taskName")
|
||||||
|
} else {
|
||||||
|
logIncremental(LEVEL, "Incremental task $taskName input is out of date, running it"
|
||||||
|
+ " old: $inputChecksum new: ${iti.inputChecksum()}")
|
||||||
|
}
|
||||||
|
project.projectExtra.isDirty = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!upToDate) {
|
||||||
|
//
|
||||||
|
// The task is out of date, invoke the task on the IncrementalTaskInfo object
|
||||||
|
//
|
||||||
|
val result = iti.task(project)
|
||||||
|
if (result.success) {
|
||||||
|
logIncremental(LEVEL, "Incremental task $taskName done running, saving checksums")
|
||||||
|
iti.inputChecksum()?.let {
|
||||||
|
saveInputChecksum(taskName, it)
|
||||||
|
logIncremental(LEVEL, " input checksum \"$it\" saved")
|
||||||
|
}
|
||||||
|
// Important to rerun the checksum here since the output of the task might have changed it
|
||||||
|
iti.outputChecksum()?.let {
|
||||||
|
saveOutputChecksum(taskName, it)
|
||||||
|
logIncremental(LEVEL, " output checksum \"$it\" saved")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
result
|
||||||
|
} else {
|
||||||
|
//
|
||||||
|
// Identical input and output checksums, don't run the task
|
||||||
|
//
|
||||||
|
logIncremental(LEVEL, "Incremental task \"$taskName\" is up to date, not running it")
|
||||||
|
iti.context.setIncrementalSuccess(project.name)
|
||||||
|
TaskResult()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val LEVEL = 3
|
val LEVEL = 2
|
||||||
private fun logIncremental(level: Int, s: String) = log(level, " INC - $s")
|
private fun logIncremental(level: Int, s: String) = log(level, " INC - $s")
|
||||||
}
|
}
|
||||||
|
|
|
@ -143,22 +143,22 @@ open class JvmCompilerPlugin @Inject constructor(
|
||||||
runAfter = arrayOf(JvmCompilerPlugin.TASK_COMPILE))
|
runAfter = arrayOf(JvmCompilerPlugin.TASK_COMPILE))
|
||||||
fun taskCompileTest(project: Project): IncrementalTaskInfo {
|
fun taskCompileTest(project: Project): IncrementalTaskInfo {
|
||||||
sourceTestDirectories.addAll(context.variant.sourceDirectories(project, context, SourceSet.of(isTest = true)))
|
sourceTestDirectories.addAll(context.variant.sourceDirectories(project, context, SourceSet.of(isTest = true)))
|
||||||
val inputChecksum = Md5.toMd5Directories(context.testSourceDirectories(project).map {
|
|
||||||
File(project.directory, it.path)
|
|
||||||
})
|
|
||||||
return IncrementalTaskInfo(
|
return IncrementalTaskInfo(
|
||||||
inputChecksum = inputChecksum,
|
inputChecksum = {
|
||||||
outputChecksum = {
|
Md5.toMd5Directories(context.testSourceDirectories(project).map { File(project.directory, it.path)})
|
||||||
Md5.toMd5Directories(listOf(KFiles.makeOutputTestDir(project)))
|
},
|
||||||
},
|
outputChecksum = {
|
||||||
task = { project -> doTaskCompileTest(project) }
|
Md5.toMd5Directories(listOf(KFiles.makeOutputTestDir(project)))
|
||||||
|
},
|
||||||
|
task = { project -> doTaskCompileTest(project)},
|
||||||
|
context = context
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@IncrementalTask(name = JvmCompilerPlugin.TASK_COMPILE, description = "Compile the project")
|
@IncrementalTask(name = JvmCompilerPlugin.TASK_COMPILE, description = "Compile the project")
|
||||||
fun taskCompile(project: Project): IncrementalTaskInfo {
|
fun taskCompile(project: Project): IncrementalTaskInfo {
|
||||||
// Generate the BuildConfig before invoking sourceDirectories() since that call
|
// Generate the BuildConfig before invoking sourceDirectories() since that call
|
||||||
// might add the buildConfig source directori
|
// might add the buildConfig source directories
|
||||||
val sourceDirectory = context.variant.maybeGenerateBuildConfig(project, context)
|
val sourceDirectory = context.variant.maybeGenerateBuildConfig(project, context)
|
||||||
if (sourceDirectory != null) {
|
if (sourceDirectory != null) {
|
||||||
sourceDirectories.add(sourceDirectory)
|
sourceDirectories.add(sourceDirectory)
|
||||||
|
@ -167,15 +167,15 @@ open class JvmCompilerPlugin @Inject constructor(
|
||||||
// Set up the source files now that we have the variant
|
// Set up the source files now that we have the variant
|
||||||
sourceDirectories.addAll(context.variant.sourceDirectories(project, context, SourceSet.of(isTest = false)))
|
sourceDirectories.addAll(context.variant.sourceDirectories(project, context, SourceSet.of(isTest = false)))
|
||||||
|
|
||||||
val inputChecksum = Md5.toMd5Directories(context.sourceDirectories(project).map {
|
|
||||||
File(project.directory, it.path)
|
|
||||||
})
|
|
||||||
return IncrementalTaskInfo(
|
return IncrementalTaskInfo(
|
||||||
inputChecksum = inputChecksum,
|
inputChecksum = {
|
||||||
|
Md5.toMd5Directories(context.sourceDirectories(project).map { File(project.directory, it.path) })
|
||||||
|
},
|
||||||
outputChecksum = {
|
outputChecksum = {
|
||||||
Md5.toMd5Directories(listOf(File(project.directory, project.classesDir(context))))
|
Md5.toMd5Directories(listOf(File(project.directory, project.classesDir(context))))
|
||||||
},
|
},
|
||||||
task = { project -> doTaskCompile(project) }
|
task = { project -> doTaskCompile(project) },
|
||||||
|
context = context
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -30,7 +30,7 @@ public class Md5 {
|
||||||
fileCount++
|
fileCount++
|
||||||
} else {
|
} else {
|
||||||
val files = KFiles.findRecursively(file) // , { f -> f.endsWith("java")})
|
val files = KFiles.findRecursively(file) // , { f -> f.endsWith("java")})
|
||||||
log(2, " Calculating checksum of ${files.size} files in $file")
|
log(2, " Calculating checksum of ${files.size} files in $file")
|
||||||
files.map {
|
files.map {
|
||||||
File(file, it)
|
File(file, it)
|
||||||
}.filter {
|
}.filter {
|
||||||
|
|
|
@ -1,14 +1,11 @@
|
||||||
package com.beust.kobalt.plugin.packaging
|
package com.beust.kobalt.plugin.packaging
|
||||||
|
|
||||||
import com.beust.kobalt.JarGenerator
|
import com.beust.kobalt.*
|
||||||
import com.beust.kobalt.KobaltException
|
|
||||||
import com.beust.kobalt.TaskResult
|
|
||||||
import com.beust.kobalt.api.*
|
import com.beust.kobalt.api.*
|
||||||
import com.beust.kobalt.api.annotation.Directive
|
import com.beust.kobalt.api.annotation.Directive
|
||||||
import com.beust.kobalt.api.annotation.ExportedProjectProperty
|
import com.beust.kobalt.api.annotation.ExportedProjectProperty
|
||||||
import com.beust.kobalt.api.annotation.Task
|
import com.beust.kobalt.api.annotation.Task
|
||||||
import com.beust.kobalt.archive.*
|
import com.beust.kobalt.archive.*
|
||||||
import com.beust.kobalt.glob
|
|
||||||
import com.beust.kobalt.internal.IncrementalManager
|
import com.beust.kobalt.internal.IncrementalManager
|
||||||
import com.beust.kobalt.internal.JvmCompilerPlugin
|
import com.beust.kobalt.internal.JvmCompilerPlugin
|
||||||
import com.beust.kobalt.maven.DependencyManager
|
import com.beust.kobalt.maven.DependencyManager
|
||||||
|
@ -26,7 +23,8 @@ class PackagingPlugin @Inject constructor(val dependencyManager : DependencyMana
|
||||||
val executors: KobaltExecutors, val jarGenerator: JarGenerator, val warGenerator: WarGenerator,
|
val executors: KobaltExecutors, val jarGenerator: JarGenerator, val warGenerator: WarGenerator,
|
||||||
val zipGenerator: ZipGenerator, val taskContributor: TaskContributor,
|
val zipGenerator: ZipGenerator, val taskContributor: TaskContributor,
|
||||||
val pomFactory: PomGenerator.IFactory, val configActor: ConfigActor<InstallConfig>)
|
val pomFactory: PomGenerator.IFactory, val configActor: ConfigActor<InstallConfig>)
|
||||||
: BasePlugin(), ITaskContributor, IAssemblyContributor, IConfigActor<InstallConfig> by configActor {
|
: BasePlugin(), ITaskContributor, IIncrementalAssemblyContributor,
|
||||||
|
IConfigActor<InstallConfig> by configActor {
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
const val PLUGIN_NAME = "Packaging"
|
const val PLUGIN_NAME = "Packaging"
|
||||||
|
@ -53,39 +51,30 @@ class PackagingPlugin @Inject constructor(val dependencyManager : DependencyMana
|
||||||
runTask = { doTaskAssemble(project) })
|
runTask = { doTaskAssemble(project) })
|
||||||
}
|
}
|
||||||
|
|
||||||
// IAssemblyContributor
|
/**
|
||||||
override fun assemble(project: Project, context: KobaltContext) : TaskResult {
|
* "assemble" is an incremental task but with a twist. Because it can be costly to determine if any
|
||||||
try {
|
* of the class files generated in the previous phase is new or not, we just don't do that and always
|
||||||
project.projectProperties.put(PACKAGES, packages)
|
* return "null" for both input and output checksums, which would cause that task to always be rerun.
|
||||||
packages.filter { it.project.name == project.name }.forEach { pkg ->
|
* However, we are depending on Kobalt's cascading incremental management to skip up whenever appropriate:
|
||||||
pkg.jars.forEach { jarGenerator.generateJar(pkg.project, context, it) }
|
* whenever a previous incremental task was a success, all following incremental tasks are automatically
|
||||||
pkg.wars.forEach { warGenerator.generateWar(pkg.project, context, it) }
|
* skipped.
|
||||||
pkg.zips.forEach { zipGenerator.generateZip(pkg.project, context, it) }
|
*/
|
||||||
if (pkg.generatePom) {
|
override fun assemble(project: Project, context: KobaltContext) : IncrementalTaskInfo {
|
||||||
pomFactory.create(project).generate()
|
return IncrementalTaskInfo({ null }, { null }, { project ->
|
||||||
|
try {
|
||||||
|
project.projectProperties.put(PACKAGES, packages)
|
||||||
|
packages.filter { it.project.name == project.name }.forEach { pkg ->
|
||||||
|
pkg.jars.forEach { jarGenerator.generateJar(pkg.project, context, it) }
|
||||||
|
pkg.wars.forEach { warGenerator.generateWar(pkg.project, context, it) }
|
||||||
|
pkg.zips.forEach { zipGenerator.generateZip(pkg.project, context, it) }
|
||||||
|
if (pkg.generatePom) {
|
||||||
|
pomFactory.create(project).generate()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
TaskResult()
|
||||||
return TaskResult()
|
} catch(ex: Exception) {
|
||||||
} catch(ex: Exception) {
|
throw KobaltException(ex)
|
||||||
throw KobaltException(ex)
|
}}, context)
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun doAssemble(project: Project, context: KobaltContext) : TaskResult {
|
|
||||||
try {
|
|
||||||
project.projectProperties.put(PACKAGES, packages)
|
|
||||||
packages.filter { it.project.name == project.name }.forEach { pkg ->
|
|
||||||
pkg.jars.forEach { jarGenerator.generateJar(pkg.project, context, it) }
|
|
||||||
pkg.wars.forEach { warGenerator.generateWar(pkg.project, context, it) }
|
|
||||||
pkg.zips.forEach { zipGenerator.generateZip(pkg.project, context, it) }
|
|
||||||
if (pkg.generatePom) {
|
|
||||||
pomFactory.create(project).generate()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return TaskResult()
|
|
||||||
} catch(ex: Exception) {
|
|
||||||
throw KobaltException(ex)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Task(name = TASK_ASSEMBLE, description = "Package the artifacts",
|
@Task(name = TASK_ASSEMBLE, description = "Package the artifacts",
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue