From fd1c6364f99d634725430cd63310313b00a5af70 Mon Sep 17 00:00:00 2001 From: Nikita Skvortsov Date: Tue, 8 May 2018 13:39:20 +0300 Subject: [PATCH] extract methods and classes --- .../resolve/CompileDependenciesProvider.java | 73 +++ .../util/resolve/DependencyResolverImpl.java | 595 +++++++++--------- .../resolve/DependencyResultsTransformer.java | 1 - .../resolve/RuntimeDependenciesProvider.java | 49 ++ 4 files changed, 418 insertions(+), 300 deletions(-) create mode 100644 plugins/gradle/tooling-extension-impl/src/org/jetbrains/plugins/gradle/tooling/util/resolve/CompileDependenciesProvider.java create mode 100644 plugins/gradle/tooling-extension-impl/src/org/jetbrains/plugins/gradle/tooling/util/resolve/RuntimeDependenciesProvider.java diff --git a/plugins/gradle/tooling-extension-impl/src/org/jetbrains/plugins/gradle/tooling/util/resolve/CompileDependenciesProvider.java b/plugins/gradle/tooling-extension-impl/src/org/jetbrains/plugins/gradle/tooling/util/resolve/CompileDependenciesProvider.java new file mode 100644 index 000000000000..7859940a42f0 --- /dev/null +++ b/plugins/gradle/tooling-extension-impl/src/org/jetbrains/plugins/gradle/tooling/util/resolve/CompileDependenciesProvider.java @@ -0,0 +1,73 @@ +// Copyright 2000-2018 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. +package org.jetbrains.plugins.gradle.tooling.util.resolve; + +import org.gradle.api.Project; +import org.gradle.api.artifacts.Configuration; +import org.gradle.api.tasks.SourceSet; +import org.gradle.util.GUtil; +import org.jetbrains.plugins.gradle.model.ExternalDependency; + +import java.io.File; +import java.util.Collection; + +public class CompileDependenciesProvider { + public static final String SCOPE = "COMPILE"; + + private final SourceSet mySourceSet; + private final Project myProject; + private Configuration myConfiguration; + private Configuration myCompileClasspathConfiguration; + private Configuration myCompileConfiguration; + private Configuration myCompileOnlyConfiguration; + private Collection myDependencies; + private Collection myFiles; + + public CompileDependenciesProvider(SourceSet sourceSet, Project project) { + mySourceSet = sourceSet; + myProject = project; + } + + public Configuration getDeprecatedCompileConfiguration() { + return myConfiguration; + } + + public Configuration getCompileClasspathConfiguration() { + return myCompileClasspathConfiguration; + } + + public Configuration getCompileConfiguration() { + return myCompileConfiguration; + } + + public Configuration getCompileOnlyConfiguration() { + return myCompileOnlyConfiguration; + } + + public Collection getDependencies() { + return myDependencies; + } + + public Collection getFiles() { + return myFiles; + } + + public CompileDependenciesProvider resolve(DependencyResolverImpl resolver) { + // resolve compile dependencies + boolean isMainSourceSet = mySourceSet.getName().equals(SourceSet.MAIN_SOURCE_SET_NAME); + String deprecatedCompileConfigurationName = isMainSourceSet ? "compile" : GUtil.toCamelCase(mySourceSet.getName()) + "Compile"; + String compileConfigurationName = mySourceSet.getCompileConfigurationName(); + + myConfiguration = myProject.getConfigurations().findByName(deprecatedCompileConfigurationName); + myCompileClasspathConfiguration = myProject.getConfigurations().findByName(compileConfigurationName + "Classpath"); + myCompileConfiguration = myProject.getConfigurations().findByName(compileConfigurationName); + Configuration compileConfiguration = myCompileClasspathConfiguration != null ? myCompileClasspathConfiguration + : myCompileConfiguration; + myCompileOnlyConfiguration = + resolver.isJavaLibraryPluginSupported ? myProject.getConfigurations().findByName(mySourceSet.getCompileOnlyConfigurationName()) : null; + + ExternalDepsResolutionResult externalDepsResolutionResult = resolver.resolveDependencies(compileConfiguration, SCOPE); + myDependencies = externalDepsResolutionResult.getExternalDeps(); + myFiles = externalDepsResolutionResult.getResolvedFiles(); + return this; + } +} diff --git a/plugins/gradle/tooling-extension-impl/src/org/jetbrains/plugins/gradle/tooling/util/resolve/DependencyResolverImpl.java b/plugins/gradle/tooling-extension-impl/src/org/jetbrains/plugins/gradle/tooling/util/resolve/DependencyResolverImpl.java index d2f8d1307fd4..4cd0d74ac1a2 100644 --- a/plugins/gradle/tooling-extension-impl/src/org/jetbrains/plugins/gradle/tooling/util/resolve/DependencyResolverImpl.java +++ b/plugins/gradle/tooling-extension-impl/src/org/jetbrains/plugins/gradle/tooling/util/resolve/DependencyResolverImpl.java @@ -19,7 +19,6 @@ import org.gradle.internal.impldep.com.google.common.collect.ArrayListMultimap; import org.gradle.internal.impldep.com.google.common.collect.Lists; import org.gradle.internal.impldep.com.google.common.collect.Multimap; import org.gradle.plugins.ide.idea.IdeaPlugin; -import org.gradle.util.GUtil; import org.gradle.util.GradleVersion; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -50,7 +49,7 @@ import static org.gradle.internal.impldep.com.google.common.collect.Iterables.fi public class DependencyResolverImpl implements DependencyResolver { private static final boolean is4OrBetter = GradleVersion.current().getBaseVersion().compareTo(GradleVersion.version("4.0")) >= 0; - private static final boolean isJavaLibraryPluginSupported = is4OrBetter || + static final boolean isJavaLibraryPluginSupported = is4OrBetter || (GradleVersion.current().compareTo(GradleVersion.version("3.4")) >= 0); private static final boolean isDependencySubstitutionsSupported = isJavaLibraryPluginSupported || (GradleVersion.current().compareTo(GradleVersion.version("2.5")) > 0); @@ -63,6 +62,7 @@ public class DependencyResolverImpl implements DependencyResolver { private final boolean myDownloadJavadoc; private final boolean myDownloadSources; private final SourceSetCachedFinder mySourceSetFinder; + public static final String PROVIDED_SCOPE = "PROVIDED"; @SuppressWarnings("GroovyUnusedDeclaration") public DependencyResolverImpl(@NotNull Project project, boolean isPreview) { @@ -157,103 +157,244 @@ public class DependencyResolverImpl implements DependencyResolver { Collection result = new ArrayList(); // resolve compile dependencies - boolean isMainSourceSet = sourceSet.getName().equals(SourceSet.MAIN_SOURCE_SET_NAME); - String deprecatedCompileConfigurationName = isMainSourceSet ? "compile" : GUtil.toCamelCase(sourceSet.getName()) + "Compile"; - Configuration deprecatedCompileConfiguration = myProject.getConfigurations().findByName(deprecatedCompileConfigurationName); - String compileConfigurationName = sourceSet.getCompileConfigurationName(); - Configuration compileClasspathConfiguration = myProject.getConfigurations().findByName(compileConfigurationName + "Classpath"); - Configuration originCompileConfiguration = myProject.getConfigurations().findByName(compileConfigurationName); - Configuration compileConfiguration = compileClasspathConfiguration != null ? compileClasspathConfiguration : originCompileConfiguration; - Configuration compileOnlyConfiguration = - isJavaLibraryPluginSupported ? myProject.getConfigurations().findByName(sourceSet.getCompileOnlyConfigurationName()) : null; - - String compileScope = "COMPILE"; - ExternalDepsResolutionResult externalDepsResolutionResult = resolveDependencies(compileConfiguration, compileScope); - Collection compileDependencies = externalDepsResolutionResult.getExternalDeps(); - Collection resolvedCompileFileDependencies = externalDepsResolutionResult.getResolvedFiles(); + CompileDependenciesProvider compileDependenciesProvider = new CompileDependenciesProvider(sourceSet, myProject).resolve(this); + Collection compileDependencies = compileDependenciesProvider.getDependencies(); // resolve runtime dependencies - String runtimeConfigurationName = sourceSet.getRuntimeConfigurationName(); - Configuration runtimeClasspathConfiguration = myProject.getConfigurations().findByName(runtimeConfigurationName + "Classpath"); - Configuration originRuntimeConfiguration = myProject.getConfigurations().findByName(runtimeConfigurationName); - Configuration runtimeConfiguration = runtimeClasspathConfiguration != null ? runtimeClasspathConfiguration : originRuntimeConfiguration; + RuntimeDependenciesProvider runtimeDependenciesProvider = new RuntimeDependenciesProvider(sourceSet, myProject).resolve(this); + Collection runtimeDependencies = runtimeDependenciesProvider.getDependencies(); - String runtimeScope = "RUNTIME"; - externalDepsResolutionResult = resolveDependencies(runtimeConfiguration, runtimeScope); - Collection runtimeDependencies = externalDepsResolutionResult.getExternalDeps(); - Collection resolvedRuntimeFileDependencies = externalDepsResolutionResult.getResolvedFiles(); + Multimap filesToDependenciesMap = + collectCompileDependencies(compileDependenciesProvider, runtimeDependenciesProvider); - - String providedScope = "PROVIDED"; - Multimap resolvedMap = ArrayListMultimap.create(); - - boolean checkCompileOnlyDeps = compileClasspathConfiguration != null && !originCompileConfiguration.getResolvedConfiguration().hasError(); - - for (ExternalDependency dep : new DependencyTraverser(compileDependencies)) { - final Collection resolvedFiles = getFiles(dep); - resolvedMap.put(resolvedFiles, dep); - - // since version 3.4 compileOnly no longer extends compile - // so, we can use compileOnly configuration for the check - if (isJavaLibraryPluginSupported) { - if (compileOnlyConfiguration != null && containsAll(compileOnlyConfiguration, resolvedFiles)) { - // deprecated 'compile' configuration still can be used - if (deprecatedCompileConfiguration == null || !containsAll(deprecatedCompileConfiguration, resolvedFiles)) { - ((AbstractExternalDependency)dep).setScope(providedScope); - } - } - } - else { - if (checkCompileOnlyDeps && ! containsAll(originCompileConfiguration, resolvedFiles) && - !containsAll(runtimeConfiguration, resolvedFiles)) { - ((AbstractExternalDependency)dep).setScope(providedScope); - } - } - } - - - Multimap resolvedRuntimeMap = ArrayListMultimap.create(); - - for (ExternalDependency dep : new DependencyTraverser(runtimeDependencies)) { - Collection dependencies = resolvedMap.get(getFiles(dep)); - if (dependencies != null && !dependencies.isEmpty() && dep.getDependencies().isEmpty()) { - runtimeDependencies.remove(dep); - ((AbstractExternalDependency)dep).setScope(compileScope); - for (ExternalDependency dependency : dependencies) { - ((AbstractExternalDependency)dependency).setScope(compileScope); - } - } - else { - if (dependencies != null && !dependencies.isEmpty()) { - ((AbstractExternalDependency)dep).setScope(compileScope); - } - resolvedRuntimeMap.put(getFiles(dep), dep); - } - } - - resolvedMap.putAll(resolvedRuntimeMap); + filterCompileDepsFromRuntime(runtimeDependencies, filesToDependenciesMap); result.addAll(compileDependencies); result.addAll(runtimeDependencies); - result = Lists.newArrayList(filter(result, not(isNull()))); + // merge file dependencies - List jvmLanguages = Lists.newArrayList("Java", "Groovy", "Scala"); + Set compileClasspathFiles = getCompileClasspathFiles(sourceSet, "Java", "Groovy", "Scala"); + Map compileClasspathOrder = addIterationOrder(compileClasspathFiles); + + Set runtimeClasspathFiles = getRuntimeClasspathFiles(sourceSet); + Map runtimeClasspathOrder = addIterationOrder(runtimeClasspathFiles); + + runtimeClasspathFiles.removeAll(compileClasspathFiles); + runtimeClasspathFiles.removeAll(sourceSet.getOutput().getFiles()); + compileClasspathFiles.removeAll(sourceSet.getOutput().getFiles()); + + Multimap resolvedDependenciesMap = ArrayListMultimap.create(); + resolvedDependenciesMap.putAll(CompileDependenciesProvider.SCOPE, compileDependenciesProvider.getFiles()); + resolvedDependenciesMap.putAll(RuntimeDependenciesProvider.SCOPE, runtimeDependenciesProvider.getFiles()); + Project rootProject = myProject.getRootProject(); + + for (ExternalDependency dependency : new DependencyTraverser(result)) { + updateDependencyOrder(compileClasspathOrder, runtimeClasspathOrder, dependency); + + resolvedDependenciesMap.putAll(dependency.getScope(), getFiles(dependency)); + + if (dependency instanceof ExternalProjectDependency) { + ExternalProjectDependency projectDependency = (ExternalProjectDependency)dependency; + Project project = rootProject.findProject(projectDependency.getProjectPath()); + SourceSet mainSourceSet; + if ((mainSourceSet = findSourceSet(project, "main")) != null) { + result.addAll(collectSourceSetOutputDirsAsSingleEntryLibraries(mainSourceSet, runtimeClasspathOrder, dependency.getScope())); + } + } + } + + // remove processed files + compileClasspathFiles.removeAll(resolvedDependenciesMap.get(CompileDependenciesProvider.SCOPE)); + compileClasspathFiles.removeAll(resolvedDependenciesMap.get(PROVIDED_SCOPE)); + + runtimeClasspathFiles.removeAll(resolvedDependenciesMap.get(RuntimeDependenciesProvider.SCOPE)); + runtimeClasspathFiles.removeAll(resolvedDependenciesMap.get(CompileDependenciesProvider.SCOPE)); + runtimeClasspathFiles.removeAll(resolvedDependenciesMap.get(PROVIDED_SCOPE)); + + // try to map to libraries + Collection fileDependencies = new ArrayList(); + fileDependencies.addAll(createLibraryDependenciesForFiles(compileClasspathFiles, CompileDependenciesProvider.SCOPE)); + fileDependencies.addAll(createLibraryDependenciesForFiles(runtimeClasspathFiles, RuntimeDependenciesProvider.SCOPE)); + + for (ExternalDependency dependency : fileDependencies) { + updateDependencyOrder(compileClasspathOrder, runtimeClasspathOrder, dependency); + } + + result.addAll(fileDependencies); + + result.addAll(createFileCollectionDependencies(compileClasspathFiles, compileClasspathOrder, CompileDependenciesProvider.SCOPE)); + result.addAll(createFileCollectionDependencies(runtimeClasspathFiles, runtimeClasspathOrder, RuntimeDependenciesProvider.SCOPE)); + + result.addAll(collectSourceSetOutputDirsAsSingleEntryLibraries(sourceSet, runtimeClasspathOrder, RuntimeDependenciesProvider.SCOPE)); + + filesToDependenciesMap = collectProvidedDependencies(sourceSet, result); + + return removeDuplicates(filesToDependenciesMap, result); + } + + @NotNull + public Multimap collectProvidedDependencies(@NotNull SourceSet sourceSet, + @NotNull Collection result) { + Multimap filesToDependenciesMap;// handle provided dependencies + final Set providedConfigurations = new LinkedHashSet(); + filesToDependenciesMap = ArrayListMultimap.create(); + for (ExternalDependency dep : new DependencyTraverser(result)) { + filesToDependenciesMap.put(getFiles(dep), dep); + } + + if (sourceSet.getName().equals("main") && myProject.getPlugins().findPlugin(WarPlugin.class) != null) { + providedConfigurations.add(myProject.getConfigurations().findByName("providedCompile")); + providedConfigurations.add(myProject.getConfigurations().findByName("providedRuntime")); + } + + final IdeaPlugin ideaPlugin = myProject.getPlugins().findPlugin(IdeaPlugin.class); + + if (ideaPlugin != null) { + Map>> scopes = ideaPlugin.getModel().getModule().getScopes(); + Map> providedPlusScopes = scopes.get(PROVIDED_SCOPE); + + if (providedPlusScopes != null && providedPlusScopes.get("plus") != null) { + Iterable ideaPluginProvidedConfigurations = filter(providedPlusScopes.get("plus"), new Predicate() { + @Override + + public boolean apply(Configuration cfg) { + // filter default 'compileClasspath' for slight optimization since it has been already processed as compile dependencies + return !cfg.getName().equals("compileClasspath") + // since gradle 3.4 'idea' plugin PROVIDED scope.plus contains 'providedCompile' and 'providedRuntime' configurations + // see https://github.com/gradle/gradle/commit/c46897ae840c5ebb32946009c83d861ee194ab96#diff-0fa13ec419e839ef2d355b7feb88b815R432 + && !providedConfigurations.contains(cfg); + } + }); + + for (Configuration configuration : ideaPluginProvidedConfigurations) { + Collection providedDependencies = resolveDependencies(configuration, PROVIDED_SCOPE).getExternalDeps(); + for(ExternalDependency it : new DependencyTraverser(providedDependencies)) { + filesToDependenciesMap.put(getFiles(it), it); + } + result.addAll(providedDependencies); + } + } + } + + for (Configuration cfg : providedConfigurations) { + Collection providedDependencies = resolveDependencies(cfg, PROVIDED_SCOPE).getExternalDeps(); + for (ExternalDependency dep : new DependencyTraverser(providedDependencies)) { + Collection dependencies = filesToDependenciesMap.get(getFiles(dep)); + if (!dependencies.isEmpty()) { + if (dep.getDependencies().isEmpty()) { + providedDependencies.remove(dep); + } + for (ExternalDependency depForScope: dependencies) { + ((AbstractExternalDependency)depForScope).setScope(PROVIDED_SCOPE); + } + } else { + filesToDependenciesMap.put(getFiles(dep), dep); + } + } + result.addAll(providedDependencies); + } + return filesToDependenciesMap; + } + + public void updateDependencyOrder(Map compileClasspathOrder, + Map runtimeClasspathOrder, + ExternalDependency dependency) { + String scope = dependency.getScope(); + Map classpathOrderMap = scope == CompileDependenciesProvider.SCOPE ? compileClasspathOrder : + scope == RuntimeDependenciesProvider.SCOPE ? runtimeClasspathOrder : null; + final Collection depFiles = getFiles(dependency); + int order = getOrder(classpathOrderMap, depFiles); + if (dependency instanceof AbstractExternalDependency) { + ((AbstractExternalDependency)dependency).setClasspathOrder(order); + } + } + + @NotNull + private Collection createFileCollectionDependencies(@NotNull final Set files, + @NotNull final Map classPathOrder, + @Nullable final String scope) { + final List result = new ArrayList(); + if (files.isEmpty()) { + return result; + } + + final DefaultFileCollectionDependency fileCollectionDependency = new DefaultFileCollectionDependency(files); + fileCollectionDependency.setScope(scope); + fileCollectionDependency.setClasspathOrder(getOrder(classPathOrder, files)); + + result.add(fileCollectionDependency); + + for (File file : files) { + SourceSet outputDirSourceSet = mySourceSetFinder.findByArtifact(file.getPath()); + if (outputDirSourceSet != null) { + result.addAll( + collectSourceSetOutputDirsAsSingleEntryLibraries(outputDirSourceSet, + classPathOrder, + scope)); + } + } + + return result; + } + + + public SourceSet findSourceSet(@Nullable final Project project, + @NotNull final String name) { + if (project == null) { + return null; + } + + if (project.hasProperty("sourceSets") + && (project.property("sourceSets") instanceof SourceSetContainer)) { + return ((SourceSetContainer)project.property("sourceSets")).findByName(name); + } + return null; + } + + + public int getOrder(@Nullable Map classpathOrderMap, + @NotNull Collection files) { + int order = -1; + for (File file : files) { + if (classpathOrderMap != null) { + Integer fileOrder = classpathOrderMap.get(file); + if (fileOrder != null && (order == -1 || fileOrder < order)) { + order = fileOrder; + } + if (order == 0) break; + } + } + return order; + } + + @NotNull + public Map addIterationOrder(Set files) { + int order = 0; + Map fileToOrder = new LinkedHashMap(); + for (File file : files) { + fileToOrder.put(file, order++); + } + return fileToOrder; + } + + @NotNull + public Set getCompileClasspathFiles(@NotNull SourceSet sourceSet, String... languages) { + List jvmLanguages = Lists.newArrayList(languages); final String sourceSetCompileTaskPrefix = sourceSet.getName() == "main" ? "" : sourceSet.getName(); - List compileTasks = Lists.transform(jvmLanguages, new Function() { + List compileTaskNames = Lists.transform(jvmLanguages, new Function() { @Override public String apply(String s) { return "compile" + capitalize(sourceSetCompileTaskPrefix) + s; } }); - Map compileClasspathOrder = new LinkedHashMap(); Set compileClasspathFiles = new LinkedHashSet(); - for (String task : compileTasks) { + for (String task : compileTaskNames) { Task compileTask = myProject.getTasks().findByName(task); if (compileTask instanceof AbstractCompile) { try { @@ -272,238 +413,90 @@ public class DependencyResolverImpl implements DependencyResolver { } catch (Exception e) { // ignore } + return compileClasspathFiles; + } - int order = 0; - for (File file : compileClasspathFiles) { - compileClasspathOrder.put(file, order++); - } - - Map runtimeClasspathOrder = new LinkedHashMap(); - order = 0; - Set runtimeClasspathFiles = new LinkedHashSet(); + public Set getRuntimeClasspathFiles(@NotNull SourceSet sourceSet) { + Set result = new LinkedHashSet(); try { - Set files = sourceSet.getRuntimeClasspath().getFiles(); - for (File file : files) { - runtimeClasspathOrder.put(file, order++); - } - runtimeClasspathFiles.addAll(files); + result.addAll(sourceSet.getRuntimeClasspath().getFiles()); } catch (Exception e) { // ignore } + return result; + } - runtimeClasspathFiles.removeAll(compileClasspathFiles); - runtimeClasspathFiles.removeAll(sourceSet.getOutput().getFiles()); - compileClasspathFiles.removeAll(sourceSet.getOutput().getFiles()); + @NotNull + public Multimap collectCompileDependencies(CompileDependenciesProvider compileDependenciesProvider, + RuntimeDependenciesProvider runtimeDependenciesProvider) { + Multimap filesToDependenciesMap = ArrayListMultimap.create(); + Collection compileDependencies = compileDependenciesProvider.getDependencies(); - Multimap resolvedDependenciesMap = ArrayListMultimap.create(); - resolvedDependenciesMap.putAll(compileScope, resolvedCompileFileDependencies); - resolvedDependenciesMap.putAll(runtimeScope, resolvedRuntimeFileDependencies); - Project rootProject = myProject.getRootProject(); + for (ExternalDependency dep : new DependencyTraverser(compileDependencies)) { + final Collection resolvedFiles = getFiles(dep); + filesToDependenciesMap.put(resolvedFiles, dep); - for (ExternalDependency dependency : new DependencyTraverser(result)) { - String scope = dependency.getScope(); - order = -1; - if (dependency instanceof ExternalProjectDependency) { - ExternalProjectDependency projectDependency = (ExternalProjectDependency)dependency; + markAsProvidedIfNeeded(compileDependenciesProvider, + runtimeDependenciesProvider, + (AbstractExternalDependency)dep); + } + return filesToDependenciesMap; + } - Project project = rootProject.findProject(projectDependency.getProjectPath()); - if (project != null) { - Configuration configuration = project.getConfigurations().findByName(projectDependency.getConfigurationName()); + @NotNull + public Multimap filterCompileDepsFromRuntime(Collection runtimeDependencies, + Multimap filesToCompileDependenciesMap) { + Multimap resolvedRuntimeMap = ArrayListMultimap.create(); - if (configuration != null) { - for (File file : configuration.getAllArtifacts().getFiles().getFiles()) { - resolvedDependenciesMap.put(scope, file); - Map classpathOrderMap = scope == compileScope ? compileClasspathOrder : - scope == runtimeScope ? runtimeClasspathOrder : null; - if (classpathOrderMap != null) { - Integer fileOrder = classpathOrderMap.get(file); - if (fileOrder != null && (order == -1 || fileOrder < order)) { - order = fileOrder; - } - } - } - } + for (ExternalDependency dep : new DependencyTraverser(runtimeDependencies)) { + final Collection resolvedFiles = getFiles(dep); - //noinspection GrUnresolvedAccess - if (project.hasProperty("sourceSets") - && (project.property("sourceSets") instanceof SourceSetContainer) - && ((SourceSetContainer)project.property("sourceSets")).findByName("main") != null) { - //noinspection GrUnresolvedAccess - addSourceSetOutputDirsAsSingleEntryLibraries(result, - ((SourceSetContainer)project.property("sourceSets")).findByName("main"), - runtimeClasspathOrder, scope); - } - } - } else if (dependency instanceof ExternalLibraryDependency) { - final File file = ((ExternalLibraryDependency)dependency).getFile(); - resolvedDependenciesMap.put(scope, file); - Map classpathOrderMap = scope == compileScope ? compileClasspathOrder : - scope == runtimeScope ? runtimeClasspathOrder : null; - if (classpathOrderMap != null) { - Integer fileOrder = classpathOrderMap.get(file); - order = fileOrder != null ? fileOrder : -1; - } - } else if (dependency instanceof FileCollectionDependency) { - for (File file : ((FileCollectionDependency)dependency).getFiles()) { - resolvedDependenciesMap.put(scope, file); - Map classpathOrderMap = scope == compileScope ? compileClasspathOrder : - scope == runtimeScope ? runtimeClasspathOrder : null; - if (classpathOrderMap != null) { - Integer fileOrder = classpathOrderMap.get(file); - if (fileOrder != null && (order == -1 || fileOrder < order)) { - order = fileOrder; - } - if (order == 0) break; - } + Collection dependencies = filesToCompileDependenciesMap.get(resolvedFiles); + final boolean hasCompileDependencies = dependencies != null && !dependencies.isEmpty(); + + if (hasCompileDependencies && dep.getDependencies().isEmpty()) { + runtimeDependencies.remove(dep); + for (ExternalDependency dependency : dependencies) { + ((AbstractExternalDependency)dependency).setScope(CompileDependenciesProvider.SCOPE); } } - - if (dependency instanceof AbstractExternalDependency) { - ((AbstractExternalDependency)dependency).setClasspathOrder(order); + else { + if (hasCompileDependencies) { + ((AbstractExternalDependency)dep).setScope(CompileDependenciesProvider.SCOPE); + } + resolvedRuntimeMap.put(resolvedFiles, dep); } } + return resolvedRuntimeMap; + } - compileClasspathFiles.removeAll(resolvedDependenciesMap.get(compileScope)); - compileClasspathFiles.removeAll(resolvedDependenciesMap.get(providedScope)); - runtimeClasspathFiles.removeAll(resolvedDependenciesMap.get(runtimeScope)); - runtimeClasspathFiles.removeAll(resolvedDependenciesMap.get(compileScope)); - runtimeClasspathFiles.removeAll(resolvedDependenciesMap.get(providedScope)); - Collection fileDependencies = new ArrayList(); - mapFileDependencies(runtimeClasspathFiles, runtimeScope, fileDependencies); - mapFileDependencies(compileClasspathFiles, compileScope, fileDependencies); + public void markAsProvidedIfNeeded(@NotNull final CompileDependenciesProvider compileDependenciesProvider, + @NotNull final RuntimeDependenciesProvider runtimeDependenciesProvider, + @NotNull final AbstractExternalDependency dep) { + Collection resolvedFiles = getFiles(dep); + Configuration compileOnlyConfiguration = compileDependenciesProvider.getCompileOnlyConfiguration(); + Configuration deprecatedCompileConfiguration = compileDependenciesProvider.getDeprecatedCompileConfiguration(); + Configuration compileConfiguration = compileDependenciesProvider.getCompileConfiguration(); - for (ExternalDependency dependency : fileDependencies) { - String scope = dependency.getScope(); - order = -1; - if (dependency instanceof ExternalLibraryDependency) { - Map classpathOrderMap = scope == compileScope ? compileClasspathOrder : - scope == runtimeScope ? runtimeClasspathOrder : null; - if (classpathOrderMap != null) { - Integer fileOrder = classpathOrderMap.get(((ExternalLibraryDependency)dependency).getFile()); - order = fileOrder != null ? fileOrder : -1; - } - } - if (dependency instanceof AbstractExternalDependency) { - ((AbstractExternalDependency)dependency).setClasspathOrder(order); - } - } - - result.addAll(fileDependencies); - - if (!compileClasspathFiles.isEmpty()) { - final DefaultFileCollectionDependency compileClasspathFilesDependency = new DefaultFileCollectionDependency(compileClasspathFiles); - compileClasspathFilesDependency.setScope(compileScope); - - order = -1; - - for (File file : compileClasspathFiles) { - Integer fileOrder = compileClasspathOrder.get(file); - if (fileOrder != null && (order == -1 || fileOrder < order)) { - order = fileOrder; - } - if (order == 0) break; - } - - if (order != -1) { - compileClasspathFilesDependency.setClasspathOrder(order); - } - - result.add(compileClasspathFilesDependency); - for (File file : compileClasspathFiles) { - SourceSet outputDirSourceSet = mySourceSetFinder.findByArtifact(file.getPath()); - if(outputDirSourceSet != null) { - addSourceSetOutputDirsAsSingleEntryLibraries(result, outputDirSourceSet, compileClasspathOrder, compileScope); + boolean checkCompileOnlyDeps = compileDependenciesProvider.getCompileClasspathConfiguration() != null && !compileConfiguration.getResolvedConfiguration().hasError(); + // since version 3.4 compileOnly no longer extends compile + // so, we can use compileOnly configuration for the check + if (isJavaLibraryPluginSupported) { + if (compileOnlyConfiguration != null && containsAll(compileOnlyConfiguration, resolvedFiles)) { + // deprecated 'compile' configuration still can be used + if (deprecatedCompileConfiguration == null || !containsAll(deprecatedCompileConfiguration, resolvedFiles)) { + dep.setScope(PROVIDED_SCOPE); } } } - - if (!runtimeClasspathFiles.isEmpty()) { - final DefaultFileCollectionDependency runtimeClasspathFilesDependency = new DefaultFileCollectionDependency(runtimeClasspathFiles); - runtimeClasspathFilesDependency.setScope(runtimeScope); - - order = -1; - for (File file : runtimeClasspathFiles) { - Integer fileOrder = runtimeClasspathOrder.get(file); - if (fileOrder != null && (order == -1 || fileOrder < order)) { - order = fileOrder; - } - if (order == 0) break; - } - - runtimeClasspathFilesDependency.setClasspathOrder(order); - result.add(runtimeClasspathFilesDependency); - - for (File file : runtimeClasspathFiles) { - SourceSet outputDirSourceSet = mySourceSetFinder.findByArtifact(file.getPath()); - if (outputDirSourceSet != null) { - addSourceSetOutputDirsAsSingleEntryLibraries(result, outputDirSourceSet, runtimeClasspathOrder, runtimeScope); - } + else { + if (checkCompileOnlyDeps + && !containsAll(compileConfiguration, resolvedFiles) + && !containsAll(runtimeDependenciesProvider.getConfiguration(), resolvedFiles)) { + dep.setScope(PROVIDED_SCOPE); } } - - addSourceSetOutputDirsAsSingleEntryLibraries(result, sourceSet, runtimeClasspathOrder, runtimeScope); - - // handle provided dependencies - final Set providedConfigurations = new LinkedHashSet(); - resolvedMap = ArrayListMultimap.create(); - for (ExternalDependency dep : new DependencyTraverser(result)) { - resolvedMap.put(getFiles(dep), dep); - } - - if (sourceSet.getName().equals("main") && myProject.getPlugins().findPlugin(WarPlugin.class) != null) { - providedConfigurations.add(myProject.getConfigurations().findByName("providedCompile")); - providedConfigurations.add(myProject.getConfigurations().findByName("providedRuntime")); - } - - final IdeaPlugin ideaPlugin = myProject.getPlugins().findPlugin(IdeaPlugin.class); - - if (ideaPlugin != null) { - Map>> scopes = ideaPlugin.getModel().getModule().getScopes(); - Map> providedPlusScopes = scopes.get(providedScope); - - if (providedPlusScopes != null && providedPlusScopes.get("plus") != null) { - Iterable ideaPluginProvidedConfigurations = filter(providedPlusScopes.get("plus"), new Predicate() { - @Override - - public boolean apply(Configuration cfg) { - // filter default 'compileClasspath' for slight optimization since it has been already processed as compile dependencies - return !cfg.getName().equals("compileClasspath") - // since gradle 3.4 'idea' plugin PROVIDED scope.plus contains 'providedCompile' and 'providedRuntime' configurations - // see https://github.com/gradle/gradle/commit/c46897ae840c5ebb32946009c83d861ee194ab96#diff-0fa13ec419e839ef2d355b7feb88b815R432 - && !providedConfigurations.contains(cfg); - } - }); - - for (Configuration configuration : ideaPluginProvidedConfigurations) { - Collection providedDependencies = resolveDependencies(configuration, providedScope).getExternalDeps(); - for(ExternalDependency it : new DependencyTraverser(providedDependencies)) { - resolvedMap.put(getFiles(it), it); - } - result.addAll(providedDependencies); - } - } - } - - for (Configuration cfg : providedConfigurations) { - Collection providedDependencies = resolveDependencies(cfg, providedScope).getExternalDeps(); - for (ExternalDependency dep : new DependencyTraverser(providedDependencies)) { - Collection dependencies = resolvedMap.get(getFiles(dep)); - if (!dependencies.isEmpty()) { - if (dep.getDependencies().isEmpty()) { - providedDependencies.remove(dep); - } - for (ExternalDependency depForScope: dependencies) { - ((AbstractExternalDependency)depForScope).setScope(providedScope); - } - } else { - resolvedMap.put(getFiles(dep), dep); - } - } - result.addAll(providedDependencies); - } - - return removeDuplicates(resolvedMap, result); } private static List removeDuplicates(Multimap resolvedMap, Collection result) { @@ -518,7 +511,7 @@ public class DependencyResolverImpl implements DependencyResolver { toRemove.add(dep); if (dep.getScope().equals("COMPILE")) { isCompileScope = true; - } else if (dep.getScope().equals("PROVIDED")) { + } else if (dep.getScope().equals(PROVIDED_SCOPE)) { isProvidedScope = true; } } @@ -540,7 +533,7 @@ public class DependencyResolverImpl implements DependencyResolver { if (isCompileScope) { ((AbstractExternalDependency)retainedDependency).setScope("COMPILE"); } else if (isProvidedScope) { - ((AbstractExternalDependency)retainedDependency).setScope("PROVIDED"); + ((AbstractExternalDependency)retainedDependency).setScope(PROVIDED_SCOPE); } } } @@ -565,19 +558,20 @@ public class DependencyResolverImpl implements DependencyResolver { return Collections.emptySet(); } - private static void addSourceSetOutputDirsAsSingleEntryLibraries( - Collection dependencies, - SourceSet sourceSet, - Map classpathOrder, - String scope) { + private static Collection collectSourceSetOutputDirsAsSingleEntryLibraries( + @NotNull final SourceSet sourceSet, + @NotNull final Map classpathOrder, + @Nullable final String scope) { + @NotNull final Collection result = new LinkedHashSet(); Set runtimeOutputDirs = sourceSet.getOutput().getDirs().getFiles(); for (File dir : runtimeOutputDirs) { DefaultFileCollectionDependency runtimeOutputDirsDependency = new DefaultFileCollectionDependency(Collections.singleton(dir)); runtimeOutputDirsDependency.setScope(scope); Integer fileOrder = classpathOrder.get(dir); runtimeOutputDirsDependency.setClasspathOrder(fileOrder != null ? fileOrder : -1); - dependencies.add(runtimeOutputDirsDependency); + result.add(runtimeOutputDirsDependency); } + return result; } @@ -650,13 +644,16 @@ public class DependencyResolverImpl implements DependencyResolver { return null; } - void mapFileDependencies(Set fileDependencies, String scope, Collection dependencies) { + Collection createLibraryDependenciesForFiles(@NotNull final Set fileDependencies, + @Nullable final String scope) { + Collection result = new LinkedHashSet(); + File modules2Dir = new File(myProject.getGradle().getGradleUserHomeDir(), "caches/modules-2/files-2.1"); List toRemove = new ArrayList(); for (File file : fileDependencies) { ExternalLibraryDependency libraryDependency = resolveLibraryByPath(file, modules2Dir, scope); if (libraryDependency != null) { - dependencies.add(libraryDependency); + result.add(libraryDependency); toRemove.add(file); } else { //noinspection GrUnresolvedAccess @@ -669,13 +666,13 @@ public class DependencyResolverImpl implements DependencyResolver { defLD.setSource(sourcesFile); defLD.setScope(scope); - dependencies.add(libraryDependency); + result.add(libraryDependency); toRemove.add(file); } } } - fileDependencies.removeAll(toRemove); + return result; } @NotNull diff --git a/plugins/gradle/tooling-extension-impl/src/org/jetbrains/plugins/gradle/tooling/util/resolve/DependencyResultsTransformer.java b/plugins/gradle/tooling-extension-impl/src/org/jetbrains/plugins/gradle/tooling/util/resolve/DependencyResultsTransformer.java index 2d9f37bfb598..63617a24b98d 100644 --- a/plugins/gradle/tooling-extension-impl/src/org/jetbrains/plugins/gradle/tooling/util/resolve/DependencyResultsTransformer.java +++ b/plugins/gradle/tooling-extension-impl/src/org/jetbrains/plugins/gradle/tooling/util/resolve/DependencyResultsTransformer.java @@ -176,7 +176,6 @@ class DependencyResultsTransformer { final ExternalDependency dependency; if (DependencyResolverImpl.isProjectDependencyArtifact(artifact)) { - final String projectPath = ((ProjectComponentIdentifier)artifact.getId().getComponentIdentifier()).getProjectPath(); dependency = createExternalProjectDep(moduleVersionId, selectionReason, diff --git a/plugins/gradle/tooling-extension-impl/src/org/jetbrains/plugins/gradle/tooling/util/resolve/RuntimeDependenciesProvider.java b/plugins/gradle/tooling-extension-impl/src/org/jetbrains/plugins/gradle/tooling/util/resolve/RuntimeDependenciesProvider.java new file mode 100644 index 000000000000..402fc2d79f2e --- /dev/null +++ b/plugins/gradle/tooling-extension-impl/src/org/jetbrains/plugins/gradle/tooling/util/resolve/RuntimeDependenciesProvider.java @@ -0,0 +1,49 @@ +package org.jetbrains.plugins.gradle.tooling.util.resolve; + +import org.gradle.api.Project; +import org.gradle.api.artifacts.Configuration; +import org.gradle.api.tasks.SourceSet; +import org.jetbrains.plugins.gradle.model.ExternalDependency; + +import java.io.File; +import java.util.Collection; + +public class RuntimeDependenciesProvider { + public static final String SCOPE = "RUNTIME"; + + private final SourceSet mySourceSet; + private final Project myProject; + private Configuration myConfiguration; + private Collection myDependencies; + private Collection myFiles; + + public RuntimeDependenciesProvider(SourceSet sourceSet, + Project project) { + mySourceSet = sourceSet; + myProject = project; + } + + public Configuration getConfiguration() { + return myConfiguration; + } + + public Collection getDependencies() { + return myDependencies; + } + + public Collection getFiles() { + return myFiles; + } + + public RuntimeDependenciesProvider resolve(DependencyResolverImpl resolver) { + String runtimeConfigurationName = mySourceSet.getRuntimeConfigurationName(); + Configuration runtimeClasspathConfiguration = myProject.getConfigurations().findByName(runtimeConfigurationName + "Classpath"); + Configuration originRuntimeConfiguration = myProject.getConfigurations().findByName(runtimeConfigurationName); + myConfiguration = runtimeClasspathConfiguration != null ? runtimeClasspathConfiguration : originRuntimeConfiguration; + + ExternalDepsResolutionResult externalDepsResolutionResult = resolver.resolveDependencies(myConfiguration, SCOPE); + myDependencies = externalDepsResolutionResult.getExternalDeps(); + myFiles = externalDepsResolutionResult.getResolvedFiles(); + return this; + } +}