/* * Copyright 2000-2015 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.service.project; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.externalSystem.model.DataNode; import com.intellij.openapi.externalSystem.model.Key; import com.intellij.openapi.externalSystem.model.ProjectKeys; import com.intellij.openapi.externalSystem.model.project.*; import com.intellij.openapi.externalSystem.model.task.TaskData; import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil; import com.intellij.openapi.externalSystem.util.ExternalSystemConstants; import com.intellij.openapi.externalSystem.util.ExternalSystemDebugEnvironment; import com.intellij.openapi.module.Module; import com.intellij.openapi.module.ModuleGrouperKt; import com.intellij.openapi.module.StdModuleTypes; import com.intellij.openapi.roots.DependencyScope; import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.util.text.StringUtil; import com.intellij.util.PathUtilRt; import com.intellij.util.containers.ContainerUtil; import org.gradle.api.artifacts.Dependency; import org.gradle.tooling.model.GradleProject; import org.gradle.tooling.model.gradle.BasicGradleProject; import org.gradle.tooling.model.gradle.GradleBuild; import org.gradle.tooling.model.idea.IdeaModule; import org.gradle.util.GradleVersion; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.plugins.gradle.DefaultExternalDependencyId; import org.jetbrains.plugins.gradle.ExternalDependencyId; import org.jetbrains.plugins.gradle.model.*; import org.jetbrains.plugins.gradle.model.data.GradleSourceSetData; import org.jetbrains.plugins.gradle.settings.GradleExecutionWorkspace; import org.jetbrains.plugins.gradle.util.GradleConstants; import org.jetbrains.plugins.gradle.util.GradleUtil; import java.io.File; import java.io.IOException; import java.util.Collection; import java.util.Collections; import java.util.Map; import java.util.Queue; import static org.jetbrains.plugins.gradle.service.project.GradleProjectResolver.CONFIGURATION_ARTIFACTS; /** * @author Vladislav.Soroka * @since 10/6/2015 */ public class GradleProjectResolverUtil { private static final Logger LOG = Logger.getInstance(GradleProjectResolverUtil.class); @NotNull private static final Key<Object> CONTAINER_KEY = Key.create(Object.class, ExternalSystemConstants.UNORDERED); @NotNull public static DataNode<ModuleData> createMainModule(@NotNull ProjectResolverContext resolverCtx, @NotNull IdeaModule gradleModule, @NotNull DataNode<ProjectData> projectDataNode) { final String moduleName = gradleModule.getName(); if (moduleName == null) { throw new IllegalStateException("Module with undefined name detected: " + gradleModule); } final ProjectData projectData = projectDataNode.getData(); final String mainModuleConfigPath = getModuleConfigPath(resolverCtx, gradleModule, projectData.getLinkedExternalProjectPath()); final String ideProjectPath = resolverCtx.getIdeProjectPath(); final String relativePath; if (FileUtil.isAncestor(projectData.getLinkedExternalProjectPath(), mainModuleConfigPath, false)) { relativePath = FileUtil.getRelativePath(projectData.getLinkedExternalProjectPath(), mainModuleConfigPath, '/'); } else { relativePath = String.valueOf(FileUtil.pathHashCode(mainModuleConfigPath)); } final String mainModuleFileDirectoryPath = ideProjectPath == null ? mainModuleConfigPath : ideProjectPath + '/' + (relativePath == null || relativePath.equals(".") ? "" : relativePath); if (ExternalSystemDebugEnvironment.DEBUG_ORPHAN_MODULES_PROCESSING) { LOG.info(String.format( "Creating module data ('%s') with the external config path: '%s'", gradleModule.getGradleProject().getPath(), mainModuleConfigPath )); } String mainModuleId = getModuleId(resolverCtx, gradleModule); final ModuleData moduleData = new ModuleData(mainModuleId, GradleConstants.SYSTEM_ID, StdModuleTypes.JAVA.getId(), moduleName, mainModuleFileDirectoryPath, mainModuleConfigPath); ExternalProject externalProject = resolverCtx.getExtraProject(gradleModule, ExternalProject.class); if (externalProject != null) { moduleData.setInternalName(getInternalModuleName(gradleModule, externalProject)); moduleData.setGroup(externalProject.getGroup()); moduleData.setVersion(externalProject.getVersion()); moduleData.setDescription(externalProject.getDescription()); if (!resolverCtx.isResolveModulePerSourceSet()) { moduleData.setArtifacts(externalProject.getArtifacts()); } } return projectDataNode.createChild(ProjectKeys.MODULE, moduleData); } @NotNull static String getInternalModuleName(@NotNull IdeaModule gradleModule, @NotNull ExternalProject externalProject) { return getInternalModuleName(gradleModule, externalProject, null); } @NotNull static String getInternalModuleName(@NotNull IdeaModule gradleModule, @NotNull ExternalProject externalProject, @Nullable String sourceSetName) { String delimiter; StringBuilder moduleName = new StringBuilder(); if (ModuleGrouperKt.isQualifiedModuleNamesEnabled()) { delimiter = "."; if (StringUtil.isNotEmpty(externalProject.getGroup())) { moduleName.append(externalProject.getGroup()).append(delimiter); } moduleName.append(externalProject.getName()); } else { delimiter = "_"; moduleName.append(gradleModule.getName()); } if (sourceSetName != null) { assert !sourceSetName.isEmpty(); moduleName.append(delimiter); moduleName.append(sourceSetName); } return PathUtilRt.suggestFileName(moduleName.toString(), true, false); } @NotNull public static String getModuleConfigPath(@NotNull ProjectResolverContext resolverCtx, @NotNull IdeaModule gradleModule, @NotNull String rootProjectPath) { GradleBuild build = resolverCtx.getExtraProject(gradleModule, GradleBuild.class); if (build != null) { String gradlePath = gradleModule.getGradleProject().getPath(); File moduleDirPath = getModuleDirPath(build, gradlePath); if (moduleDirPath == null) { throw new IllegalStateException(String.format("Unable to find root directory for module '%s'", gradleModule.getName())); } try { return ExternalSystemApiUtil.toCanonicalPath(moduleDirPath.getCanonicalPath()); } catch (IOException e) { LOG.warn("construction of the canonical path for the module fails", e); } } return GradleUtil.getConfigPath(gradleModule.getGradleProject(), rootProjectPath); } /** * Returns the physical path of the module's root directory (the path in the file system.) * <p> * It is important to note that Gradle has its own "logical" path that may or may not be equal to the physical path of a Gradle project. * For example, the sub-project at ${projectRootDir}/apps/app will have the Gradle path :apps:app. Gradle also allows mapping physical * paths to a different logical path. For example, in settings.gradle: * <pre> * include ':app' * project(':app').projectDir = new File(rootDir, 'apps/app') * </pre> * In this example, sub-project at ${projectRootDir}/apps/app will have the Gradle path :app. * </p> * * @param build contains information about the root Gradle project and its sub-projects. Such information includes the physical path of * the root Gradle project and its sub-projects. * @param path the Gradle "logical" path. This path uses colon as separator, and may or may not be equal to the physical path of a * Gradle project. * @return the physical path of the module's root directory. */ @Nullable public static File getModuleDirPath(@NotNull GradleBuild build, @NotNull String path) { for (BasicGradleProject project : build.getProjects()) { if (project.getPath().equals(path)) { return project.getProjectDirectory(); } } return null; } @NotNull public static String getModuleId(@NotNull ProjectResolverContext resolverCtx, @NotNull IdeaModule gradleModule) { GradleProject gradleProject = gradleModule.getGradleProject(); String gradlePath = gradleProject.getPath(); String compositePrefix = ""; if (gradleModule.getProject() != resolverCtx.getModels().getIdeaProject()) { if (!StringUtil.isEmpty(gradlePath) && !":".equals(gradlePath)) { compositePrefix = gradleModule.getProject().getName(); } } return compositePrefix + getModuleId(gradlePath, gradleModule.getName()); } @NotNull public static String getModuleId(String gradlePath, String moduleName) { return StringUtil.isEmpty(gradlePath) || ":".equals(gradlePath) ? moduleName : gradlePath; } @NotNull public static String getModuleId(@NotNull ExternalProject externalProject) { return externalProject.getId(); } @NotNull public static String getModuleId(@NotNull ExternalProject externalProject, @NotNull ExternalSourceSet sourceSet) { String mainModuleId = getModuleId(externalProject); return mainModuleId + ":" + sourceSet.getName(); } @NotNull public static String getModuleId(@NotNull ProjectResolverContext resolverCtx, @NotNull IdeaModule gradleModule, @NotNull ExternalSourceSet sourceSet) { String mainModuleId = getModuleId(resolverCtx, gradleModule); return mainModuleId + ":" + sourceSet.getName(); } @NotNull public static String getModuleId(@NotNull ExternalProjectDependency projectDependency) { DependencyScope dependencyScope = getDependencyScope(projectDependency.getScope()); String projectPath = projectDependency.getProjectPath(); String moduleId = StringUtil.isEmpty(projectPath) || ":".equals(projectPath) ? projectDependency.getName() : projectPath; if (Dependency.DEFAULT_CONFIGURATION.equals(projectDependency.getConfigurationName())) { moduleId += dependencyScope == DependencyScope.TEST ? ":test" : ":main"; } else { moduleId += (':' + projectDependency.getConfigurationName()); } return moduleId; } @Nullable public static String getSourceSetName(final Module module) { if (!ExternalSystemApiUtil.isExternalSystemAwareModule(GradleConstants.SYSTEM_ID, module)) return null; if (!GradleConstants.GRADLE_SOURCE_SET_MODULE_TYPE_KEY.equals(ExternalSystemApiUtil.getExternalModuleType(module))) return null; String externalProjectId = ExternalSystemApiUtil.getExternalProjectId(module); if (externalProjectId == null) return null; int i = externalProjectId.lastIndexOf(':'); if (i == -1 || externalProjectId.length() < i + 1) return null; return externalProjectId.substring(i + 1); } @Nullable public static String getGradlePath(final Module module) { if (!ExternalSystemApiUtil.isExternalSystemAwareModule(GradleConstants.SYSTEM_ID, module)) return null; final String projectId = ExternalSystemApiUtil.getExternalProjectId(module); if (projectId == null) return null; final String moduleType = ExternalSystemApiUtil.getExternalModuleType(module); final String gradlePath; if (GradleConstants.GRADLE_SOURCE_SET_MODULE_TYPE_KEY.equals(moduleType)) { int lastColonIndex = projectId.lastIndexOf(':'); assert lastColonIndex != -1; int firstColonIndex = projectId.indexOf(':'); gradlePath = firstColonIndex == lastColonIndex ? ":" : projectId.substring(firstColonIndex, lastColonIndex); } else { gradlePath = projectId.charAt(0) == ':' ? projectId : ":"; } return gradlePath; } @NotNull public static DependencyScope getDependencyScope(@Nullable String scope) { return scope != null ? DependencyScope.valueOf(scope) : DependencyScope.COMPILE; } public static void attachGradleSdkSources(@NotNull final IdeaModule gradleModule, @Nullable final File libFile, @NotNull final LibraryData library, @NotNull final ProjectResolverContext resolverCtx) { final BuildScriptClasspathModel buildScriptClasspathModel = resolverCtx.getExtraProject(gradleModule, BuildScriptClasspathModel.class); if (buildScriptClasspathModel == null) return; final File gradleHomeDir = buildScriptClasspathModel.getGradleHomeDir(); if (gradleHomeDir == null) return; final GradleVersion gradleVersion = GradleVersion.version(buildScriptClasspathModel.getGradleVersion()); attachGradleSdkSources(libFile, library, gradleHomeDir, gradleVersion); } public static void attachGradleSdkSources(@Nullable final File libFile, @NotNull final LibraryData library, @NotNull final File gradleHomeDir, @NotNull final GradleVersion gradleVersion) { if (libFile == null || !libFile.getName().startsWith("gradle-")) return; if (!FileUtil.isAncestor(gradleHomeDir, libFile, true)) return; File libOrPluginsFile = libFile.getParentFile(); if (libOrPluginsFile != null && ("plugins".equals(libOrPluginsFile.getName()))) { libOrPluginsFile = libOrPluginsFile.getParentFile(); } if (libOrPluginsFile != null && "lib".equals(libOrPluginsFile.getName()) && libOrPluginsFile.getParentFile() != null) { File srcDir = new File(libOrPluginsFile.getParentFile(), "src"); if (gradleVersion.compareTo(GradleVersion.version("1.9")) >= 0) { int endIndex = libFile.getName().indexOf(gradleVersion.getVersion()); if (endIndex != -1) { String srcDirChild = libFile.getName().substring("gradle-".length(), endIndex - 1); srcDir = new File(srcDir, srcDirChild); } } if (srcDir.isDirectory()) { library.addPath(LibraryPathType.SOURCE, srcDir.getAbsolutePath()); } } } @SuppressWarnings("unchecked") public static Collection<DependencyData> getIdeDependencies(@NotNull ProjectResolverContext resolverCtx, @NotNull DataNode<? extends ModuleData> moduleDataNode, @NotNull Collection<ExternalDependency> dependencies) throws IllegalStateException { final DataNode<ProjectData> ideProject = ExternalSystemApiUtil.findParent(moduleDataNode, ProjectKeys.PROJECT); assert ideProject != null; final Map<String, Pair<DataNode<GradleSourceSetData>, ExternalSourceSet>> sourceSetMap = ideProject.getUserData(GradleProjectResolver.RESOLVED_SOURCE_SETS); assert sourceSetMap != null; final Map<String, String> artifactsMap = ideProject.getUserData(CONFIGURATION_ARTIFACTS); assert artifactsMap != null; DataNode fakeNode = new DataNode(CONTAINER_KEY, moduleDataNode.getData(), null); buildDependencies(resolverCtx, sourceSetMap, artifactsMap, fakeNode, dependencies, null); final Collection<DataNode<?>> dataNodes = ExternalSystemApiUtil.findAllRecursively(fakeNode, node -> node.getData() instanceof DependencyData); return ContainerUtil.map(dataNodes, node -> (DependencyData)node.getData()); } public static void buildDependencies(@NotNull ProjectResolverContext resolverCtx, @NotNull Map<String, Pair<DataNode<GradleSourceSetData>, ExternalSourceSet>> sourceSetMap, @NotNull final Map<String, String> artifactsMap, @NotNull DataNode<? extends ExternalEntityData> ownerDataNode, @NotNull Collection<ExternalDependency> dependencies, @Nullable DataNode<ProjectData> ideProject) throws IllegalStateException { Map<ExternalDependencyId, ExternalDependency> dependencyMap = ContainerUtil.newHashMap(); Queue<ExternalDependency> queue = ContainerUtil.newLinkedList(dependencies); while (!queue.isEmpty()) { final ExternalDependency dependency = queue.remove(); ExternalDependency seenDependency = dependencyMap.get(dependency.getId()); if (seenDependency != null) { if (dependency instanceof ExternalLibraryDependency) { if (seenDependency instanceof ExternalLibraryDependency && !FileUtil.filesEqual(((ExternalLibraryDependency)seenDependency).getFile(), ((ExternalLibraryDependency)dependency).getFile())) { DefaultExternalMultiLibraryDependency mergedDependency = new DefaultExternalMultiLibraryDependency(); mergedDependency.setName(dependency.getId().getName()); mergedDependency.setGroup(dependency.getId().getGroup()); mergedDependency.setVersion(dependency.getId().getVersion()); mergedDependency.setPackaging(dependency.getId().getPackaging()); mergedDependency.setClassifier(dependency.getId().getClassifier()); mergedDependency.setScope(dependency.getScope()); mergedDependency.setClasspathOrder(dependency.getClasspathOrder()); mergedDependency.getDependencies().addAll(dependency.getDependencies()); mergedDependency.getFiles().addAll(ContainerUtil.packNullables( ((ExternalLibraryDependency)seenDependency).getFile(), ((ExternalLibraryDependency)dependency).getFile())); mergedDependency.getSources().addAll((ContainerUtil.packNullables( ((ExternalLibraryDependency)seenDependency).getSource(), ((ExternalLibraryDependency)dependency).getSource()))); mergedDependency.getJavadoc().addAll((ContainerUtil.packNullables( ((ExternalLibraryDependency)seenDependency).getJavadoc(), ((ExternalLibraryDependency)dependency).getJavadoc()))); dependencyMap.put(dependency.getId(), mergedDependency); continue; } else if (seenDependency instanceof DefaultExternalMultiLibraryDependency) { DefaultExternalMultiLibraryDependency mergedDependency = (DefaultExternalMultiLibraryDependency)seenDependency; mergedDependency.getFiles().addAll(ContainerUtil.packNullables(((ExternalLibraryDependency)dependency).getFile())); mergedDependency.getSources().addAll(ContainerUtil.packNullables(((ExternalLibraryDependency)dependency).getSource())); mergedDependency.getJavadoc().addAll(ContainerUtil.packNullables(((ExternalLibraryDependency)dependency).getJavadoc())); continue; } } DependencyScope prevScope = seenDependency.getScope() == null ? DependencyScope.COMPILE : DependencyScope.valueOf(seenDependency.getScope()); DependencyScope currentScope = dependency.getScope() == null ? DependencyScope.COMPILE : DependencyScope.valueOf(dependency.getScope()); if (prevScope.isForProductionCompile()) continue; if (prevScope.isForProductionRuntime() && currentScope.isForProductionRuntime()) continue; } dependencyMap.put(new DefaultExternalDependencyId(dependency.getId()), dependency); queue.addAll(dependency.getDependencies()); } doBuildDependencies(resolverCtx, sourceSetMap, artifactsMap, dependencyMap, ownerDataNode, dependencies, ideProject); } private static void doBuildDependencies(@NotNull ProjectResolverContext resolverCtx, @NotNull Map<String, Pair<DataNode<GradleSourceSetData>, ExternalSourceSet>> sourceSetMap, @NotNull final Map<String, String> artifactsMap, @NotNull Map<ExternalDependencyId, ExternalDependency> mergedDependencyMap, @NotNull DataNode<? extends ExternalEntityData> ownerDataNode, @NotNull Collection<ExternalDependency> dependencies, @Nullable DataNode<ProjectData> ideProject) throws IllegalStateException { Map<ExternalDependencyId, ExternalDependency> dependencyMap = ContainerUtil.newLinkedHashMap(); for (ExternalDependency dependency : dependencies) { final ExternalDependency dep = dependencyMap.get(dependency.getId()); if (dep instanceof AbstractExternalDependency) { dep.getDependencies().addAll(ContainerUtil.subtract(dependency.getDependencies(), dep.getDependencies())); } else { dependencyMap.put(dependency.getId(), dependency); } } for (ExternalDependency dependency : dependencyMap.values()) { final ExternalDependency mergedDependency = ContainerUtil.getOrElse(mergedDependencyMap, dependency.getId(), dependency); DependencyScope dependencyScope = getDependencyScope(mergedDependency.getScope()); ModuleData ownerModule = null; if (ownerDataNode.getData() instanceof ModuleData) { ownerModule = (ModuleData)ownerDataNode.getData(); } else if (ownerDataNode.getData() instanceof DependencyData) { ownerModule = ((DependencyData)ownerDataNode.getData()).getOwnerModule(); } assert ownerModule != null; DataNode<? extends ExternalEntityData> depOwnerDataNode = null; if (mergedDependency instanceof ExternalProjectDependency) { class ProjectDependencyInfo { @NotNull ModuleData myModuleData; @Nullable ExternalSourceSet mySourceSet; Collection<File> dependencyArtifacts; public ProjectDependencyInfo(@NotNull ModuleData moduleData, @Nullable ExternalSourceSet sourceSet, Collection<File> dependencyArtifacts) { this.myModuleData = moduleData; this.mySourceSet = sourceSet; this.dependencyArtifacts = dependencyArtifacts; } } final ExternalProjectDependency projectDependency = (ExternalProjectDependency)mergedDependency; Collection<ProjectDependencyInfo> projectDependencyInfos = ContainerUtil.newArrayList(); String selectionReason = projectDependency.getSelectionReason(); if ("composite build substitution".equals(selectionReason) && resolverCtx.getSettings() != null) { GradleExecutionWorkspace executionWorkspace = resolverCtx.getSettings().getExecutionWorkspace(); ModuleData moduleData = executionWorkspace.findModuleDataByArtifacts(projectDependency.getProjectDependencyArtifacts()); if (moduleData != null) { projectDependencyInfos.add(new ProjectDependencyInfo(moduleData, null, projectDependency.getProjectDependencyArtifacts())); } } else { String moduleId = getModuleId(projectDependency); Pair<DataNode<GradleSourceSetData>, ExternalSourceSet> projectPair = sourceSetMap.get(moduleId); if (projectPair == null) { for (File file : projectDependency.getProjectDependencyArtifacts()) { moduleId = artifactsMap.get(ExternalSystemApiUtil.toCanonicalPath(file.getAbsolutePath())); if (moduleId == null) continue; projectPair = sourceSetMap.get(moduleId); if (projectPair == null) continue; projectDependencyInfos.add(new ProjectDependencyInfo( projectPair.first.getData(), projectPair.second, Collections.singleton(file))); } } else { projectDependencyInfos.add(new ProjectDependencyInfo(projectPair.first.getData(), projectPair.second, projectDependency.getProjectDependencyArtifacts())); } } if (projectDependencyInfos.isEmpty()) { final LibraryLevel level = LibraryLevel.MODULE; final LibraryData library = new LibraryData(GradleConstants.SYSTEM_ID, ""); LibraryDependencyData libraryDependencyData = new LibraryDependencyData(ownerModule, library, level); libraryDependencyData.setScope(dependencyScope); libraryDependencyData.setOrder(mergedDependency.getClasspathOrder()); libraryDependencyData.setExported(mergedDependency.getExported()); if (!projectDependency.getProjectDependencyArtifacts().isEmpty()) { for (File artifact : projectDependency.getProjectDependencyArtifacts()) { library.addPath(LibraryPathType.BINARY, artifact.getPath()); } depOwnerDataNode = ownerDataNode.createChild(ProjectKeys.LIBRARY_DEPENDENCY, libraryDependencyData); } else { depOwnerDataNode = ownerDataNode; } } else { for (ProjectDependencyInfo projectDependencyInfo : projectDependencyInfos) { ModuleDependencyData moduleDependencyData = new ModuleDependencyData(ownerModule, projectDependencyInfo.myModuleData); moduleDependencyData.setScope(dependencyScope); if (projectDependencyInfo.mySourceSet != null && "test".equals(projectDependencyInfo.mySourceSet.getName())) { moduleDependencyData.setProductionOnTestDependency(true); } moduleDependencyData.setOrder(mergedDependency.getClasspathOrder()); moduleDependencyData.setExported(mergedDependency.getExported()); moduleDependencyData.setModuleDependencyArtifacts(ContainerUtil.map(projectDependencyInfo.dependencyArtifacts, File::getPath)); depOwnerDataNode = ownerDataNode.createChild(ProjectKeys.MODULE_DEPENDENCY, moduleDependencyData); } // put transitive dependencies to the ownerDataNode, // since we can not determine from what project dependency artifact it was originated if(projectDependencyInfos.size() > 1) { depOwnerDataNode = ownerDataNode; } } } else if (mergedDependency instanceof ExternalLibraryDependency) { String libraryName = mergedDependency.getId().getPresentableName(); final LibraryLevel level = StringUtil.isNotEmpty(libraryName) ? LibraryLevel.PROJECT : LibraryLevel.MODULE; final LibraryData library = new LibraryData(GradleConstants.SYSTEM_ID, libraryName); LibraryDependencyData libraryDependencyData = new LibraryDependencyData(ownerModule, library, level); libraryDependencyData.setScope(dependencyScope); libraryDependencyData.setOrder(mergedDependency.getClasspathOrder()); libraryDependencyData.setExported(mergedDependency.getExported()); library.addPath(LibraryPathType.BINARY, ((ExternalLibraryDependency)mergedDependency).getFile().getAbsolutePath()); File sourcePath = ((ExternalLibraryDependency)mergedDependency).getSource(); if (sourcePath != null) { library.addPath(LibraryPathType.SOURCE, sourcePath.getAbsolutePath()); } File javaDocPath = ((ExternalLibraryDependency)mergedDependency).getJavadoc(); if (javaDocPath != null) { library.addPath(LibraryPathType.DOC, javaDocPath.getAbsolutePath()); } depOwnerDataNode = ownerDataNode.createChild(ProjectKeys.LIBRARY_DEPENDENCY, libraryDependencyData); if (StringUtil.isNotEmpty(libraryName)) { linkProjectLibrary(ideProject, library); } } else if (mergedDependency instanceof ExternalMultiLibraryDependency) { final LibraryLevel level = LibraryLevel.MODULE; String libraryName = mergedDependency.getId().getPresentableName(); final LibraryData library = new LibraryData(GradleConstants.SYSTEM_ID, libraryName); LibraryDependencyData libraryDependencyData = new LibraryDependencyData(ownerModule, library, level); libraryDependencyData.setScope(dependencyScope); libraryDependencyData.setOrder(mergedDependency.getClasspathOrder()); libraryDependencyData.setExported(mergedDependency.getExported()); for (File file : ((ExternalMultiLibraryDependency)mergedDependency).getFiles()) { library.addPath(LibraryPathType.BINARY, file.getAbsolutePath()); } for (File file : ((ExternalMultiLibraryDependency)mergedDependency).getSources()) { library.addPath(LibraryPathType.SOURCE, file.getAbsolutePath()); } for (File file : ((ExternalMultiLibraryDependency)mergedDependency).getJavadoc()) { library.addPath(LibraryPathType.DOC, file.getAbsolutePath()); } depOwnerDataNode = ownerDataNode.createChild(ProjectKeys.LIBRARY_DEPENDENCY, libraryDependencyData); } else if (mergedDependency instanceof FileCollectionDependency) { final LibraryLevel level = LibraryLevel.MODULE; String libraryName = ""; final LibraryData library = new LibraryData(GradleConstants.SYSTEM_ID, libraryName); LibraryDependencyData libraryDependencyData = new LibraryDependencyData(ownerModule, library, level); libraryDependencyData.setScope(dependencyScope); libraryDependencyData.setOrder(mergedDependency.getClasspathOrder()); libraryDependencyData.setExported(mergedDependency.getExported()); for (File file : ((FileCollectionDependency)mergedDependency).getFiles()) { library.addPath(LibraryPathType.BINARY, file.getAbsolutePath()); } ownerDataNode.createChild(ProjectKeys.LIBRARY_DEPENDENCY, libraryDependencyData); } else if (mergedDependency instanceof UnresolvedExternalDependency) { final LibraryLevel level = LibraryLevel.PROJECT; String libraryName = mergedDependency.getId().getPresentableName(); final LibraryData library = new LibraryData(GradleConstants.SYSTEM_ID, libraryName, true); LibraryDependencyData libraryDependencyData = new LibraryDependencyData(ownerModule, library, level); libraryDependencyData.setScope(dependencyScope); final String failureMessage = ((UnresolvedExternalDependency)mergedDependency).getFailureMessage(); if (failureMessage != null) { library.addPath(LibraryPathType.BINARY, failureMessage); } ownerDataNode.createChild(ProjectKeys.LIBRARY_DEPENDENCY, libraryDependencyData); linkProjectLibrary(ideProject, library); } if (depOwnerDataNode != null) { doBuildDependencies(resolverCtx, sourceSetMap, artifactsMap, mergedDependencyMap, depOwnerDataNode, dependency.getDependencies(), ideProject); } } } public static void linkProjectLibrary(@Nullable DataNode<ProjectData> ideProject, @NotNull final LibraryData library) { if (ideProject == null) return; DataNode<LibraryData> libraryData = ExternalSystemApiUtil.find(ideProject, ProjectKeys.LIBRARY, node -> library.equals(node.getData())); if (libraryData == null) { ideProject.createChild(ProjectKeys.LIBRARY, library); } } public static boolean isIdeaTask(final String taskName, @Nullable String group) { if ((group == null || "ide".equalsIgnoreCase(group)) && StringUtil.containsIgnoreCase(taskName, "idea")) return true; return "other".equalsIgnoreCase(group) && StringUtil.containsIgnoreCase(taskName, "idea"); } @Nullable public static DataNode<ModuleData> findModule(@Nullable final DataNode<ProjectData> projectNode, @NotNull final String modulePath) { if (projectNode == null) return null; return ExternalSystemApiUtil.find(projectNode, ProjectKeys.MODULE, node -> node.getData().getLinkedExternalProjectPath().equals(modulePath)); } @Nullable public static DataNode<ModuleData> findModuleById(@Nullable final DataNode<ProjectData> projectNode, @NotNull final String path) { if (projectNode == null) return null; return ExternalSystemApiUtil.find(projectNode, ProjectKeys.MODULE, node -> node.getData().getId().equals(path)); } @Nullable public static DataNode<TaskData> findTask(@Nullable final DataNode<ProjectData> projectNode, @NotNull final String modulePath, @NotNull final String taskPath) { DataNode<ModuleData> moduleNode; final String taskName; if (StringUtil.startsWith(taskPath, ":")) { final int i = taskPath.lastIndexOf(':'); String path = taskPath.substring(0, i); moduleNode = findModuleById(projectNode, path); if (moduleNode == null || !FileUtil.isAncestor(moduleNode.getData().getLinkedExternalProjectPath(), modulePath, false)) { moduleNode = findModule(projectNode, modulePath); } taskName = (i + 1) <= taskPath.length() ? taskPath.substring(i + 1) : taskPath; } else { moduleNode = findModule(projectNode, modulePath); taskName = taskPath; } if (moduleNode == null) return null; return ExternalSystemApiUtil.find(moduleNode, ProjectKeys.TASK, node -> { String name = node.getData().getName(); return name.equals(taskName) || name.equals(taskPath); }); } }