f945e46e4ffd8b90bdd37c537be8492a81667591
[idea/community.git] / plugins / gradle / tooling-extension-impl / src / org / jetbrains / plugins / gradle / tooling / tasks / DependenciesReport.groovy
1 // Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
2 package org.jetbrains.plugins.gradle.tooling.tasks
3
4 import com.google.gson.GsonBuilder
5 import com.intellij.openapi.externalSystem.model.project.dependencies.*
6 import groovy.transform.CompileStatic
7 import org.gradle.api.DefaultTask
8 import org.gradle.api.Project
9 import org.gradle.api.artifacts.Configuration
10 import org.gradle.api.artifacts.component.ModuleComponentIdentifier
11 import org.gradle.api.artifacts.component.ProjectComponentIdentifier
12 import org.gradle.api.artifacts.result.ResolutionResult
13 import org.gradle.api.tasks.Input
14 import org.gradle.api.tasks.OutputFile
15 import org.gradle.api.tasks.TaskAction
16 import org.gradle.api.tasks.diagnostics.internal.graph.nodes.RenderableDependency
17 import org.gradle.api.tasks.diagnostics.internal.graph.nodes.RenderableModuleResult
18 import org.gradle.util.GradleVersion
19
20 @CompileStatic
21 class DependenciesReport extends DefaultTask {
22
23   @Input
24   List<String> configurations = []
25   @OutputFile
26   File outputFile
27
28   @TaskAction
29   void generate() {
30     Collection<Configuration> configurationList
31     if (configurations.isEmpty()) {
32       configurationList = project.configurations
33     }
34     else {
35       configurationList = new ArrayList<>()
36       for (configurationName in configurations) {
37         def configuration = project.configurations.findByName(configurationName)
38         if (configuration != null) {
39           configurationList.add(configuration)
40         }
41       }
42     }
43
44     def projectNameFunction = new ProjectNameFunction()
45     List<DependencyScopeNode> graph = []
46     for (configuration in configurationList) {
47       if (!configuration.isCanBeResolved()) continue
48       graph.add(doBuildDependenciesGraph(configuration, project, projectNameFunction))
49     }
50     outputFile.parentFile.mkdirs()
51     outputFile.text = new GsonBuilder().create().toJson(graph)
52   }
53
54   static DependencyScopeNode buildDependenciesGraph(Configuration configuration, Project project) {
55     return doBuildDependenciesGraph(configuration, project, new ProjectNameFunction())
56   }
57
58   private static DependencyScopeNode doBuildDependenciesGraph(Configuration configuration,
59                                                               Project project,
60                                                               ProjectNameFunction projectNameFunction) {
61     if (!project.configurations.contains(configuration)) {
62       throw new IllegalArgumentException("configurations of the project should be used")
63     }
64     ResolutionResult resolutionResult = configuration.getIncoming().getResolutionResult()
65     RenderableDependency root = new RenderableModuleResult(resolutionResult.root)
66     String configurationName = configuration.name
67     IdGenerator idGenerator = new IdGenerator()
68     long id = idGenerator.getId(root, configurationName)
69     String scopeDisplayName = "project " + project.path + " (" + configurationName + ")"
70     DependencyScopeNode node = new DependencyScopeNode(id, configurationName, scopeDisplayName, configuration.getDescription())
71     node.setResolutionState(root.resolutionState.name())
72     Map<Object, DependencyNode> added = [:]
73     for (RenderableDependency child in root.getChildren()) {
74       node.dependencies.add(toNode(child, configurationName, added, idGenerator, projectNameFunction))
75     }
76     return node
77   }
78
79   static private DependencyNode toNode(RenderableDependency dependency,
80                                        String configurationName,
81                                        Map<Object, DependencyNode> added,
82                                        IdGenerator idGenerator,
83                                        ProjectNameFunction projectNameFunction) {
84     long id = idGenerator.getId(dependency, configurationName)
85     DependencyNode alreadySeenNode = added.get(id)
86     if (alreadySeenNode != null) {
87       return new ReferenceNode(id)
88     }
89
90     AbstractDependencyNode node
91     if (dependency.id instanceof ProjectComponentIdentifier) {
92       ProjectComponentIdentifier projectId = dependency.id as ProjectComponentIdentifier
93       node = new ProjectDependencyNodeImpl(id, projectNameFunction.fun(projectId))
94     }
95     else if (dependency.id instanceof ModuleComponentIdentifier) {
96       ModuleComponentIdentifier moduleId = dependency.id as ModuleComponentIdentifier
97       node = new ArtifactDependencyNodeImpl(id, moduleId.group, moduleId.module, moduleId.version)
98     }
99     else {
100       node = new UnknownDependencyNode(id, dependency.name)
101     }
102     node.setResolutionState(dependency.resolutionState.name())
103     added.put(id, node)
104     Iterator<? extends RenderableDependency> iterator = dependency.getChildren().iterator()
105     while (iterator.hasNext()) {
106       RenderableDependency child = iterator.next()
107       node.dependencies.add(toNode(child, configurationName, added, idGenerator, projectNameFunction))
108     }
109     return node
110   }
111
112   static class ProjectNameFunction {
113     def is45OrNewer = GradleVersion.current() >= GradleVersion.version("4.5")
114
115     String fun(ProjectComponentIdentifier identifier) {
116       return is45OrNewer ? identifier.projectName : identifier.projectPath
117     }
118   }
119
120   private static class IdGenerator {
121     private Map<String, Long> idMap = new HashMap<>()
122     private long value
123
124     private long getId(RenderableDependency dependency, String configurationName) {
125       def key = dependency.id.toString() + '_' + configurationName
126       def id = idMap.get(key)
127       if (id == null) {
128         idMap[key] = ++value
129         id = value
130       }
131       return id
132     }
133   }
134 }