diff --git a/plugins/gradle/resources/i18n/GradleBundle.properties b/plugins/gradle/resources/i18n/GradleBundle.properties index e85e37d53385..2f5a36196e9f 100644 --- a/plugins/gradle/resources/i18n/GradleBundle.properties +++ b/plugins/gradle/resources/i18n/GradleBundle.properties @@ -55,6 +55,7 @@ gradle.sync.change.type.conflict=Settings conflict gradle.sync.change.type.unchanged=Unchanged setting gradle.sync.change.type.confirmed=Confirmed settings diff gradle.sync.change.entity.type.module=module +gradle.sync.change.entity.type.module.dependency=module dependency gradle.sync.change.entity.type.library.dependency=library dependency gradle.sync.change.library.path=library ''{0}'' binary path gradle.sync.change.project.name.text=project name diff --git a/plugins/gradle/src/META-INF/plugin.xml b/plugins/gradle/src/META-INF/plugin.xml index 71c23dd96f02..50b6a4bbf64c 100644 --- a/plugins/gradle/src/META-INF/plugin.xml +++ b/plugins/gradle/src/META-INF/plugin.xml @@ -38,6 +38,7 @@ + diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/diff/GradleAbstractDependencyStructureChangesCalculator.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/diff/GradleAbstractDependencyStructureChangesCalculator.java new file mode 100644 index 000000000000..5c6977b2ae36 --- /dev/null +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/diff/GradleAbstractDependencyStructureChangesCalculator.java @@ -0,0 +1,25 @@ +package org.jetbrains.plugins.gradle.diff; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.plugins.gradle.model.gradle.GradleEntity; + +/** + * Manages common dependency properties like 'scope', 'exported'. + *

+ * Thread-safe. + * + * @author Denis Zhdanov + * @since 2/20/12 11:17 AM + */ +public abstract class GradleAbstractDependencyStructureChangesCalculator + implements GradleStructureChangesCalculator +{ + @Override + public void calculate(@NotNull G gradleEntity, @NotNull I intellijEntity, @NotNull GradleChangesCalculationContext context) + { + // TODO den process common dependency properties here. + doCalculate(gradleEntity, intellijEntity, context); + } + + protected abstract void doCalculate(@NotNull G gradleEntity, @NotNull I intellijEntity, @NotNull GradleChangesCalculationContext context); +} diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/diff/GradleChangesCalculationContext.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/diff/GradleChangesCalculationContext.java new file mode 100644 index 000000000000..7511561cb088 --- /dev/null +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/diff/GradleChangesCalculationContext.java @@ -0,0 +1,53 @@ +package org.jetbrains.plugins.gradle.diff; + +import org.jetbrains.annotations.NotNull; + +import java.util.HashSet; +import java.util.Set; + +/** + * 'Parameter object' to use during project structure changes calculations. + *

+ * Thread-safe. + */ +public class GradleChangesCalculationContext { + + @NotNull private final Set myKnownChanges = new HashSet(); + @NotNull private final Set myCurrentChanges = new HashSet(); + + @NotNull private final PlatformFacade myPlatformFacade; + + /** + * @param knownChanges changes between the gradle and intellij project structure that has been known up until now + * @param platformFacade platform facade to use during the calculations + */ + public GradleChangesCalculationContext(@NotNull Set knownChanges, + @NotNull PlatformFacade platformFacade) + { + myKnownChanges.addAll(knownChanges); + myPlatformFacade = platformFacade; + } + + @NotNull + public Set getKnownChanges() { + return myKnownChanges; + } + + @NotNull + public Set getCurrentChanges() { + return myCurrentChanges; + } + + public void register(@NotNull GradleProjectStructureChange change) { + myCurrentChanges.add(change); + } + + public boolean hasNewChanges() { + return !myKnownChanges.equals(myCurrentChanges); + } + + @NotNull + public PlatformFacade getPlatformFacade() { + return myPlatformFacade; + } +} diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/diff/GradleDiffUtil.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/diff/GradleDiffUtil.java index 243003b92ff7..16ee64b7690f 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/diff/GradleDiffUtil.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/diff/GradleDiffUtil.java @@ -1,11 +1,17 @@ package org.jetbrains.plugins.gradle.diff; import com.intellij.openapi.module.Module; +import com.intellij.openapi.project.Project; import com.intellij.openapi.roots.LibraryOrderEntry; +import com.intellij.openapi.roots.ModuleOrderEntry; +import com.intellij.openapi.roots.OrderEntry; import org.jetbrains.annotations.NotNull; import org.jetbrains.plugins.gradle.model.gradle.*; +import org.jetbrains.plugins.gradle.model.intellij.IntellijEntityVisitor; +import org.jetbrains.plugins.gradle.util.GradleUtil; -import java.util.*; +import java.util.HashMap; +import java.util.Map; /** * Contains various utility methods for building changes between the gradle and intellij project structures. @@ -25,10 +31,10 @@ public class GradleDiffUtil { * Example: particular module has been added at the gradle side. We want to mark that module, its content root(s), dependencies etc * as gradle-local changes. * - * @param entity target gradle-local entity - * @param currentChanges holder for the changes built during the current call + * @param entity target gradle-local entity + * @param context changes calculation context to use */ - public static void buildLocalChanges(@NotNull GradleEntity entity, @NotNull final Set currentChanges) { + public static void buildLocalChanges(@NotNull GradleEntity entity, @NotNull final GradleChangesCalculationContext context) { entity.invite(new GradleEntityVisitor() { @Override public void visit(@NotNull GradleProject project) { @@ -37,7 +43,7 @@ public class GradleDiffUtil { @Override public void visit(@NotNull GradleModule module) { - currentChanges.add(new GradleModulePresenceChange(module, null)); + context.register(new GradleModulePresenceChange(module, null)); for (GradleDependency dependency : module.getDependencies()) { dependency.invite(this); } @@ -55,59 +61,56 @@ public class GradleDiffUtil { @Override public void visit(@NotNull GradleModuleDependency dependency) { - // TODO den implement + context.register(new GradleModuleDependencyPresenceChange(dependency, null)); } @Override public void visit(@NotNull GradleLibraryDependency dependency) { - currentChanges.add(new GradleLibraryDependencyPresenceChange(dependency, null)); + context.register(new GradleLibraryDependencyPresenceChange(dependency, null)); } }); } - /** - * Analogues to {@link #buildLocalChanges} but targets intellij entity. - * - * @param module target intellij-local module that doesn't present at the gradle side - * @param currentChanges holder for the changes built during the current call - */ - public static void buildLocalChanges(@NotNull Module module, - @NotNull Set currentChanges) - { - currentChanges.add(new GradleModulePresenceChange(null, module)); - // TODO den process module sub-entities here (content roots and dependencies). - } - - /** - * Analogues to {@link #buildLocalChanges} but targets intellij entity. - * - * @param libraryDependency target intellij-local library dependency that doesn't present at the gradle side - * @param currentChanges holder for the changes built during the current call - */ - public static void buildLocalChanges(@NotNull LibraryOrderEntry libraryDependency, - @NotNull Set currentChanges) - { - final String libraryName = libraryDependency.getLibraryName(); - if (libraryName != null) { - currentChanges.add(new GradleLibraryDependencyPresenceChange(null, libraryDependency)); - } - } - /** * Performs argument type-based dispatch and delegates to one of strongly typed 'buildLocalChanges()' methods. * - * @param entity target intellij-local entity that doesn't present at the gradle side - * @param currentChanges holder for the changes built during the current call + * @param entity target intellij-local entity that doesn't present at the gradle side + * @param context changes calculation context to use */ - public static void buildLocalChanges(@NotNull Object entity, @NotNull Set currentChanges) { + public static void buildLocalChanges(@NotNull Object entity, @NotNull final GradleChangesCalculationContext context) { if (entity instanceof GradleEntity) { - buildLocalChanges((GradleEntity)entity, currentChanges); + buildLocalChanges((GradleEntity)entity, context); } - else if (entity instanceof Module) { - buildLocalChanges((Module)entity, currentChanges); - } - else if (entity instanceof LibraryOrderEntry) { - buildLocalChanges((LibraryOrderEntry)entity, currentChanges); + else { + GradleUtil.dispatch(entity, new IntellijEntityVisitor() { + @Override + public void visit(@NotNull Project project) { + } + + @Override + public void visit(@NotNull Module module) { + context.register(new GradleModulePresenceChange(null, module)); + for (OrderEntry entry : context.getPlatformFacade().getOrderEntries(module)) { + GradleUtil.dispatch(entry, this); + } + } + + @Override + public void visit(@NotNull LibraryOrderEntry libraryDependency) { + final String libraryName = libraryDependency.getLibraryName(); + if (libraryName != null) { + context.register(new GradleLibraryDependencyPresenceChange(null, libraryDependency)); + } + } + + @Override + public void visit(@NotNull ModuleOrderEntry moduleDependency) { + final Module module = moduleDependency.getModule(); + if (module != null) { + context.register(new GradleModuleDependencyPresenceChange(null, moduleDependency)); + } + } + }); } } @@ -120,8 +123,7 @@ public class GradleDiffUtil { * @param calculator comparison strategy that works with the single entities (not collection of entities) * @param gradleEntities entities available at the gradle side * @param intellijEntities entities available at the intellij side - * @param knownChanges collection that contains known changes about the entities - * @param currentChanges holder for the changes discovered during the current call + * @param context changes calculation context * @param target intellij entity type * @param target gradle entity type */ @@ -129,8 +131,7 @@ public class GradleDiffUtil { @NotNull GradleStructureChangesCalculator calculator, @NotNull Iterable gradleEntities, @NotNull Iterable intellijEntities, - @NotNull Set knownChanges, - @NotNull Set currentChanges) + @NotNull GradleChangesCalculationContext context) { Map intellijEntitiesByKeys = new HashMap(); for (I entity : intellijEntities) { @@ -138,17 +139,17 @@ public class GradleDiffUtil { assert previous == null; } for (G gradleEntity: gradleEntities) { - I intellijEntity = intellijEntitiesByKeys.remove(calculator.getGradleKey(gradleEntity, knownChanges)); + I intellijEntity = intellijEntitiesByKeys.remove(calculator.getGradleKey(gradleEntity, context)); if (intellijEntity == null) { - buildLocalChanges(gradleEntity, currentChanges); + buildLocalChanges(gradleEntity, context); } else { - calculator.calculate(gradleEntity, intellijEntity, knownChanges, currentChanges); + calculator.calculate(gradleEntity, intellijEntity, context); } } for (I entity : intellijEntitiesByKeys.values()) { - buildLocalChanges(entity, currentChanges); + buildLocalChanges(entity, context); } } } diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/diff/GradleLibraryDependencyStructureChangesCalculator.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/diff/GradleLibraryDependencyStructureChangesCalculator.java index 68d2fe30c243..68e360327790 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/diff/GradleLibraryDependencyStructureChangesCalculator.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/diff/GradleLibraryDependencyStructureChangesCalculator.java @@ -5,14 +5,12 @@ import com.intellij.openapi.roots.libraries.Library; import org.jetbrains.annotations.NotNull; import org.jetbrains.plugins.gradle.model.gradle.GradleLibraryDependency; -import java.util.Set; - /** * @author Denis Zhdanov * @since 1/24/12 1:37 PM */ public class GradleLibraryDependencyStructureChangesCalculator - implements GradleStructureChangesCalculator + extends GradleAbstractDependencyStructureChangesCalculator { private final GradleLibraryStructureChangesCalculator myLibraryCalculator; @@ -22,28 +20,30 @@ public class GradleLibraryDependencyStructureChangesCalculator } @Override - public void calculate(@NotNull GradleLibraryDependency gradleEntity, - @NotNull LibraryOrderEntry intellijEntity, - @NotNull Set knownChanges, - @NotNull Set currentChanges) + public void doCalculate(@NotNull GradleLibraryDependency gradleEntity, + @NotNull LibraryOrderEntry intellijEntity, + @NotNull GradleChangesCalculationContext context) { final Library library = intellijEntity.getLibrary(); if (library == null) { return; } - myLibraryCalculator.calculate(gradleEntity.getTarget(), library, knownChanges, currentChanges); + myLibraryCalculator.calculate(gradleEntity.getTarget(), library, context); } @NotNull @Override public Object getIntellijKey(@NotNull LibraryOrderEntry entity) { - final String result = entity.getLibraryName(); - return result == null ? "" : result; + final Library library = entity.getLibrary(); + if (library == null) { + return ""; + } + return myLibraryCalculator.getIntellijKey(library); } @NotNull @Override - public Object getGradleKey(@NotNull GradleLibraryDependency entity, @NotNull Set knownChanges) { - return myLibraryCalculator.getGradleKey(entity.getTarget(), knownChanges); + public Object getGradleKey(@NotNull GradleLibraryDependency entity, @NotNull GradleChangesCalculationContext context) { + return myLibraryCalculator.getGradleKey(entity.getTarget(), context); } } diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/diff/GradleLibraryStructureChangesCalculator.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/diff/GradleLibraryStructureChangesCalculator.java index ec95f20ffd1f..b1cf497ff872 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/diff/GradleLibraryStructureChangesCalculator.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/diff/GradleLibraryStructureChangesCalculator.java @@ -25,8 +25,7 @@ public class GradleLibraryStructureChangesCalculator implements GradleStructureC @Override public void calculate(@NotNull GradleLibrary gradleEntity, @NotNull Library intellijEntity, - @NotNull Set knownChanges, - @NotNull Set currentChanges) + @NotNull GradleChangesCalculationContext context) { final Set gradleBinaryPaths = new HashSet(gradleEntity.getPaths(LibraryPathType.BINARY)); final Set intellijBinaryPaths = new HashSet(); @@ -38,7 +37,7 @@ public class GradleLibraryStructureChangesCalculator implements GradleStructureC } if (!gradleBinaryPaths.equals(intellijBinaryPaths)) { - currentChanges.add(new GradleMismatchedLibraryPathChange(intellijEntity, gradleBinaryPaths, intellijBinaryPaths)); + context.register(new GradleMismatchedLibraryPathChange(intellijEntity, gradleBinaryPaths, intellijBinaryPaths)); } } @@ -50,7 +49,7 @@ public class GradleLibraryStructureChangesCalculator implements GradleStructureC @NotNull @Override - public Object getGradleKey(@NotNull GradleLibrary entity, @NotNull Set knownChanges) { + public Object getGradleKey(@NotNull GradleLibrary entity, @NotNull GradleChangesCalculationContext context) { // TODO den consider the known changes return entity.getName(); } diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/diff/GradleModuleDependencyPresenceChange.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/diff/GradleModuleDependencyPresenceChange.java new file mode 100644 index 000000000000..54a352245e51 --- /dev/null +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/diff/GradleModuleDependencyPresenceChange.java @@ -0,0 +1,43 @@ +package org.jetbrains.plugins.gradle.diff; + +import com.intellij.openapi.roots.ModuleOrderEntry; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.plugins.gradle.model.gradle.GradleModuleDependency; +import org.jetbrains.plugins.gradle.model.id.GradleEntityIdMapper; +import org.jetbrains.plugins.gradle.model.id.GradleModuleDependencyId; +import org.jetbrains.plugins.gradle.util.GradleBundle; + +/** + * @author Denis Zhdanov + * @since 2/17/12 3:14 PM + */ +public class GradleModuleDependencyPresenceChange extends GradleEntityPresenceChange { + + public GradleModuleDependencyPresenceChange(@Nullable GradleModuleDependency gradle, + @Nullable ModuleOrderEntry intellij) + { + super(GradleBundle.message("gradle.sync.change.entity.type.module.dependency"), of(gradle), of(intellij)); + } + + @Override + public void invite(@NotNull GradleProjectStructureChangeVisitor visitor) { + visitor.visit(this); + } + + @Nullable + private static GradleModuleDependencyId of(@Nullable GradleModuleDependency dependency) { + if (dependency == null) { + return null; + } + return GradleEntityIdMapper.mapEntityToId(dependency); + } + + @Nullable + private static GradleModuleDependencyId of(@Nullable ModuleOrderEntry dependency) { + if (dependency == null) { + return null; + } + return GradleEntityIdMapper.mapEntityToId(dependency); + } +} diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/diff/GradleModuleDependencyStructureChangesCalculator.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/diff/GradleModuleDependencyStructureChangesCalculator.java new file mode 100644 index 000000000000..9374b83dab87 --- /dev/null +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/diff/GradleModuleDependencyStructureChangesCalculator.java @@ -0,0 +1,39 @@ +package org.jetbrains.plugins.gradle.diff; + +import com.intellij.openapi.roots.ModuleOrderEntry; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.plugins.gradle.model.gradle.GradleModuleDependency; + +/** + * @author Denis Zhdanov + * @since 2/20/12 11:10 AM + */ +public class GradleModuleDependencyStructureChangesCalculator + extends GradleAbstractDependencyStructureChangesCalculator +{ + + @Override + public void doCalculate(@NotNull GradleModuleDependency gradleEntity, + @NotNull ModuleOrderEntry intellijEntity, + @NotNull GradleChangesCalculationContext context) + { + // Assuming that the modules referenced by the given dependencies are compared independently. + } + + @NotNull + @Override + public Object getIntellijKey(@NotNull ModuleOrderEntry entity) { + final String intellijModuleName = entity.getModuleName(); + if (intellijModuleName == null) { + return ""; + } + return intellijModuleName; + } + + @NotNull + @Override + public Object getGradleKey(@NotNull GradleModuleDependency entity, @NotNull GradleChangesCalculationContext context) { + // TODO den consider known changes here. + return entity.getTarget().getName(); + } +} diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/diff/GradleModuleStructureChangesCalculator.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/diff/GradleModuleStructureChangesCalculator.java index 5638b9df1541..1fe1c70a5f79 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/diff/GradleModuleStructureChangesCalculator.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/diff/GradleModuleStructureChangesCalculator.java @@ -16,13 +16,15 @@ package org.jetbrains.plugins.gradle.diff; import com.intellij.openapi.module.Module; -import com.intellij.openapi.roots.*; +import com.intellij.openapi.roots.LibraryOrderEntry; +import com.intellij.openapi.roots.ModuleOrderEntry; +import com.intellij.openapi.roots.OrderEntry; +import com.intellij.openapi.roots.RootPolicy; import org.jetbrains.annotations.NotNull; import org.jetbrains.plugins.gradle.model.gradle.*; import java.util.ArrayList; import java.util.List; -import java.util.Set; /** * Encapsulates functionality of calculating changes between Gradle and IntelliJ IDEA module hierarchies. @@ -34,25 +36,24 @@ import java.util.Set; */ public class GradleModuleStructureChangesCalculator implements GradleStructureChangesCalculator { - private final GradleLibraryDependencyStructureChangesCalculator myLibraryDependencyCalculator; - private final PlatformFacade myStructureHelper; + @NotNull private final GradleLibraryDependencyStructureChangesCalculator myLibraryDependencyCalculator; + @NotNull private final GradleModuleDependencyStructureChangesCalculator myModuleDependencyCalculator; public GradleModuleStructureChangesCalculator(@NotNull GradleLibraryDependencyStructureChangesCalculator libraryDependencyCalculator, - @NotNull PlatformFacade structureHelper) + @NotNull GradleModuleDependencyStructureChangesCalculator moduleDependencyCalculator) { myLibraryDependencyCalculator = libraryDependencyCalculator; - myStructureHelper = structureHelper; + myModuleDependencyCalculator = moduleDependencyCalculator; } @Override public void calculate(@NotNull GradleModule gradleEntity, @NotNull Module intellijEntity, - @NotNull Set knownChanges, - @NotNull Set currentChanges) + @NotNull GradleChangesCalculationContext context) { //TODO den process module-local settings //TODO den process content roots - checkDependencies(gradleEntity, intellijEntity, knownChanges, currentChanges); + checkDependencies(gradleEntity, intellijEntity, context); } @NotNull @@ -63,15 +64,14 @@ public class GradleModuleStructureChangesCalculator implements GradleStructureCh @NotNull @Override - public Object getGradleKey(@NotNull GradleModule entity, @NotNull Set knownChanges) { + public Object getGradleKey(@NotNull GradleModule entity, @NotNull GradleChangesCalculationContext context) { // TODO den consider the known changes return entity.getName(); } private void checkDependencies(@NotNull GradleModule gradleModule, @NotNull Module intellijModule, - @NotNull Set knownChanges, - @NotNull Set currentChanges) + @NotNull GradleChangesCalculationContext context) { // Prepare intellij part. final List intellijModuleDependencies = new ArrayList(); @@ -89,7 +89,7 @@ public class GradleModuleStructureChangesCalculator implements GradleStructureCh return libraryOrderEntry; } }; - for (OrderEntry orderEntry : myStructureHelper.getOrderEntries(intellijModule)) { + for (OrderEntry orderEntry : context.getPlatformFacade().getOrderEntries(intellijModule)) { orderEntry.accept(policy, null); } @@ -112,8 +112,7 @@ public class GradleModuleStructureChangesCalculator implements GradleStructureCh } // Calculate changes. - // TODO den process module dependencies here as well. - GradleDiffUtil.calculate(myLibraryDependencyCalculator, gradleLibraryDependencies, intellijLibraryDependencies, - knownChanges, currentChanges); + GradleDiffUtil.calculate(myLibraryDependencyCalculator, gradleLibraryDependencies, intellijLibraryDependencies, context); + GradleDiffUtil.calculate(myModuleDependencyCalculator, gradleModuleDependencies, intellijModuleDependencies, context); } } diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/diff/GradleProjectStructureChangeVisitor.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/diff/GradleProjectStructureChangeVisitor.java index 0a41c198a88b..5b8fc2e6f680 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/diff/GradleProjectStructureChangeVisitor.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/diff/GradleProjectStructureChangeVisitor.java @@ -28,5 +28,6 @@ public interface GradleProjectStructureChangeVisitor { void visit(@NotNull GradleLanguageLevelChange change); void visit(@NotNull GradleModulePresenceChange change); void visit(@NotNull GradleLibraryDependencyPresenceChange change); + void visit(@NotNull GradleModuleDependencyPresenceChange change); void visit(@NotNull GradleMismatchedLibraryPathChange change); } diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/diff/GradleProjectStructureChangeVisitorAdapter.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/diff/GradleProjectStructureChangeVisitorAdapter.java deleted file mode 100644 index 6e963b8ea895..000000000000 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/diff/GradleProjectStructureChangeVisitorAdapter.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright 2000-2011 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.diff; - -import org.jetbrains.annotations.NotNull; - -/** - * @author Denis Zhdanov - * @since 11/16/11 8:49 PM - */ -public class GradleProjectStructureChangeVisitorAdapter implements GradleProjectStructureChangeVisitor { - - @Override - public void visit(@NotNull GradleProjectRenameChange change) { - } - - @Override - public void visit(@NotNull GradleLanguageLevelChange change) { - } - - @Override - public void visit(@NotNull GradleModulePresenceChange change) { - } - - @Override - public void visit(@NotNull GradleLibraryDependencyPresenceChange change) { - } - - @Override - public void visit(@NotNull GradleMismatchedLibraryPathChange change) { - } -} diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/diff/GradleProjectStructureChangesCalculator.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/diff/GradleProjectStructureChangesCalculator.java index 7b64e2613f13..1c512480105e 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/diff/GradleProjectStructureChangesCalculator.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/diff/GradleProjectStructureChangesCalculator.java @@ -21,25 +21,24 @@ import java.util.Set; public class GradleProjectStructureChangesCalculator implements GradleStructureChangesCalculator { private final GradleModuleStructureChangesCalculator myModuleChangesCalculator; - private final PlatformFacade myStructureHelper; + private final PlatformFacade myPlatformFacade; public GradleProjectStructureChangesCalculator(@NotNull GradleModuleStructureChangesCalculator moduleCalculator, - @NotNull PlatformFacade structureHelper) { + @NotNull PlatformFacade platformFacade) { myModuleChangesCalculator = moduleCalculator; - myStructureHelper = structureHelper; + myPlatformFacade = platformFacade; } @Override public void calculate(@NotNull GradleProject gradleEntity, @NotNull Project intellijEntity, - @NotNull Set knownChanges, - @NotNull Set currentChanges) + @NotNull GradleChangesCalculationContext context) { - calculateProjectChanges(gradleEntity, intellijEntity, currentChanges); + calculateProjectChanges(gradleEntity, intellijEntity, context.getCurrentChanges()); final Set gradleSubEntities = gradleEntity.getModules(); - final Collection intellijSubEntities = myStructureHelper.getModules(intellijEntity); - GradleDiffUtil.calculate(myModuleChangesCalculator, gradleSubEntities, intellijSubEntities, knownChanges, currentChanges); + final Collection intellijSubEntities = myPlatformFacade.getModules(intellijEntity); + GradleDiffUtil.calculate(myModuleChangesCalculator, gradleSubEntities, intellijSubEntities, context); } @NotNull @@ -50,7 +49,7 @@ public class GradleProjectStructureChangesCalculator implements GradleStructureC @NotNull @Override - public Object getGradleKey(@NotNull GradleProject entity, @NotNull Set knownChanges) { + public Object getGradleKey(@NotNull GradleProject entity, @NotNull GradleChangesCalculationContext context) { // TODO den consider the known changes return entity.getName(); } @@ -79,7 +78,7 @@ public class GradleProjectStructureChangesCalculator implements GradleStructureC @NotNull Set currentChanges) { LanguageLevel gradleLevel = gradleProject.getLanguageLevel(); - LanguageLevel intellijLevel = myStructureHelper.getLanguageLevel(intellijProject); + LanguageLevel intellijLevel = myPlatformFacade.getLanguageLevel(intellijProject); if (gradleLevel != intellijLevel) { currentChanges.add(new GradleLanguageLevelChange(gradleLevel, intellijLevel)); } diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/diff/GradleStructureChangesCalculator.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/diff/GradleStructureChangesCalculator.java index 53db9679b2ae..04feeaa63b4d 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/diff/GradleStructureChangesCalculator.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/diff/GradleStructureChangesCalculator.java @@ -3,8 +3,6 @@ package org.jetbrains.plugins.gradle.diff; import org.jetbrains.annotations.NotNull; import org.jetbrains.plugins.gradle.model.gradle.GradleEntity; -import java.util.Set; - /** * Defines common interface to the strategy that calculates difference between the corresponding gradle and intellij entities * (e.g. between the gradle and intellij module). @@ -20,18 +18,12 @@ public interface GradleStructureChangesCalculator { /** * Calculates changes between the given entities. - * + * * @param gradleEntity target gradle entity * @param intellijEntity target intellij entity - * @param knownChanges changes between the gradle and intellij project structure that has been known up until now - * @param currentChanges holder for the changes between the given entities discovered by the current call. Note that - * it must contain the change objects that have been known (contained at the 'knownChanges') - * but are still in place + * @param context target diff calculation context */ - void calculate(@NotNull G gradleEntity, - @NotNull I intellijEntity, - @NotNull Set knownChanges, - @NotNull Set currentChanges); + void calculate(@NotNull G gradleEntity, @NotNull I intellijEntity, @NotNull GradleChangesCalculationContext context); /** * There are three possible situations when we compare a set of gradle entities with a set of intellij entities: @@ -43,16 +35,16 @@ public interface GradleStructureChangesCalculator { * * *

- * The general idea is to map evey item at the given sets of gradle and intellij entities to particular key (both gradle and + * The general idea is to map every item at the given sets of gradle and intellij entities to particular key (both gradle and * intellij keys are expected to belong to the same class) and then compare them. Matched keys shows that corresponding - * entities should be {@link #calculate(GradleEntity, Object, Set, Set)} compared to each other}; non-matched indicate that corresponding - * entities are gradle- or intellij-local. + * entities should be {@link #calculate(GradleEntity, Object, GradleChangesCalculationContext) compared to each other}; + * non-matched indicate that corresponding entities are gradle- or intellij-local. *

* This method allows to match intellij entity to the target key. * * @param entity intellij entity to match * @return key for the given entity - * @see #getGradleKey(GradleEntity, Set) + * @see #getGradleKey(GradleEntity, GradleChangesCalculationContext) */ @NotNull Object getIntellijKey(@NotNull I entity); @@ -68,10 +60,10 @@ public interface GradleStructureChangesCalculator { * So, we take into consideration the known changes only during {@code gradle-entity -> key} processing. * * @param entity target gradle entity that should be mapped to a key - * @param knownChanges known changes between the gradle and intellij structures + * @param context changes calculation context * @return key for the given entity * @see #getIntellijKey(Object) */ @NotNull - Object getGradleKey(@NotNull G entity, @NotNull Set knownChanges); + Object getGradleKey(@NotNull G entity, @NotNull GradleChangesCalculationContext context); } diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/model/GradleEntityType.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/model/GradleEntityType.java index 4f43cc086056..59550283de6e 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/model/GradleEntityType.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/model/GradleEntityType.java @@ -11,7 +11,7 @@ import javax.swing.*; */ public enum GradleEntityType { PROJECT(GradleIcons.PROJECT_ICON), MODULE(GradleIcons.MODULE_ICON), MODULE_DEPENDENCY(GradleIcons.MODULE_ICON), - LIBRARY_DEPENDENCY(GradleIcons.LIB_ICON), CONTENT_ROOT(GradleIcons.CONTENT_ROOT_ICON), SYNTHETIC(null); + LIBRARY(GradleIcons.LIB_ICON), LIBRARY_DEPENDENCY(GradleIcons.LIB_ICON), CONTENT_ROOT(GradleIcons.CONTENT_ROOT_ICON), SYNTHETIC(null); @Nullable private final Icon myIcon; diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/model/gradle/GradleModule.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/model/gradle/GradleModule.java index dcfeff87a3af..9a0622dd7083 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/model/gradle/GradleModule.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/model/gradle/GradleModule.java @@ -89,6 +89,10 @@ public class GradleModule extends AbstractNamedGradleEntity implements Named { myDependencies.add(dependency); } + public void clearDependencies() { + myDependencies.clear(); + } + @Override public void invite(@NotNull GradleEntityVisitor visitor) { visitor.visit(this); diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/model/id/GradleAbstractDependencyId.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/model/id/GradleAbstractDependencyId.java new file mode 100644 index 000000000000..413b9017e6d5 --- /dev/null +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/model/id/GradleAbstractDependencyId.java @@ -0,0 +1,55 @@ +package org.jetbrains.plugins.gradle.model.id; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.plugins.gradle.model.GradleEntityOwner; +import org.jetbrains.plugins.gradle.model.GradleEntityType; + +/** + * @author Denis Zhdanov + * @since 2/20/12 12:01 PM + */ +public abstract class GradleAbstractDependencyId extends GradleAbstractEntityId { + + @NotNull private final String myOwnerModuleName; + @NotNull private final String myDependencyName; + + public GradleAbstractDependencyId(@NotNull GradleEntityType type, + @NotNull GradleEntityOwner owner, + @NotNull String ownerModuleName, + @NotNull String dependencyName) + { + super(type, owner); + myOwnerModuleName = ownerModuleName; + myDependencyName = dependencyName; + } + + @NotNull + public String getOwnerModuleName() { + return myOwnerModuleName; + } + + @NotNull + public String getDependencyName() { + return myDependencyName; + } + + @NotNull + public GradleModuleId getOwnerModuleId() { + return new GradleModuleId(getOwner(), myOwnerModuleName); + } + + @Override + public int hashCode() { + int result = 31 * super.hashCode() + myOwnerModuleName.hashCode(); + return 31 * result + myDependencyName.hashCode(); + } + + @Override + public boolean equals(Object o) { + if (!super.equals(o)) { + return false; + } + GradleAbstractDependencyId that = (GradleAbstractDependencyId)o; + return myOwnerModuleName.equals(that.myOwnerModuleName) && myDependencyName.equals(that.myDependencyName); + } +} diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/model/id/GradleEntityIdMapper.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/model/id/GradleEntityIdMapper.java index 4d5f08219d8f..7e5c93141ff4 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/model/id/GradleEntityIdMapper.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/model/id/GradleEntityIdMapper.java @@ -59,7 +59,7 @@ public class GradleEntityIdMapper { @Override public void visit(@NotNull GradleModuleDependency dependency) { - result.set(new GradleLibraryDependencyId(GradleEntityOwner.GRADLE, dependency.getOwnerModule().getName(), dependency.getName())); + result.set(new GradleModuleDependencyId(GradleEntityOwner.GRADLE, dependency.getOwnerModule().getName(), dependency.getName())); } @Override @@ -74,7 +74,7 @@ public class GradleEntityIdMapper { @Override public void visit(@NotNull GradleLibrary library) { - // TODO den implement + result.set(new GradleLibraryId(GradleEntityOwner.GRADLE, library.getName())); } }); } diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/model/id/GradleLibraryDependencyId.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/model/id/GradleLibraryDependencyId.java index b0584a9dc072..6ad1b6187bdc 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/model/id/GradleLibraryDependencyId.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/model/id/GradleLibraryDependencyId.java @@ -8,60 +8,26 @@ import org.jetbrains.plugins.gradle.model.GradleEntityType; * @author Denis Zhdanov * @since 2/14/12 1:59 PM */ -public class GradleLibraryDependencyId extends GradleAbstractEntityId { +public class GradleLibraryDependencyId extends GradleAbstractDependencyId { - @NotNull private final String myModuleName; - @NotNull private final String myLibraryName; - public GradleLibraryDependencyId(@NotNull GradleEntityOwner owner, @NotNull String moduleName, @NotNull String libraryName) { - super(GradleEntityType.LIBRARY_DEPENDENCY, owner); - myModuleName = moduleName; - myLibraryName = libraryName; + super(GradleEntityType.LIBRARY_DEPENDENCY, owner, moduleName, libraryName); } - @NotNull - public String getModuleName() { - return myModuleName; - } - - @NotNull - public String getLibraryName() { - return myLibraryName; - } - - @NotNull - public GradleModuleId getModuleId() { - return new GradleModuleId(getOwner(), myModuleName); - } - @Override public Object mapToEntity(@NotNull GradleEntityMappingContext context) { switch (getOwner()) { - case GRADLE: return context.getProjectStructureHelper().findGradleLibraryDependency(myModuleName, myLibraryName); - case INTELLIJ: return context.getProjectStructureHelper().findIntellijLibraryDependency(myModuleName, myLibraryName); + case GRADLE: return context.getProjectStructureHelper().findGradleLibraryDependency(getOwnerModuleName(), getDependencyName()); + case INTELLIJ: return context.getProjectStructureHelper().findIntellijLibraryDependency(getOwnerModuleName(), getDependencyName()); } throw new IllegalStateException(String.format( - "Can't map id to the target library dependency. Owner: %s, module: '%s', library: '%s'", getOwner(), myModuleName, myLibraryName + "Can't map id to the target library dependency. Owner: %s, module: '%s', library: '%s'", + getOwner(), getOwnerModuleName(), getDependencyName() )); } - @Override - public int hashCode() { - int result = 31 * super.hashCode() + myModuleName.hashCode(); - return 31 * result + myLibraryName.hashCode(); - } - - @Override - public boolean equals(Object o) { - if (!super.equals(o)) { - return false; - } - GradleLibraryDependencyId that = (GradleLibraryDependencyId)o; - return myModuleName.equals(that.myModuleName) && myLibraryName.equals(that.myLibraryName); - } - @Override public String toString() { - return String.format("library dependency:owner module='%s'|library='%s'", myModuleName, myLibraryName); + return String.format("library dependency:owner module='%s'|library='%s'", getOwnerModuleName(), getDependencyName()); } } diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/model/id/GradleLibraryId.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/model/id/GradleLibraryId.java new file mode 100644 index 000000000000..803262104548 --- /dev/null +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/model/id/GradleLibraryId.java @@ -0,0 +1,49 @@ +package org.jetbrains.plugins.gradle.model.id; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.plugins.gradle.model.GradleEntityOwner; +import org.jetbrains.plugins.gradle.model.GradleEntityType; + +/** + * @author Denis Zhdanov + * @since 2/20/12 7:12 PM + */ +public class GradleLibraryId extends GradleAbstractEntityId { + + @NotNull private final String myLibraryName; + + public GradleLibraryId(@NotNull GradleEntityOwner owner, @NotNull String libraryName) { + super(GradleEntityType.LIBRARY, owner); + myLibraryName = libraryName; + } + + @Override + public Object mapToEntity(@NotNull GradleEntityMappingContext context) { + switch (getOwner()) { + case GRADLE: return context.getProjectStructureHelper().findGradleLibrary(myLibraryName); + case INTELLIJ: return context.getProjectStructureHelper().findIntellijLibrary(myLibraryName); + } + throw new IllegalStateException(String.format( + "Can't map library id to the target library. Id owner: %s, name: '%s'", getOwner(), myLibraryName + )); + } + + @Override + public int hashCode() { + return 31 * super.hashCode() + myLibraryName.hashCode(); + } + + @Override + public boolean equals(Object o) { + if (!super.equals(o)) { + return false; + } + GradleLibraryId that = (GradleLibraryId)o; + return myLibraryName.equals(that.myLibraryName); + } + + @Override + public String toString() { + return "library '" + myLibraryName + "'"; + } +} diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/model/id/GradleModuleDependencyId.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/model/id/GradleModuleDependencyId.java index 285626fdb950..342962b324a5 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/model/id/GradleModuleDependencyId.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/model/id/GradleModuleDependencyId.java @@ -8,46 +8,26 @@ import org.jetbrains.plugins.gradle.model.GradleEntityType; * @author Denis Zhdanov * @since 2/14/12 2:06 PM */ -public class GradleModuleDependencyId extends GradleAbstractEntityId { +public class GradleModuleDependencyId extends GradleAbstractDependencyId { - @NotNull private final String myOwnerModuleName; - @NotNull private final String myDependencyModuleName; - public GradleModuleDependencyId(@NotNull GradleEntityOwner owner, @NotNull String ownerModuleName, @NotNull String dependencyModuleName) { - super(GradleEntityType.MODULE, owner); - myOwnerModuleName = ownerModuleName; - myDependencyModuleName = dependencyModuleName; + super(GradleEntityType.MODULE_DEPENDENCY, owner, ownerModuleName, dependencyModuleName); } @Override public Object mapToEntity(@NotNull GradleEntityMappingContext context) { switch (getOwner()) { - case GRADLE: return context.getProjectStructureHelper().findGradleModuleDependency(myOwnerModuleName, myDependencyModuleName); - case INTELLIJ: return context.getProjectStructureHelper().findIntellijModuleDependency(myOwnerModuleName, myDependencyModuleName); + case GRADLE: return context.getProjectStructureHelper().findGradleModuleDependency(getOwnerModuleName(), getDependencyName()); + case INTELLIJ: return context.getProjectStructureHelper().findIntellijModuleDependency(getOwnerModuleName(), getDependencyName()); } throw new IllegalStateException(String.format( "Can't map id to the target module dependency. Owner: %s, owner module: '%s', dependency module: '%s'", - getOwner(), myOwnerModuleName, myDependencyModuleName + getOwner(), getOwnerModuleName(), getDependencyName() )); } - @Override - public int hashCode() { - int result = 31 * super.hashCode() + myOwnerModuleName.hashCode(); - return 31 * result + myDependencyModuleName.hashCode(); - } - - @Override - public boolean equals(Object o) { - if (!super.equals(o)) { - return false; - } - GradleModuleDependencyId that = (GradleModuleDependencyId)o; - return myOwnerModuleName.equals(that.myOwnerModuleName) && myDependencyModuleName.equals(that.myDependencyModuleName); - } - @Override public String toString() { - return String.format("module dependency:owner module='%s'|dependency module='%s'", myOwnerModuleName, myDependencyModuleName); + return String.format("module dependency:owner module='%s'|dependency module='%s'", getOwnerModuleName(), getDependencyName()); } } diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/model/id/GradleModuleId.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/model/id/GradleModuleId.java index e447f2189540..275887045ed8 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/model/id/GradleModuleId.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/model/id/GradleModuleId.java @@ -46,4 +46,9 @@ public class GradleModuleId extends GradleAbstractEntityId { GradleModuleId that = (GradleModuleId)o; return myModuleName.equals(that.myModuleName); } + + @Override + public String toString() { + return "module '" + myModuleName + "'"; + } } diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/sync/GradleProjectStructureChangesModel.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/sync/GradleProjectStructureChangesModel.java index f91b30f579dd..a05831228288 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/sync/GradleProjectStructureChangesModel.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/sync/GradleProjectStructureChangesModel.java @@ -4,8 +4,10 @@ import com.intellij.openapi.components.AbstractProjectComponent; import com.intellij.openapi.project.Project; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.jetbrains.plugins.gradle.diff.GradleChangesCalculationContext; import org.jetbrains.plugins.gradle.diff.GradleProjectStructureChange; import org.jetbrains.plugins.gradle.diff.GradleStructureChangesCalculator; +import org.jetbrains.plugins.gradle.diff.PlatformFacade; import org.jetbrains.plugins.gradle.model.gradle.GradleProject; import java.util.HashSet; @@ -28,14 +30,17 @@ public class GradleProjectStructureChangesModel extends AbstractProjectComponent = new AtomicReference>(new HashSet()); private final AtomicReference myGradleProject = new AtomicReference(); - - private final GradleStructureChangesCalculator myChangesCalculator; + + @NotNull private final GradleStructureChangesCalculator myChangesCalculator; + @NotNull private final PlatformFacade myPlatformFacade; public GradleProjectStructureChangesModel(@NotNull Project project, - @NotNull GradleStructureChangesCalculator changesCalculator) + @NotNull GradleStructureChangesCalculator changesCalculator, + @NotNull PlatformFacade platformFacade) { super(project); myChangesCalculator = changesCalculator; + myPlatformFacade = platformFacade; } /** @@ -58,15 +63,14 @@ public class GradleProjectStructureChangesModel extends AbstractProjectComponent */ public void update(@NotNull GradleProject gradleProject) { myGradleProject.set(gradleProject); - Set knownChanges = new HashSet(myChanges.get()); - Set currentChanges = new HashSet(); - myChangesCalculator.calculate(gradleProject, myProject, knownChanges, currentChanges); - if (currentChanges.equals(knownChanges)) { + GradleChangesCalculationContext context = new GradleChangesCalculationContext(myChanges.get(), myPlatformFacade); + myChangesCalculator.calculate(gradleProject, myProject, context); + if (!context.hasNewChanges()) { return; } - myChanges.set(currentChanges); + myChanges.set(context.getCurrentChanges()); for (GradleProjectStructureChangeListener listener : myListeners) { - listener.onChanges(knownChanges, currentChanges); + listener.onChanges(context.getKnownChanges(), context.getCurrentChanges()); } } diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/sync/GradleProjectStructureHelper.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/sync/GradleProjectStructureHelper.java index 268fe0d2d1be..63f41e11b0b2 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/sync/GradleProjectStructureHelper.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/sync/GradleProjectStructureHelper.java @@ -15,6 +15,7 @@ import org.jetbrains.annotations.Nullable; import org.jetbrains.plugins.gradle.diff.PlatformFacade; import org.jetbrains.plugins.gradle.model.gradle.*; import org.jetbrains.plugins.gradle.model.id.GradleLibraryDependencyId; +import org.jetbrains.plugins.gradle.model.id.GradleModuleDependencyId; /** * Thread-safe. @@ -49,23 +50,7 @@ public class GradleProjectStructureHelper extends AbstractProjectComponent { * false otherwise */ public boolean isIntellijLibraryDependencyExist(@NotNull final GradleLibraryDependencyId id) { - final Module module = findIntellijModule(id.getModuleName()); - if (module == null) { - return false; - } - - RootPolicy visitor = new RootPolicy() { - @Override - public Boolean visitLibraryOrderEntry(LibraryOrderEntry libraryOrderEntry, Boolean value) { - return id.getLibraryName().equals(libraryOrderEntry.getLibraryName()); - } - }; - for (OrderEntry entry : myFacade.getOrderEntries(module)) { - if (entry.accept(visitor, false)) { - return true; - } - } - return false; + return findIntellijLibraryDependency(id.getOwnerModuleName(), id.getDependencyName()) != null; } /** @@ -76,7 +61,15 @@ public class GradleProjectStructureHelper extends AbstractProjectComponent { * false otherwise */ public boolean isGradleLibraryDependencyExist(@NotNull final GradleLibraryDependencyId id) { - return findGradleLibraryDependency(id.getModuleName(), id.getLibraryName()) != null; + return findGradleLibraryDependency(id.getOwnerModuleName(), id.getDependencyName()) != null; + } + + public boolean isIntellijModuleDependencyExist(@NotNull final GradleModuleDependencyId id) { + return findIntellijModuleDependency(id.getOwnerModuleName(), id.getDependencyName()) != null; + } + + public boolean isGradleModuleDependencyExist(@NotNull final GradleModuleDependencyId id) { + return findIntellijModuleDependency(id.getOwnerModuleName(), id.getDependencyName()) != null; } @Nullable @@ -111,10 +104,15 @@ public class GradleProjectStructureHelper extends AbstractProjectComponent { @Nullable public Library findIntellijLibrary(@NotNull final GradleLibrary library) { + return findIntellijLibrary(library.getName()); + } + + @Nullable + public Library findIntellijLibrary(@NotNull String libraryName) { final LibraryTable libraryTable = myFacade.getProjectLibraryTable(myProject); for (Library intellijLibrary : libraryTable.getLibraries()) { // TODO den consider 'merged libraries' at the registered project structure changes here. - if (library.getName().equals(intellijLibrary.getName())) { + if (libraryName.equals(intellijLibrary.getName())) { return intellijLibrary; } } @@ -145,6 +143,20 @@ public class GradleProjectStructureHelper extends AbstractProjectComponent { } return null; } + + @Nullable + public GradleLibrary findGradleLibrary(@NotNull final String libraryName) { + final GradleProject project = myModel.getGradleProject(); + if (project == null) { + return null; + } + for (GradleLibrary library : project.getLibraries()) { + if (libraryName.equals(library.getName())) { + return library; + } + } + return null; + } @Nullable public GradleLibraryDependency findGradleLibraryDependency(@NotNull final String moduleName, @NotNull final String libraryName) { diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/sync/GradleProjectStructureTreeModel.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/sync/GradleProjectStructureTreeModel.java index e99f44b6b11c..848cd3317863 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/sync/GradleProjectStructureTreeModel.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/sync/GradleProjectStructureTreeModel.java @@ -92,7 +92,7 @@ public class GradleProjectStructureTreeModel extends DefaultTreeModel { return value; } GradleLibraryDependencyId id = GradleEntityIdMapper.mapEntityToId(libraryOrderEntry); - dependencies.add(buildNode(id, id.getLibraryName())); + dependencies.add(buildNode(id, id.getDependencyName())); return value; } }; @@ -137,6 +137,7 @@ public class GradleProjectStructureTreeModel extends DefaultTreeModel { GradleProjectStructureNode moduleNode = getModuleNode(id); GradleProjectStructureNode result = new GradleProjectStructureNode(GradleConstants.DEPENDENCIES_NODE_DESCRIPTOR); + result.addListener(myNodeListener); moduleNode.add(result); myModuleDependencies.put(id.getModuleName(), result); @@ -196,7 +197,7 @@ public class GradleProjectStructureTreeModel extends DefaultTreeModel { for (GradleProjectStructureNode holder : myModuleDependencies.values()) { for (GradleProjectStructureNode dependencyNode : holder.getChildren(GradleLibraryDependencyId.class)) { final GradleLibraryDependencyId id = dependencyNode.getDescriptor().getElement(); - if (change.getLibraryName().equals(id.getLibraryName())) { + if (change.getLibraryName().equals(id.getDependencyName())) { dependencyNode.addConflictChange(change); break; } @@ -205,25 +206,31 @@ public class GradleProjectStructureTreeModel extends DefaultTreeModel { } private void processNewLibraryDependencyPresenceChange(@NotNull GradleLibraryDependencyPresenceChange change) { - GradleLibraryDependencyId id = change.getGradleEntity(); + processNewDependencyPresenceChange(change); + } + + private void processNewModuleDependencyPresenceChange(@NotNull GradleModuleDependencyPresenceChange change) { + processNewDependencyPresenceChange(change); + } + + private void processNewDependencyPresenceChange(@NotNull GradleEntityPresenceChange change) { + I id = change.getGradleEntity(); TextAttributesKey attributes = GradleTextAttributes.GRADLE_LOCAL_CHANGE; if (id == null) { id = change.getIntellijEntity(); attributes = GradleTextAttributes.INTELLIJ_LOCAL_CHANGE; } assert id != null; - final GradleProjectStructureNode dependenciesNode = getDependenciesNode(id.getModuleId()); - for (GradleProjectStructureNode node : dependenciesNode.getChildren(GradleLibraryDependencyId.class)) { - GradleProjectStructureNodeDescriptor d = node.getDescriptor(); - if (id.equals(d.getElement())) { - d.setAttributes(attributes); - nodeStructureChanged(node); + final GradleProjectStructureNode dependenciesNode = getDependenciesNode(id.getOwnerModuleId()); + for (GradleProjectStructureNode node : dependenciesNode.getChildren(id.getClass())) { + if (id.equals(node.getDescriptor().getElement())) { + node.setAttributes(attributes); return; } } - GradleProjectStructureNode newNode = buildNode(id, id.getLibraryName()); - newNode.setAttributes(attributes); + GradleProjectStructureNode newNode = buildNode(id, id.getDependencyName()); dependenciesNode.add(newNode); + newNode.setAttributes(attributes); } private void processNewModulePresenceChange(@NotNull GradleModulePresenceChange change) { @@ -254,7 +261,7 @@ public class GradleProjectStructureTreeModel extends DefaultTreeModel { for (GradleProjectStructureNode holder : myModuleDependencies.values()) { for (GradleProjectStructureNode node : holder.getChildren(GradleLibraryDependencyId.class)) { final GradleLibraryDependencyId id = node.getDescriptor().getElement(); - if (id.getLibraryName().equals(change.getLibraryName())) { + if (id.getDependencyName().equals(change.getLibraryName())) { node.removeConflictChange(change); break; } @@ -274,7 +281,25 @@ public class GradleProjectStructureTreeModel extends DefaultTreeModel { else { removeNode = !myProjectStructureHelper.isGradleLibraryDependencyExist(id); } - final GradleProjectStructureNode holder = myModuleDependencies.get(id.getModuleName()); + processObsoleteDependencyPresenceChange(id, removeNode); + } + + private void processObsoleteModuleDependencyPresenceChange(@NotNull GradleModuleDependencyPresenceChange change) { + GradleModuleDependencyId id = change.getGradleEntity(); + boolean removeNode; + if (id == null) { + id = change.getIntellijEntity(); + assert id != null; + removeNode = !myProjectStructureHelper.isIntellijModuleDependencyExist(id); + } + else { + removeNode = !myProjectStructureHelper.isGradleModuleDependencyExist(id); + } + processObsoleteDependencyPresenceChange(id, removeNode); + } + + private void processObsoleteDependencyPresenceChange(@NotNull GradleAbstractDependencyId id, boolean removeNode) { + final GradleProjectStructureNode holder = myModuleDependencies.get(id.getOwnerModuleName()); if (holder == null) { return; } @@ -285,8 +310,8 @@ public class GradleProjectStructureTreeModel extends DefaultTreeModel { // We should distinguish between those situations because we need to mark the node as 'synced' at one case and // completely removed at another one. - for (GradleProjectStructureNode node : holder.getChildren(GradleLibraryDependencyId.class)) { - GradleProjectStructureNodeDescriptor descriptor = node.getDescriptor(); + for (GradleProjectStructureNode node : holder.getChildren(id.getClass())) { + GradleProjectStructureNodeDescriptor descriptor = node.getDescriptor(); if (!id.equals(descriptor.getElement())) { continue; } @@ -303,12 +328,31 @@ public class GradleProjectStructureTreeModel extends DefaultTreeModel { private void processObsoleteModulePresenceChange(@NotNull GradleModulePresenceChange change) { GradleModuleId id = change.getGradleEntity(); + boolean removeNode; if (id == null) { id = change.getIntellijEntity(); + assert id != null; + removeNode = myProjectStructureHelper.findIntellijModule(id.getModuleName()) == null; } - assert id != null; + else { + removeNode = myProjectStructureHelper.findGradleModule(id.getModuleName()) == null; + } + + + // There are two possible cases why 'module presence' change is obsolete: + // 1. Corresponding module has been added at the counterparty; + // 2. The 'local module' has been removed; + // We should distinguish between those situations because we need to mark the node as 'synced' at one case and + // completely removed at another one. + final GradleProjectStructureNode moduleNode = myModules.get(id.getModuleName()); - if (moduleNode != null) { + if (moduleNode == null) { + return; + } + if (removeNode) { + moduleNode.removeFromParent(); + } + else { moduleNode.getDescriptor().setAttributes(GradleTextAttributes.GRADLE_NO_CHANGE); } } @@ -322,10 +366,13 @@ public class GradleProjectStructureTreeModel extends DefaultTreeModel { } @Override - public void onNodeRemoved(@NotNull GradleProjectStructureNode node, int index) { - myIndexHolder[0] = index; - myNodeHolder[0] = node; - nodesWereRemoved(node.getParent(), myIndexHolder, myNodeHolder); + public void onNodeRemoved(@NotNull GradleProjectStructureNode parent, + @NotNull GradleProjectStructureNode removedChild, + int removedChildIndex) + { + myIndexHolder[0] = removedChildIndex; + myNodeHolder[0] = removedChild; + nodesWereRemoved(parent, myIndexHolder, myNodeHolder); } @Override @@ -339,6 +386,8 @@ public class GradleProjectStructureTreeModel extends DefaultTreeModel { @Override public void visit(@NotNull GradleLanguageLevelChange change) { processNewLanguageLevelChange(change); } @Override public void visit(@NotNull GradleModulePresenceChange change) { processNewModulePresenceChange(change); } @Override public void visit(@NotNull GradleLibraryDependencyPresenceChange change) { processNewLibraryDependencyPresenceChange(change); } + @Override public void visit(@NotNull GradleModuleDependencyPresenceChange change) { processNewModuleDependencyPresenceChange(change); } + @Override public void visit(@NotNull GradleMismatchedLibraryPathChange change) { processNewMismatchedLibraryPathChange(change); } } @@ -349,6 +398,9 @@ public class GradleProjectStructureTreeModel extends DefaultTreeModel { @Override public void visit(@NotNull GradleLibraryDependencyPresenceChange change) { processObsoleteLibraryDependencyPresenceChange(change); } + @Override public void visit(@NotNull GradleModuleDependencyPresenceChange change) { + processObsoleteModuleDependencyPresenceChange(change); + } @Override public void visit(@NotNull GradleMismatchedLibraryPathChange change) { processObsoleteMismatchedLibraryPathChange(change); } } } diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/task/GradleResolveProjectTask.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/task/GradleResolveProjectTask.java index 2fbce6411fea..0ad2b87a27a6 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/task/GradleResolveProjectTask.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/task/GradleResolveProjectTask.java @@ -39,7 +39,7 @@ public class GradleResolveProjectTask extends AbstractGradleTask { final GradleProject project = resolver.resolveProjectInfo(getId(), myProjectPath, myResolveLibraries); myGradleProject.set(project); setState(GradleTaskState.FINISHED); - if (myIntellijProject == null) { + if (myIntellijProject == null || myIntellijProject.isDisposed()) { return; } final GradleProjectStructureChangesModel model = myIntellijProject.getComponent(GradleProjectStructureChangesModel.class); diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/ui/GradleProjectStructureNode.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/ui/GradleProjectStructureNode.java index 00d7209ec8b1..aadfc3359366 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/ui/GradleProjectStructureNode.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/ui/GradleProjectStructureNode.java @@ -70,13 +70,11 @@ public class GradleProjectStructureNode extends Defaul for (int i = 0; i < getChildCount(); i++) { GradleProjectStructureNode node = getChildAt(i); if (NODE_COMPARATOR.compare((GradleProjectStructureNode)newChild, node) <= 0) { - insert(newChild, i); - onNodeAdded((GradleProjectStructureNode)newChild, i); + insert(newChild, i); // Assuming that the node listeners are notified during the nested call. return; } } - super.add(newChild); - onNodeAdded((GradleProjectStructureNode)newChild, getChildCount() - 1); + super.add(newChild); // Assuming that the node listeners are notified during the nested call to 'insert()'. } @Override @@ -108,7 +106,7 @@ public class GradleProjectStructureNode extends Defaul */ public void correctChildPositionIfNecessary(@NotNull GradleProjectStructureNode child) { int currentPosition = -1; - int desiredPosition = getChildCount() - 1; + int desiredPosition = getChildCount(); for (int i = 0; i < getChildCount(); i++) { GradleProjectStructureNode node = getChildAt(i); if (node == child) { @@ -117,12 +115,21 @@ public class GradleProjectStructureNode extends Defaul } if (NODE_COMPARATOR.compare(child, node) <= 0) { desiredPosition = i; + if (currentPosition >= 0) { + break; + } } } if (currentPosition < 0) { // Given node is not a child of the current node. return; } + if (currentPosition < desiredPosition) { + desiredPosition--; + } + if (currentPosition == desiredPosition) { + return; + } remove(currentPosition); insert(child, desiredPosition); } @@ -237,9 +244,9 @@ public class GradleProjectStructureNode extends Defaul } } - private void onNodeRemoved(@NotNull GradleProjectStructureNode node, int index) { + private void onNodeRemoved(@NotNull GradleProjectStructureNode node, int removedChildIndex) { for (Listener listener : myListeners) { - listener.onNodeRemoved(node, index); + listener.onNodeRemoved(this, node, removedChildIndex); } } @@ -251,7 +258,9 @@ public class GradleProjectStructureNode extends Defaul public interface Listener { void onNodeAdded(@NotNull GradleProjectStructureNode node, int index); - void onNodeRemoved(@NotNull GradleProjectStructureNode node, int index); + void onNodeRemoved(@NotNull GradleProjectStructureNode parent, + @NotNull GradleProjectStructureNode removedChild, + int removedChildIndex); void onNodeChanged(@NotNull GradleProjectStructureNode node); } } diff --git a/plugins/gradle/testSources/org/jetbrains/plugins/gradle/sync/GradleProjectStructureChangesModelTest.groovy b/plugins/gradle/testSources/org/jetbrains/plugins/gradle/sync/GradleProjectStructureChangesModelTest.groovy index 3ad729659a6c..274e539f7fe8 100644 --- a/plugins/gradle/testSources/org/jetbrains/plugins/gradle/sync/GradleProjectStructureChangesModelTest.groovy +++ b/plugins/gradle/testSources/org/jetbrains/plugins/gradle/sync/GradleProjectStructureChangesModelTest.groovy @@ -40,8 +40,8 @@ public class GradleProjectStructureChangesModelTest extends AbstractGradleTest { // Check that the initial projects state is correctly parsed. checkChanges { presence { - library(gradle: gradle.modules.dependencies.flatten().findAll { it.name == "lib2" }) - library(gradle: gradle.modules.dependencies.flatten().findAll { it.name == "lib3" }) + library(gradle: gradle.libraryDependencies.values().flatten().findAll { it.name == "lib2" }) + library(gradle: gradle.libraryDependencies.values().flatten().findAll { it.name == "lib3" }) } } checkTree { project { @@ -63,7 +63,7 @@ public class GradleProjectStructureChangesModelTest extends AbstractGradleTest { checkChanges { presence { - library(gradle: gradle.modules.dependencies.flatten().findAll { it.name == "lib3" }) + library(gradle: gradle.libraryDependencies.values().flatten().findAll { it.name == "lib3" }) } } checkTree { project { @@ -144,7 +144,7 @@ public class GradleProjectStructureChangesModelTest extends AbstractGradleTest { } } } } ) checkChanges { - libraryConflict(entity: intellij.dependencies.values().flatten().find {it.library.name == 'lib2' }.library) { + libraryConflict(entity: intellij.libraryDependencies.values().flatten().find {it.library.name == 'lib2' }.library) { binaryPath(gradle: null, intellij: '3') } } checkTree { @@ -209,8 +209,8 @@ public class GradleProjectStructureChangesModelTest extends AbstractGradleTest { } } ) checkChanges { presence { - module(gradle: gradle.modules.find { it.name == 'module2'}) - libraryDependency(gradle: gradle.modules.dependencies.flatten()) + module(gradle: gradle.modules['module2']) + libraryDependency(gradle: gradle.modules['module2'].dependencies) } } checkTree { project { @@ -237,7 +237,7 @@ public class GradleProjectStructureChangesModelTest extends AbstractGradleTest { ) checkChanges { presence { - module(gradle: gradle.modules.find { it.name == 'module2' }) + module(gradle: gradle.modules['module2']) } } checkTree { project { @@ -286,8 +286,8 @@ public class GradleProjectStructureChangesModelTest extends AbstractGradleTest { checkChanges { presence { - module(gradle: gradle.modules.find { it.name == 'module2' }) - libraryDependency(gradle: gradle.dependencies[gradle.modules.find { it.name == 'module2' }].first()) + module(gradle: gradle.modules['module2']) + libraryDependency(gradle: gradle.libraryDependencies[gradle.modules['module2']].first()) } libraryConflict(entity: intellij.libraries['lib1']) { binaryPath(gradle: ['1'], intellij: ['2']) @@ -303,4 +303,181 @@ public class GradleProjectStructureChangesModelTest extends AbstractGradleTest { lib1('gradle') // This is the point of the test. We don't expect to see 'conflict' here. } } } } } + + @Test + public void "mismatched module dependency import"() { + init( + gradle: { + project { + module('module1') + module('module2') + module('module3') { + dependencies { + module('module1') + module('module2') + } } } }, + intellij: { + project { + module('module2') + module('module4') + module('module3') { + dependencies { + module('module2') + module('module4') + } } } } + ) + checkChanges { + presence { + module(gradle: gradle.modules['module1']) + module(intellij: intellij.modules['module4']) + moduleDependency(gradle: gradle.moduleDependencies[gradle.modules['module3']].find { it.target == gradle.modules['module1']}) + moduleDependency(intellij: intellij.moduleDependencies[intellij.modules['module3']].find { it.moduleName == 'module4'}) + } } + checkTree { + project { + module1('gradle') + module2() + module3() { + dependencies { + module1('gradle') + module2() + module4('intellij') + } } + module4('intellij') + } } + + Closure newProjectState = { + project { + module('module1') + module('module2') + module('module4') + module('module3') { + dependencies { + module('module1') + module('module2') + module('module4') + } } } } + setState(gradle: newProjectState, intellij: newProjectState) + checkChanges { } // No changes + checkTree { + project { + module1() + module2() + module3 { + dependencies { + module1() + module2() + module4() + } } + module4() + } } + } + + @Test + public void "mismatched module dependency removal"() { + init( + gradle: { + project { + module('module1') + module('module2') + module('module3') { + dependencies { + module('module1') + module('module2') + } } } }, + intellij: { + project { + module('module2') + module('module4') + module('module3') { + dependencies { + module('module2') + module('module4') + } } } } + ) + checkChanges { + presence { + module(gradle: gradle.modules['module1']) + module(intellij: intellij.modules['module4']) + moduleDependency(gradle: gradle.moduleDependencies[gradle.modules['module3']].find { it.target == gradle.modules['module1']}) + moduleDependency(intellij: intellij.moduleDependencies[intellij.modules['module3']].find { it.moduleName == 'module4'}) + } } + checkTree { + project { + module1('gradle') + module2() + module3() { + dependencies { + module1('gradle') + module2() + module4('intellij') + } } + module4('intellij') + } } + + Closure newProjectState = { + project { + module('module2') + module('module3') { + dependencies { + module('module2') + } } } } + setState(gradle: newProjectState, intellij: newProjectState) + checkChanges { } // No changes + checkTree { + project { + module2() + module3 { + dependencies { + module2() + } } } } + } + + @Test + public void "cycled module dependencies"() { + init( + gradle: { + project { + module('module1') { + dependencies { + module('module2') + } } + module('module2') { + dependencies { + module('module1') + } } } }, + intellij: { + project { + module('module2') { + dependencies { + module('module3') + } } + module('module3') { + dependencies { + module('module2') + } } } } + ) + checkChanges { + presence { + module(gradle: gradle.modules['module1']) + module(intellij: intellij.modules['module3']) + moduleDependency(gradle: gradle.moduleDependencies.values().flatten()) + moduleDependency(intellij: intellij.moduleDependencies.values().flatten()) + } } + checkTree { + project { + module1('gradle') { + dependencies { + module2('gradle') + } } + module2() { + dependencies { + module1('gradle') + module3('intellij') + } } + module3('intellij') { + dependencies { + module2('intellij') + } } } } + } } diff --git a/plugins/gradle/testSources/org/jetbrains/plugins/gradle/testutil/AbstractGradleTest.groovy b/plugins/gradle/testSources/org/jetbrains/plugins/gradle/testutil/AbstractGradleTest.groovy index a6aa6d127d44..07a2475e8e86 100644 --- a/plugins/gradle/testSources/org/jetbrains/plugins/gradle/testutil/AbstractGradleTest.groovy +++ b/plugins/gradle/testSources/org/jetbrains/plugins/gradle/testutil/AbstractGradleTest.groovy @@ -1,23 +1,18 @@ package org.jetbrains.plugins.gradle.testutil +import com.intellij.openapi.project.Project +import com.intellij.util.containers.ContainerUtil +import org.jetbrains.plugins.gradle.model.id.GradleEntityIdMapper +import org.jetbrains.plugins.gradle.sync.GradleProjectStructureChangeListener import org.jetbrains.plugins.gradle.sync.GradleProjectStructureChangesModel +import org.jetbrains.plugins.gradle.sync.GradleProjectStructureHelper import org.jetbrains.plugins.gradle.sync.GradleProjectStructureTreeModel import org.junit.Before -import org.picocontainer.defaults.DefaultPicoContainer -import com.intellij.openapi.project.Project -import org.jetbrains.plugins.gradle.diff.PlatformFacade -import org.jetbrains.plugins.gradle.diff.GradleStructureChangesCalculator -import org.jetbrains.plugins.gradle.diff.GradleProjectStructureChangesCalculator -import org.jetbrains.plugins.gradle.diff.GradleModuleStructureChangesCalculator -import org.jetbrains.plugins.gradle.diff.GradleLibraryDependencyStructureChangesCalculator -import org.jetbrains.plugins.gradle.diff.GradleLibraryStructureChangesCalculator -import org.jetbrains.plugins.gradle.sync.GradleProjectStructureHelper -import com.intellij.util.containers.ContainerUtil -import org.jetbrains.plugins.gradle.sync.GradleProjectStructureChangeListener - -import static org.junit.Assert.assertEquals import org.picocontainer.MutablePicoContainer -import org.jetbrains.plugins.gradle.model.id.GradleEntityIdMapper; +import org.picocontainer.defaults.DefaultPicoContainer +import org.jetbrains.plugins.gradle.diff.* + +import static org.junit.Assert.fail /** * @author Denis Zhdanov @@ -48,6 +43,7 @@ public abstract class AbstractGradleTest { container.registerComponentImplementation(GradleProjectStructureHelper) container.registerComponentImplementation(GradleStructureChangesCalculator, GradleProjectStructureChangesCalculator) container.registerComponentImplementation(GradleModuleStructureChangesCalculator) + container.registerComponentImplementation(GradleModuleDependencyStructureChangesCalculator) container.registerComponentImplementation(GradleLibraryDependencyStructureChangesCalculator) container.registerComponentImplementation(GradleLibraryStructureChangesCalculator) container.registerComponentImplementation(GradleEntityIdMapper) @@ -96,7 +92,22 @@ public abstract class AbstractGradleTest { if (!expected) { expected = [].toSet() } - assertEquals(expected, changesModel.changes) + def actual = new HashSet(changesModel.changes) + if (expected == actual) { + return + } + actual.removeAll(expected) + expected.removeAll(changesModel.changes) + def message = "Project structure changes are mismatched." + if (expected) { + message += "\n Expected but not matched:" + expected.each { message += "\n * $it"} + } + if (actual) { + message += "\n Unexpected:" + actual.each { message += "\n * $it"} + } + fail(message) } protected def checkTree(c) { diff --git a/plugins/gradle/testSources/org/jetbrains/plugins/gradle/testutil/AbstractProjectBuilder.groovy b/plugins/gradle/testSources/org/jetbrains/plugins/gradle/testutil/AbstractProjectBuilder.groovy index 4b031f380a76..4b6ad6712fb7 100644 --- a/plugins/gradle/testSources/org/jetbrains/plugins/gradle/testutil/AbstractProjectBuilder.groovy +++ b/plugins/gradle/testSources/org/jetbrains/plugins/gradle/testutil/AbstractProjectBuilder.groovy @@ -1,6 +1,7 @@ package org.jetbrains.plugins.gradle.testutil import com.intellij.pom.java.LanguageLevel +import com.intellij.openapi.util.text.StringUtil /** * @author Denis Zhdanov @@ -12,16 +13,28 @@ public abstract class AbstractProjectBuilder extends BuilderSupport { private static int COUNTER def project - def modules = [] + + /** [module name; module] */ + def modules = [:] + /** Holds (library name; library) pairs for the active configuration. */ def libraries = [:] + + /** [module; dependency list] */ + def libraryDependencies = [:].withDefault {[]} + + /** [module; dependency list] */ + def moduleDependencies = [:].withDefault {[]} + /** * Holds (library name; library) pairs for the whole test. I.e. there is a possible case that we define particular configuration * initially and the adjust it. We need to use the same library instance then in order to pass hashCode()/equals() checks then. * This map works as a test-wide storage. */ def librariesCache = [:] - def dependencies = [:].withDefault {[]} + + /** [module name; module] */ + def modulesCache = [:] @Override protected void setParent(Object parent, Object child) { @@ -43,37 +56,54 @@ public abstract class AbstractProjectBuilder extends BuilderSupport { } @Override - protected Object createNode(Object name, Map attributes) { + protected Object createNode(name, Map attributes) { switch (name) { case "dependencies": return current // Assuming that 'current' is a module object case "project": - reset() + clear() return project = createProject(attributes.name?: same, attributes.langLevel?: LanguageLevel.JDK_1_6) - case "module": def module = createModule(attributes.name?: same); modules << module; return module + case "module": case "library": + def n = StringUtil.capitalize(name) if (current == project) { - // Library. - return getLibrary(attributes) - } - else { - // Library dependency. - def module = current - def dep = createLibraryDependency(module, getLibrary(attributes)) - dependencies[module] << dep - return dep + // Not a dependency. + return "get$n"(attributes) } + def ownerModule = current + def dep = "create${n}Dependency"(ownerModule, "get$n"(attributes)) + "get${n}Dependencies"()[ownerModule] << dep + return dep } } protected abstract def createProject(String name, LanguageLevel languageLevel) protected abstract def createModule(String name) + protected abstract def registerModule(module) protected abstract def createLibrary(String name, Map paths) protected abstract def applyLibraryPaths(library, Map paths) protected abstract def createLibraryDependency(module, library) + protected abstract def createModuleDependency(ownerModule, targetModule) + protected abstract def reset(); protected String getUnique() { "./${COUNTER++}" } protected String getSame() { SAME_TOKEN } + private def getModule(Map attributes) { + def name = attributes.name?: same + def result = modules[name] + if (result) return result + result = modulesCache[name] + if (result) { + registerModule(result) + } + else { + result = createModule(name) + modulesCache[name] = result + } + modules[name] = result + result + } + private def getLibrary(Map attributes) { def name = attributes.name?: same def result = libraries[name] @@ -89,8 +119,9 @@ public abstract class AbstractProjectBuilder extends BuilderSupport { libraries[name] = result result } - - private def reset() { - [modules, dependencies, libraries]*.clear() + + private def clear() { + reset() + [modules, libraryDependencies, libraries, moduleDependencies]*.clear() } } diff --git a/plugins/gradle/testSources/org/jetbrains/plugins/gradle/testutil/ChangeBuilder.groovy b/plugins/gradle/testSources/org/jetbrains/plugins/gradle/testutil/ChangeBuilder.groovy index 2f6fc75a8862..07a7219421ae 100644 --- a/plugins/gradle/testSources/org/jetbrains/plugins/gradle/testutil/ChangeBuilder.groovy +++ b/plugins/gradle/testSources/org/jetbrains/plugins/gradle/testutil/ChangeBuilder.groovy @@ -6,6 +6,7 @@ import org.jetbrains.plugins.gradle.diff.GradleMismatchedLibraryPathChange import com.intellij.openapi.roots.libraries.Library import org.jetbrains.plugins.gradle.util.GradleUtil import org.jetbrains.plugins.gradle.diff.GradleModulePresenceChange +import org.jetbrains.plugins.gradle.diff.GradleModuleDependencyPresenceChange /** * @author Denis Zhdanov @@ -34,6 +35,10 @@ public class ChangeBuilder extends BuilderSupport { changes.addAll attributes.gradle.collect { new GradleModulePresenceChange(it, null)} changes.addAll attributes.intellij.collect { new GradleModulePresenceChange(null, it)} return changes + case "moduleDependency": + changes.addAll attributes.gradle.collect { new GradleModuleDependencyPresenceChange(it, null) } + changes.addAll attributes.intellij.collect { new GradleModuleDependencyPresenceChange(null, it) } + return changes case "library": changes.addAll attributes.gradle.collect { new GradleLibraryDependencyPresenceChange(it, null)} changes.addAll attributes.intellij.collect { new GradleLibraryDependencyPresenceChange(null, it)} @@ -52,7 +57,7 @@ public class ChangeBuilder extends BuilderSupport { // Assuming that we're processing library binary path conflict here register(new GradleMismatchedLibraryPathChange( current as Library, collectPaths(attributes.gradle), collectPaths(attributes.intellij) - )) + )) } changes } diff --git a/plugins/gradle/testSources/org/jetbrains/plugins/gradle/testutil/GradleProjectBuilder.groovy b/plugins/gradle/testSources/org/jetbrains/plugins/gradle/testutil/GradleProjectBuilder.groovy index 9926a3f7f3b8..be6902acd9dc 100644 --- a/plugins/gradle/testSources/org/jetbrains/plugins/gradle/testutil/GradleProjectBuilder.groovy +++ b/plugins/gradle/testSources/org/jetbrains/plugins/gradle/testutil/GradleProjectBuilder.groovy @@ -6,6 +6,7 @@ import org.jetbrains.plugins.gradle.model.gradle.GradleLibraryDependency import org.jetbrains.plugins.gradle.model.gradle.GradleLibrary import org.jetbrains.plugins.gradle.model.gradle.LibraryPathType import com.intellij.pom.java.LanguageLevel +import org.jetbrains.plugins.gradle.model.gradle.GradleModuleDependency /** * @author Denis Zhdanov @@ -23,8 +24,19 @@ class GradleProjectBuilder extends AbstractProjectBuilder { @Override protected createModule(String name) { - def result = new GradleModule(name, unique) - project.addModule(result) + registerModule(new GradleModule(name, unique)) + } + + @Override + protected registerModule(module) { + project.addModule(module) + module + } + + @Override + protected createModuleDependency(ownerModule, targetModule) { + def result = new GradleModuleDependency(ownerModule, targetModule) + ownerModule.addDependency(result) result } @@ -49,4 +61,9 @@ class GradleProjectBuilder extends AbstractProjectBuilder { key, type -> paths[key]?.each { library.addPath(type, it) } } } + + @Override + protected reset() { + modulesCache.values().each { it.clearDependencies() } + } } diff --git a/plugins/gradle/testSources/org/jetbrains/plugins/gradle/testutil/IntellijProjectBuilder.groovy b/plugins/gradle/testSources/org/jetbrains/plugins/gradle/testutil/IntellijProjectBuilder.groovy index c2530ad59f2e..9a694bef6d3e 100644 --- a/plugins/gradle/testSources/org/jetbrains/plugins/gradle/testutil/IntellijProjectBuilder.groovy +++ b/plugins/gradle/testSources/org/jetbrains/plugins/gradle/testutil/IntellijProjectBuilder.groovy @@ -13,6 +13,7 @@ import com.intellij.openapi.vfs.VirtualFile import com.intellij.openapi.roots.OrderRootType import org.jetbrains.plugins.gradle.util.GradleUtil import com.intellij.openapi.roots.libraries.LibraryTable +import com.intellij.openapi.roots.ModuleOrderEntry /** * @author Denis Zhdanov @@ -30,8 +31,8 @@ class IntellijProjectBuilder extends AbstractProjectBuilder { def projectLibraryTable = projectLibraryTableStub as LibraryTable def platformFacade = [ - getModules: { modules }, - getOrderEntries: { dependencies[it] }, + getModules: { modules.values() }, + getOrderEntries: { libraryDependencies[it] + moduleDependencies[it] }, getProjectIcon: { IconLoader.getIcon("/nodes/ideaProject.png") }, getLocalFileSystemPath: { it.path }, getProjectLibraryTable: { projectLibraryTable } @@ -42,7 +43,7 @@ class IntellijProjectBuilder extends AbstractProjectBuilder { @Override protected createProject(String name, LanguageLevel languageLevel) { projectStub.getName = { name } - platformFacade.getLanguageLevel = { languageLevel } + platformFacade.getLanguageLevel = { languageLevel } as Closure project } @@ -51,6 +52,20 @@ class IntellijProjectBuilder extends AbstractProjectBuilder { [ getName: { name } ] as Module } + @Override + protected registerModule(Object module) { } + + @Override + protected createModuleDependency(ownerModule, targetModule) { + def stub = [:] + def result = stub as ModuleOrderEntry + stub.accept = { policy, defaultValue -> policy.visitModuleOrderEntry(result, defaultValue) } + stub.getModule = { targetModule } + stub.getOwnerModule = { ownerModule } + stub.getModuleName = { targetModule.name } + result + } + @Override protected createLibrary(String name, Map paths) { libraryPaths[name] = paths @@ -81,4 +96,7 @@ class IntellijProjectBuilder extends AbstractProjectBuilder { protected applyLibraryPaths(library, Map paths) { libraryPaths[library.name] = paths } + + @Override + protected reset() { } }