IDEA-155548 gradle: classpath does not include generated resources appcode/162.332 clion/162.334 phpstorm/162.333 pycharm/162.335 rubymine/162.339
authorVladislav.Soroka <Vladislav.Soroka@jetbrains.com>
Fri, 20 May 2016 10:10:30 +0000 (13:10 +0300)
committerVladislav.Soroka <Vladislav.Soroka@jetbrains.com>
Fri, 20 May 2016 10:11:47 +0000 (13:11 +0300)
plugins/gradle/testSources/org/jetbrains/plugins/gradle/importing/GradleDependenciesImportingTest.java
plugins/gradle/tooling-extension-impl/src/org/jetbrains/plugins/gradle/tooling/builder/ExternalProjectBuilderImpl.groovy
plugins/gradle/tooling-extension-impl/src/org/jetbrains/plugins/gradle/tooling/builder/ModelBuildScriptClasspathBuilderImpl.java
plugins/gradle/tooling-extension-impl/src/org/jetbrains/plugins/gradle/tooling/util/DependencyResolverImpl.groovy
plugins/gradle/tooling-extension-impl/src/org/jetbrains/plugins/gradle/tooling/util/SourceSetCachedFinder.groovy [new file with mode: 0644]

index d69e7c441f702f76c876e68fe29831d64daeaaad..425cf98da138b285038d4a62cbae69f5e0ba6e03 100644 (file)
@@ -326,6 +326,45 @@ public class GradleDependenciesImportingTest extends GradleImportingTestCase {
     assertModuleLibDepScope("project_main", depName, DependencyScope.RUNTIME);
   }
 
