From 12ed7b2fc23423c9388f93132f09d7559f0c19a9 Mon Sep 17 00:00:00 2001 From: "Vladislav.Soroka" Date: Tue, 17 Apr 2018 18:12:01 +0300 Subject: [PATCH] IDEA-189333 Gradle: buildscript classpath resolve doesn't work for included build project dependency --- .../importing/GradleFindUsagesTest.java | 63 ++++++++++++------- .../model/ExternalProjectDependency.java | 2 + .../DefaultExternalProjectDependency.java | 10 +++ .../ModelBuildScriptClasspathBuilderImpl.java | 17 +++-- .../tooling/util/DependencyResolverImpl.java | 27 ++++++-- .../tooling/util/SourceSetCachedFinder.groovy | 41 ++++++++++-- 6 files changed, 124 insertions(+), 36 deletions(-) diff --git a/plugins/gradle/java/testSources/importing/GradleFindUsagesTest.java b/plugins/gradle/java/testSources/importing/GradleFindUsagesTest.java index 921b1d4e386e..ef906317e445 100644 --- a/plugins/gradle/java/testSources/importing/GradleFindUsagesTest.java +++ b/plugins/gradle/java/testSources/importing/GradleFindUsagesTest.java @@ -117,31 +117,45 @@ public class GradleFindUsagesTest extends GradleImportingTestCase { createProjectSubFile("buildSrc/src/main/groovy/org/buildsrc/BuildSrcClass.groovy", "package org.buildsrc;\n" + "public class BuildSrcClass {}"); - createProjectSubFile("build.gradle", "def foo = new org.buildsrc.BuildSrcClass()"); - createProjectSubFile("app/build.gradle", "def foo1 = new org.buildsrc.BuildSrcClass()"); + createProjectSubFile("build.gradle", "buildscript {\n" + + " dependencies {\n" + + " classpath 'my.included:gradle-plugin:0'\n" + + " }\n" + + "}\n" + + "def foo1 = new org.buildsrc.BuildSrcClass()\n" + + "def foo2 = new org.included.IncludedBuildClass()"); + createProjectSubFile("app/build.gradle", "def foo1 = new org.buildsrc.BuildSrcClass()\n" + + "def foo2 = new org.included.IncludedBuildClass()"); // included build createProjectSubFile("gradle-plugin/settings.gradle", ""); - createProjectSubFile("gradle-plugin/build.gradle", "def foo = new org.buildsrc.IncludedBuildSrcClass()"); + createProjectSubFile("gradle-plugin/build.gradle", "group 'my.included'\n" + + "apply plugin: 'java'\n" + + "def foo = new org.included.buildsrc.IncludedBuildSrcClass()"); createProjectSubFile("gradle-plugin/buildSrc/src/main/groovy/org/included/buildsrc/IncludedBuildSrcClass.groovy", - "package org.buildsrc;\n" + + "package org.included.buildsrc;\n" + "public class IncludedBuildSrcClass {}"); + createProjectSubFile("gradle-plugin/src/main/java/org/included/IncludedBuildClass.java", + "package org.included;\n" + + "public class IncludedBuildClass {}"); importProject(); assertModules("multiproject", "app", "multiproject_buildSrc", "multiproject_buildSrc_main", "multiproject_buildSrc_test", - "gradle-plugin", - "gradle-plugin_buildSrc", "gradle-plugin_buildSrc_main", "gradle-plugin_buildSrc_test"); + "gradle-plugin", "gradle-plugin_test", "gradle-plugin_main", + "my.included_buildSrc", "my.included_buildSrc_main", "my.included_buildSrc_test"); assertUsages("org.buildsrc.BuildSrcClass", 2); - assertUsages("org.buildsrc.IncludedBuildSrcClass", 1); + assertUsages("org.included.buildsrc.IncludedBuildSrcClass", 1); + assertUsages("org.included.IncludedBuildClass", 2); importProjectUsingSingeModulePerGradleProject(); assertModules("multiproject", "app", "multiproject_buildSrc", "gradle-plugin", - "gradle-plugin_buildSrc"); - assertUsages(pair("org.buildsrc.BuildSrcClass", 2), pair("org.buildsrc.IncludedBuildSrcClass", 1)); + "my.included_buildSrc"); + assertUsages(pair("org.buildsrc.BuildSrcClass", 2), pair("org.included.buildsrc.IncludedBuildSrcClass", 1)); + assertUsages("org.included.IncludedBuildClass", 2); // check for qualified module names getCurrentExternalProjectSettings().setUseQualifiedModuleNames(true); @@ -149,37 +163,38 @@ public class GradleFindUsagesTest extends GradleImportingTestCase { importProject(); assertModules("multiproject", "multiproject.app", "multiproject.buildSrc", "multiproject.buildSrc.main", "multiproject.buildSrc.test", - "gradle-plugin", - "gradle-plugin.buildSrc", "gradle-plugin.buildSrc.main", "gradle-plugin.buildSrc.test"); - assertUsages(pair("org.buildsrc.BuildSrcClass", 2), pair("org.buildsrc.IncludedBuildSrcClass", 1)); + "my.included.gradle-plugin", "my.included.gradle-plugin.test", "my.included.gradle-plugin.main", + "my.included.buildSrc", "my.included.buildSrc.main", "my.included.buildSrc.test"); + assertUsages(pair("org.buildsrc.BuildSrcClass", 2), pair("org.included.buildsrc.IncludedBuildSrcClass", 1)); + assertUsages("org.included.IncludedBuildClass", 2); importProjectUsingSingeModulePerGradleProject(); assertModules("multiproject", "multiproject.app", "multiproject.buildSrc", - "gradle-plugin", - "gradle-plugin.buildSrc"); - assertUsages(pair("org.buildsrc.BuildSrcClass", 2), pair("org.buildsrc.IncludedBuildSrcClass", 1)); + "my.included.gradle-plugin", + "my.included.buildSrc"); + assertUsages(pair("org.buildsrc.BuildSrcClass", 2), pair("org.included.buildsrc.IncludedBuildSrcClass", 1)); + assertUsages("org.included.IncludedBuildClass", 2); } - private void assertUsages(String fqn, GlobalSearchScope scope, int count) { - edt(() -> { - PsiClass[] psiClasses = JavaPsiFacade.getInstance(myProject).findClasses(fqn, scope); - assertEquals(1, psiClasses.length); - assertUsagesCount(count, psiClasses[0]); - }); + private void assertUsages(String fqn, GlobalSearchScope scope, int count) throws Exception { + final PsiClass[][] psiClasses = new PsiClass[1][1]; + edt(() -> psiClasses[0] = JavaPsiFacade.getInstance(myProject).findClasses(fqn, scope)); + assertEquals(1, psiClasses[0].length); + assertUsagesCount(count, psiClasses[0][0]); } - private void assertUsages(String fqn, int count) { + private void assertUsages(String fqn, int count) throws Exception { assertUsages(fqn, GlobalSearchScope.projectScope(myProject), count); } - private void assertUsages(Trinity... classUsageCount) { + private void assertUsages(Trinity... classUsageCount) throws Exception { for (Trinity trinity : classUsageCount) { assertUsages(trinity.first, trinity.second, trinity.third); } } - private void assertUsages(Pair... classUsageCount) { + private void assertUsages(Pair... classUsageCount) throws Exception { for (Pair pair : classUsageCount) { assertUsages(Trinity.create(pair.first, GlobalSearchScope.projectScope(myProject), pair.second)); } diff --git a/plugins/gradle/tooling-extension-api/src/org/jetbrains/plugins/gradle/model/ExternalProjectDependency.java b/plugins/gradle/tooling-extension-api/src/org/jetbrains/plugins/gradle/model/ExternalProjectDependency.java index 5ce558346e4e..092a2d836329 100644 --- a/plugins/gradle/tooling-extension-api/src/org/jetbrains/plugins/gradle/model/ExternalProjectDependency.java +++ b/plugins/gradle/tooling-extension-api/src/org/jetbrains/plugins/gradle/model/ExternalProjectDependency.java @@ -29,4 +29,6 @@ public interface ExternalProjectDependency extends ExternalDependency { String getConfigurationName(); Collection getProjectDependencyArtifacts(); + + Collection getProjectDependencyArtifactsSources(); } diff --git a/plugins/gradle/tooling-extension-impl/src/org/jetbrains/plugins/gradle/model/DefaultExternalProjectDependency.java b/plugins/gradle/tooling-extension-impl/src/org/jetbrains/plugins/gradle/model/DefaultExternalProjectDependency.java index 982df36e858a..56acd73043a1 100644 --- a/plugins/gradle/tooling-extension-impl/src/org/jetbrains/plugins/gradle/model/DefaultExternalProjectDependency.java +++ b/plugins/gradle/tooling-extension-impl/src/org/jetbrains/plugins/gradle/model/DefaultExternalProjectDependency.java @@ -33,6 +33,7 @@ public class DefaultExternalProjectDependency extends AbstractExternalDependency private String myProjectPath; private String myConfigurationName = Dependency.DEFAULT_CONFIGURATION; private Collection myProjectDependencyArtifacts; + private Collection myProjectDependencyArtifactsSources; public DefaultExternalProjectDependency() { } @@ -78,6 +79,15 @@ public class DefaultExternalProjectDependency extends AbstractExternalDependency myProjectDependencyArtifacts = projectArtifacts; } + @Override + public Collection getProjectDependencyArtifactsSources() { + return myProjectDependencyArtifactsSources; + } + + public void setProjectDependencyArtifactsSources(Collection projectArtifactsSources) { + myProjectDependencyArtifactsSources = projectArtifactsSources; + } + @Override public boolean equals(Object o) { if (this == o) return true; diff --git a/plugins/gradle/tooling-extension-impl/src/org/jetbrains/plugins/gradle/tooling/builder/ModelBuildScriptClasspathBuilderImpl.java b/plugins/gradle/tooling-extension-impl/src/org/jetbrains/plugins/gradle/tooling/builder/ModelBuildScriptClasspathBuilderImpl.java index c53f5644cb8d..aeb4fea05cd5 100644 --- a/plugins/gradle/tooling-extension-impl/src/org/jetbrains/plugins/gradle/tooling/builder/ModelBuildScriptClasspathBuilderImpl.java +++ b/plugins/gradle/tooling-extension-impl/src/org/jetbrains/plugins/gradle/tooling/builder/ModelBuildScriptClasspathBuilderImpl.java @@ -89,7 +89,17 @@ public class ModelBuildScriptClasspathBuilderImpl implements ModelBuilderService new DependencyResolverImpl(project, false, downloadJavadoc, downloadSources, mySourceSetFinder).resolveDependencies(classpathConfiguration); for (ExternalDependency dependency : new DependencyTraverser(dependencies)) { - if (dependency instanceof ExternalLibraryDependency) { + if (dependency instanceof ExternalProjectDependency) { + ExternalProjectDependency projectDependency = (ExternalProjectDependency)dependency; + Collection projectDependencyArtifacts = projectDependency.getProjectDependencyArtifacts(); + Collection projectDependencyArtifactsSources = projectDependency.getProjectDependencyArtifactsSources(); + buildScriptClasspath.add(new ClasspathEntryModelImpl( + pathSet(projectDependencyArtifacts), + pathSet(projectDependencyArtifactsSources), + new HashSet() + )); + } + else if (dependency instanceof ExternalLibraryDependency) { final ExternalLibraryDependency libraryDep = (ExternalLibraryDependency)dependency; buildScriptClasspath.add(new ClasspathEntryModelImpl( pathSet(libraryDep.getFile()), @@ -97,7 +107,7 @@ public class ModelBuildScriptClasspathBuilderImpl implements ModelBuilderService pathSet(libraryDep.getJavadoc()) )); } - if (dependency instanceof ExternalMultiLibraryDependency) { + else if (dependency instanceof ExternalMultiLibraryDependency) { ExternalMultiLibraryDependency multiLibraryDependency = (ExternalMultiLibraryDependency)dependency; buildScriptClasspath.add(new ClasspathEntryModelImpl( pathSet(multiLibraryDependency.getFiles()), @@ -105,8 +115,7 @@ public class ModelBuildScriptClasspathBuilderImpl implements ModelBuilderService pathSet(multiLibraryDependency.getJavadoc()) )); } - - if (dependency instanceof FileCollectionDependency) { + else if (dependency instanceof FileCollectionDependency) { FileCollectionDependency fileCollectionDependency = (FileCollectionDependency)dependency; buildScriptClasspath.add(new ClasspathEntryModelImpl( pathSet(fileCollectionDependency.getFiles()), diff --git a/plugins/gradle/tooling-extension-impl/src/org/jetbrains/plugins/gradle/tooling/util/DependencyResolverImpl.java b/plugins/gradle/tooling-extension-impl/src/org/jetbrains/plugins/gradle/tooling/util/DependencyResolverImpl.java index fccbb9a3a1e0..6eb5ea56ed1b 100644 --- a/plugins/gradle/tooling-extension-impl/src/org/jetbrains/plugins/gradle/tooling/util/DependencyResolverImpl.java +++ b/plugins/gradle/tooling-extension-impl/src/org/jetbrains/plugins/gradle/tooling/util/DependencyResolverImpl.java @@ -904,7 +904,9 @@ public class DependencyResolverImpl implements DependencyResolver { projectDependency.setScope(scope); projectDependency.setProjectPath(project.getPath()); projectDependency.setConfigurationName(targetConfiguration.getName()); - projectDependency.setProjectDependencyArtifacts(targetConfiguration.getAllArtifacts().getFiles().getFiles()); + Set artifacts = targetConfiguration.getAllArtifacts().getFiles().getFiles(); + projectDependency.setProjectDependencyArtifacts(artifacts); + setProjectDependencyArtifactsSources(projectDependency, artifacts, mySourceSetFinder); result.add(projectDependency); } else if (it != null) { @@ -1034,7 +1036,9 @@ public class DependencyResolverImpl implements DependencyResolver { dependency.setSelectionReason(selectionReason); dependency.setProjectPath(((ProjectComponentSelector)componentSelector).getProjectPath()); dependency.setConfigurationName(it.getName()); - dependency.setProjectDependencyArtifacts(it.getAllArtifacts().getFiles().getFiles()); + Set artifacts = it.getAllArtifacts().getFiles().getFiles(); + dependency.setProjectDependencyArtifacts(artifacts); + setProjectDependencyArtifactsSources(dependency, artifacts, mySourceSetFinder); resolvedDepsFiles.addAll(dependency.getProjectDependencyArtifacts()); @@ -1060,7 +1064,9 @@ public class DependencyResolverImpl implements DependencyResolver { dependency.setSelectionReason(selectionReason); dependency.setProjectPath(((ProjectComponentSelector)componentSelector).getProjectPath()); dependency.setConfigurationName(it.getName()); - dependency.setProjectDependencyArtifacts(it.getAllArtifacts().getFiles().getFiles()); + Set artifactsFiles = it.getAllArtifacts().getFiles().getFiles(); + dependency.setProjectDependencyArtifacts(artifactsFiles); + setProjectDependencyArtifactsSources(dependency, artifactsFiles, mySourceSetFinder); resolvedDepsFiles.addAll(dependency.getProjectDependencyArtifacts()); @@ -1164,9 +1170,9 @@ public class DependencyResolverImpl implements DependencyResolver { files.add(resolvedArtifact.getFile()); } dDep.setProjectDependencyArtifacts(files); + setProjectDependencyArtifactsSources(dDep, files, mySourceSetFinder); resolvedDepsFiles.addAll(dDep.getProjectDependencyArtifacts()); } - else { dependency = new DefaultExternalLibraryDependency(); DefaultExternalLibraryDependency dDep = (DefaultExternalLibraryDependency)dependency; @@ -1228,6 +1234,19 @@ public class DependencyResolverImpl implements DependencyResolver { } } + private static void setProjectDependencyArtifactsSources(DefaultExternalProjectDependency projectDependency, + Collection artifactFiles, + SourceSetCachedFinder sourceSetFinder) { + List artifactSources = new ArrayList(); + for (File artifactFile : artifactFiles) { + SourceSet sourceSet = sourceSetFinder.findByArtifact(artifactFile.getPath()); + if (sourceSet != null) { + artifactSources.addAll(sourceSet.getAllJava().getSrcDirs()); + } + } + projectDependency.setProjectDependencyArtifactsSources(artifactSources); + } + @Nullable private static ResolvedArtifactResult findMatchingArtifact(ResolvedArtifact artifact, ComponentArtifactsResult componentArtifacts, diff --git a/plugins/gradle/tooling-extension-impl/src/org/jetbrains/plugins/gradle/tooling/util/SourceSetCachedFinder.groovy b/plugins/gradle/tooling-extension-impl/src/org/jetbrains/plugins/gradle/tooling/util/SourceSetCachedFinder.groovy index 63d51c9b8b19..fe571d206af3 100644 --- a/plugins/gradle/tooling-extension-impl/src/org/jetbrains/plugins/gradle/tooling/util/SourceSetCachedFinder.groovy +++ b/plugins/gradle/tooling-extension-impl/src/org/jetbrains/plugins/gradle/tooling/util/SourceSetCachedFinder.groovy @@ -17,10 +17,13 @@ package org.jetbrains.plugins.gradle.tooling.util import groovy.transform.CompileStatic import org.gradle.api.Project +import org.gradle.api.initialization.IncludedBuild import org.gradle.api.plugins.JavaPluginConvention import org.gradle.api.tasks.SourceSet import org.gradle.api.tasks.SourceSetContainer import org.gradle.api.tasks.bundling.AbstractArchiveTask +import org.gradle.composite.internal.IncludedBuildInternal +import org.gradle.util.GradleVersion import org.jetbrains.annotations.NotNull /** @@ -29,14 +32,31 @@ import org.jetbrains.annotations.NotNull */ @CompileStatic class SourceSetCachedFinder { - private final Map myArtifactsMap = new HashMap() + private final Map myArtifactsMap @SuppressWarnings("GrUnresolvedAccess") SourceSetCachedFinder(@NotNull Project project) { def rootProject = project.rootProject - for (Project p : rootProject.subprojects) { + def extraProperties = rootProject.extensions.extraProperties + def key = "$SourceSetCachedFinder.name${System.identityHashCode(SourceSetCachedFinder.class)}" + + if (extraProperties.has(key)) { + def cached = extraProperties.get(key) + if (cached instanceof SourceSetCachedFinder) { + myArtifactsMap = (cached as SourceSetCachedFinder).myArtifactsMap + return + } + } + + def artifactsMap = new HashMap() + def projects = new ArrayList(rootProject.allprojects) + def isCompositeBuildsSupported = GradleVersion.current() >= GradleVersion.version("3.1") + if (isCompositeBuildsSupported) { + projects = exposeIncludedBuilds(project, projects) + } + for (Project p : projects) { SourceSetContainer sourceSetContainer = getSourceSetContainer(p) - if(sourceSetContainer == null || sourceSetContainer.isEmpty()) continue + if (sourceSetContainer == null || sourceSetContainer.isEmpty()) continue for (SourceSet sourceSet : sourceSetContainer) { def task = p.tasks.findByName(sourceSet.getJarTaskName()) @@ -44,11 +64,24 @@ class SourceSetCachedFinder { AbstractArchiveTask jarTask = (AbstractArchiveTask)task def archivePath = jarTask?.getArchivePath() if (archivePath) { - myArtifactsMap[archivePath.path] = sourceSet + artifactsMap[archivePath.path] = sourceSet + } } } } + + myArtifactsMap = Collections.unmodifiableMap(artifactsMap) + extraProperties.set(key, this) + } + + private static List exposeIncludedBuilds(Project project, List projects) { + for (IncludedBuild includedBuild : project.gradle.includedBuilds) { + if (includedBuild instanceof IncludedBuildInternal) { + def build = includedBuild as IncludedBuildInternal + projects += build.configuredBuild.rootProject.allprojects + } } + return projects } SourceSet findByArtifact(String artifactPath) {