1
0
Fork 0
mirror of https://github.com/ethauvin/kobalt.git synced 2025-04-26 00:17:11 -07:00

More incremental task work.

This commit is contained in:
Cedric Beust 2015-12-20 10:27:53 +04:00
parent 8883055337
commit 8eacf476a1
5 changed files with 97 additions and 49 deletions

View file

@ -2,4 +2,12 @@ package com.beust.kobalt
import com.beust.kobalt.api.Project
class IncrementalTaskInfo(val inputChecksum: String, val outputChecksum: String, task: (Project) -> TaskResult)
/**
* @param inputChecksum The checksum for the input to this task. It gets compared against the checksum of
* 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
* 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.
* @param task The task to run.
*/
class IncrementalTaskInfo(val inputChecksum: String, val outputChecksum: String?, val task: (Project) -> TaskResult)

View file

@ -1,6 +1,7 @@
package com.beust.kobalt
import com.beust.kobalt.api.*
import com.beust.kobalt.api.annotation.IncrementalTask
import com.beust.kobalt.api.annotation.Task
import com.beust.kobalt.internal.PluginInfo
import com.beust.kobalt.internal.TaskManager
@ -63,31 +64,13 @@ public class Plugins @Inject constructor (val taskManagerProvider : Provider<Tas
plugin.apply(project, context)
}
var currentClass : Class<in Any> = plugin.javaClass
// Tasks can come from two different places: plugin classes and build files.
// When a task is read from a build file, ScriptCompiler adds it right away to plugin.methodTasks.
// The following loop introspects the current plugin, finds all the tasks using the @Task annotation
// and adds them to plugin.methodTasks
while (! (currentClass.equals(Any::class.java))) {
currentClass.declaredMethods.map {
Pair(it, it.getAnnotation(Task::class.java))
}.filter {
it.second != null
}.filter {
isValidTaskMethod(it.first)
}.forEach {
if (Modifier.isPrivate(it.first.modifiers)) {
throw KobaltException("A task method cannot be private: ${it.first}")
}
val annotation = it.second
taskManager.addStaticTask(plugin, it.first, annotation)
}
currentClass = currentClass.superclass
findStaticTasks(plugin, Task::class.java, { method -> isValidTaskMethod(method)}).forEach {
taskManager.addAnnotationTask(plugin, it.first, it.second)
}
findStaticTasks(plugin, IncrementalTask::class.java,
{ method -> isValidIncrementalTaskMethod(method)}).forEach {
taskManager.addIncrementalTask(plugin, it.first, it.second)
}
}
// Collect all the tasks from the task contributors
@ -99,6 +82,47 @@ public class Plugins @Inject constructor (val taskManagerProvider : Provider<Tas
taskManager.computePluginTasks(plugins, projects)
}
private fun <T: Annotation> findStaticTasks(plugin: IPlugin, klass: Class<T>, validate: (Method) -> Boolean)
: List<Pair<Method, T>> {
val result = arrayListOf<Pair<Method, T>>()
var currentClass : Class<in Any> = plugin.javaClass
// Tasks can come from two different places: plugin classes and build files.
// When a task is read from a build file, ScriptCompiler adds it right away to plugin.methodTasks.
// The following loop introspects the current plugin, finds all the tasks using the @Task annotation
// and adds them to plugin.methodTasks
while (currentClass != null && ! (klass.equals(currentClass))) {
currentClass.declaredMethods.map {
Pair(it, it.getAnnotation(klass))
}.filter {
it.second != null
}.filter {
validate(it.first)
}.forEach {
if (Modifier.isPrivate(it.first.modifiers)) {
throw KobaltException("A task method cannot be private: ${it.first}")
}
result.add(it)
}
currentClass = currentClass.superclass
}
return result
}
/**
* Make sure this task method has the right signature.
*/
private fun isValidIncrementalTaskMethod(method: Method): Boolean {
val t = "Task ${method.declaringClass.simpleName}.${method.name}: "
if (method.returnType != IncrementalTaskInfo::class.java) {
throw IllegalArgumentException("${t}should return a IncrementalTaskInfo")
}
return true
}
/**
* Make sure this task method has the right signature.
*/

View file

