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:
parent
8883055337
commit
8eacf476a1
5 changed files with 97 additions and 49 deletions
|
@ -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)
|
||||
|
|
|
@ -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.
|
||||
*/
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue