diff --git a/.run/taskTree.run.xml b/.run/taskTree.run.xml
index 6b951ab..be40bb9 100644
--- a/.run/taskTree.run.xml
+++ b/.run/taskTree.run.xml
@@ -4,7 +4,7 @@
-
+
diff --git a/libs.versions.toml b/libs.versions.toml
index 68136c1..92000f3 100644
--- a/libs.versions.toml
+++ b/libs.versions.toml
@@ -1,6 +1,6 @@
[versions]
-tasktree = "0.0.10"
+tasktree = "0.0.12"
[libraries]
diff --git a/readme.md b/readme.md
index 74580fa..b9fb9e8 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.10"
+ id("com.github.klee0kai.tasktree") version "0.0.12"
}
tasktree {
@@ -20,7 +20,7 @@ tasktree {
}
```
-Report your build graph
+Project build report in the form of a build graph. [Diagon](https://github.com/ArthurSonzogni/Diagon) must be installed
```bash
./gradlew taskTree assemble
@@ -37,7 +37,8 @@ Verify project's module dependency depth
```bash
./gradlew projectTree --verifyDepth=1
->> Heavy projects: ':example' depth: 2
+>> :dynamic_findstorage price: 3; depth: 3; importance: 0; relativePrice: 1,00; relativeDepth: 1,00; depth dependencies: :dynamic_findstorage <- :app_mobile <- :core;
+ Heavy projects: ':dynamic_findstorage' depth: 3
```
Build graphs
@@ -65,11 +66,11 @@ initscript {
maven(url = "https://jitpack.io")
}
dependencies {
- classpath("com.github.klee0kai.tasktree:com.github.klee0kai.tasktree.gradle.plugin:0.0.10")
+ classpath("com.github.klee0kai:tasktree:0.0.12")
}
}
-rootProject{
+rootProject {
pluginManager.apply(com.github.klee0kai.tasktree.TaskTreePlugin::class.java)
extensions.findByType(com.github.klee0kai.tasktree.TaskTreeExtension::class.java)
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 2a3e6ac..5cdb676 100644
--- a/tasktree/src/main/kotlin/com/github/klee0kai/tasktree/TaskTreePlugin.kt
+++ b/tasktree/src/main/kotlin/com/github/klee0kai/tasktree/TaskTreePlugin.kt
@@ -21,13 +21,14 @@ open class TaskTreePlugin : Plugin {
private fun Project.applyTaskReportOnProject(ext: TaskTreeExtension) {
- afterEvaluate {
+ afterEvaluate(10) {
val taskTree = tasks.register("taskTree", TaskTreeTask::class.java, ext)
val taskDag = tasks.register("taskGraph", TaskGraphTask::class.java)
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
@@ -35,7 +36,19 @@ open class TaskTreePlugin : Plugin {
}
}
}
+ }
+ /**
+ * we make sure that dependencies between tasks will no longer be configured
+ */
+ private fun Project.afterEvaluate(count: Int = 1, block: () -> Unit) {
+ if (count <= 0) {
+ block()
+ } else {
+ afterEvaluate {
+ afterEvaluate(count - 1, block)
+ }
+ }
}
}
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 a210508..0d14e3f 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
@@ -37,21 +37,28 @@ class TaskStat(
return field
}
- var depth: Int = 0
+ val depth: Int get() = depthDependencies.size
+
+ var depthDependencies: List = emptyList()
private set
get() {
- if (field != 0) return field
- var maxDepth = 1
- val checked = mutableSetOf()
- val deps = LinkedList(dependencies.map { it to 2 }.toMutableList())
+ if (field.isNotEmpty()) return field
+ val checked = mutableMapOf>()
+ val deps = LinkedList(dependencies.map { listOf(this@TaskStat, it) }.toMutableList())
while (deps.isNotEmpty()) {
val dep = deps.pollFirst()
- if (checked.contains(dep.first.id)) continue
- if (dep.second > maxDepth) maxDepth = dep.second
- checked.add(dep.first.id)
- deps.addAll(0, dep.first.dependencies.map { it to dep.second + 1 })
+ val checkedDepthDeps = checked.getOrDefault(dep.last().id, emptyList())
+ if (checkedDepthDeps.size >= dep.size
+ || checkedDepthDeps.isNotEmpty()
+ && dep.take(checkedDepthDeps.size).map { it.id } == checkedDepthDeps.map { it.id } // ignore doubles
+ ) {
+ continue
+ }
+ checked[dep.last().id] = dep
+ deps.removeAll { task -> task.last().id in dep.last().dependencies.map { it.id } }
+ deps.addAll(0, dep.last().dependencies.map { dep + it })
}
- field = maxDepth
+ field = checked.values.maxByOrNull { it.size } ?: emptyList()
return field
}
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 ed17cb4..33272dc 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
@@ -8,7 +8,8 @@ import org.gradle.api.tasks.diagnostics.internal.ProjectDetails
object TaskStatHelper {
fun collectAllTasksInfo(project: Project): List {
- val tasksInfos = project.tasks.map { task ->
+ val allTasks = project.tasks.toList()
+ val tasksInfos = allTasks.map { task ->
TaskInfo(
id = System.identityHashCode(task),
taskName = task.name,
@@ -20,7 +21,7 @@ object TaskStatHelper {
)
}.associateBy { task -> task.id }
- project.tasks.forEach { task ->
+ allTasks.forEach { task ->
runCatching {
task.taskDependencies.getDependencies(task).forEach { dependsOn ->
val taskStat = tasksInfos[System.identityHashCode(dependsOn)] ?: return@forEach
diff --git a/tasktree/src/main/kotlin/com/github/klee0kai/tasktree/projectInfo/ProjectInfo.kt b/tasktree/src/main/kotlin/com/github/klee0kai/tasktree/projectInfo/ProjectInfo.kt
index 5fc9f7f..b5f1ef7 100644
--- a/tasktree/src/main/kotlin/com/github/klee0kai/tasktree/projectInfo/ProjectInfo.kt
+++ b/tasktree/src/main/kotlin/com/github/klee0kai/tasktree/projectInfo/ProjectInfo.kt
@@ -27,7 +27,7 @@ class ProjectInfo(
private set
get() {
if (field != 0) return field
- field = allDependedOnTasks.count()
+ field = allDependedOnProject.count()
return field
}
@@ -44,7 +44,7 @@ class ProjectInfo(
}
}
- val allDependedOnTasks = sequence {
+ val allDependedOnProject = sequence {
val sent = mutableSetOf()
val deps = LinkedList(dependedOnProjects.toMutableList())
while (deps.isNotEmpty()) {
@@ -56,21 +56,27 @@ class ProjectInfo(
}
}
- var depth: Int = 0
+ val depth: Int get() = depthDependencies.size
+
+ var depthDependencies: List = emptyList()
private set
get() {
- if (field != 0) return field
- var maxDepth = 1
- val checked = mutableSetOf()
- val deps = LinkedList(dependencies.map { it to 2 }.toMutableList())
+ if (field.isNotEmpty()) return field
+ val checked = mutableMapOf>()
+ val deps = LinkedList(dependencies.map { listOf(this@ProjectInfo, it) }.toMutableList())
while (deps.isNotEmpty()) {
val dep = deps.pollFirst()
- if (checked.contains(dep.first.path)) continue
- if (dep.second > maxDepth) maxDepth = dep.second
- checked.add(dep.first.path)
- deps.addAll(0, dep.first.dependencies.map { it to dep.second + 1 })
+ val checkedDepthDeps = checked.getOrDefault(dep.last().path, emptyList())
+ if (checkedDepthDeps.size >= dep.size
+ || checkedDepthDeps.isNotEmpty()
+ && dep.take(checkedDepthDeps.size).map { it.path } == checkedDepthDeps.map { it.path } // ignore doubles
+ ) {
+ continue
+ }
+ checked[dep.last().path] = dep
+ deps.addAll(0, dep.last().dependencies.map { dep + it })
}
- field = maxDepth
+ field = checked.values.maxByOrNull { it.size } ?: emptyList()
return field
}
diff --git a/tasktree/src/main/kotlin/com/github/klee0kai/tasktree/projectInfo/ProjectStatHelper.kt b/tasktree/src/main/kotlin/com/github/klee0kai/tasktree/projectInfo/ProjectStatHelper.kt
index 217154c..b51c94b 100644
--- a/tasktree/src/main/kotlin/com/github/klee0kai/tasktree/projectInfo/ProjectStatHelper.kt
+++ b/tasktree/src/main/kotlin/com/github/klee0kai/tasktree/projectInfo/ProjectStatHelper.kt
@@ -15,16 +15,18 @@ object ProjectStatHelper {
path = it.path,
projectDetails = ProjectDetails.of(it),
)
- }.associateBy { it.name }
+ }.associateBy { it.path }
rootProject.allprojects.forEach { project ->
- val projectInfo = projectInfos[project.name] ?: return@forEach
+ val projectInfo = projectInfos[project.path] ?: return@forEach
project.configurations
.firstOrNull { it.name.contains("implementation") }
?.allDependencies
?.filterIsInstance()
?.forEach { dep ->
- val depProjectInfo = projectInfos[dep.name] ?: return@forEach
+ val depProjectInfo = runCatching { projectInfos[dep.path] }.getOrNull()
+ ?: runCatching { projectInfos[dep.dependencyProject.path] }.getOrNull()
+ ?: return@forEach
projectInfo.dependencies.add(depProjectInfo)
}
}
@@ -54,4 +56,14 @@ object ProjectStatHelper {
}
+ fun filterByRequestedProject(
+ projectStats: List,
+ target: String?,
+ ): List {
+ if (target.isNullOrBlank()) return projectStats
+ return projectStats.filter {
+ it.fullName == target || it.allDependedOnProject.any { it.fullName == target }
+ }
+ }
+
}
\ No newline at end of file
diff --git a/tasktree/src/main/kotlin/com/github/klee0kai/tasktree/tasks/ProjectTreeTask.kt b/tasktree/src/main/kotlin/com/github/klee0kai/tasktree/tasks/ProjectTreeTask.kt
index c5d870b..338f5e1 100644
--- a/tasktree/src/main/kotlin/com/github/klee0kai/tasktree/tasks/ProjectTreeTask.kt
+++ b/tasktree/src/main/kotlin/com/github/klee0kai/tasktree/tasks/ProjectTreeTask.kt
@@ -23,7 +23,12 @@ open class ProjectTreeTask @Inject constructor(
private val projectsInfos = Cached.of { ProjectStatHelper.collectProjectDependencies(project) }
- private val projectsStats by lazy { ProjectStatHelper.calcToProjectStats(projectsInfos.get()) }
+ private var projectsStats: List = emptyList()
+
+ @Input
+ @Optional
+ @set:Option(option = "target", description = "Build graph to module as target")
+ protected var projectTarget: String? = null
@Input
@Optional
@@ -35,8 +40,13 @@ open class ProjectTreeTask @Inject constructor(
@set:Option(option = "verifyPrice", description = "Verify project's module price")
protected var verifyPrice: String? = null
+ override fun getDescription(): String = "Display the hierarchy of module dependencies in a project"
+
@TaskAction
fun generate() {
+ projectsStats = ProjectStatHelper.calcToProjectStats(projectInfos = projectsInfos.get())
+ .let { ProjectStatHelper.filterByRequestedProject(projectStats = it, target = projectTarget) }
+
renderedProjects.clear()
reportGenerator().generateReport(
listOf(projectDetails.get()),
@@ -44,7 +54,13 @@ open class ProjectTreeTask @Inject constructor(
) { projects ->
val graphRenderer = GraphRenderer(renderer.textOutput)
val topProjects = projectsStats
- .filter { project -> project.allDependedOnCount <= 0L }
+ .filter { project ->
+ if (!projectTarget.isNullOrBlank()) {
+ project.fullName == projectTarget
+ } else {
+ project.allDependedOnCount <= 0L
+ }
+ }
.sortedByDescending { it.depth }
topProjects.forEach { graphRenderer.render(it) }
@@ -103,14 +119,17 @@ open class ProjectTreeTask @Inject constructor(
allStat.forEach {
renderer.textOutput
- .printProjectShort(it)
+ .printProjectShort(projectInfo = it, printDepthLine = true)
.println()
}
textOutput.println()
}
}
- private fun StyledTextOutput.printProjectShort(projectInfo: ProjectInfo) = apply {
+ private fun StyledTextOutput.printProjectShort(
+ projectInfo: ProjectInfo,
+ printDepthLine: Boolean = false,
+ ) = apply {
withStyle(Identifier)
.text(projectInfo.fullName)
@@ -120,6 +139,8 @@ open class ProjectTreeTask @Inject constructor(
withStyle(Description)
.text(" depth: ${projectInfo.depth};")
+
+
}
if (ext.printImportance) {
withStyle(Description)
@@ -132,6 +153,11 @@ open class ProjectTreeTask @Inject constructor(
withStyle(Description)
.text(" relativeDepth: ${projectInfo.relativeDepth.formatString()};")
}
+
+ if (ext.printPrice && printDepthLine) {
+ withStyle(Description)
+ .text(" depth dependencies: ${projectInfo.depthDependencies.joinToString(" <- ") { it.fullName }};")
+ }
}
diff --git a/tasktree/src/main/kotlin/com/github/klee0kai/tasktree/tasks/ProjectsGraphTask.kt b/tasktree/src/main/kotlin/com/github/klee0kai/tasktree/tasks/ProjectsGraphTask.kt
index 8f2dbcf..60d3a9c 100644
--- a/tasktree/src/main/kotlin/com/github/klee0kai/tasktree/tasks/ProjectsGraphTask.kt
+++ b/tasktree/src/main/kotlin/com/github/klee0kai/tasktree/tasks/ProjectsGraphTask.kt
@@ -1,11 +1,13 @@
package com.github.klee0kai.tasktree.tasks
+import com.github.klee0kai.tasktree.projectInfo.ProjectInfo
import com.github.klee0kai.tasktree.projectInfo.ProjectStatHelper
import org.apache.tools.ant.util.TeeOutputStream
import org.gradle.api.model.ObjectFactory
import org.gradle.api.tasks.Input
-import org.gradle.api.tasks.Internal
+import org.gradle.api.tasks.Optional
import org.gradle.api.tasks.TaskAction
+import org.gradle.api.tasks.options.Option
import org.gradle.internal.serialization.Cached
import org.gradle.process.internal.ExecActionFactory
import org.gradle.process.internal.ExecException
@@ -22,15 +24,22 @@ open class ProjectsGraphTask @Inject constructor(
private val projectsInfos = Cached.of { ProjectStatHelper.collectProjectDependencies(project) }
- private val projectsStats by lazy { ProjectStatHelper.calcToProjectStats(projectsInfos.get()) }
+ private var projectsStats: List = emptyList()
+
+ @Input
+ @Optional
+ @set:Option(option = "target", description = "Build graph to module as target")
+ protected var target: String? = null
- @Internal
override fun getDescription(): String =
- "Draw tasktree graph use Diagon. More: https://github.com/ArthurSonzogni/Diagon"
+ "Draw project's dependencies graph use Diagon. More: https://github.com/ArthurSonzogni/Diagon"
@TaskAction
fun generate() {
+ projectsStats = ProjectStatHelper.calcToProjectStats(projectInfos = projectsInfos.get())
+ .let { ProjectStatHelper.filterByRequestedProject(projectStats = it, target = target) }
+
val depsCode = projectsStats.joinToString("\n") { project ->
project.dependencies.joinToString("\n") { dep ->
"${dep.fullName} -> ${project.fullName}"
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 9d2d63d..ed82afb 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
@@ -23,10 +23,7 @@ open class TaskTreeTask @Inject constructor(
private val tasksInfos = Cached.of { TaskStatHelper.collectAllTasksInfo(project) }
- private val tasksStats by lazy {
- TaskStatHelper.calcToTaskStats(tasksInfos.get())
- .let { TaskStatHelper.filterByRequestedTasks(it, allRequestedTasksIds.get()) }
- }
+ private var tasksStats: List = emptyList()
@Input
@Optional
@@ -40,6 +37,9 @@ open class TaskTreeTask @Inject constructor(
@TaskAction
fun generate() {
+ tasksStats = TaskStatHelper.calcToTaskStats(tasksInfos.get())
+ .let { TaskStatHelper.filterByRequestedTasks(it, allRequestedTasksIds.get()) }
+
renderedTasks.clear()
reportGenerator().generateReport(
listOf(projectDetails.get()),
@@ -62,7 +62,11 @@ open class TaskTreeTask @Inject constructor(
}
}
- private fun GraphRenderer.render(taskStat: TaskStat, lastChild: Boolean = true, depth: Int = 0) {
+ private fun GraphRenderer.render(
+ taskStat: TaskStat,
+ lastChild: Boolean = true,
+ depth: Int = 0,
+ ) {
visit({
printTaskShort(taskStat)
@@ -108,7 +112,7 @@ open class TaskTreeTask @Inject constructor(
allStat.forEach {
renderer.textOutput
- .printTaskShort(it)
+ .printTaskShort(taskStat = it, printDepthLine = true)
.println()
}
textOutput.println()
@@ -116,7 +120,10 @@ open class TaskTreeTask @Inject constructor(
}
- private fun StyledTextOutput.printTaskShort(taskStat: TaskStat) = apply {
+ private fun StyledTextOutput.printTaskShort(
+ taskStat: TaskStat,
+ printDepthLine: Boolean = false,
+ ) = apply {
withStyle(Identifier)
.text(taskStat.fullName)
@@ -137,6 +144,12 @@ open class TaskTreeTask @Inject constructor(
withStyle(Description)
.text(" relativeDepth: ${taskStat.relativeDepth.formatString()};")
}
+
+
+ if (ext.printPrice && printDepthLine) {
+ withStyle(Description)
+ .text(" depth dependencies: ${taskStat.depthDependencies.joinToString(" <- ") { it.fullName }};")
+ }
}