@ -53,7 +53,7 @@ public class TaskManager @Inject constructor(val args: Args) {
// There can be multiple tasks by the same name (e.g. PackagingPlugin and AndroidPlugin both
// define "install"), so use a multimap
val tasksByNames = ArrayListMultimap.create<String, PluginTask>()
tasks.filter {
annotationTasks.filter {
it.project.name == project.name
}.forEach {
tasksByNames.put(it.name, it)
@ -221,33 +221,53 @@ public class TaskManager @Inject constructor(val args: Args) {
// Manage the tasks
//
// Both @Task and @IncrementalTask get stored as a TaskAnnotation so they can be treated uniformly
// Both @Task and @IncrementalTask get stored as a TaskAnnotation so they can be treated uniformly.
// They only differ in the way they are invoked (see below)
private val taskAnnotations = arrayListOf<TaskAnnotation>()
class TaskAnnotation(val method: Method, val plugin: IPlugin, val name: String, val description: String,
val runBefore: Array<String>, val runAfter: Array<String>, val alwaysRunAfter: Array<String>)
val runBefore: Array<String>, val runAfter: Array<String>, val alwaysRunAfter: Array<String>,
val callable: (Project) -> TaskResult)
/**
* Invoking a @Task means simply calling the method and returning its result TaskResult.
*/
fun toTaskAnnotation(method: Method, plugin: IPlugin, ta: Task)
= TaskAnnotation(method, plugin, ta.name, ta.description, ta.runBefore, ta.runAfter, ta.alwaysRunAfter)
= TaskAnnotation(method, plugin, ta.name, ta.description, ta.runBefore, ta.runAfter, ta.alwaysRunAfter,
{ project ->
method.invoke(plugin, project) as TaskResult
})
/**
* Invoking an @IncrementalTask means invoking the method and then deciding what to do based on the content
* of the returned IncrementalTaskInfo.
*/
fun toTaskAnnotation(method: Method, plugin: IPlugin, ta: IncrementalTask)
= TaskAnnotation(method, plugin, ta.name, ta.description, ta.runBefore, ta.runAfter, ta.alwaysRunAfter)
= TaskAnnotation(method, plugin, ta.name, ta.description, ta.runBefore, ta.runAfter, ta.alwaysRunAfter,
{ project ->
val iit = method.invoke(plugin, project) as IncrementalTaskInfo
iit.task(project)
})
class PluginDynamicTask(val plugin: IPlugin, val task: DynamicTask)
val tasks = arrayListOf<PluginTask>()
/** Tasks annotated with @Task or @IncrementalTask */
val annotationTasks = arrayListOf<PluginTask>()
/** Tasks provided by ITaskContributors */
val dynamicTasks = arrayListOf<PluginDynamicTask>()
fun addStaticTask(plugin: IPlugin, method: Method, annotation: Task) =
fun addAnnotationTask(plugin: IPlugin, method: Method, annotation: Task) =
taskAnnotations.add(toTaskAnnotation(method, plugin, annotation))
fun addIncrementalTask(plugin: IPlugin, method: Method, annotation: IncrementalTask) =
taskAnnotations.add(toTaskAnnotation(method, plugin, annotation))
taskAnnotations.add(toTaskAnnotation(method, plugin, annotation))
/**
* Turn all the static and dynamic tasks into plug-in tasks, which are then suitable to be executed.
*/
fun computePluginTasks(plugins: List<IPlugin>, projects: List<Project>) {
addStaticTasks(projects)
installAnnotationTasks(projects)
addDynamicTasks(projects)
}
@ -261,28 +281,21 @@ public class TaskManager @Inject constructor(val args: Args) {
}
}
private fun addStaticTasks(projects: List<Project>) {
private fun installAnnotationTasks(projects: List<Project>) {
taskAnnotations.forEach { staticTask ->
val method = staticTask.method
val methodName = method.declaringClass.toString() + "." + method.name
log(3, " Found task:${staticTask.name} method: $methodName")
fun toTask(m: Method, project: Project, plugin: IPlugin): (Project) -> TaskResult {
val result: (Project) -> TaskResult = {
m.invoke(plugin, project) as TaskResult
}
return result
}
val plugin = staticTask.plugin
projects.filter { plugin.accept(it) }.forEach { project ->
addStaticTask(plugin, project, staticTask, toTask(method, project, plugin))
addAnnotationTask(plugin, project, staticTask, staticTask.callable)
}
}
}
private fun addStaticTask(plugin: IPlugin, project: Project, annotation: TaskAnnotation,
private fun addAnnotationTask(plugin: IPlugin, project: Project, annotation: TaskAnnotation,
task: (Project) -> TaskResult) {
addTask(plugin, project, annotation.name, annotation.description, annotation.runBefore.toList(),
annotation.runAfter.toList(), annotation.alwaysRunAfter.toList(), task)
@ -293,7 +306,7 @@ public class TaskManager @Inject constructor(val args: Args) {
runAfter: List<String> = listOf<String>(),
alwaysRunAfter: List<String> = listOf<String>(),
task: (Project) -> TaskResult) {
tasks.add(
annotationTasks.add(
object : BasePluginTask(plugin, name, description, project) {
override fun call(): TaskResult2<PluginTask> {
val taskResult = task(project)