mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
IDEA-53476 Gradle integration (Maven's level - dependencies, modules, repositories)
1. Corrected gradle entities cloning; 2. Added null-check to the class which hashCode()/equals() are called during deserialization when the state is not initialised yet; 3. Improve automatic library name generation algorithm;
This commit is contained in:
+2
-1
@@ -57,7 +57,8 @@ public abstract class AbstractGradleDependency extends AbstractGradleEntity impl
|
||||
public String toString() {
|
||||
return "scope: " + getScope() + ", exported: " + isExported();
|
||||
}
|
||||
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public GradleDependency clone() {
|
||||
try {
|
||||
|
||||
+2
-1
@@ -99,8 +99,9 @@ public class GradleContentRoot extends AbstractGradleEntity {
|
||||
return buffer.toString();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public GradleContentRoot clone() {
|
||||
public GradleContentRoot clone(@NotNull GradleEntityCloneContext context) {
|
||||
GradleContentRoot result = new GradleContentRoot(getRootPath());
|
||||
for (Map.Entry<SourceType, Collection<String>> entry : myData.entrySet()) {
|
||||
for (String path : entry.getValue()) {
|
||||
|
||||
+2
-1
@@ -16,5 +16,6 @@ public interface GradleDependency extends GradleEntity {
|
||||
@NotNull
|
||||
DependencyScope getScope();
|
||||
|
||||
GradleDependency clone();
|
||||
@NotNull
|
||||
GradleDependency clone(@NotNull GradleEntityCloneContext context);
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@ import java.io.Serializable;
|
||||
* @author Denis Zhdanov
|
||||
* @since 8/12/11 12:50 PM
|
||||
*/
|
||||
public interface GradleEntity extends Cloneable, Serializable {
|
||||
public interface GradleEntity extends Serializable {
|
||||
|
||||
/**
|
||||
* Follows contract of {@link PropertyChangeSupport#addPropertyChangeListener(PropertyChangeListener)}
|
||||
@@ -25,4 +25,7 @@ public interface GradleEntity extends Cloneable, Serializable {
|
||||
void addPropertyChangeListener(@NotNull PropertyChangeListener listener);
|
||||
|
||||
void invite(@NotNull GradleEntityVisitor visitor);
|
||||
|
||||
@NotNull
|
||||
GradleEntity clone(@NotNull GradleEntityCloneContext context);
|
||||
}
|
||||
|
||||
+44
@@ -0,0 +1,44 @@
|
||||
package org.jetbrains.plugins.gradle.importing.model;
|
||||
|
||||
import com.intellij.util.containers.hash.HashMap;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* We need to be able to perform cloning of gradle entities. However, there is a possible case that particular entity
|
||||
* encapsulates graph of other entities. For example, {@link GradleModule} has a number of
|
||||
* {@link GradleModule#getDependencies() dependencies} where those dependencies can reference other modules that, in turn, also
|
||||
* have dependencies.
|
||||
* <p/>
|
||||
* The problem is that we need to ensure that particular entity is shared within a single entities graph (e.g. there should
|
||||
* be a single shared instance of {@link GradleModule gradle module} after cloning). That's why we need some place to serve
|
||||
* as a cache during cloning. This class serves that purpose.
|
||||
*
|
||||
* @author Denis Zhdanov
|
||||
* @since 9/28/11 12:36 PM
|
||||
*/
|
||||
public class GradleEntityCloneContext {
|
||||
|
||||
private final Map<GradleLibrary, GradleLibrary> myLibraries = new HashMap<GradleLibrary, GradleLibrary>();
|
||||
private final Map<GradleModule, GradleModule> myModules = new HashMap<GradleModule, GradleModule>();
|
||||
|
||||
@Nullable
|
||||
public GradleLibrary getLibrary(@NotNull GradleLibrary library) {
|
||||
return myLibraries.get(library);
|
||||
}
|
||||
|
||||
public void store(@NotNull GradleLibrary key, @NotNull GradleLibrary value) {
|
||||
myLibraries.put(key, value);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public GradleModule getModule(@NotNull GradleModule module) {
|
||||
return myModules.get(module);
|
||||
}
|
||||
|
||||
public void store(@NotNull GradleModule key, @NotNull GradleModule value) {
|
||||
myModules.put(key, value);
|
||||
}
|
||||
}
|
||||
@@ -56,12 +56,17 @@ public class GradleLibrary extends AbstractNamedGradleEntity implements Named {
|
||||
return "library: " + getName();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
protected GradleLibrary clone() {
|
||||
GradleLibrary result = new GradleLibrary(getName());
|
||||
for (Map.Entry<LibraryPathType, String> entry : myPaths.entrySet()) {
|
||||
result.addPath(entry.getKey(), entry.getValue());
|
||||
}
|
||||
public GradleLibrary clone(@NotNull GradleEntityCloneContext context) {
|
||||
GradleLibrary result = context.getLibrary(this);
|
||||
if (result == null) {
|
||||
result = new GradleLibrary(getName());
|
||||
context.store(this, result);
|
||||
for (Map.Entry<LibraryPathType, String> entry : myPaths.entrySet()) {
|
||||
result.addPath(entry.getKey(), entry.getValue());
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
+3
-2
@@ -46,9 +46,10 @@ public class GradleLibraryDependency extends AbstractGradleDependency {
|
||||
return super.toString() + ", dependency library: " + getLibrary();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public GradleLibraryDependency clone() {
|
||||
GradleLibraryDependency result = new GradleLibraryDependency(getLibrary().clone());
|
||||
public GradleLibraryDependency clone(@NotNull GradleEntityCloneContext context) {
|
||||
GradleLibraryDependency result = new GradleLibraryDependency(getLibrary().clone(context));
|
||||
copyTo(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -97,10 +97,13 @@ public class GradleModule extends AbstractNamedGradleEntity implements Named {
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = super.hashCode();
|
||||
result = 31 * result + myModuleFilePath.hashCode();
|
||||
|
||||
// Sometimes instance fields are not initialised here during deserialization. Seems to be standard library bug. That's why we
|
||||
// do null-check here.
|
||||
result = myModuleFilePath == null ? result : (31 * result + myModuleFilePath.hashCode());
|
||||
result = 31 * result + (myInheritProjectCompileOutputPath ? 1 : 0);
|
||||
result = 31 * result + myCompileOutputPaths.hashCode();
|
||||
result = 31 * result + myContentRoots.hashCode();
|
||||
result = myCompileOutputPaths == null ? result : (31 * result + myCompileOutputPaths.hashCode());
|
||||
result = myContentRoots == null ? result : (31 * result + myContentRoots.hashCode());
|
||||
|
||||
// We intentionally don't use dependencies here in order to allow module mappings before and after external libraries
|
||||
// resolving (downloading)
|
||||
@@ -116,10 +119,13 @@ public class GradleModule extends AbstractNamedGradleEntity implements Named {
|
||||
GradleModule that = (GradleModule)o;
|
||||
|
||||
if (!super.equals(that)) return false;
|
||||
if (!myModuleFilePath.equals(that.myModuleFilePath)) return false;
|
||||
// Sometimes instance fields are not initialised here during deserialization. Seems to be standard library bug. That's why we
|
||||
// do null-check here.
|
||||
if (myModuleFilePath == null ? that.myModuleFilePath != null : !myModuleFilePath.equals(that.myModuleFilePath)) return false;
|
||||
if (myInheritProjectCompileOutputPath != that.myInheritProjectCompileOutputPath) return false;
|
||||
if (!myCompileOutputPaths.equals(that.myCompileOutputPaths)) return false;
|
||||
if (!myContentRoots.equals(that.myContentRoots)) return false;
|
||||
if (myCompileOutputPaths == null
|
||||
? that.myCompileOutputPaths != null : !myCompileOutputPaths.equals(that.myCompileOutputPaths)) return false;
|
||||
if (myContentRoots == null ? that.myContentRoots != null : !myContentRoots.equals(that.myContentRoots)) return false;
|
||||
|
||||
// We intentionally don't use dependencies here in order to allow module mappings before and after external libraries
|
||||
// resolving (downloading)
|
||||
@@ -135,18 +141,24 @@ public class GradleModule extends AbstractNamedGradleEntity implements Named {
|
||||
);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public GradleModule clone() {
|
||||
GradleModule result = new GradleModule(getName(), new File(getModuleFilePath()).getParent());
|
||||
public GradleModule clone(@NotNull GradleEntityCloneContext context) {
|
||||
GradleModule result = context.getModule(this);
|
||||
if (result != null) {
|
||||
return result;
|
||||
}
|
||||
result = new GradleModule(getName(), new File(getModuleFilePath()).getParent());
|
||||
context.store(this, result);
|
||||
result.setInheritProjectCompileOutputPath(isInheritProjectCompileOutputPath());
|
||||
for (GradleContentRoot contentRoot : getContentRoots()) {
|
||||
result.addContentRoot(contentRoot.clone());
|
||||
result.addContentRoot(contentRoot.clone(context));
|
||||
}
|
||||
for (Map.Entry<SourceType, String> entry : myCompileOutputPaths.entrySet()) {
|
||||
result.setCompileOutputPath(entry.getKey(), entry.getValue());
|
||||
}
|
||||
for (GradleDependency dependency : getDependencies()) {
|
||||
result.addDependency(dependency.clone());
|
||||
result.addDependency(dependency.clone(context));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
+4
-3
@@ -54,10 +54,11 @@ public class GradleModuleDependency extends AbstractGradleDependency {
|
||||
return super.toString() + ", dependency module: " + getModule();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public GradleModuleDependency clone() {
|
||||
GradleModuleDependency result = new GradleModuleDependency(getModule().clone());
|
||||
copyTo(result);
|
||||
public GradleModuleDependency clone(@NotNull GradleEntityCloneContext context) {
|
||||
GradleModuleDependency result = new GradleModuleDependency(getModule().clone(context));
|
||||
copyTo(result);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -194,17 +194,18 @@ public class GradleProject extends AbstractNamedGradleEntity {
|
||||
getName(), getJdkVersion(), getLanguageLevel(), getModules());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public GradleProject clone() {
|
||||
public GradleProject clone(@NotNull GradleEntityCloneContext context) {
|
||||
GradleProject result = new GradleProject(getProjectFileDirectoryPath(), getCompileOutputPath());
|
||||
result.setName(getName());
|
||||
result.setJdkVersion(getJdkVersion());
|
||||
result.setLanguageLevel(getLanguageLevel());
|
||||
for (GradleModule module : getModules()) {
|
||||
result.addModule(module.clone());
|
||||
result.addModule(module.clone(context));
|
||||
}
|
||||
for (GradleLibrary library : getLibraries()) {
|
||||
result.addLibrary(library.clone());
|
||||
result.addLibrary(library.clone(context));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
+3
-2
@@ -174,9 +174,10 @@ public class GradleAdjustImportSettingsStep extends AbstractImportFromGradleWiza
|
||||
Collections.sort(modules, Named.COMPARATOR);
|
||||
List<MutableTreeNode> moduleNodes = new ArrayList<MutableTreeNode>();
|
||||
Map<GradleModule, GradleModule> moduleMappings = new HashMap<GradleModule, GradleModule>();
|
||||
|
||||
|
||||
GradleEntityCloneContext cloneContext = new GradleEntityCloneContext();
|
||||
for (GradleModule module : modules) {
|
||||
GradleModule moduleCopy = module.clone();
|
||||
GradleModule moduleCopy = module.clone(cloneContext);
|
||||
moduleMappings.put(module, moduleCopy);
|
||||
DefaultMutableTreeNode moduleNode = buildNode(module, entity2nodes, counter++);
|
||||
moduleNodes.add(moduleNode);
|
||||
|
||||
+47
-3
@@ -13,8 +13,6 @@ import org.gradle.tooling.model.idea.*;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.plugins.gradle.importing.model.*;
|
||||
import org.jetbrains.plugins.gradle.importing.model.GradleLibraryDependency;
|
||||
import org.jetbrains.plugins.gradle.importing.model.GradleProject;
|
||||
import org.jetbrains.plugins.gradle.remote.GradleProjectResolver;
|
||||
import org.jetbrains.plugins.gradle.remote.RemoteGradleProcessSettings;
|
||||
import org.jetbrains.plugins.gradle.remote.RemoteGradleService;
|
||||
@@ -24,6 +22,7 @@ import org.jetbrains.plugins.gradle.util.GradleUtil;
|
||||
|
||||
import java.io.File;
|
||||
import java.rmi.RemoteException;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
@@ -37,7 +36,11 @@ import java.util.concurrent.atomic.AtomicReference;
|
||||
* @since 8/8/11 11:09 AM
|
||||
*/
|
||||
public class GradleProjectResolverImpl extends RemoteObject implements GradleProjectResolver, RemoteGradleService {
|
||||
|
||||
|
||||
private static final Set<String> NON_UNIQUE_PATH_ENTRIES = new HashSet<String>(Arrays.asList(
|
||||
"src", "main", "java", "test", "resources"
|
||||
));
|
||||
|
||||
private final BlockingQueue<ProjectConnection> myConnections = new LinkedBlockingQueue<ProjectConnection>();
|
||||
private final AtomicReference<RemoteGradleProcessSettings> mySettings = new AtomicReference<RemoteGradleProcessSettings>();
|
||||
|
||||
@@ -55,6 +58,7 @@ public class GradleProjectResolverImpl extends RemoteObject implements GradlePro
|
||||
// populating dependent module object.
|
||||
Map<String, Pair<GradleModule, IdeaModule>> modules = createModules(project, result);
|
||||
populateModules(modules.values(), result);
|
||||
diversifyLibraryNamesIfNecessary(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -310,6 +314,46 @@ public class GradleProjectResolverImpl extends RemoteObject implements GradlePro
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gradle API doesn't provide library names at the moment, so, we deduce them from the path. However, it's possible to have identical
|
||||
* names then.
|
||||
* <p/>
|
||||
* This method solves that by diversifying duplicate library names.
|
||||
*
|
||||
* @param project target project which library names should be diversified if necessary
|
||||
*/
|
||||
private static void diversifyLibraryNamesIfNecessary(@NotNull GradleProject project) {
|
||||
Map<String, GradleLibrary> libraries = new HashMap<String, GradleLibrary>();
|
||||
for (GradleLibrary library : project.getLibraries()) {
|
||||
GradleLibrary previous = libraries.remove(library.getName());
|
||||
if (previous == null) {
|
||||
libraries.put(library.getName(), library);
|
||||
continue;
|
||||
}
|
||||
previous.setName(generateName(previous));
|
||||
libraries.put(previous.getName(), previous);
|
||||
library.setName(generateName(library));
|
||||
libraries.put(library.getName(), library);
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static String generateName(@NotNull GradleLibrary library) {
|
||||
for (LibraryPathType pathType : LibraryPathType.values()) {
|
||||
String path = library.getPath(pathType);
|
||||
if (path == null) {
|
||||
continue;
|
||||
}
|
||||
File file = new File(path).getParentFile();
|
||||
for (; file != null; file = file.getParentFile()) {
|
||||
if (!NON_UNIQUE_PATH_ENTRIES.contains(file.getName())) {
|
||||
return file.getName() + "-" + library.getName();
|
||||
}
|
||||
}
|
||||
}
|
||||
return library.getName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows to retrieve gradle api connection to use for the given project.
|
||||
|
||||
Reference in New Issue
Block a user