From 3c6f2ae281b902ce5a9d79a785f0d3e89dc95955 Mon Sep 17 00:00:00 2001 From: LEE YOU BIN Date: Fri, 21 Jun 2024 05:44:59 +0900 Subject: [PATCH] =?UTF-8?q?[FEAT/#22]=20=EC=9D=98=EC=A1=B4=20=EA=B7=B8?= =?UTF-8?q?=EB=9E=98=ED=94=84=20=EB=A7=8C=EB=93=A4=EA=B8=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.gradle | 5 +- gradle/projectDependencyGraph.gradle | 127 +++++++++++++++++++++++++++ 2 files changed, 131 insertions(+), 1 deletion(-) create mode 100644 gradle/projectDependencyGraph.gradle diff --git a/build.gradle b/build.gradle index 5a74b2f..c4a6e3f 100644 --- a/build.gradle +++ b/build.gradle @@ -7,7 +7,6 @@ plugins { id 'org.jetbrains.kotlin.android' version '1.9.0' apply false id 'org.jetbrains.kotlin.jvm' version '1.9.0' apply false id 'com.google.dagger.hilt.android' version '2.48.1' apply false - id "com.vanniktech.dependency.graph.generator" version "0.7.0" } ext { @@ -19,4 +18,8 @@ allprojects { jvmTarget = "1.8" } } +} + +apply { + from("gradle/projectDependencyGraph.gradle") } \ No newline at end of file diff --git a/gradle/projectDependencyGraph.gradle b/gradle/projectDependencyGraph.gradle new file mode 100644 index 0000000..e8de499 --- /dev/null +++ b/gradle/projectDependencyGraph.gradle @@ -0,0 +1,127 @@ +task projectDependencyGraph { + doLast { + def dot = new File(rootProject.rootDir, '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() + def dependencies = new LinkedHashMap, List>() + def multiplatformProjects = [] + def jsProjects = [] + def androidProjects = [] + def androidDynamicFeatureProjects = [] + 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('kotlin2js')) { + jsProjects.add(project) + } + if (project.plugins.hasPlugin('com.android.library') || + project.plugins.hasPlugin('com.android.application')) { + androidProjects.add(project) + } + if (project.plugins.hasPlugin('com.android.dynamic-feature')) { + androidDynamicFeatureProjects.add(project) + } + if (project.plugins.hasPlugin('java-library') || project.plugins.hasPlugin('java')) { + javaProjects.add(project) + } + + project.configurations.all { config -> + if (config.name.toLowerCase().contains("test")) return + config.dependencies + .withType(ProjectDependency) + .collect { it.dependencyProject } + .each { dependency -> + projects.add(project) + projects.add(dependency) + rootProjects.remove(dependency) + + def graphKey = new Tuple2(project, dependency) + def traits = dependencies.computeIfAbsent(graphKey) { new ArrayList() } + + 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 (androidDynamicFeatureProjects.contains(project)) { + traits.add('fillcolor="#c9baff"') + } 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 dotPath = "C:/Program Files/Graphviz/bin/dot" + def p = "${dotPath} -Tpng -O project.dot".execute([], dot.parentFile) + + p.waitFor() + if (p.exitValue() != 0) { + throw new RuntimeException(p.errorStream.text) + } + dot.delete() + + println("Project module dependency graph created at ${dot.absolutePath}.png") + } +} \ No newline at end of file