mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
IDEA-75728 Gradle: Try to ensure that libraries of the imported project have distinct names
This commit is contained in:
+2
-12
@@ -35,22 +35,12 @@ public abstract class AbstractGradleDependency extends AbstractGradleEntity impl
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = myScope.hashCode();
|
||||
result = 31 * result + (myExported ? 1 : 0);
|
||||
return result;
|
||||
return 31;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
|
||||
AbstractGradleDependency that = (AbstractGradleDependency)o;
|
||||
|
||||
if (myExported != that.myExported) return false;
|
||||
if (myScope != that.myScope) return false;
|
||||
|
||||
return true;
|
||||
return this == o || (o != null && getClass() == o.getClass());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+222
@@ -0,0 +1,222 @@
|
||||
package org.jetbrains.plugins.gradle.remote.impl;
|
||||
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.util.containers.HashMap;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.plugins.gradle.importing.model.GradleLibrary;
|
||||
import org.jetbrains.plugins.gradle.importing.model.LibraryPathType;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* Encapsulates logic of checking if particular collection of gradle libraries contains libraries with the same names and
|
||||
* tries to diversify them in the case of the positive answer.
|
||||
* <p/>
|
||||
* Thread-safe.
|
||||
*
|
||||
* @author Denis Zhdanov
|
||||
* @since 10/19/11 2:04 PM
|
||||
*/
|
||||
public class GradleLibraryNamesMixer {
|
||||
|
||||
/**
|
||||
* Holds mappings like <code>('file name'; boolean)</code> where <code>'file name'</code> defines 'too common' file/dir
|
||||
* name that should not be used during library name generation. Boolean flag indicates if 'common file name' may be used
|
||||
* if 'non-common' files are the same.
|
||||
* <p/>
|
||||
* Example: consider the following file system tree:
|
||||
* <pre>
|
||||
* module
|
||||
* |_src
|
||||
* |_main
|
||||
* | |_resources
|
||||
* |
|
||||
* |_test
|
||||
* |_resources
|
||||
* </pre>
|
||||
* Let's say we have two libraries where one of them points to <code>'src/main/resources'</code> and another one
|
||||
* to <code>'src/test/resources'</code>. We want to generate names <code>'module-resources'</code> and
|
||||
* <code>'module-test-resources'</code> respectively because <code>'test'</code> entry at the current collection is
|
||||
* stored with <code>'true'</code> flag.
|
||||
*/
|
||||
private static final Map<String, Boolean> NON_UNIQUE_PATH_ENTRIES = new HashMap<String, Boolean>();
|
||||
static {
|
||||
NON_UNIQUE_PATH_ENTRIES.put("src", false);
|
||||
NON_UNIQUE_PATH_ENTRIES.put("main", false);
|
||||
NON_UNIQUE_PATH_ENTRIES.put("test", true);
|
||||
NON_UNIQUE_PATH_ENTRIES.put("resources", false);
|
||||
NON_UNIQUE_PATH_ENTRIES.put("java", false);
|
||||
NON_UNIQUE_PATH_ENTRIES.put("groovy", false);
|
||||
}
|
||||
private static final char NAME_SEPARATOR = '-';
|
||||
|
||||
/**
|
||||
* Tries to ensure that given libraries have distinct names, i.e. traverses all of them and tries to generate
|
||||
* unique name for those with equal names.
|
||||
*
|
||||
* @param libraries libraries to process
|
||||
*/
|
||||
@SuppressWarnings("MethodMayBeStatic")
|
||||
public void mixNames(@NotNull Iterable<? extends GradleLibrary> libraries) {
|
||||
Map<String, Wrapped> names = new HashMap<String, Wrapped>();
|
||||
List<Wrapped> data = new ArrayList<Wrapped>();
|
||||
for (GradleLibrary library : libraries) {
|
||||
Wrapped wrapped = new Wrapped(library);
|
||||
data.add(wrapped);
|
||||
}
|
||||
boolean mixed = false;
|
||||
while (!mixed) {
|
||||
mixed = doMixNames(data, names);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Does the same as {@link #mixNames(Iterable)} but uses given <code>('library name; wrapped library'}</code> mappings cache.
|
||||
*
|
||||
* @param libraries libraries to process
|
||||
* @param cache cache to use
|
||||
* @return <code>true</code> if all of the given libraries have distinct names now; <code>false</code> otherwise
|
||||
*/
|
||||
private static boolean doMixNames(@NotNull Collection<Wrapped> libraries, @NotNull Map<String, Wrapped> cache) {
|
||||
cache.clear();
|
||||
for (Wrapped current : libraries) {
|
||||
Wrapped previous = cache.remove(current.library.getName());
|
||||
if (previous == null) {
|
||||
cache.put(current.library.getName(), current);
|
||||
}
|
||||
else {
|
||||
mixNames(current, previous);
|
||||
return current.library.getName().equals(previous.library.getName()); // Stop processing if it's not possible to generate
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tries to generate distinct names for the given wrapped libraries (assuming that they have equal names at the moment).
|
||||
*
|
||||
* @param wrapped1 one of the libraries with equal names
|
||||
* @param wrapped2 another library which name is equal to the name of the given one
|
||||
*/
|
||||
@SuppressWarnings("AssignmentToForLoopParameter")
|
||||
private static void mixNames(@NotNull Wrapped wrapped1, @NotNull Wrapped wrapped2) {
|
||||
if (!wrapped1.prepare() || !wrapped2.prepare()) {
|
||||
return;
|
||||
}
|
||||
String wrapped1AltText = null;
|
||||
String wrapped2AltText = null;
|
||||
|
||||
for (File file1 = wrapped1.currentFile, file2 = wrapped2.currentFile;
|
||||
file1 != null && file2 != null;
|
||||
file1 = file1.getParentFile(), file2 = file2.getParentFile())
|
||||
{
|
||||
while (file1 != null && !StringUtil.isEmpty(file1.getName()) && NON_UNIQUE_PATH_ENTRIES.containsKey(file1.getName())) {
|
||||
if (NON_UNIQUE_PATH_ENTRIES.get(file1.getName())) {
|
||||
if (StringUtil.isEmpty(wrapped1AltText)) {
|
||||
wrapped1AltText = file1.getName();
|
||||
}
|
||||
else {
|
||||
wrapped1AltText += NAME_SEPARATOR + file1.getName();
|
||||
}
|
||||
}
|
||||
file1 = file1.getParentFile();
|
||||
}
|
||||
while (file2 != null && !StringUtil.isEmpty(file2.getName()) && NON_UNIQUE_PATH_ENTRIES.containsKey(file2.getName())) {
|
||||
if (NON_UNIQUE_PATH_ENTRIES.get(file2.getName())) {
|
||||
if (StringUtil.isEmpty(wrapped2AltText)) {
|
||||
wrapped2AltText = file2.getName();
|
||||
}
|
||||
else {
|
||||
wrapped2AltText += NAME_SEPARATOR + file2.getName();
|
||||
}
|
||||
}
|
||||
file2 = file2.getParentFile();
|
||||
}
|
||||
|
||||
if (file1 == null) {
|
||||
wrapped1.nextFile();
|
||||
}
|
||||
if (file2 == null) {
|
||||
wrapped2.nextFile();
|
||||
}
|
||||
|
||||
if (file1 != null && file2 != null && !file1.getName().equals(file2.getName())) {
|
||||
wrapped1.library.setName(file1.getName() + NAME_SEPARATOR + wrapped1.library.getName());
|
||||
wrapped2.library.setName(file2.getName() + NAME_SEPARATOR + wrapped2.library.getName());
|
||||
}
|
||||
|
||||
if (wrapped1.library.getName().equals(wrapped2.library.getName())) {
|
||||
if (wrapped1AltText != null) {
|
||||
diversifyName(wrapped1AltText, wrapped1, file1);
|
||||
return;
|
||||
}
|
||||
else if (wrapped2AltText != null) {
|
||||
diversifyName(wrapped2AltText, wrapped2, file1);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else {
|
||||
return;
|
||||
}
|
||||
|
||||
if (file1 == null || file2 == null) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("ConstantConditions")
|
||||
private static void diversifyName(@NotNull String changeText, @NotNull Wrapped wrapped, @Nullable File file) {
|
||||
String name = wrapped.library.getName();
|
||||
int i = file == null ? - 1 : name.indexOf(file.getName());
|
||||
final String newName;
|
||||
if (i >= 0) {
|
||||
newName = name.substring(0, i + file.getName().length()) + NAME_SEPARATOR + changeText + name.substring(i + file.getName().length());
|
||||
}
|
||||
else {
|
||||
newName = changeText + NAME_SEPARATOR + name;
|
||||
}
|
||||
wrapped.library.setName(newName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Wraps target library and hold auxiliary information required for the processing.
|
||||
*/
|
||||
private static class Wrapped {
|
||||
/** Holds list of files that may be used for name generation. */
|
||||
public final Set<File> files = new HashSet<File>();
|
||||
/** File that was used for the current name generation. */
|
||||
public File currentFile;
|
||||
/** Target library. */
|
||||
public GradleLibrary library;
|
||||
|
||||
Wrapped(@NotNull GradleLibrary library) {
|
||||
this.library = library;
|
||||
for (LibraryPathType pathType : LibraryPathType.values()) {
|
||||
String path = library.getPath(pathType);
|
||||
if (path != null) {
|
||||
files.add(new File(path));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean prepare() {
|
||||
if (currentFile != null) {
|
||||
return true;
|
||||
}
|
||||
return nextFile();
|
||||
}
|
||||
|
||||
public boolean nextFile() {
|
||||
if (files.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
Iterator<File> iterator = files.iterator();
|
||||
currentFile = iterator.next();
|
||||
iterator.remove();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
+71
@@ -0,0 +1,71 @@
|
||||
package org.jetbrains.plugins.gradle.remote.impl;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.plugins.gradle.importing.model.GradleLibrary;
|
||||
import org.jetbrains.plugins.gradle.importing.model.LibraryPathType;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.IdentityHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
/**
|
||||
* @author Denis Zhdanov
|
||||
* @since 10/19/11 5:25 PM
|
||||
*/
|
||||
public class GradleLibraryNamesMixerTest {
|
||||
|
||||
private GradleLibraryNamesMixer myMixer;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
myMixer = new GradleLibraryNamesMixer();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void sourceVsTest() {
|
||||
doTest(
|
||||
t("resources", "my-module-resources", "dir1/dir2/my-module/src/main/resources"),
|
||||
t("resources", "my-module-test-resources", "dir1/dir2/my-module/src/test/resources"),
|
||||
t("resources", "my-another-module-resources", "dir1/dir2/my-another-module/src/main/resources"),
|
||||
t("resources", "my-another-module-test-resources", "dir1/dir2/my-another-module/src/test/resources")
|
||||
);
|
||||
}
|
||||
|
||||
private void doTest(TestDataEntry... entries) {
|
||||
Map<GradleLibrary, String> expected = new IdentityHashMap<GradleLibrary, String>();
|
||||
List<GradleLibrary> libraries = new ArrayList<GradleLibrary>();
|
||||
for (TestDataEntry entry : entries) {
|
||||
GradleLibrary library = new GradleLibrary(entry.initialName);
|
||||
library.addPath(LibraryPathType.BINARY, entry.path);
|
||||
libraries.add(library);
|
||||
expected.put(library, entry.expectedName);
|
||||
}
|
||||
|
||||
myMixer.mixNames(libraries);
|
||||
for (GradleLibrary library : libraries) {
|
||||
assertEquals(expected.get(library), library.getName());
|
||||
}
|
||||
}
|
||||
|
||||
private static class TestDataEntry {
|
||||
|
||||
public String initialName;
|
||||
public String expectedName;
|
||||
public String path;
|
||||
|
||||
TestDataEntry(@NotNull String initialName, @NotNull String expectedName, @NotNull String path) {
|
||||
this.initialName = initialName;
|
||||
this.expectedName = expectedName;
|
||||
this.path = path;
|
||||
}
|
||||
}
|
||||
|
||||
public static TestDataEntry t(@NotNull String initialName, @NotNull String expectedName, @NotNull String path) {
|
||||
return new TestDataEntry(initialName, expectedName, path);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user