| /* |
| * Copyright (C) 2013 The Android Open Source Project |
| * |
| * 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 com.android.tools.idea.gradle.dependency; |
| |
| import com.google.common.collect.ArrayListMultimap; |
| import com.google.common.collect.Maps; |
| import com.google.common.collect.Multimap; |
| import org.jetbrains.annotations.NotNull; |
| |
| import java.util.Collection; |
| import java.util.Map; |
| |
| import static com.android.tools.idea.gradle.dependency.Dependency.SUPPORTED_SCOPES; |
| |
| /** |
| * Collection of an IDEA module's dependencies. |
| */ |
| public class DependencySet { |
| private final Multimap<String, LibraryDependency> myLibrariesByName = ArrayListMultimap.create(); |
| private final Map<String, ModuleDependency> myModulesByPath = Maps.newHashMap(); |
| |
| /** |
| * Adds the given dependency to this collection. If this collection already has a dependency under the same name, the dependency with the |
| * wider scope is stored: {@link com.intellij.openapi.roots.DependencyScope#COMPILE} has wider scope than |
| * {@link com.intellij.openapi.roots.DependencyScope#TEST}. |
| * <p/> |
| * It is not uncommon that the Android Gradle plug-in lists the same dependency as explicitly having both "compile" and "test" scopes. In |
| * IDEA there is no such distinction, a dependency with "compile" scope is also available to test code. |
| * |
| * @param dependency the dependency to add. |
| */ |
| void add(@NotNull LibraryDependency dependency) { |
| String originalName = dependency.getName(); |
| Collection<LibraryDependency> allStored = myLibrariesByName.get(originalName); |
| if (allStored == null || allStored.isEmpty()) { |
| myLibrariesByName.put(originalName, dependency); |
| return; |
| } |
| |
| LibraryDependency toAdd = dependency; |
| LibraryDependency replaced = null; |
| |
| for (LibraryDependency stored : allStored) { |
| if (areSameArtifact(dependency, stored)) { |
| toAdd = null; |
| if (hasHigherScope(dependency, stored)) { |
| // replace the existing one if the new one has higher scope. (e.g. "compile" scope is higher than "test" scope.) |
| replaced = stored; |
| dependency.setName(stored.getName()); |
| myLibrariesByName.put(originalName, dependency); |
| } |
| break; |
| } |
| } |
| |
| if (replaced != null) { |
| myLibrariesByName.remove(originalName, replaced); |
| } |
| |
| if (toAdd != null) { |
| String newName = allStored.size() + "_" + dependency.getName(); |
| dependency.setName(newName); |
| myLibrariesByName.put(originalName, dependency); |
| } |
| } |
| |
| private static boolean areSameArtifact(@NotNull LibraryDependency d1, @NotNull LibraryDependency d2) { |
| Collection<String> binaryPaths1 = d1.getPaths(LibraryDependency.PathType.BINARY); |
| Collection<String> binaryPaths2 = d2.getPaths(LibraryDependency.PathType.BINARY); |
| return binaryPaths1.equals(binaryPaths2); |
| } |
| |
| /** |
| * Adds the given dependency to this collection. If this collection already has a dependency under the same name, the dependency with the |
| * wider scope is stored: {@link com.intellij.openapi.roots.DependencyScope#COMPILE} has wider scope than |
| * {@link com.intellij.openapi.roots.DependencyScope#TEST}. |
| * <p> |
| * It is not uncommon that the Android Gradle plug-in lists the same dependency as explicitly having both "compile" and "test" scopes. In |
| * IDEA there is no such distinction, a dependency with "compile" scope is also available to test code. |
| * |
| * @param dependency the dependency to add. |
| */ |
| void add(@NotNull ModuleDependency dependency) { |
| String gradlePath = dependency.getGradlePath(); |
| Dependency storedDependency = myModulesByPath.get(gradlePath); |
| if (storedDependency == null || hasHigherScope(dependency, storedDependency)) { |
| myModulesByPath.put(gradlePath, dependency); |
| } |
| } |
| |
| private static <T extends Dependency> boolean hasHigherScope(T d1, T d2) { |
| return SUPPORTED_SCOPES.indexOf(d1.getScope()) < SUPPORTED_SCOPES.indexOf(d2.getScope()); |
| } |
| |
| @NotNull |
| public Collection<LibraryDependency> onLibraries() { |
| return myLibrariesByName.values(); |
| } |
| |
| @NotNull |
| public Collection<ModuleDependency> onModules() { |
| return myModulesByPath.values(); |
| } |
| } |