+  @Test
+  public void testSourceSetOutputDirsAsRuntimeDependenciesOfDependantModules() throws Exception {
+    createSettingsFile("include 'projectA', 'projectB', 'projectC' ");
+    importProject(
+      "project(':projectA') {\n" +
+      "  apply plugin: 'java'\n" +
+      "  sourceSets.main.output.dir file(\"$buildDir/generated-resources/main\")\n" +
+      "}\n" +
+      "project(':projectB') {\n" +
+      "  apply plugin: 'java'\n" +
+      "  dependencies {\n" +
+      "    compile project(':projectA')\n" +
+      "  }\n" +
+      "}\n" +
+      "project(':projectC') {\n" +
+      "  apply plugin: 'java'\n" +
+      "  dependencies {\n" +
+      "    runtime project(':projectB')\n" +
+      "  }\n" +
+      "}"
+    );
+
+    assertModules("project", "projectA", "projectA_main", "projectA_test", "projectB", "projectB_main", "projectB_test", "projectC", "projectC_main", "projectC_test");
+
+    assertModuleModuleDepScope("projectB_main", "projectA_main", DependencyScope.COMPILE);
+    assertModuleModuleDepScope("projectC_main", "projectA_main", DependencyScope.RUNTIME);
+    assertModuleModuleDepScope("projectC_main", "projectB_main", DependencyScope.RUNTIME);
+
+    final String path = pathFromBasedir("projectA/build/generated-resources/main");
+    final String classesPath = "file://" + path;
+    final String depName = PathUtil.toPresentableUrl(path);
+    assertModuleLibDep("projectA_main", depName, classesPath);
+    assertModuleLibDepScope("projectA_main", depName, DependencyScope.RUNTIME);
+    assertModuleLibDep("projectB_main", depName, classesPath);
+    assertModuleLibDepScope("projectB_main", depName, DependencyScope.COMPILE);
+    assertModuleLibDep("projectC_main", depName, classesPath);
+    assertModuleLibDepScope("projectC_main", depName, DependencyScope.RUNTIME);
+  }
+
   @Test
   public void testProjectArtifactDependencyInTestAndArchivesConfigurations() throws Exception {
     createSettingsFile("include 'api', 'impl' ");
index a741a1524f21d8e0dd6ee0ec6e628bd5b241407a..698ee075bbc0369cae9b97135f0c87cfe6ea943e 100644 (file)
@@ -1,7 +1,7 @@
 /*
- * Copyright 2000-2014 JetBrains s.r.o.
+ * Copyright 2000-2016 JetBrains s.r.o.
  *
- * Licensed under the Apache License, Version 2.0 (the "License")
+ * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
  *
@@ -36,6 +36,7 @@ import org.jetbrains.plugins.gradle.model.*
 import org.jetbrains.plugins.gradle.tooling.ErrorMessageBuilder
 import org.jetbrains.plugins.gradle.tooling.ModelBuilderService
 import org.jetbrains.plugins.gradle.tooling.util.DependencyResolverImpl
+import org.jetbrains.plugins.gradle.tooling.util.SourceSetCachedFinder
 
 import java.util.concurrent.ConcurrentHashMap
 
@@ -47,10 +48,11 @@ class ExternalProjectBuilderImpl implements ModelBuilderService {
 
   private final cache = new ConcurrentHashMap<String, ExternalProject>()
   private final myTasksFactory = new TasksFactory()
+  private SourceSetCachedFinder mySourceSetFinder
 
   @Override
   public boolean canBuild(String modelName) {
-    return ExternalProject.name.equals(modelName) || ExternalProjectPreview.name.equals(modelName)
+    return ExternalProject.name == modelName || ExternalProjectPreview.name == modelName
   }
 
   @Nullable
@@ -59,12 +61,14 @@ class ExternalProjectBuilderImpl implements ModelBuilderService {
     ExternalProject externalProject = cache[project.path]
     if (externalProject != null) return externalProject
 
+    if(!mySourceSetFinder) mySourceSetFinder = new SourceSetCachedFinder(project)
+
     def resolveSourceSetDependencies = System.properties.'idea.resolveSourceSetDependencies' as boolean
-    def isPreview = ExternalProjectPreview.name.equals(modelName)
+    def isPreview = ExternalProjectPreview.name == modelName
     DefaultExternalProject defaultExternalProject = new DefaultExternalProject()
     defaultExternalProject.externalSystemId = "GRADLE"
     defaultExternalProject.name = project.name
-    defaultExternalProject.QName = ":".equals(project.path) ? project.name : project.path
+    defaultExternalProject.QName = ":" == project.path ? project.name : project.path
     defaultExternalProject.version = wrap(project.version)
     defaultExternalProject.description = project.description
     defaultExternalProject.buildDir = project.buildDir
@@ -148,7 +152,7 @@ class ExternalProjectBuilderImpl implements ModelBuilderService {
     result
   }
 
-  static Map<String, ExternalSourceSet> getSourceSets(Project project, boolean isPreview, boolean resolveSourceSetDependencies) {
+  private Map<String, ExternalSourceSet> getSourceSets(Project project, boolean isPreview, boolean resolveSourceSetDependencies) {
     final IdeaPlugin ideaPlugin = project.getPlugins().findPlugin(IdeaPlugin.class);
     def ideaPluginModule = ideaPlugin?.model?.module
     boolean inheritOutputDirs = ideaPluginModule?.inheritOutputDirs ?: false
@@ -256,7 +260,7 @@ class ExternalProjectBuilderImpl implements ModelBuilderService {
         additionalIdeaGenDirs.removeAll(files)
       }
 
-      if (SourceSet.TEST_SOURCE_SET_NAME.equals(sourceSet.name)) {
+      if (SourceSet.TEST_SOURCE_SET_NAME == sourceSet.name) {
         if (!inheritOutputDirs && ideaTestOutDir != null) {
           javaDirectorySet.outputDir = ideaTestOutDir
           resourcesDirectorySet.outputDir = ideaTestOutDir
@@ -271,7 +275,7 @@ class ExternalProjectBuilderImpl implements ModelBuilderService {
         }
       }
       else {
-        if (!inheritOutputDirs && SourceSet.MAIN_SOURCE_SET_NAME.equals(sourceSet.name) && ideaOutDir != null) {
+        if (!inheritOutputDirs && SourceSet.MAIN_SOURCE_SET_NAME == sourceSet.name && ideaOutDir != null) {
           javaDirectorySet.outputDir = ideaOutDir
           resourcesDirectorySet.outputDir = ideaOutDir
         }
@@ -325,7 +329,7 @@ class ExternalProjectBuilderImpl implements ModelBuilderService {
           }
         }
 
-        if (ideaPluginModule && !SourceSet.MAIN_SOURCE_SET_NAME.equals(sourceSet.name) && !SourceSet.TEST_SOURCE_SET_NAME.equals(sourceSet.name)) {
+        if (ideaPluginModule && SourceSet.MAIN_SOURCE_SET_NAME != sourceSet.name && SourceSet.TEST_SOURCE_SET_NAME != sourceSet.name) {
           sources.values().each {
             ideaSourceDirs.removeAll(it.srcDirs)
             ideaTestSourceDirs.removeAll(it.srcDirs)
@@ -334,7 +338,7 @@ class ExternalProjectBuilderImpl implements ModelBuilderService {
       }
 
       if(resolveSourceSetDependencies) {
-        def dependencies = new DependencyResolverImpl(project, isPreview, downloadJavadoc, downloadSources).resolveDependencies(sourceSet)
+        def dependencies = new DependencyResolverImpl(project, isPreview, downloadJavadoc, downloadSources, mySourceSetFinder).resolveDependencies(sourceSet)
         externalSourceSet.dependencies.addAll(dependencies)
       }
 
index acb71e3dc9087ebf775838c25d7aebd8bf148965..c53f5644cb8dfd65b547ca165d3f8e6ed1e40209 100644 (file)
@@ -29,6 +29,7 @@ import org.jetbrains.plugins.gradle.tooling.internal.BuildScriptClasspathModelIm
 import org.jetbrains.plugins.gradle.tooling.internal.ClasspathEntryModelImpl;
 import org.jetbrains.plugins.gradle.tooling.util.DependencyResolverImpl;
 import org.jetbrains.plugins.gradle.tooling.util.DependencyTraverser;
+import org.jetbrains.plugins.gradle.tooling.util.SourceSetCachedFinder;
 
 import java.io.File;
 import java.util.*;
@@ -42,6 +43,7 @@ public class ModelBuildScriptClasspathBuilderImpl implements ModelBuilderService
 
   private static final String CLASSPATH_CONFIGURATION_NAME = "classpath";
   private final Map<String, BuildScriptClasspathModelImpl> cache = new ConcurrentHashMap<String, BuildScriptClasspathModelImpl>();
+  private SourceSetCachedFinder mySourceSetFinder = null;
 
   @Override
   public boolean canBuild(String modelName) {
@@ -54,6 +56,8 @@ public class ModelBuildScriptClasspathBuilderImpl implements ModelBuilderService
     BuildScriptClasspathModelImpl buildScriptClasspath = cache.get(project.getPath());
     if (buildScriptClasspath != null) return buildScriptClasspath;
 
+    if(mySourceSetFinder == null) mySourceSetFinder = new SourceSetCachedFinder(project);
+
     buildScriptClasspath = new BuildScriptClasspathModelImpl();
     final File gradleHomeDir = project.getGradle().getGradleHomeDir();
     buildScriptClasspath.setGradleHomeDir(gradleHomeDir);
@@ -82,7 +86,7 @@ public class ModelBuildScriptClasspathBuilderImpl implements ModelBuilderService
     if (classpathConfiguration == null) return null;
 
     Collection<ExternalDependency> dependencies =
-      new DependencyResolverImpl(project, false, downloadJavadoc, downloadSources).resolveDependencies(classpathConfiguration);
+      new DependencyResolverImpl(project, false, downloadJavadoc, downloadSources, mySourceSetFinder).resolveDependencies(classpathConfiguration);
 
     for (ExternalDependency dependency : new DependencyTraverser(dependencies)) {
       if (dependency instanceof ExternalLibraryDependency) {
index a70ebf92463ecf4944c9122fa03825a073618364..69472611725d0a9d0c61ed45a0431123cf34028b 100644 (file)
@@ -57,14 +57,15 @@ import java.util.regex.Pattern
  */
 class DependencyResolverImpl implements DependencyResolver {
 
-  private static isArtifactResolutionQuerySupported = GradleVersion.current().compareTo(GradleVersion.version("2.0")) >= 0
-  private static isDependencySubstitutionsSupported = GradleVersion.current().compareTo(GradleVersion.version("2.5")) >= 0
+  private static isArtifactResolutionQuerySupported = GradleVersion.current() >= GradleVersion.version("2.0")
+  private static isDependencySubstitutionsSupported = GradleVersion.current() >= GradleVersion.version("2.5")
 
   @NotNull
   private final Project myProject
   private final boolean myIsPreview
   private final boolean myDownloadJavadoc
   private final boolean myDownloadSources
+  private final SourceSetCachedFinder mySourceSetFinder
 
   @SuppressWarnings("GroovyUnusedDeclaration")
   DependencyResolverImpl(@NotNull Project project, boolean isPreview) {
@@ -72,13 +73,20 @@ class DependencyResolverImpl implements DependencyResolver {
     myIsPreview = isPreview
     myDownloadJavadoc = false
     myDownloadSources = false
+    mySourceSetFinder = new SourceSetCachedFinder(project)
   }
 
-  DependencyResolverImpl(@NotNull Project project, boolean isPreview, boolean downloadJavadoc, boolean downloadSources) {
+  DependencyResolverImpl(
+    @NotNull Project project,
+    boolean isPreview,
+    boolean downloadJavadoc,
+    boolean downloadSources,
+    SourceSetCachedFinder sourceSetFinder) {
     myProject = project
     myIsPreview = isPreview
     myDownloadJavadoc = downloadJavadoc
     myDownloadSources = downloadSources
+    mySourceSetFinder = sourceSetFinder
   }
 
   @Override
@@ -295,7 +303,7 @@ class DependencyResolverImpl implements DependencyResolver {
         //noinspection GrUnresolvedAccess
         if (project.hasProperty("sourceSets") && (project.sourceSets instanceof SourceSetContainer) && project.sourceSets.main) {
           //noinspection GrUnresolvedAccess
-          addSourceSetOutputDirsAsSingleEntryLibraries(result, project.sourceSets.main, runtimeClasspathOrder, runtimeScope)
+          addSourceSetOutputDirsAsSingleEntryLibraries(result, project.sourceSets.main, runtimeClasspathOrder, scope)
         }
       }
       else if (dependency instanceof ExternalLibraryDependency) {
@@ -372,6 +380,12 @@ class DependencyResolverImpl implements DependencyResolver {
         compileClasspathFilesDependency.classpathOrder = order
       }
       result.add(compileClasspathFilesDependency)
+      for (File file : compileClasspathFiles) {
+        def outputDirSourceSet = mySourceSetFinder.findByArtifact(file.path)
+        if(outputDirSourceSet) {
+          addSourceSetOutputDirsAsSingleEntryLibraries(result, outputDirSourceSet, compileClasspathOrder, compileScope)
+        }
+      }
     }
 
     if (!runtimeClasspathFiles.isEmpty()) {
@@ -389,6 +403,13 @@ class DependencyResolverImpl implements DependencyResolver {
 
       runtimeClasspathFilesDependency.classpathOrder = order
       result.add(runtimeClasspathFilesDependency)
+
+      for (File file : runtimeClasspathFiles) {
+        def outputDirSourceSet = mySourceSetFinder.findByArtifact(file.path)
+        if(outputDirSourceSet) {
+          addSourceSetOutputDirsAsSingleEntryLibraries(result, outputDirSourceSet, runtimeClasspathOrder, runtimeScope)
+        }
+      }
     }
 
     addSourceSetOutputDirsAsSingleEntryLibraries(result, sourceSet, runtimeClasspathOrder, runtimeScope)
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
new file mode 100644 (file)
index 0000000..e656b4e
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2000-2016 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.plugins.gradle.tooling.util
+
+import org.gradle.api.Project
+import org.gradle.api.tasks.SourceSet
+import org.gradle.api.tasks.SourceSetContainer
+import org.jetbrains.annotations.NotNull
+
+/**
+ * @author Vladislav.Soroka
+ * @since 5/19/2016
+ */
+class SourceSetCachedFinder {
+  private final myArtifactsMap = new HashMap<String, SourceSet>()
+
+  @SuppressWarnings("GrUnresolvedAccess")
+  SourceSetCachedFinder(@NotNull Project project) {
+    def rootProject = project.rootProject
+    rootProject.subprojects.each { Project p ->
+      if (p.hasProperty("sourceSets") && (p.sourceSets instanceof SourceSetContainer)) {
+        p.sourceSets.each { SourceSet sourceSet ->
+          def jarTask = p.tasks.findByName(sourceSet.getJarTaskName())
+          def file = jarTask?.archivePath as File
+          if (file) {
+            myArtifactsMap[file.path] = sourceSet
+          }
+        }
+      }
+    }
+  }
+
+  SourceSet findByArtifact(String artifactPath) {
+    return myArtifactsMap[artifactPath]
+  }
+}