mirror of
https://github.com/ethauvin/kobalt.git
synced 2025-04-26 08:27:12 -07:00
Target engine refactor.
This commit is contained in:
parent
952464e3fa
commit
0fe686122f
1 changed files with 127 additions and 109 deletions
|
@ -6,9 +6,11 @@ import com.beust.kobalt.api.PluginTask
|
||||||
import com.beust.kobalt.api.Project
|
import com.beust.kobalt.api.Project
|
||||||
import com.beust.kobalt.misc.KobaltLogger
|
import com.beust.kobalt.misc.KobaltLogger
|
||||||
import com.beust.kobalt.maven.KobaltException
|
import com.beust.kobalt.maven.KobaltException
|
||||||
|
import com.beust.kobalt.plugins
|
||||||
import com.google.common.collect.HashMultimap
|
import com.google.common.collect.HashMultimap
|
||||||
import com.google.common.collect.TreeMultimap
|
import com.google.common.collect.TreeMultimap
|
||||||
import java.util.HashSet
|
import org.jetbrains.kotlin.cfg.pseudocode.or
|
||||||
|
import java.util.*
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
import javax.inject.Singleton
|
import javax.inject.Singleton
|
||||||
|
|
||||||
|
@ -34,126 +36,73 @@ public class TaskManager @Inject constructor(val plugins: Plugins, val args: Arg
|
||||||
wrapAfter.put(task1, task2)
|
wrapAfter.put(task1, task2)
|
||||||
}
|
}
|
||||||
|
|
||||||
class TaskInfo(val id: String) {
|
data class TaskInfo(val id: String) {
|
||||||
|
constructor(project: String, task: String) : this(project + ":" + task)
|
||||||
|
|
||||||
val project: String?
|
val project: String?
|
||||||
get() = if (id.contains(":")) id.split(":").get(0) else null
|
get() = if (id.contains(":")) id.split(":").get(0) else null
|
||||||
val task: String
|
val task: String
|
||||||
get() = if (id.contains(":")) id.split(":").get(1) else id
|
get() = if (id.contains(":")) id.split(":").get(1) else id
|
||||||
|
fun matches(projectName: String) = project == null || project == projectName
|
||||||
}
|
}
|
||||||
|
|
||||||
public fun runTargets(targets: List<String>, projects: List<Project>) {
|
public fun runTargets(targets: List<String>, projects: List<Project>) {
|
||||||
val tasksByNames = HashMultimap.create<String, PluginTask>()
|
val tasksAlreadyRun = hashSetOf<String>()
|
||||||
|
|
||||||
projects.forEach { project ->
|
projects.forEach { project ->
|
||||||
|
val projectName = project.name!!
|
||||||
|
val tasksByNames = hashMapOf<String, PluginTask>()
|
||||||
|
plugins.allTasks.filter {
|
||||||
|
it.project.name == project.name
|
||||||
|
}.forEach {
|
||||||
|
tasksByNames.put(it.name, it)
|
||||||
|
}
|
||||||
|
|
||||||
log(1, "")
|
log(1, "")
|
||||||
log(1, " Building project ${project.name}")
|
log(1, " Building project ${project.name}")
|
||||||
log(1, "")
|
log(1, "")
|
||||||
|
|
||||||
val allTasksByNames = hashMapOf<String, PluginTask>()
|
targets.forEach { target ->
|
||||||
plugins.allTasks.forEach { allTasksByNames.put(TaskInfo(it.name).task, it)}
|
tasksAlreadyRun.add(TaskInfo(projectName, target).id)
|
||||||
|
|
||||||
//
|
|
||||||
// Locate all the tasks
|
|
||||||
//
|
|
||||||
plugins.allTasks.filter { it.project.name == project.name }.forEach { rt ->
|
|
||||||
tasksByNames.put(rt.name, rt)
|
|
||||||
if (rt.runBefore.size() > 0) {
|
|
||||||
rt.runBefore.forEach { d ->
|
|
||||||
runBefore.put(rt.name, d)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
val freeTaskMap = hashMapOf<String, PluginTask>()
|
|
||||||
tasksByNames.keySet().forEach {
|
|
||||||
if (! runBefore.containsKey(it)) freeTaskMap.put(it, tasksByNames.get(it).elementAt(0))
|
|
||||||
}
|
|
||||||
|
|
||||||
log(2, "Free tasks: ${freeTaskMap.keySet()}")
|
|
||||||
log(2, "Dependent tasks:")
|
|
||||||
runBefore.keySet().forEach { t ->
|
|
||||||
log(2, " ${t} -> ${runBefore.get(t)}}")
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// Find the tasks required to run the targets and add them to the dynamic graph
|
|
||||||
//
|
|
||||||
val transitiveClosure = hashSetOf<String>()
|
|
||||||
val seen = HashSet(targets)
|
|
||||||
val toProcess = HashSet(targets)
|
|
||||||
var done = false
|
|
||||||
while (!done) {
|
|
||||||
val newToProcess = hashSetOf<String>()
|
|
||||||
log(3, "toProcess size: " + toProcess.size())
|
|
||||||
toProcess.forEach { target ->
|
|
||||||
val pluginTask = allTasksByNames.get(target)
|
|
||||||
// Only calculate the transitive closure for this target if its plug-in accepts the
|
|
||||||
// current project
|
|
||||||
if (pluginTask != null && pluginTask.plugin.accept(project)) {
|
|
||||||
log(3, "Processing ${target}")
|
|
||||||
val actualTarget =
|
|
||||||
if (target.contains(":")) {
|
|
||||||
// The target specifies a project explicitly
|
|
||||||
target.split(":").let {
|
|
||||||
val projectName = it[0]
|
|
||||||
if (projectName == project.name) {
|
|
||||||
it[1]
|
|
||||||
} else {
|
|
||||||
null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
target
|
|
||||||
}
|
|
||||||
if (actualTarget != null) {
|
|
||||||
wrapAfter.get(actualTarget).let {
|
|
||||||
newToProcess.addAll(it)
|
|
||||||
}
|
|
||||||
transitiveClosure.add(actualTarget)
|
|
||||||
val tasks = tasksByNames.get(actualTarget)
|
|
||||||
if (tasks.isEmpty()) {
|
|
||||||
throw KobaltException("Unknown task: ${target}")
|
|
||||||
}
|
|
||||||
tasks.forEach { task ->
|
|
||||||
val dependencyNames = runBefore.get(task.name)
|
|
||||||
dependencyNames.forEach { dependencyName ->
|
|
||||||
if (!seen.contains(dependencyName)) {
|
|
||||||
newToProcess.add(dependencyName)
|
|
||||||
seen.add(dependencyName)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
log(2, "Target ${target} specified so not running it for project ${project.name}")
|
|
||||||
}
|
|
||||||
} else if (pluginTask == null) {
|
|
||||||
throw AssertionError("Should have found the task for $target")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
done = newToProcess.isEmpty()
|
|
||||||
toProcess.clear()
|
|
||||||
toProcess.addAll(newToProcess)
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// Create a dynamic graph with the transitive closure
|
|
||||||
//
|
|
||||||
val graph = DynamicGraph<PluginTask>()
|
val graph = DynamicGraph<PluginTask>()
|
||||||
freeTaskMap.values().filter { transitiveClosure.contains(it.name) } forEach { graph.addNode(it) }
|
|
||||||
runBefore.entries().filter {
|
val ti = TaskInfo(target)
|
||||||
transitiveClosure.contains(it.key)
|
if (ti.matches(projectName)) {
|
||||||
}.forEach { entry ->
|
val task = tasksByNames.get(ti.task)
|
||||||
plugins.findTasks(entry.key).filter { it.project.name == project.name }.forEach { from ->
|
if (task != null && task.plugin.accept(project)) {
|
||||||
plugins.findTasks(entry.value).filter { it.project.name == project.name }.forEach { to ->
|
//
|
||||||
if (from.project.name == to.project.name) {
|
// Add free tasks as nodes to the graph
|
||||||
graph.addEdge(from, to)
|
//
|
||||||
|
calculateFreeTasks(tasksByNames).forEach {
|
||||||
|
val thisTaskInfo = TaskInfo(projectName, it.name)
|
||||||
|
if (! tasksAlreadyRun.contains(thisTaskInfo.id)) {
|
||||||
|
graph.addNode(it)
|
||||||
|
tasksAlreadyRun.add(thisTaskInfo.id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Add the transitive closure of the current task as edges to the graph
|
||||||
|
//
|
||||||
|
calculateTransitiveClosure(project, tasksByNames, ti, task).forEach { pluginTask ->
|
||||||
|
val rb = runBefore.get(pluginTask.name)
|
||||||
|
rb.forEach {
|
||||||
|
val to = tasksByNames.get(it)
|
||||||
|
if (to != null) {
|
||||||
|
val taskInfo = TaskInfo(projectName, to.name)
|
||||||
|
if (! tasksAlreadyRun.contains(taskInfo.id)) {
|
||||||
|
graph.addEdge(pluginTask, to)
|
||||||
|
tasksAlreadyRun.add(taskInfo.id)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw KobaltException("Should have found $it")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// Run the dynamic graph
|
// Now that we have a full graph, run it
|
||||||
//
|
//
|
||||||
val factory = object : IThreadWorkerFactory<PluginTask> {
|
val factory = object : IThreadWorkerFactory<PluginTask> {
|
||||||
override public fun createWorkers(nodes: List<PluginTask>): List<IWorker<PluginTask>> {
|
override public fun createWorkers(nodes: List<PluginTask>): List<IWorker<PluginTask>> {
|
||||||
|
@ -169,6 +118,75 @@ public class TaskManager @Inject constructor(val plugins: Plugins, val args: Arg
|
||||||
executor.run()
|
executor.run()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find the free tasks of the graph.
|
||||||
|
*/
|
||||||
|
private fun calculateFreeTasks(tasksByNames: Map<String, PluginTask>): Collection<PluginTask> {
|
||||||
|
val freeTaskMap = hashMapOf<String, PluginTask>()
|
||||||
|
tasksByNames.keySet().forEach {
|
||||||
|
if (! runBefore.containsKey(it)) {
|
||||||
|
freeTaskMap.put(it, tasksByNames.get(it)!!)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
log(2, "Free tasks: ${freeTaskMap.keySet()}")
|
||||||
|
log(2, "Dependent tasks:")
|
||||||
|
runBefore.keySet().forEach { t ->
|
||||||
|
log(2, " ${t} -> ${runBefore.get(t)}}")
|
||||||
|
}
|
||||||
|
|
||||||
|
return freeTaskMap.values()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find the transitive closure for the given TaskInfo
|
||||||
|
*/
|
||||||
|
private fun calculateTransitiveClosure(project: Project, tasksByNames: Map<String, PluginTask>, ti: TaskInfo,
|
||||||
|
task: PluginTask): HashSet<PluginTask> {
|
||||||
|
log(3, "Processing ${ti.task}")
|
||||||
|
|
||||||
|
val transitiveClosure = hashSetOf<PluginTask>()
|
||||||
|
val seen = hashSetOf(ti.task)
|
||||||
|
val toProcess = hashSetOf(ti)
|
||||||
|
var done = false
|
||||||
|
while (! done) {
|
||||||
|
val newToProcess = hashSetOf<TaskInfo>()
|
||||||
|
log(3, "toProcess size: " + toProcess.size())
|
||||||
|
toProcess.forEach { target ->
|
||||||
|
|
||||||
|
// wrapAfter.get(ti.id).let {
|
||||||
|
// newToProcess.addAll(it)
|
||||||
|
// }
|
||||||
|
|
||||||
|
val currentTask = TaskInfo(project.name!!, target.task)
|
||||||
|
transitiveClosure.add(tasksByNames.get(currentTask.task)!!)
|
||||||
|
val task = tasksByNames.get(target.task)
|
||||||
|
if (task == null) {
|
||||||
|
throw KobaltException("Unknown task: ${target}")
|
||||||
|
} else {
|
||||||
|
val dependencyNames = runBefore.get(task.name)
|
||||||
|
dependencyNames.forEach { dependencyName ->
|
||||||
|
if (! seen.contains(dependencyName)) {
|
||||||
|
newToProcess.add(currentTask)
|
||||||
|
seen.add(dependencyName)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
runBefore.get(task.name).forEach {
|
||||||
|
newToProcess.add(TaskInfo(project.name!!, it))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
done = newToProcess.isEmpty()
|
||||||
|
toProcess.clear()
|
||||||
|
toProcess.addAll(newToProcess)
|
||||||
|
}
|
||||||
|
|
||||||
|
return transitiveClosure
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class TaskWorker(val tasks: List<PluginTask>, val dryRun: Boolean) : IWorker<PluginTask>, KobaltLogger {
|
class TaskWorker(val tasks: List<PluginTask>, val dryRun: Boolean) : IWorker<PluginTask>, KobaltLogger {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue