mirror of
https://github.com/ethauvin/kobalt.git
synced 2025-04-26 08:27:12 -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
|
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
|
package com.beust.kobalt
|
||||||
|
|
||||||
import com.beust.kobalt.api.*
|
import com.beust.kobalt.api.*
|
||||||
|
import com.beust.kobalt.api.annotation.IncrementalTask
|
||||||
import com.beust.kobalt.api.annotation.Task
|
import com.beust.kobalt.api.annotation.Task
|
||||||
import com.beust.kobalt.internal.PluginInfo
|
import com.beust.kobalt.internal.PluginInfo
|
||||||
import com.beust.kobalt.internal.TaskManager
|
import com.beust.kobalt.internal.TaskManager
|
||||||
|
@ -63,31 +64,13 @@ public class Plugins @Inject constructor (val taskManagerProvider : Provider<Tas
|
||||||
plugin.apply(project, context)
|
plugin.apply(project, context)
|
||||||
}
|
}
|
||||||
|
|
||||||
var currentClass : Class<in Any> = plugin.javaClass
|
findStaticTasks(plugin, Task::class.java, { method -> isValidTaskMethod(method)}).forEach {
|
||||||
|
taskManager.addAnnotationTask(plugin, it.first, it.second)
|
||||||
// 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.
|
findStaticTasks(plugin, IncrementalTask::class.java,
|
||||||
// The following loop introspects the current plugin, finds all the tasks using the @Task annotation
|
{ method -> isValidIncrementalTaskMethod(method)}).forEach {
|
||||||
// and adds them to plugin.methodTasks
|
taskManager.addIncrementalTask(plugin, it.first, it.second)
|
||||||
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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Collect all the tasks from the task contributors
|
// 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)
|
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.
|
* 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
|
// There can be multiple tasks by the same name (e.g. PackagingPlugin and AndroidPlugin both
|
||||||
// define "install"), so use a multimap
|
// define "install"), so use a multimap
|
||||||
val tasksByNames = ArrayListMultimap.create<String, PluginTask>()
|
val tasksByNames = ArrayListMultimap.create<String, PluginTask>()
|
||||||
tasks.filter {
|
annotationTasks.filter {
|
||||||
it.project.name == project.name
|
it.project.name == project.name
|
||||||
}.forEach {
|
}.forEach {
|
||||||
tasksByNames.put(it.name, it)
|
tasksByNames.put(it.name, it)
|
||||||
|
@ -221,33 +221,53 @@ public class TaskManager @Inject constructor(val args: Args) {
|
||||||
// Manage the tasks
|
// 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>()
|
private val taskAnnotations = arrayListOf<TaskAnnotation>()
|
||||||
class TaskAnnotation(val method: Method, val plugin: IPlugin, val name: String, val description: String,
|
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)
|
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)
|
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)
|
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>()
|
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))
|
taskAnnotations.add(toTaskAnnotation(method, plugin, annotation))
|
||||||
|
|
||||||
fun addIncrementalTask(plugin: IPlugin, method: Method, annotation: IncrementalTask) =
|
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.
|
* 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>) {
|
fun computePluginTasks(plugins: List<IPlugin>, projects: List<Project>) {
|
||||||
addStaticTasks(projects)
|
installAnnotationTasks(projects)
|
||||||
addDynamicTasks(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 ->
|
taskAnnotations.forEach { staticTask ->
|
||||||
val method = staticTask.method
|
val method = staticTask.method
|
||||||
|
|
||||||
val methodName = method.declaringClass.toString() + "." + method.name
|
val methodName = method.declaringClass.toString() + "." + method.name
|
||||||
log(3, " Found task:${staticTask.name} method: $methodName")
|
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
|
val plugin = staticTask.plugin
|
||||||
projects.filter { plugin.accept(it) }.forEach { project ->
|
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) {
|
task: (Project) -> TaskResult) {
|
||||||
addTask(plugin, project, annotation.name, annotation.description, annotation.runBefore.toList(),
|
addTask(plugin, project, annotation.name, annotation.description, annotation.runBefore.toList(),
|
||||||
annotation.runAfter.toList(), annotation.alwaysRunAfter.toList(), task)
|
annotation.runAfter.toList(), annotation.alwaysRunAfter.toList(), task)
|
||||||
|
@ -293,7 +306,7 @@ public class TaskManager @Inject constructor(val args: Args) {
|
||||||
runAfter: List<String> = listOf<String>(),
|
runAfter: List<String> = listOf<String>(),
|
||||||
alwaysRunAfter: List<String> = listOf<String>(),
|
alwaysRunAfter: List<String> = listOf<String>(),
|
||||||
task: (Project) -> TaskResult) {
|
task: (Project) -> TaskResult) {
|
||||||
tasks.add(
|
annotationTasks.add(
|
||||||
object : BasePluginTask(plugin, name, description, project) {
|
object : BasePluginTask(plugin, name, description, project) {
|
||||||
override fun call(): TaskResult2<PluginTask> {
|
override fun call(): TaskResult2<PluginTask> {
|
||||||
val taskResult = task(project)
|
val taskResult = task(project)
|
||||||
|
|
|
@ -214,7 +214,7 @@ private class Main @Inject constructor(
|
||||||
// List of tasks, --tasks
|
// List of tasks, --tasks
|
||||||
//
|
//
|
||||||
val tasksByPlugins = HashMultimap.create<String, PluginTask>()
|
val tasksByPlugins = HashMultimap.create<String, PluginTask>()
|
||||||
taskManager.tasks.forEach {
|
taskManager.annotationTasks.forEach {
|
||||||
tasksByPlugins.put(it.plugin.name, it)
|
tasksByPlugins.put(it.plugin.name, it)
|
||||||
}
|
}
|
||||||
val sb = StringBuffer("List of tasks\n")
|
val sb = StringBuffer("List of tasks\n")
|
||||||
|
|
|
@ -5,6 +5,7 @@ import com.beust.kobalt.Plugins
|
||||||
import com.beust.kobalt.api.IPlugin
|
import com.beust.kobalt.api.IPlugin
|
||||||
import com.beust.kobalt.api.KobaltContext
|
import com.beust.kobalt.api.KobaltContext
|
||||||
import com.beust.kobalt.api.Project
|
import com.beust.kobalt.api.Project
|
||||||
|
import com.beust.kobalt.api.annotation.IncrementalTask
|
||||||
import com.beust.kobalt.api.annotation.Task
|
import com.beust.kobalt.api.annotation.Task
|
||||||
import com.beust.kobalt.internal.TaskManager
|
import com.beust.kobalt.internal.TaskManager
|
||||||
import com.beust.kobalt.internal.build.BuildFile
|
import com.beust.kobalt.internal.build.BuildFile
|
||||||
|
@ -85,9 +86,11 @@ class BuildScriptUtil @Inject constructor(val plugins: Plugins, val files: KFile
|
||||||
throw ex.cause ?: KobaltException(ex)
|
throw ex.cause ?: KobaltException(ex)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
val taskAnnotation = method.getAnnotation(Task::class.java)
|
method.getAnnotation(Task::class.java)?.let {
|
||||||
if (taskAnnotation != null) {
|
taskManager.addAnnotationTask(defaultPlugin, method, it)
|
||||||
taskManager.addStaticTask(defaultPlugin, method, taskAnnotation)
|
}
|
||||||
|
method.getAnnotation(IncrementalTask::class.java)?.let {
|
||||||
|
taskManager.addIncrementalTask(defaultPlugin, method, it)
|
||||||
}
|
}
|
||||||
|
|
||||||
}}
|
}}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue