mirror of
https://github.com/ethauvin/kobalt.git
synced 2025-04-26 16:28:12 -07:00
Revamp the graph dependency/ordering logic.
This commit is contained in:
parent
2dd20b43b1
commit
458b40eafc
10 changed files with 128 additions and 175 deletions
|
@ -11,7 +11,8 @@ interface ITaskContributor : IContributor {
|
||||||
}
|
}
|
||||||
|
|
||||||
class DynamicTask(val plugin: IPlugin, val name: String, val description: String = "",
|
class DynamicTask(val plugin: IPlugin, val name: String, val description: String = "",
|
||||||
|
val dependsOn: List<String> = listOf<String>(),
|
||||||
|
val reverseDependsOn: List<String> = listOf<String>(),
|
||||||
val runBefore: List<String> = listOf<String>(),
|
val runBefore: List<String> = listOf<String>(),
|
||||||
val runAfter: List<String> = listOf<String>(),
|
val runAfter: List<String> = listOf<String>(),
|
||||||
val alwaysRunAfter: List<String> = listOf<String>(),
|
|
||||||
val closure: (Project) -> TaskResult)
|
val closure: (Project) -> TaskResult)
|
||||||
|
|
|
@ -23,16 +23,18 @@ class TaskContributor @Inject constructor(val incrementalManagerFactory: Increme
|
||||||
* depends on variants of that task.
|
* depends on variants of that task.
|
||||||
*/
|
*/
|
||||||
fun addVariantTasks(plugin: IPlugin, project: Project, context: KobaltContext, taskName: String,
|
fun addVariantTasks(plugin: IPlugin, project: Project, context: KobaltContext, taskName: String,
|
||||||
|
dependsOn: List<String> = emptyList(),
|
||||||
|
reverseDependsOn : List<String> = emptyList(),
|
||||||
runBefore : List<String> = emptyList(),
|
runBefore : List<String> = emptyList(),
|
||||||
runAfter : List<String> = emptyList(),
|
runAfter : List<String> = emptyList(),
|
||||||
alwaysRunAfter : List<String> = emptyList(),
|
|
||||||
runTask: (Project) -> TaskResult) {
|
runTask: (Project) -> TaskResult) {
|
||||||
Variant.allVariants(project).forEach { variant ->
|
Variant.allVariants(project).forEach { variant ->
|
||||||
val variantTaskName = variant.toTask(taskName)
|
val variantTaskName = variant.toTask(taskName)
|
||||||
dynamicTasks.add(DynamicTask(plugin, variantTaskName, variantTaskName,
|
dynamicTasks.add(DynamicTask(plugin, variantTaskName, variantTaskName,
|
||||||
|
dependsOn = dependsOn.map { variant.toTask(it) },
|
||||||
|
reverseDependsOn = reverseDependsOn.map { variant.toTask(it) },
|
||||||
runBefore = runBefore.map { variant.toTask(it) },
|
runBefore = runBefore.map { variant.toTask(it) },
|
||||||
runAfter = runAfter.map { variant.toTask(it) },
|
runAfter = runAfter.map { variant.toTask(it) },
|
||||||
alwaysRunAfter = alwaysRunAfter.map { variant.toTask(it) },
|
|
||||||
closure = { p: Project ->
|
closure = { p: Project ->
|
||||||
context.variant = variant
|
context.variant = variant
|
||||||
runTask(project)
|
runTask(project)
|
||||||
|
@ -41,16 +43,18 @@ class TaskContributor @Inject constructor(val incrementalManagerFactory: Increme
|
||||||
}
|
}
|
||||||
|
|
||||||
fun addIncrementalVariantTasks(plugin: IPlugin, project: Project, context: KobaltContext, taskName: String,
|
fun addIncrementalVariantTasks(plugin: IPlugin, project: Project, context: KobaltContext, taskName: String,
|
||||||
|
dependsOn: List<String> = emptyList(),
|
||||||
|
reverseDependsOn : List<String> = emptyList(),
|
||||||
runBefore : List<String> = emptyList(),
|
runBefore : List<String> = emptyList(),
|
||||||
runAfter : List<String> = emptyList(),
|
runAfter : List<String> = emptyList(),
|
||||||
alwaysRunAfter : List<String> = emptyList(),
|
|
||||||
runTask: (Project) -> IncrementalTaskInfo) {
|
runTask: (Project) -> IncrementalTaskInfo) {
|
||||||
Variant.allVariants(project).forEach { variant ->
|
Variant.allVariants(project).forEach { variant ->
|
||||||
val variantTaskName = variant.toTask(taskName)
|
val variantTaskName = variant.toTask(taskName)
|
||||||
dynamicTasks.add(DynamicTask(plugin, variantTaskName, variantTaskName,
|
dynamicTasks.add(DynamicTask(plugin, variantTaskName, variantTaskName,
|
||||||
|
dependsOn = dependsOn.map { variant.toTask(it) },
|
||||||
|
reverseDependsOn = reverseDependsOn.map { variant.toTask(it) },
|
||||||
runBefore = runBefore.map { variant.toTask(it) },
|
runBefore = runBefore.map { variant.toTask(it) },
|
||||||
runAfter = runAfter.map { variant.toTask(it) },
|
runAfter = runAfter.map { variant.toTask(it) },
|
||||||
alwaysRunAfter = alwaysRunAfter.map { variant.toTask(it) },
|
|
||||||
closure = incrementalManagerFactory.create().toIncrementalTaskClosure(taskName, runTask, variant)))
|
closure = incrementalManagerFactory.create().toIncrementalTaskClosure(taskName, runTask, variant)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,14 +11,17 @@ annotation class Task(
|
||||||
val name: String,
|
val name: String,
|
||||||
val description: String = "",
|
val description: String = "",
|
||||||
|
|
||||||
/** Tasks that this task depends on */
|
/** Dependency: tasks this task depends on */
|
||||||
|
val dependsOn: Array<String> = arrayOf(),
|
||||||
|
|
||||||
|
/** Dependency: tasks this task will be made dependend upon */
|
||||||
|
val reverseDependsOn: Array<String> = arrayOf(),
|
||||||
|
|
||||||
|
/** Ordering: tasks that need to be run before this one */
|
||||||
val runBefore: Array<String> = arrayOf(),
|
val runBefore: Array<String> = arrayOf(),
|
||||||
|
|
||||||
/** Tasks that this task will run after if they get run */
|
/** Ordering: tasks this task runs after */
|
||||||
val runAfter: Array<String> = arrayOf(),
|
val runAfter: Array<String> = arrayOf(),
|
||||||
|
|
||||||
/** Tasks that this task will always run after */
|
|
||||||
val alwaysRunAfter: Array<String> = arrayOf()
|
|
||||||
)
|
)
|
||||||
|
|
||||||
@Retention(AnnotationRetention.RUNTIME)
|
@Retention(AnnotationRetention.RUNTIME)
|
||||||
|
@ -26,14 +29,17 @@ annotation class IncrementalTask(
|
||||||
val name: String,
|
val name: String,
|
||||||
val description: String = "",
|
val description: String = "",
|
||||||
|
|
||||||
|
/** Dependency: tasks this task depends on */
|
||||||
|
val dependsOn: Array<String> = arrayOf(),
|
||||||
|
|
||||||
|
/** Dependency: tasks this task will be made dependend upon */
|
||||||
|
val reverseDependsOn: Array<String> = arrayOf(),
|
||||||
|
|
||||||
/** Tasks that this task depends on */
|
/** Tasks that this task depends on */
|
||||||
val runBefore: Array<String> = arrayOf(),
|
val runBefore: Array<String> = arrayOf(),
|
||||||
|
|
||||||
/** Tasks that this task will run after if they get run */
|
/** Ordering: tasks this task runs after */
|
||||||
val runAfter: Array<String> = arrayOf(),
|
val runAfter: Array<String> = arrayOf(),
|
||||||
|
|
||||||
/** Tasks that this task will always run after */
|
|
||||||
val alwaysRunAfter: Array<String> = arrayOf()
|
|
||||||
)
|
)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -24,7 +24,7 @@ class Node<T>(val value: T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
class DynamicGraph<T> {
|
class DynamicGraph<T> {
|
||||||
val VERBOSE = 1
|
val VERBOSE = 2
|
||||||
val values : Collection<T> get() = nodes.map { it.value }
|
val values : Collection<T> get() = nodes.map { it.value }
|
||||||
val nodes = hashSetOf<Node<T>>()
|
val nodes = hashSetOf<Node<T>>()
|
||||||
private val dependedUpon = HashMultimap.create<Node<T>, Node<T>>()
|
private val dependedUpon = HashMultimap.create<Node<T>, Node<T>>()
|
||||||
|
|
|
@ -78,7 +78,7 @@ open class JvmCompilerPlugin @Inject constructor(
|
||||||
val taskName = if (config.name.isEmpty()) "test" else "test" + config.name
|
val taskName = if (config.name.isEmpty()) "test" else "test" + config.name
|
||||||
|
|
||||||
taskManager.addTask(this, project, taskName,
|
taskManager.addTask(this, project, taskName,
|
||||||
runAfter = listOf(JvmCompilerPlugin.TASK_COMPILE, JvmCompilerPlugin.TASK_COMPILE_TEST),
|
dependsOn = listOf(JvmCompilerPlugin.TASK_COMPILE, JvmCompilerPlugin.TASK_COMPILE_TEST),
|
||||||
task = { taskTest(project, config.name)} )
|
task = { taskTest(project, config.name)} )
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -140,7 +140,7 @@ open class JvmCompilerPlugin @Inject constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
@IncrementalTask(name = TASK_COMPILE_TEST, description = "Compile the tests",
|
@IncrementalTask(name = TASK_COMPILE_TEST, description = "Compile the tests",
|
||||||
runAfter = arrayOf(TASK_COMPILE))
|
dependsOn = arrayOf(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)))
|
||||||
return IncrementalTaskInfo(
|
return IncrementalTaskInfo(
|
||||||
|
|
|
@ -21,30 +21,32 @@ import javax.inject.Inject
|
||||||
import javax.inject.Singleton
|
import javax.inject.Singleton
|
||||||
|
|
||||||
@Singleton
|
@Singleton
|
||||||
public class TaskManager @Inject constructor(val args: Args,
|
class TaskManager @Inject constructor(val args: Args,
|
||||||
val incrementalManagerFactory: IncrementalManager.IFactory) {
|
val incrementalManagerFactory: IncrementalManager.IFactory) {
|
||||||
|
private val dependsOn = TreeMultimap.create<String, String>()
|
||||||
|
private val reverseDependsOn = TreeMultimap.create<String, String>()
|
||||||
private val runBefore = TreeMultimap.create<String, String>()
|
private val runBefore = TreeMultimap.create<String, String>()
|
||||||
private val runAfter = TreeMultimap.create<String, String>()
|
private val runAfter = TreeMultimap.create<String, String>()
|
||||||
private val alwaysRunAfter = TreeMultimap.create<String, String>()
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called by plugins to indicate task dependencies defined at runtime. Keys depend on values.
|
* Dependency: task2 depends on task 1.
|
||||||
* Declare that `task1` depends on `task2`.
|
|
||||||
*
|
|
||||||
* Note: there is no runAfter on this class since a runAfter(a, b) in a task simply translates
|
|
||||||
* to a runBefore(b, a) here.
|
|
||||||
*/
|
*/
|
||||||
fun runBefore(task1: String, task2: String) {
|
fun dependsOn(task1: String, task2: String) = dependsOn.put(task2, task1)
|
||||||
runBefore.put(task1, task2)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun runAfter(task1: String, task2: String) {
|
/**
|
||||||
runAfter.put(task1, task2)
|
* Dependency: task2 depends on task 1.
|
||||||
}
|
*/
|
||||||
|
fun reverseDependsOn(task1: String, task2: String) = reverseDependsOn.put(task1, task2)
|
||||||
|
|
||||||
fun alwaysRunAfter(task1: String, task2: String) {
|
/**
|
||||||
alwaysRunAfter.put(task1, task2)
|
* Ordering: task1 runs before task 2.
|
||||||
}
|
*/
|
||||||
|
fun runBefore(task1: String, task2: String) = runBefore.put(task1, task2)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ordering: task2 runs after task 1.
|
||||||
|
*/
|
||||||
|
fun runAfter(task1: String, task2: String) = runAfter.put(task2, task1)
|
||||||
|
|
||||||
data class TaskInfo(val id: String) {
|
data class TaskInfo(val id: String) {
|
||||||
constructor(project: String, task: String) : this(project + ":" + task)
|
constructor(project: String, task: String) : this(project + ":" + task)
|
||||||
|
@ -58,7 +60,7 @@ public class TaskManager @Inject constructor(val args: Args,
|
||||||
|
|
||||||
class RunTargetResult(val exitCode: Int, val messages: List<String>)
|
class RunTargetResult(val exitCode: Int, val messages: List<String>)
|
||||||
|
|
||||||
public fun runTargets(taskNames: List<String>, projects: List<Project>) : RunTargetResult {
|
fun runTargets(taskNames: List<String>, projects: List<Project>) : RunTargetResult {
|
||||||
var result = 0
|
var result = 0
|
||||||
val failedProjects = hashSetOf<String>()
|
val failedProjects = hashSetOf<String>()
|
||||||
val messages = Collections.synchronizedList(arrayListOf<String>())
|
val messages = Collections.synchronizedList(arrayListOf<String>())
|
||||||
|
@ -94,7 +96,7 @@ public class TaskManager @Inject constructor(val args: Args,
|
||||||
}
|
}
|
||||||
|
|
||||||
val graph = createGraph(project.name, taskNames, tasksByNames,
|
val graph = createGraph(project.name, taskNames, tasksByNames,
|
||||||
runBefore, runAfter, alwaysRunAfter,
|
dependsOn, reverseDependsOn, runBefore, runAfter,
|
||||||
{ task: PluginTask -> task.name },
|
{ task: PluginTask -> task.name },
|
||||||
{ task: PluginTask -> task.plugin.accept(project) })
|
{ task: PluginTask -> task.plugin.accept(project) })
|
||||||
|
|
||||||
|
@ -122,109 +124,81 @@ public class TaskManager @Inject constructor(val args: Args,
|
||||||
return RunTargetResult(result, messages)
|
return RunTargetResult(result, messages)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a dynamic graph representing all the tasks that need to be run.
|
||||||
|
*/
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
fun <T> createGraph(projectName: String, taskNames: List<String>, dependencies: Multimap<String, T>,
|
fun <T> createGraph(projectName: String, taskNames: List<String>, nodeMap: Multimap<String, T>,
|
||||||
|
dependsOn: TreeMultimap<String, String>,
|
||||||
|
reverseDependsOn: TreeMultimap<String, String>,
|
||||||
runBefore: TreeMultimap<String, String>,
|
runBefore: TreeMultimap<String, String>,
|
||||||
runAfter: TreeMultimap<String, String>,
|
runAfter: TreeMultimap<String, String>,
|
||||||
alwaysRunAfter: TreeMultimap<String, String>,
|
|
||||||
toName: (T) -> String,
|
toName: (T) -> String,
|
||||||
accept: (T) -> Boolean):
|
accept: (T) -> Boolean):
|
||||||
DynamicGraph<T> {
|
DynamicGraph<T> {
|
||||||
val graph = DynamicGraph<T>()
|
|
||||||
|
val result = DynamicGraph<T>()
|
||||||
taskNames.forEach { taskName ->
|
taskNames.forEach { taskName ->
|
||||||
val ti = TaskInfo(taskName)
|
val ti = TaskInfo(taskName)
|
||||||
if (!dependencies.keys().contains(ti.taskName)) {
|
if (!nodeMap.keys().contains(ti.taskName)) {
|
||||||
throw KobaltException("Unknown task: $taskName")
|
throw KobaltException("Unknown task: $taskName")
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ti.matches(projectName)) {
|
if (ti.matches(projectName)) {
|
||||||
dependencies[ti.taskName].forEach { task ->
|
nodeMap[ti.taskName].forEach { task ->
|
||||||
if (task != null && accept(task)) {
|
if (task != null && accept(task)) {
|
||||||
val reverseAfter = hashMapOf<String, String>()
|
val toProcess = arrayListOf(task)
|
||||||
alwaysRunAfter.keys().forEach { from ->
|
val seen = hashSetOf<String>()
|
||||||
val tasks = alwaysRunAfter.get(from)
|
val newToProcess = arrayListOf<T>()
|
||||||
tasks.forEach {
|
while (toProcess.size > 0) {
|
||||||
reverseAfter.put(it, from)
|
toProcess.forEach { current ->
|
||||||
}
|
result.addNode(current)
|
||||||
}
|
seen.add(toName(current))
|
||||||
|
|
||||||
//
|
fun maybeAddEdge(taskName: String, mm: Multimap<String, String>, isDependency: Boolean,
|
||||||
// If the current target is free, add it as a single node to the graph
|
reverseEdges: Boolean = false) {
|
||||||
//
|
mm[taskName]?.forEach {
|
||||||
val allFreeTasks = calculateFreeTasks(dependencies, reverseAfter)
|
val addEdge = isDependency || (!isDependency && taskNames.contains(it))
|
||||||
val currentFreeTask = allFreeTasks.filter {
|
log(3, " addEdge: $addEdge $taskName")
|
||||||
TaskInfo(projectName, toName(it)).taskName == toName(task)
|
if (addEdge) {
|
||||||
}
|
nodeMap[it].forEach { to ->
|
||||||
if (currentFreeTask.size == 1) {
|
if (reverseEdges) {
|
||||||
currentFreeTask[0].let {
|
log(3, " Adding reverse edge $to -> $task")
|
||||||
graph.addNode(it)
|
result.addEdge(to, task)
|
||||||
}
|
} else {
|
||||||
}
|
log(3, " Adding edge $task -> $to")
|
||||||
|
result.addEdge(task, to)
|
||||||
//
|
}
|
||||||
// Add the transitive closure of the current task as edges to the graph
|
if (!seen.contains(it)) newToProcess.add(to)
|
||||||
//
|
|
||||||
val transitiveClosure = calculateTransitiveClosure(projectName, dependencies, ti)
|
|
||||||
transitiveClosure.forEach { pluginTask ->
|
|
||||||
val rb = runBefore.get(toName(pluginTask))
|
|
||||||
rb.forEach {
|
|
||||||
val tos = dependencies[it]
|
|
||||||
if (tos != null && tos.size > 0) {
|
|
||||||
tos.forEach { to ->
|
|
||||||
graph.addEdge(pluginTask, to)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
log(2, "Couldn't find node $it: not applicable to project $projectName")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// runAfter nodes are run only if they are explicitly requested
|
|
||||||
//
|
|
||||||
arrayListOf<T>().let { allNodes ->
|
|
||||||
allNodes.addAll(graph.values)
|
|
||||||
allNodes.forEach { node ->
|
|
||||||
val nodeName = toName(node)
|
|
||||||
if (taskNames.contains(nodeName)) {
|
|
||||||
val ra = runAfter[nodeName]
|
|
||||||
ra?.forEach { o ->
|
|
||||||
dependencies[o]?.forEach {
|
|
||||||
if (taskNames.contains(toName(it))) {
|
|
||||||
graph.addEdge(node, it)
|
|
||||||
}
|
}
|
||||||
|
seen.add(it)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
maybeAddEdge(ti.taskName, dependsOn, true, false)
|
||||||
|
maybeAddEdge(ti.taskName, reverseDependsOn, true, true)
|
||||||
|
maybeAddEdge(ti.taskName, runBefore, false, false)
|
||||||
|
maybeAddEdge(ti.taskName, runAfter, false, false)
|
||||||
}
|
}
|
||||||
}
|
toProcess.clear()
|
||||||
|
toProcess.addAll(newToProcess)
|
||||||
//
|
newToProcess.clear()
|
||||||
// If any of the nodes in the graph has an "alwaysRunAfter", add that edge too
|
|
||||||
//
|
|
||||||
arrayListOf<T>().let { allNodes ->
|
|
||||||
allNodes.addAll(graph.values)
|
|
||||||
allNodes.forEach { node ->
|
|
||||||
val ra = alwaysRunAfter[toName(node)]
|
|
||||||
ra?.forEach { o ->
|
|
||||||
dependencies[o]?.forEach {
|
|
||||||
graph.addEdge(it, node)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
log(3, "Task $taskName does not match the current project $projectName, skipping it")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
println("@@@ " + graph.dump())
|
return result
|
||||||
return graph
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Find the free tasks of the graph.
|
* Find the free tasks of the graph.
|
||||||
*/
|
*/
|
||||||
private fun <T> calculateFreeTasks(tasksByNames: Multimap<String, T>, reverseAfter: HashMap<String, String>)
|
private fun <T> calculateFreeTasks(tasksByNames: Multimap<String, T>, runBefore: TreeMultimap<String, String>,
|
||||||
|
reverseAfter: HashMap<String,
|
||||||
|
String>)
|
||||||
: Collection<T> {
|
: Collection<T> {
|
||||||
val freeTaskMap = hashMapOf<String, T>()
|
val freeTaskMap = hashMapOf<String, T>()
|
||||||
tasksByNames.keys().forEach {
|
tasksByNames.keys().forEach {
|
||||||
|
@ -238,49 +212,6 @@ public class TaskManager @Inject constructor(val args: Args,
|
||||||
return freeTaskMap.values
|
return freeTaskMap.values
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Find the transitive closure for the given TaskInfo
|
|
||||||
*/
|
|
||||||
private fun <T> calculateTransitiveClosure(projectName: String, tasksByNames: Multimap<String, T>, ti: TaskInfo):
|
|
||||||
HashSet<T> {
|
|
||||||
log(3, "Processing ${ti.taskName}")
|
|
||||||
|
|
||||||
val transitiveClosure = hashSetOf<T>()
|
|
||||||
val seen = hashSetOf(ti.taskName)
|
|
||||||
val toProcess = hashSetOf(ti)
|
|
||||||
var done = false
|
|
||||||
while (! done) {
|
|
||||||
val newToProcess = hashSetOf<TaskInfo>()
|
|
||||||
log(3, "toProcess size: " + toProcess.size)
|
|
||||||
toProcess.forEach { target ->
|
|
||||||
|
|
||||||
val currentTask = TaskInfo(projectName, target.taskName)
|
|
||||||
val thisTask = tasksByNames[currentTask.taskName]
|
|
||||||
if (thisTask != null) {
|
|
||||||
transitiveClosure.addAll(thisTask)
|
|
||||||
val dependencyNames = runBefore.get(currentTask.taskName)
|
|
||||||
dependencyNames.forEach { dependencyName ->
|
|
||||||
if (!seen.contains(dependencyName)) {
|
|
||||||
newToProcess.add(currentTask)
|
|
||||||
seen.add(dependencyName)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
dependencyNames.forEach {
|
|
||||||
newToProcess.add(TaskInfo(projectName, it))
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
log(1, "Couldn't find task ${currentTask.taskName}: not applicable to project $projectName")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
done = newToProcess.isEmpty()
|
|
||||||
toProcess.clear()
|
|
||||||
toProcess.addAll(newToProcess)
|
|
||||||
}
|
|
||||||
|
|
||||||
return transitiveClosure
|
|
||||||
}
|
|
||||||
|
|
||||||
/////
|
/////
|
||||||
// Manage the tasks
|
// Manage the tasks
|
||||||
//
|
//
|
||||||
|
@ -290,14 +221,16 @@ public class TaskManager @Inject constructor(val args: Args,
|
||||||
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 dependsOn: Array<String>, val reverseDependsOn: Array<String>,
|
||||||
|
val runBefore: Array<String>, val runAfter: Array<String>,
|
||||||
val callable: (Project) -> TaskResult)
|
val callable: (Project) -> TaskResult)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Invoking a @Task means simply calling the method and returning its returned TaskResult.
|
* Invoking a @Task means simply calling the method and returning its returned 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.dependsOn, ta.reverseDependsOn,
|
||||||
|
ta.runBefore, ta.runAfter,
|
||||||
{ project ->
|
{ project ->
|
||||||
method.invoke(plugin, project) as TaskResult
|
method.invoke(plugin, project) as TaskResult
|
||||||
})
|
})
|
||||||
|
@ -307,7 +240,8 @@ public class TaskManager @Inject constructor(val args: Args,
|
||||||
* of the returned IncrementalTaskInfo.
|
* 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.dependsOn, ta.reverseDependsOn,
|
||||||
|
ta.runBefore, ta.runAfter,
|
||||||
incrementalManagerFactory.create().toIncrementalTaskClosure(ta.name, { project ->
|
incrementalManagerFactory.create().toIncrementalTaskClosure(ta.name, { project ->
|
||||||
method.invoke(plugin, project) as IncrementalTaskInfo
|
method.invoke(plugin, project) as IncrementalTaskInfo
|
||||||
}))
|
}))
|
||||||
|
@ -338,8 +272,9 @@ public class TaskManager @Inject constructor(val args: Args,
|
||||||
dynamicTasks.forEach { dynamicTask ->
|
dynamicTasks.forEach { dynamicTask ->
|
||||||
val task = dynamicTask.task
|
val task = dynamicTask.task
|
||||||
projects.filter { dynamicTask.plugin.accept(it) }.forEach { project ->
|
projects.filter { dynamicTask.plugin.accept(it) }.forEach { project ->
|
||||||
addTask(dynamicTask.plugin, project, task.name, task.description, task.runBefore, task.runAfter,
|
addTask(dynamicTask.plugin, project, task.name, task.description,
|
||||||
task.alwaysRunAfter, task.closure)
|
task.dependsOn, task.reverseDependsOn, task.runBefore, task.runAfter,
|
||||||
|
task.closure)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -360,14 +295,17 @@ public class TaskManager @Inject constructor(val args: Args,
|
||||||
|
|
||||||
private fun addAnnotationTask(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.runAfter.toList(), annotation.alwaysRunAfter.toList(), task)
|
annotation.dependsOn.toList(), annotation.reverseDependsOn.toList(),
|
||||||
|
annotation.runBefore.toList(), annotation.runAfter.toList(),
|
||||||
|
task)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun addTask(plugin: IPlugin, project: Project, name: String, description: String = "",
|
fun addTask(plugin: IPlugin, project: Project, name: String, description: String = "",
|
||||||
|
dependsOn: List<String> = listOf<String>(),
|
||||||
|
reverseDependsOn: List<String> = listOf<String>(),
|
||||||
runBefore: List<String> = listOf<String>(),
|
runBefore: List<String> = listOf<String>(),
|
||||||
runAfter: List<String> = listOf<String>(),
|
runAfter: List<String> = listOf<String>(),
|
||||||
alwaysRunAfter: List<String> = listOf<String>(),
|
|
||||||
task: (Project) -> TaskResult) {
|
task: (Project) -> TaskResult) {
|
||||||
annotationTasks.add(
|
annotationTasks.add(
|
||||||
object : BasePluginTask(plugin, name, description, project) {
|
object : BasePluginTask(plugin, name, description, project) {
|
||||||
|
@ -376,9 +314,10 @@ public class TaskManager @Inject constructor(val args: Args,
|
||||||
return TaskResult2(taskResult.success, taskResult.errorMessage, this)
|
return TaskResult2(taskResult.success, taskResult.errorMessage, this)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
dependsOn.forEach { dependsOn(it, name) }
|
||||||
|
reverseDependsOn.forEach { reverseDependsOn(it, name) }
|
||||||
runBefore.forEach { runBefore(it, name) }
|
runBefore.forEach { runBefore(it, name) }
|
||||||
runAfter.forEach { runAfter(it, name) }
|
runAfter.forEach { runAfter(it, name) }
|
||||||
alwaysRunAfter.forEach { alwaysRunAfter(it, name)}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
|
|
|
@ -52,7 +52,7 @@ class ApplicationPlugin @Inject constructor(val configActor: ConfigActor<Applica
|
||||||
runTask = { taskRun(project) })
|
runTask = { taskRun(project) })
|
||||||
}
|
}
|
||||||
|
|
||||||
@Task(name = "run", description = "Run the main class", runAfter = arrayOf("install"))
|
@Task(name = "run", description = "Run the main class", dependsOn = arrayOf("install"))
|
||||||
fun taskRun(project: Project): TaskResult {
|
fun taskRun(project: Project): TaskResult {
|
||||||
val runContributor = ActorUtils.selectAffinityActor(project, context,
|
val runContributor = ActorUtils.selectAffinityActor(project, context,
|
||||||
context.pluginInfo.runnerContributors)
|
context.pluginInfo.runnerContributors)
|
||||||
|
|
|
@ -79,7 +79,7 @@ class PackagingPlugin @Inject constructor(val dependencyManager : DependencyMana
|
||||||
}
|
}
|
||||||
|
|
||||||
@Task(name = TASK_ASSEMBLE, description = "Package the artifacts",
|
@Task(name = TASK_ASSEMBLE, description = "Package the artifacts",
|
||||||
runAfter = arrayOf(JvmCompilerPlugin.TASK_COMPILE))
|
dependsOn = arrayOf(JvmCompilerPlugin.TASK_COMPILE))
|
||||||
fun doTaskAssemble(project: Project) : TaskResult {
|
fun doTaskAssemble(project: Project) : TaskResult {
|
||||||
// Incremental assembly contributors
|
// Incremental assembly contributors
|
||||||
context.pluginInfo.incrementalAssemblyContributors.forEach {
|
context.pluginInfo.incrementalAssemblyContributors.forEach {
|
||||||
|
@ -131,7 +131,7 @@ class PackagingPlugin @Inject constructor(val dependencyManager : DependencyMana
|
||||||
|
|
||||||
|
|
||||||
@Task(name = PackagingPlugin.TASK_INSTALL, description = "Install the artifacts",
|
@Task(name = PackagingPlugin.TASK_INSTALL, description = "Install the artifacts",
|
||||||
runAfter = arrayOf(PackagingPlugin.TASK_ASSEMBLE))
|
dependsOn = arrayOf(PackagingPlugin.TASK_ASSEMBLE))
|
||||||
fun taskInstall(project: Project) : TaskResult {
|
fun taskInstall(project: Project) : TaskResult {
|
||||||
val config = configurationFor(project) ?: InstallConfig()
|
val config = configurationFor(project) ?: InstallConfig()
|
||||||
val buildDir = project.projectProperties.getString(LIBS_DIR)
|
val buildDir = project.projectProperties.getString(LIBS_DIR)
|
||||||
|
|
|
@ -33,7 +33,7 @@ public class PublishPlugin @Inject constructor(val files: KFiles, val factory: P
|
||||||
}
|
}
|
||||||
|
|
||||||
@Suppress("UNUSED_FUNCTION_LITERAL")
|
@Suppress("UNUSED_FUNCTION_LITERAL")
|
||||||
@Task(name = TASK_GENERATE_POM, description = "Generate the .pom file", runAfter = arrayOf("assemble"))
|
@Task(name = TASK_GENERATE_POM, description = "Generate the .pom file", dependsOn = arrayOf("assemble"))
|
||||||
fun taskGeneratePom(project: Project): TaskResult {
|
fun taskGeneratePom(project: Project): TaskResult {
|
||||||
factory.create(project).generate()
|
factory.create(project).generate()
|
||||||
return TaskResult()
|
return TaskResult()
|
||||||
|
@ -56,7 +56,7 @@ public class PublishPlugin @Inject constructor(val files: KFiles, val factory: P
|
||||||
}
|
}
|
||||||
|
|
||||||
@Task(name = TASK_UPLOAD_BINTRAY, description = "Upload files to Bintray",
|
@Task(name = TASK_UPLOAD_BINTRAY, description = "Upload files to Bintray",
|
||||||
runAfter = arrayOf(TASK_GENERATE_POM))
|
dependsOn = arrayOf(TASK_GENERATE_POM))
|
||||||
fun taskUploadBintray(project: Project): TaskResult {
|
fun taskUploadBintray(project: Project): TaskResult {
|
||||||
validateProject(project)
|
validateProject(project)
|
||||||
return uploadBintray(project)
|
return uploadBintray(project)
|
||||||
|
@ -100,7 +100,7 @@ public class PublishPlugin @Inject constructor(val files: KFiles, val factory: P
|
||||||
}
|
}
|
||||||
|
|
||||||
@Task(name = TASK_UPLOAD_GITHUB, description = "Upload files to Github",
|
@Task(name = TASK_UPLOAD_GITHUB, description = "Upload files to Github",
|
||||||
runAfter = arrayOf(TASK_GENERATE_POM))
|
dependsOn = arrayOf(TASK_GENERATE_POM))
|
||||||
fun taskUploadGithub(project: Project): TaskResult {
|
fun taskUploadGithub(project: Project): TaskResult {
|
||||||
validateProject(project)
|
validateProject(project)
|
||||||
return uploadGithub(project)
|
return uploadGithub(project)
|
||||||
|
|
|
@ -31,22 +31,24 @@ class TaskManagerTest @Inject constructor(val taskManager: TaskManager) {
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun runTasks(tasks: List<String>) : List<String> {
|
private fun runTasks(tasks: List<String>) : List<String> {
|
||||||
val runBefore = TreeMultimap.create<String, String>().apply {
|
val dependsOn = TreeMultimap.create<String, String>().apply {
|
||||||
put("assemble", "compile")
|
put("assemble", "compile")
|
||||||
}
|
}
|
||||||
|
val reverseDependsOn = TreeMultimap.create<String, String>().apply {
|
||||||
|
put("clean", "copyVersion")
|
||||||
|
put("compile", "postCompile")
|
||||||
|
}
|
||||||
|
val runBefore = TreeMultimap.create<String, String>().apply {
|
||||||
|
}
|
||||||
val runAfter = TreeMultimap.create<String, String>().apply {
|
val runAfter = TreeMultimap.create<String, String>().apply {
|
||||||
put("compile", "clean")
|
put("compile", "clean")
|
||||||
put("postCompile", "compile")
|
|
||||||
}
|
|
||||||
val alwaysRunAfter = TreeMultimap.create<String, String>().apply {
|
|
||||||
put("clean", "copyVersion")
|
|
||||||
}
|
}
|
||||||
val dependencies = TreeMultimap.create<String, String>().apply {
|
val dependencies = TreeMultimap.create<String, String>().apply {
|
||||||
listOf("assemble", "compile", "clean", "copyVersion", "postCompile").forEach {
|
listOf("assemble", "compile", "clean", "copyVersion", "postCompile").forEach {
|
||||||
put(it, it)
|
put(it, it)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
val graph = taskManager.createGraph("", tasks, dependencies, runBefore, runAfter, alwaysRunAfter,
|
val graph = taskManager.createGraph("", tasks, dependencies, dependsOn, reverseDependsOn, runBefore, runAfter,
|
||||||
{ it }, { t -> true })
|
{ it }, { t -> true })
|
||||||
val result = DryRunGraphExecutor(graph).run()
|
val result = DryRunGraphExecutor(graph).run()
|
||||||
return result
|
return result
|
||||||
|
@ -55,11 +57,12 @@ class TaskManagerTest @Inject constructor(val taskManager: TaskManager) {
|
||||||
@Test
|
@Test
|
||||||
fun graphTest() {
|
fun graphTest() {
|
||||||
KobaltLogger.LOG_LEVEL = 3
|
KobaltLogger.LOG_LEVEL = 3
|
||||||
|
Assert.assertEquals(runTasks(listOf("compile")), listOf("compile", "postCompile"))
|
||||||
Assert.assertEquals(runTasks(listOf("postCompile")), listOf("postCompile"))
|
Assert.assertEquals(runTasks(listOf("postCompile")), listOf("postCompile"))
|
||||||
Assert.assertEquals(runTasks(listOf("compile")), listOf("compile"))
|
|
||||||
Assert.assertEquals(runTasks(listOf("compile", "postCompile")), listOf("compile", "postCompile"))
|
Assert.assertEquals(runTasks(listOf("compile", "postCompile")), listOf("compile", "postCompile"))
|
||||||
Assert.assertEquals(runTasks(listOf("clean")), listOf("clean", "copyVersion"))
|
Assert.assertEquals(runTasks(listOf("clean")), listOf("clean", "copyVersion"))
|
||||||
Assert.assertEquals(runTasks(listOf("clean", "compile")), listOf("clean", "compile", "copyVersion"))
|
Assert.assertEquals(runTasks(listOf("clean", "compile")), listOf("clean", "compile", "copyVersion",
|
||||||
|
"postCompile"))
|
||||||
Assert.assertEquals(runTasks(listOf("assemble")), listOf("compile", "assemble"))
|
Assert.assertEquals(runTasks(listOf("assemble")), listOf("compile", "assemble"))
|
||||||
Assert.assertEquals(runTasks(listOf("clean", "assemble")), listOf("clean", "compile", "assemble",
|
Assert.assertEquals(runTasks(listOf("clean", "assemble")), listOf("clean", "compile", "assemble",
|
||||||
"copyVersion"))
|
"copyVersion"))
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue