1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116
| task projectDependencyGraph { doLast { def dot = new File(rootProject.buildDir, 'reports/dependency-graph/project.dot') dot.parentFile.mkdirs() dot.delete()
dot << 'digraph {\n' dot << " graph [label=\"${rootProject.name}\\n \",labelloc=t,fontsize=30,ranksep=1.4];\n" dot << ' node [style=filled, fillcolor="#bbbbbb"];\n' dot << ' rankdir=TB;\n'
def rootProjects = [] def queue = [rootProject] while (!queue.isEmpty()) { def project = queue.remove(0) rootProjects.add(project) queue.addAll(project.childProjects.values()) }
def projects = new LinkedHashSet<Project>() def dependencies = new LinkedHashMap<Tuple2<Project, Project>, List<String>>() def multiplatformProjects = [] def jsProjects = [] def androidProjects = [] def javaProjects = []
queue = [rootProject] while (!queue.isEmpty()) { def project = queue.remove(0) queue.addAll(project.childProjects.values())
if (project.plugins.hasPlugin('org.jetbrains.kotlin.multiplatform')) { multiplatformProjects.add(project) } if (project.plugins.hasPlugin('org.jetbrains.kotlin.js')) { jsProjects.add(project) } if (project.plugins.hasPlugin('com.android.library') || project.plugins.hasPlugin('com.android.application')) { androidProjects.add(project) } if (project.plugins.hasPlugin('java-library') || project.plugins.hasPlugin('java')) { javaProjects.add(project) }
project.configurations.all { config -> config.dependencies .withType(ProjectDependency) .collect { it.dependencyProject } .each { dependency -> projects.add(project) projects.add(dependency) rootProjects.remove(dependency)
def graphKey = new Tuple2<Project, Project>(project, dependency) def traits = dependencies.computeIfAbsent(graphKey) { new ArrayList<String>() }
if (config.name.toLowerCase().endsWith('implementation')) { traits.add('style=dotted') } } } }
projects = projects.sort { it.path }
dot << '\n # Projects\n\n' for (project in projects) { def traits = []
if (rootProjects.contains(project)) { traits.add('shape=box') }
if (multiplatformProjects.contains(project)) { traits.add('fillcolor="#ffd2b3"') } else if (jsProjects.contains(project)) { traits.add('fillcolor="#ffffba"') } else if (androidProjects.contains(project)) { traits.add('fillcolor="#baffc9"') } else if (javaProjects.contains(project)) { traits.add('fillcolor="#ffb3ba"') } else { traits.add('fillcolor="#eeeeee"') }
dot << " \"${project.path}\" [${traits.join(", ")}];\n" }
dot << '\n {rank = same;' for (project in projects) { if (rootProjects.contains(project)) { dot << " \"${project.path}\";" } } dot << '}\n'
dot << '\n # Dependencies\n\n' dependencies.forEach { key, traits -> dot << " \"${key.first.path}\" -> \"${key.second.path}\"" if (!traits.isEmpty()) { dot << " [${traits.join(", ")}]" } dot << '\n' }
dot << '}\n'
def p = 'dot -Tpng -O project.dot'.execute([], dot.parentFile) p.waitFor() if (p.exitValue() != 0) { throw new RuntimeException(p.errorStream.text) }
println("Project module dependency graph created at ${dot.absolutePath}.png") } }
|