diff --git a/.run/taskTree.run.xml b/.run/taskTree.run.xml
index be40bb9..6aca1fb 100644
--- a/.run/taskTree.run.xml
+++ b/.run/taskTree.run.xml
@@ -4,21 +4,26 @@
-
+
true
true
+ false
false
false
+ false
+ false
\ No newline at end of file
diff --git a/libs.versions.toml b/libs.versions.toml
index 92000f3..6766371 100644
--- a/libs.versions.toml
+++ b/libs.versions.toml
@@ -1,14 +1,35 @@
[versions]
-tasktree = "0.0.12"
+tasktree = "0.0.13"
+
+kotlin = "2.2.21"
+kotlin-serialization = "1.10.0"
+ktor = "3.1.3"
[libraries]
+kotlinx-serialization-json = { module = "org.jetbrains.kotlinx:kotlinx-serialization-json", version.ref = "kotlin-serialization" }
+
+ktor-serialization-json = { group = "io.ktor", name = "ktor-serialization-kotlinx-json", version.ref = "ktor" }
+ktor-utils = { group = "io.ktor", name = "ktor-utils", version.ref = "ktor" }
+ktor-io = { group = "io.ktor", name = "ktor-io", version.ref = "ktor" }
+
+ktor-client-core = { group = "io.ktor", name = "ktor-client-core", version.ref = "ktor" }
+ktor-client-okhttp = { group = "io.ktor", name = "ktor-client-okhttp", version.ref = "ktor" }
+ktor-client-content-negotiation = { group = "io.ktor", name = "ktor-client-content-negotiation", version.ref = "ktor" }
+ktor-client-logging = { group = "io.ktor", name = "ktor-client-logging", version.ref = "ktor" }
+ktor-client-android = { group = "io.ktor", name = "ktor-client-android", version.ref = "ktor" }
+ktor-client-plugins = { group = "io.ktor", name = "ktor-client-plugins", version.ref = "ktor" }
+
[bundles]
+ktor-common = ["ktor-serialization-json", "ktor-utils", "ktor-io"]
+ktor-client = ["ktor-client-core", "ktor-client-okhttp", "ktor-client-content-negotiation",
+ "ktor-client-logging", "ktor-client-android"]
[plugins]
publish-plugin = { id = "com.gradle.plugin-publish", version = "1.1.0" }
+kotlin-serialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlin" }
tasktree = { id = "com.github.klee0kai.tasktree", version.ref = "tasktree" }
diff --git a/readme.md b/readme.md
index b9fb9e8..d121a43 100644
--- a/readme.md
+++ b/readme.md
@@ -11,7 +11,7 @@ Apply plugin in your module's `build.gradle`:
```kotlin
plugins {
- id("com.github.klee0kai.tasktree") version "0.0.12"
+ id("com.github.klee0kai.tasktree") version "0.0.13"
}
tasktree {
@@ -20,6 +20,8 @@ tasktree {
}
```
+All params available [here](https://github.com/klee0kai/tasktree/blob/dev/tasktree/src/main/kotlin/com/github/klee0kai/tasktree/TaskTreeExtension.kt)
+
Project build report in the form of a build graph. [Diagon](https://github.com/ArthurSonzogni/Diagon) must be installed
```bash
@@ -66,7 +68,7 @@ initscript {
maven(url = "https://jitpack.io")
}
dependencies {
- classpath("com.github.klee0kai:tasktree:0.0.12")
+ classpath("com.github.klee0kai:tasktree:0.0.13")
}
}
diff --git a/tasktree/build.gradle.kts b/tasktree/build.gradle.kts
index be83815..ed71537 100644
--- a/tasktree/build.gradle.kts
+++ b/tasktree/build.gradle.kts
@@ -2,6 +2,7 @@ plugins {
`kotlin-dsl`
`java-gradle-plugin`
alias(libs.plugins.publish.plugin)
+ alias(libs.plugins.kotlin.serialization)
}
group = libs.plugins.tasktree.get().pluginId
@@ -23,6 +24,9 @@ tasks.withType().configureEach {
dependencies {
implementation(gradleApi())
+ implementation(libs.kotlinx.serialization.json)
+ implementation(libs.bundles.ktor.common)
+ implementation(libs.bundles.ktor.client)
}
diff --git a/tasktree/src/main/kotlin/com/github/klee0kai/tasktree/TaskTreeExtension.kt b/tasktree/src/main/kotlin/com/github/klee0kai/tasktree/TaskTreeExtension.kt
index d6bafb0..e52f42d 100644
--- a/tasktree/src/main/kotlin/com/github/klee0kai/tasktree/TaskTreeExtension.kt
+++ b/tasktree/src/main/kotlin/com/github/klee0kai/tasktree/TaskTreeExtension.kt
@@ -1,6 +1,9 @@
package com.github.klee0kai.tasktree
-open class TaskTreeExtension {
+import org.gradle.api.provider.Property
+import java.net.URL
+
+abstract class TaskTreeExtension {
/**
* Graph max depth
@@ -38,6 +41,15 @@ open class TaskTreeExtension {
*/
var printMostExpensive: Boolean = false
+
+ /**
+ * output url
+ * Examples :
+ * - file:/home/user/test.txt
+ * - http://localhost:2334/
+ */
+ abstract val output: Property
+
}
diff --git a/tasktree/src/main/kotlin/com/github/klee0kai/tasktree/TaskTreePlugin.kt b/tasktree/src/main/kotlin/com/github/klee0kai/tasktree/TaskTreePlugin.kt
index 5cdb676..84071d9 100644
--- a/tasktree/src/main/kotlin/com/github/klee0kai/tasktree/TaskTreePlugin.kt
+++ b/tasktree/src/main/kotlin/com/github/klee0kai/tasktree/TaskTreePlugin.kt
@@ -27,8 +27,10 @@ open class TaskTreePlugin : Plugin {
val flatlist = tasks.register("flatList", FlatListTask::class.java, ext)
taskGraph.whenReady {
- val isTaskTreeRequested =
- hasTask(taskTree.get()) || hasTask(taskDag.get()) || hasTask(flatlist.get())
+ val isTaskTreeRequested = hasTask(taskTree.get())
+ || hasTask(taskDag.get())
+ || hasTask(flatlist.get())
+
if (isTaskTreeRequested) {
allRequestedTasks.forEach {
it.enabled = false
@@ -36,6 +38,7 @@ open class TaskTreePlugin : Plugin {
}
}
}
+
}
/**
diff --git a/tasktree/src/main/kotlin/com/github/klee0kai/tasktree/info/TaskInfo.kt b/tasktree/src/main/kotlin/com/github/klee0kai/tasktree/info/TaskInfo.kt
index d342b9f..bc3c519 100644
--- a/tasktree/src/main/kotlin/com/github/klee0kai/tasktree/info/TaskInfo.kt
+++ b/tasktree/src/main/kotlin/com/github/klee0kai/tasktree/info/TaskInfo.kt
@@ -1,15 +1,14 @@
package com.github.klee0kai.tasktree.info
-import org.gradle.api.tasks.diagnostics.internal.ProjectDetails
-
class TaskInfo(
- val id: Int = 0,
+ val path: String,
val taskName: String,
+ val group: String,
+ val description: String,
+ val termDir: String,
val className: Class<*>? = null,
val simpleClassName: String? = null,
val projectName: String? = null,
- val projectDetails: ProjectDetails? = null,
- val rootProjectDetails: ProjectDetails? = null,
- val dependencies: MutableList = mutableListOf()
+ val dependencies: MutableList = mutableListOf(),
)
diff --git a/tasktree/src/main/kotlin/com/github/klee0kai/tasktree/info/TaskStat.kt b/tasktree/src/main/kotlin/com/github/klee0kai/tasktree/info/TaskStat.kt
index 0d14e3f..68bac60 100644
--- a/tasktree/src/main/kotlin/com/github/klee0kai/tasktree/info/TaskStat.kt
+++ b/tasktree/src/main/kotlin/com/github/klee0kai/tasktree/info/TaskStat.kt
@@ -1,16 +1,13 @@
package com.github.klee0kai.tasktree.info
-import org.gradle.api.tasks.diagnostics.internal.ProjectDetails
import java.util.*
class TaskStat(
- val id: Int = 0,
+ val path: String,
val taskName: String,
val className: Class<*>? = null,
val simpleClassName: String? = null,
val projectName: String? = null,
- val projectDetails: ProjectDetails? = null,
- val rootProjectDetails: ProjectDetails? = null,
val dependencies: MutableSet = mutableSetOf(),
val dependedOnTasks: MutableSet = mutableSetOf(),
) {
@@ -43,19 +40,20 @@ class TaskStat(
private set
get() {
if (field.isNotEmpty()) return field
- val checked = mutableMapOf>()
+ val checked = mutableMapOf>()
val deps = LinkedList(dependencies.map { listOf(this@TaskStat, it) }.toMutableList())
while (deps.isNotEmpty()) {
val dep = deps.pollFirst()
- val checkedDepthDeps = checked.getOrDefault(dep.last().id, emptyList())
+ val checkedDepthDeps = checked.getOrDefault(dep.last().path, emptyList())
if (checkedDepthDeps.size >= dep.size
|| checkedDepthDeps.isNotEmpty()
- && dep.take(checkedDepthDeps.size).map { it.id } == checkedDepthDeps.map { it.id } // ignore doubles
+ && dep.take(checkedDepthDeps.size)
+ .map { it.path } == checkedDepthDeps.map { it.path } // ignore doubles
) {
continue
}
- checked[dep.last().id] = dep
- deps.removeAll { task -> task.last().id in dep.last().dependencies.map { it.id } }
+ checked[dep.last().path] = dep
+ deps.removeAll { task -> task.last().path in dep.last().dependencies.map { it.path } }
deps.addAll(0, dep.last().dependencies.map { dep + it })
}
field = checked.values.maxByOrNull { it.size } ?: emptyList()
@@ -63,25 +61,25 @@ class TaskStat(
}
val allDependencies = sequence {
- val sent = mutableSetOf()
+ val sent = mutableSetOf()
val deps = LinkedList(dependencies.toMutableList())
while (deps.isNotEmpty()) {
val dep = deps.pollFirst()
- if (sent.contains(dep.id)) continue
+ if (sent.contains(dep.path)) continue
yield(dep)
- sent.add(dep.id)
+ sent.add(dep.path)
deps.addAll(dep.dependencies)
}
}
val allDependedOnTasks = sequence {
- val sent = mutableSetOf()
+ val sent = mutableSetOf()
val deps = LinkedList(dependedOnTasks.toMutableList())
while (deps.isNotEmpty()) {
val dep = deps.pollFirst()
- if (sent.contains(dep.id)) continue
+ if (sent.contains(dep.path)) continue
yield(dep)
- sent.add(dep.id)
+ sent.add(dep.path)
deps.addAll(dep.dependedOnTasks)
}
}
@@ -99,11 +97,9 @@ class TaskStat(
fun TaskInfo.toTaskStat(
) = TaskStat(
- id,
- taskName,
- className,
- simpleClassName,
- projectName,
- projectDetails,
- rootProjectDetails,
+ path = path,
+ taskName = taskName,
+ className = className,
+ simpleClassName = simpleClassName,
+ projectName = projectName,
)
\ No newline at end of file
diff --git a/tasktree/src/main/kotlin/com/github/klee0kai/tasktree/info/TaskStatHelper.kt b/tasktree/src/main/kotlin/com/github/klee0kai/tasktree/info/TaskStatHelper.kt
index 33272dc..5736cfd 100644
--- a/tasktree/src/main/kotlin/com/github/klee0kai/tasktree/info/TaskStatHelper.kt
+++ b/tasktree/src/main/kotlin/com/github/klee0kai/tasktree/info/TaskStatHelper.kt
@@ -3,29 +3,30 @@ package com.github.klee0kai.tasktree.info
import com.github.klee0kai.tasktree.utils.fullName
import com.github.klee0kai.tasktree.utils.simpleClassName
import org.gradle.api.Project
-import org.gradle.api.tasks.diagnostics.internal.ProjectDetails
object TaskStatHelper {
fun collectAllTasksInfo(project: Project): List {
val allTasks = project.tasks.toList()
val tasksInfos = allTasks.map { task ->
+
TaskInfo(
- id = System.identityHashCode(task),
+ path = task.path,
taskName = task.name,
+ group = task.group ?: "",
+ description = task.description ?: "",
+ termDir = task.temporaryDir.path,
className = task::class.java,
simpleClassName = task.simpleClassName,
projectName = project.fullName,
- projectDetails = ProjectDetails.of(project),
- rootProjectDetails = ProjectDetails.of(project.rootProject),
)
- }.associateBy { task -> task.id }
+ }.associateBy { task -> task.path }
allTasks.forEach { task ->
runCatching {
task.taskDependencies.getDependencies(task).forEach { dependsOn ->
- val taskStat = tasksInfos[System.identityHashCode(dependsOn)] ?: return@forEach
- tasksInfos[System.identityHashCode(task)]?.dependencies?.add(taskStat)
+ val taskStat = tasksInfos[dependsOn.path] ?: return@forEach
+ tasksInfos[dependsOn.path]?.dependencies?.add(taskStat)
}
}
}
@@ -34,7 +35,7 @@ object TaskStatHelper {
fun calcToTaskStats(taskInfos: List): List {
val taskStats = taskInfos.map { taskInfo -> taskInfo.toTaskStat() }
- .associateBy { task -> task.id }
+ .associateBy { task -> task.path }
taskStats.values.forEach { task ->
task.allTasksCount = taskInfos.size
@@ -43,7 +44,7 @@ object TaskStatHelper {
taskInfos.forEach { taskInfo ->
taskInfo.dependencies.forEach { dependsOn ->
- taskStats[taskInfo.id]?.dependencies?.add(taskStats[dependsOn.id] ?: return@forEach)
+ taskStats[taskInfo.path]?.dependencies?.add(taskStats[dependsOn.path] ?: return@forEach)
}
}
@@ -65,11 +66,11 @@ object TaskStatHelper {
fun filterByRequestedTasks(
tasksStats: List,
- allRequestedTasksIds: Set,
+ allRequestedTasksIds: Set,
): List {
if (allRequestedTasksIds.isEmpty()) return tasksStats
return tasksStats.filter {
- it.id in allRequestedTasksIds
+ it.path in allRequestedTasksIds
}
}
diff --git a/tasktree/src/main/kotlin/com/github/klee0kai/tasktree/output/ProjectNode.kt b/tasktree/src/main/kotlin/com/github/klee0kai/tasktree/output/ProjectNode.kt
new file mode 100644
index 0000000..529d910
--- /dev/null
+++ b/tasktree/src/main/kotlin/com/github/klee0kai/tasktree/output/ProjectNode.kt
@@ -0,0 +1,9 @@
+package com.github.klee0kai.tasktree.output
+
+import kotlinx.serialization.Serializable
+
+@Serializable
+data class ProjectNode(
+ val id: Int,
+ val name: String,
+)
diff --git a/tasktree/src/main/kotlin/com/github/klee0kai/tasktree/output/TaskNode.kt b/tasktree/src/main/kotlin/com/github/klee0kai/tasktree/output/TaskNode.kt
new file mode 100644
index 0000000..1036ccc
--- /dev/null
+++ b/tasktree/src/main/kotlin/com/github/klee0kai/tasktree/output/TaskNode.kt
@@ -0,0 +1,29 @@
+package com.github.klee0kai.tasktree.output
+
+import com.github.klee0kai.tasktree.info.TaskInfo
+import kotlinx.serialization.Serializable
+
+@Serializable
+data class TaskNode(
+ val path: String,
+ val name: String,
+ val className: String,
+ val projectName: String,
+ val group: String,
+ val description: String,
+ val termDir: String,
+ val dependencies: List = mutableListOf(),
+)
+
+
+fun TaskInfo.toTaskNode(
+): TaskNode = TaskNode(
+ path = path,
+ name = taskName,
+ group = group,
+ description = description,
+ termDir = termDir,
+ className = className!!.canonicalName,
+ projectName = projectName ?: "",
+ dependencies = dependencies.map { it.path }.toSet().toList(),
+)
diff --git a/tasktree/src/main/kotlin/com/github/klee0kai/tasktree/output/TaskTreeResult.kt b/tasktree/src/main/kotlin/com/github/klee0kai/tasktree/output/TaskTreeResult.kt
new file mode 100644
index 0000000..42a096b
--- /dev/null
+++ b/tasktree/src/main/kotlin/com/github/klee0kai/tasktree/output/TaskTreeResult.kt
@@ -0,0 +1,9 @@
+package com.github.klee0kai.tasktree.output
+
+import kotlinx.serialization.Serializable
+
+@Serializable
+data class TaskTreeResult(
+ val projects: List,
+ val tasks: List,
+)
diff --git a/tasktree/src/main/kotlin/com/github/klee0kai/tasktree/tasks/BaseReportTask.kt b/tasktree/src/main/kotlin/com/github/klee0kai/tasktree/tasks/BaseReportTask.kt
index 6ed5678..dedddef 100644
--- a/tasktree/src/main/kotlin/com/github/klee0kai/tasktree/tasks/BaseReportTask.kt
+++ b/tasktree/src/main/kotlin/com/github/klee0kai/tasktree/tasks/BaseReportTask.kt
@@ -1,13 +1,13 @@
package com.github.klee0kai.tasktree.tasks
import com.github.klee0kai.tasktree.utils.allRequestedTasks
+import com.github.klee0kai.tasktree.utils.fullName
import org.gradle.api.tasks.Internal
import org.gradle.api.tasks.diagnostics.ConventionReportTask
import org.gradle.api.tasks.diagnostics.internal.ProjectDetails
import org.gradle.api.tasks.diagnostics.internal.ReportGenerator
import org.gradle.api.tasks.diagnostics.internal.ReportRenderer
import org.gradle.api.tasks.diagnostics.internal.TextReportRenderer
-import org.gradle.internal.graph.GraphRenderer
import org.gradle.internal.serialization.Cached
abstract class BaseReportTask : ConventionReportTask() {
@@ -17,7 +17,7 @@ abstract class BaseReportTask : ConventionReportTask() {
@get:Internal
protected val allRequestedTasksIds = Cached.of {
- project.allRequestedTasks.map { System.identityHashCode(it) }.toSet()
+ project.allRequestedTasks.map { it.path }.toSet()
}
@Internal
diff --git a/tasktree/src/main/kotlin/com/github/klee0kai/tasktree/tasks/TaskTreeTask.kt b/tasktree/src/main/kotlin/com/github/klee0kai/tasktree/tasks/TaskTreeTask.kt
index ed82afb..9ef96c0 100644
--- a/tasktree/src/main/kotlin/com/github/klee0kai/tasktree/tasks/TaskTreeTask.kt
+++ b/tasktree/src/main/kotlin/com/github/klee0kai/tasktree/tasks/TaskTreeTask.kt
@@ -3,7 +3,11 @@ package com.github.klee0kai.tasktree.tasks
import com.github.klee0kai.tasktree.TaskTreeExtension
import com.github.klee0kai.tasktree.info.TaskStat
import com.github.klee0kai.tasktree.info.TaskStatHelper
+import com.github.klee0kai.tasktree.output.TaskTreeResult
+import com.github.klee0kai.tasktree.output.toTaskNode
import com.github.klee0kai.tasktree.utils.formatString
+import com.github.klee0kai.tasktree.utils.sendToUrl
+import kotlinx.coroutines.runBlocking
import org.gradle.api.tasks.Input
import org.gradle.api.tasks.Optional
import org.gradle.api.tasks.TaskAction
@@ -35,31 +39,48 @@ open class TaskTreeTask @Inject constructor(
@set:Option(option = "verifyPrice", description = "Verify tasks price")
protected var verifyPrice: String? = null
+
+ /**
+ * output url
+ * Examples :
+ * - file://home/user/test.txt
+ * - http://localhost:2334/
+ */
+ @Input
+ @Optional
+ @set:Option(option = "outputJson", description = "Write results to output JSON")
+ protected var outputJson: String? = null
+
@TaskAction
- fun generate() {
+ fun generate() = runBlocking {
tasksStats = TaskStatHelper.calcToTaskStats(tasksInfos.get())
.let { TaskStatHelper.filterByRequestedTasks(it, allRequestedTasksIds.get()) }
- renderedTasks.clear()
- reportGenerator().generateReport(
- listOf(projectDetails.get()),
- { it }
- ) { projectTasks ->
- val graphRenderer = GraphRenderer(renderer.textOutput)
- val topTasks = tasksStats
- .filter { task ->
- if (allRequestedTasksIds.get().isNotEmpty()) {
- task.dependedOnTasks.none { allRequestedTasksIds.get().contains(it.id) }
- } else {
- task.allDependedOnCount <= 0L
+ if (outputJson != null) {
+ printResultToUrl(outputJson!!)
+ } else {
+ renderedTasks.clear()
+ reportGenerator().generateReport(
+ listOf(projectDetails.get()),
+ { it }
+ ) { projectTasks ->
+ val graphRenderer = GraphRenderer(renderer.textOutput)
+ val topTasks = tasksStats
+ .filter { task ->
+ if (allRequestedTasksIds.get().isNotEmpty()) {
+ task.dependedOnTasks.none { allRequestedTasksIds.get().contains(it.path) }
+ } else {
+ task.allDependedOnCount <= 0L
+ }
}
- }
- .sortedByDescending { it.depth }
- topTasks.forEach { graphRenderer.render(it) }
+ .sortedByDescending { it.depth }
+ topTasks.forEach { graphRenderer.render(it) }
- renderer.printMostExpensiveTasksIfNeed()
- verifyIfNeed()
+ renderer.printMostExpensiveTasksIfNeed()
+ }
}
+
+ verifyIfNeed()
}
private fun GraphRenderer.render(
@@ -68,7 +89,6 @@ open class TaskTreeTask @Inject constructor(
depth: Int = 0,
) {
visit({
-
printTaskShort(taskStat)
if (ext.printDetails) {
@@ -119,7 +139,6 @@ open class TaskTreeTask @Inject constructor(
}
}
-
private fun StyledTextOutput.printTaskShort(
taskStat: TaskStat,
printDepthLine: Boolean = false,
@@ -152,7 +171,6 @@ open class TaskTreeTask @Inject constructor(
}
}
-
private fun verifyIfNeed() {
val verifyDepth = verifyDepth?.toInt() ?: return
var heavyTasks = tasksStats.filter { it.depth > verifyDepth }
@@ -167,6 +185,18 @@ open class TaskTreeTask @Inject constructor(
}
}
+ private suspend fun printResultToUrl(outputJson: String) {
+ val topTasks = tasksInfos
+ .get()
+ .sortedByDescending { it.path }
+ .map { it.toTaskNode() }
+
+ val result = TaskTreeResult(
+ projects = emptyList(),
+ tasks = topTasks,
+ )
+ sendToUrl(outputJson, result)
+ }
}
diff --git a/tasktree/src/main/kotlin/com/github/klee0kai/tasktree/utils/OutputStream.kt b/tasktree/src/main/kotlin/com/github/klee0kai/tasktree/utils/OutputStream.kt
new file mode 100644
index 0000000..5442f61
--- /dev/null
+++ b/tasktree/src/main/kotlin/com/github/klee0kai/tasktree/utils/OutputStream.kt
@@ -0,0 +1,39 @@
+package com.github.klee0kai.tasktree.utils
+
+import io.ktor.client.*
+import io.ktor.client.engine.okhttp.*
+import io.ktor.client.plugins.contentnegotiation.*
+import io.ktor.client.request.*
+import io.ktor.http.*
+import io.ktor.serialization.kotlinx.json.json
+import kotlinx.serialization.json.Json
+import java.io.File
+
+suspend inline fun sendToUrl(
+ url: String,
+ value: T,
+) {
+ when {
+ url.startsWith("file:") -> {
+ val file = File(url.substringAfter("file:"))
+ file.outputStream().use {
+ it.write(Json.encodeToString(value).toByteArray(Charsets.UTF_8))
+ }
+ }
+
+ url.startsWith("http:") || url.startsWith("https:") -> {
+ val client = HttpClient(OkHttp) {
+ install(ContentNegotiation){
+ json()
+ }
+ }
+
+ client.post(url) {
+ contentType(ContentType.Application.Json)
+ setBody(value)
+ }
+
+ client.close()
+ }
+ }
+}
\ No newline at end of file