From 2359dd30e4319ca953dce4d1860ddeaa2af37229 Mon Sep 17 00:00:00 2001 From: "Denis.Zhdanov" Date: Wed, 14 Mar 2012 12:30:15 +0400 Subject: [PATCH] IDEA-81764 Gradle home is not accepted as Groovy home Groovy sdk from the gradle distribution is automatically configured for the project imported from gradle --- .../resources/i18n/GradleBundle.properties | 3 + plugins/gradle/src/META-INF/plugin.xml | 5 +- .../AbstractGradleLinkedProjectAction.java | 4 +- .../action/GradleLinkToProjectAction.java | 2 +- .../gradle/config/GradleConfigNotifier.java | 10 ++ .../config/GradleConfigNotifierAdapter.java | 18 +++ .../gradle/config/GradleConfigurable.java | 10 +- .../gradle/config/GradleGroovyEnabler.java | 140 ++++++++++++++++++ .../gradle/config/GradleScriptType.java | 6 +- .../plugins/gradle/config/GradleSettings.java | 39 ++++- .../gradle/config/GradleToolWindowPanel.java | 4 +- ...ter.java => GradleDependencyImporter.java} | 121 ++++++++------- .../importing/GradleLibraryImporter.java | 73 ++++++--- .../GradleLocalNodeImportHelper.java | 4 +- .../importing/GradleModuleImporter.java | 4 +- .../importing/GradleModulesImporter.java | 31 +++- .../importing/GradleProjectImportBuilder.java | 18 ++- .../GradleProjectStructureChangesPanel.java | 1 + .../sync/GradleProjectStructureTreeModel.java | 1 + .../gradle/util/GradleLibraryManager.java | 2 +- .../plugins/gradle/util/GradleUtil.java | 3 +- .../GradleLocalNodeImportHelperTest.groovy | 2 +- 22 files changed, 390 insertions(+), 111 deletions(-) create mode 100644 plugins/gradle/src/org/jetbrains/plugins/gradle/config/GradleConfigNotifierAdapter.java create mode 100644 plugins/gradle/src/org/jetbrains/plugins/gradle/config/GradleGroovyEnabler.java rename plugins/gradle/src/org/jetbrains/plugins/gradle/importing/{GradleModuleDependencyImporter.java => GradleDependencyImporter.java} (56%) diff --git a/plugins/gradle/resources/i18n/GradleBundle.properties b/plugins/gradle/resources/i18n/GradleBundle.properties index 2fb6c89c3dcf..ffd1725562bd 100644 --- a/plugins/gradle/resources/i18n/GradleBundle.properties +++ b/plugins/gradle/resources/i18n/GradleBundle.properties @@ -89,3 +89,6 @@ gradle.settings.color.text.sample.node.sync.name=node-with-same-setup gradle.settings.color.text.sample.node.gradle.name=node-added-at-Gradle gradle.settings.color.text.sample.node.intellij.name=node-added-at-{0} gradle.settings.color.text.sample.node.confirmed.name=node-with-different-but-confirmed-setup + +gradle.run.no.sdk.text=Gradle is not configured. Do you want to configure it? +gradle.run.no.sdk.title=Configure Gradle SDK \ No newline at end of file diff --git a/plugins/gradle/src/META-INF/plugin.xml b/plugins/gradle/src/META-INF/plugin.xml index 6798caa9da4c..02a615f25e5c 100644 --- a/plugins/gradle/src/META-INF/plugin.xml +++ b/plugins/gradle/src/META-INF/plugin.xml @@ -48,7 +48,7 @@ - + @@ -95,6 +95,9 @@ org.jetbrains.plugins.gradle.sync.GradleProjectStructureChangesDetector + + org.jetbrains.plugins.gradle.config.GradleGroovyEnabler + diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/action/AbstractGradleLinkedProjectAction.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/action/AbstractGradleLinkedProjectAction.java index 701da05b145b..7f228ee17aa5 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/action/AbstractGradleLinkedProjectAction.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/action/AbstractGradleLinkedProjectAction.java @@ -11,7 +11,7 @@ import org.jetbrains.plugins.gradle.config.GradleSettings; import java.io.File; /** - * Common super class for gradle actions that require {@link GradleSettings#LINKED_PROJECT_FILE_PATH linked project}. + * Common super class for gradle actions that require {@link GradleSettings#getLinkedProjectPath()} linked project}. *

* Not thread-safe. * @@ -56,7 +56,7 @@ public abstract class AbstractGradleLinkedProjectAction extends AnAction { return null; } - final String path = GradleSettings.getInstance(project).LINKED_PROJECT_FILE_PATH; + final String path = GradleSettings.getInstance(project).getLinkedProjectPath(); if (StringUtil.isEmpty(path) || !new File(path).isFile()) { return null; } diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/action/GradleLinkToProjectAction.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/action/GradleLinkToProjectAction.java index 113156d0ecba..6908d4f7b3dc 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/action/GradleLinkToProjectAction.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/action/GradleLinkToProjectAction.java @@ -36,6 +36,6 @@ public class GradleLinkToProjectAction extends AnAction implements DumbAware { if (file == null) { return; } - GradleSettings.setLinkedProjectPath(file.getPath(), project); + GradleSettings.applyLinkedProjectPath(file.getPath(), project); } } diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/config/GradleConfigNotifier.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/config/GradleConfigNotifier.java index 977c5bef1d23..e7bf3e57ab58 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/config/GradleConfigNotifier.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/config/GradleConfigNotifier.java @@ -15,6 +15,16 @@ public interface GradleConfigNotifier { Topic TOPIC = Topic.create("Gradle config", GradleConfigNotifier.class); + /** + * Is expected to be invoked when gradle home path is changed. + *

+ * Note: this callback is executed after the actual config change. + * + * @param oldPath old path (if any) + * @param newPath new path (if any) + */ + void onGradleHomeChange(@Nullable String oldPath, @Nullable String newPath); + /** * Is expected to be invoked when linked gradle project path (path of the 'build.gradle' file) is changed. *

diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/config/GradleConfigNotifierAdapter.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/config/GradleConfigNotifierAdapter.java new file mode 100644 index 000000000000..3849e3feaf32 --- /dev/null +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/config/GradleConfigNotifierAdapter.java @@ -0,0 +1,18 @@ +package org.jetbrains.plugins.gradle.config; + +import org.jetbrains.annotations.Nullable; + +/** + * @author Denis Zhdanov + * @since 3/13/12 3:53 PM + */ +public class GradleConfigNotifierAdapter implements GradleConfigNotifier { + + @Override + public void onGradleHomeChange(@Nullable String oldPath, @Nullable String newPath) { + } + + @Override + public void onLinkedProjectPathChange(@Nullable String oldPath, @Nullable String newPath) { + } +} diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/config/GradleConfigurable.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/config/GradleConfigurable.java index 6c9a30839205..142ae0d0a319 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/config/GradleConfigurable.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/config/GradleConfigurable.java @@ -167,7 +167,7 @@ public class GradleConfigurable implements SearchableConfigurable, Configurable. return false; } String newPath = myGradleHomeComponent.getPath(); - String oldPath = GradleSettings.getInstance(myProject).GRADLE_HOME; + String oldPath = GradleSettings.getInstance(myProject).getGradleHome(); boolean modified = newPath == null ? oldPath == null : !newPath.equals(oldPath); if (modified) { useNormalColorForPath(); @@ -179,7 +179,7 @@ public class GradleConfigurable implements SearchableConfigurable, Configurable. public void apply() { useNormalColorForPath(); String path = myGradleHomeComponent.getPath(); - GradleSettings.getInstance(myProject).GRADLE_HOME = path; + GradleSettings.applyGradleHome(path, myProject); // There is a possible case that user defines gradle home for particular open project. We want to apply that value // to the default project as well if it's still non-defined. @@ -193,7 +193,7 @@ public class GradleConfigurable implements SearchableConfigurable, Configurable. if (!StringUtil.isEmpty(path) && !Boolean.parseBoolean(PropertiesComponent.getInstance().getValue(NOT_PROPAGATE_GRADLE_HOME_TO_DEFAULT_PROJECT))) { - GradleSettings.getInstance(defaultProject).GRADLE_HOME = path; + GradleSettings.applyGradleHome(path, defaultProject); } } @@ -201,9 +201,9 @@ public class GradleConfigurable implements SearchableConfigurable, Configurable. public void reset() { useNormalColorForPath(); myPathManuallyModified = false; - String valueToUse = GradleSettings.getInstance(myProject).GRADLE_HOME; + String valueToUse = GradleSettings.getInstance(myProject).getGradleHome(); if (StringUtil.isEmpty(valueToUse)) { - valueToUse = GradleSettings.getInstance(ProjectManager.getInstance().getDefaultProject()).GRADLE_HOME; + valueToUse = GradleSettings.getInstance(ProjectManager.getInstance().getDefaultProject()).getGradleHome(); } if (!StringUtil.isEmpty(valueToUse)) { myGradleHomeSettingType = myLibraryManager.isGradleSdkHome(new File(valueToUse)) ? diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/config/GradleGroovyEnabler.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/config/GradleGroovyEnabler.java new file mode 100644 index 000000000000..237c324647d0 --- /dev/null +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/config/GradleGroovyEnabler.java @@ -0,0 +1,140 @@ +package org.jetbrains.plugins.gradle.config; + +import com.intellij.openapi.components.AbstractProjectComponent; +import com.intellij.openapi.module.Module; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.roots.OrderRootType; +import com.intellij.openapi.roots.libraries.Library; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.util.messages.MessageBusConnection; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.plugins.gradle.importing.GradleDependencyImporter; +import org.jetbrains.plugins.gradle.importing.GradleLibraryImporter; +import org.jetbrains.plugins.gradle.model.intellij.ModuleAwareContentRoot; +import org.jetbrains.plugins.gradle.util.GradleConstants; +import org.jetbrains.plugins.groovy.config.GroovyConfigUtils; +import org.jetbrains.plugins.groovy.util.GroovyUtils; +import org.jetbrains.plugins.groovy.util.LibrariesUtil; + +import java.io.File; +import java.util.*; + +/** + * Automatically configures groovy sdk for the modules that has '*.gradle' files. + *

+ * Thread-safe. + * + * @author Denis Zhdanov + * @since 3/13/12 3:12 PM + */ +public class GradleGroovyEnabler extends AbstractProjectComponent { + + @NotNull private final PlatformFacade myPlatformFacade; + @NotNull private final GradleLibraryImporter myLibraryImporter; + @NotNull private final GradleDependencyImporter myDependencyImporter; + + public GradleGroovyEnabler(@NotNull Project project, + @NotNull PlatformFacade facade, + @NotNull GradleLibraryImporter libraryImporter, + @NotNull GradleDependencyImporter importer) + { + super(project); + myPlatformFacade = facade; + myLibraryImporter = libraryImporter; + myDependencyImporter = importer; + final MessageBusConnection connection = project.getMessageBus().connect(project); + connection.subscribe(GradleConfigNotifier.TOPIC, new GradleConfigNotifierAdapter() { + @Override + public void onGradleHomeChange(@Nullable String oldPath, @Nullable String newPath) { + GradleGroovyEnabler.this.onGradleHomeChange(newPath); + } + }); + } + + public void onGradleHomeChange(@Nullable String newPath) { + if (newPath == null) { + return; + } + setupGroovySdkIfNecessary(newPath); + } + + /** + * Configures groovy sdk for the modules that require it (have gradle scripts but no groovy sdk). + * + * @param gradleHome gradle home to use + * @return groovy sdk library if the one has been created and configured; + * null otherwise (no module requires groovy support or all target modules already have groovy sdk) + */ + @Nullable + public Library setupGroovySdkIfNecessary(@NotNull String gradleHome) { + final Collection modules = getModulesThatRequireSupport(); + if (modules.isEmpty()) { + return null; + } + final Library sdk = getGroovySdk(gradleHome); + if (sdk == null) { + return null; + } + for (Module module : modules) { + applySdk(module, sdk); + } + return sdk; + } + + /** + * @return all modules of the current project that have dedicated gradle config script but don't have groovy sdk + */ + @NotNull + private Collection getModulesThatRequireSupport() { + final List result = new ArrayList(); + for (Module module : myPlatformFacade.getModules(myProject)) { + // Skip module if it already has groovy support. + if (LibrariesUtil.hasGroovySdk(module)) { + continue; + } + + // Skip module if it doesn't have a dedicated gradle script. + boolean needGroovy = false; + for (ModuleAwareContentRoot root : myPlatformFacade.getContentRoots(module)) { + final VirtualFile file = root.getFile(); + if (!file.isDirectory()) { + continue; + } + final VirtualFile child = file.findChild(GradleConstants.DEFAULT_SCRIPT_NAME); + if (child != null) { + needGroovy = true; + break; + } + } + if (needGroovy) { + result.add(module); + } + } + return result; + } + + /** + * Checks if there is groovy sdk configured at the project-level; configures the one to the groovy bundled by the gradle and returns it. + * + * @param gradleHome target gradle home to use for groovy sdk configuration + * @return groovy sdk library if it's possible to find/configure the one; null otherwise + */ + @Nullable + private Library getGroovySdk(@NotNull String gradleHome) { + final Library[] libraries = GroovyConfigUtils.getInstance().getAllSDKLibraries(myProject); + if (libraries != null && libraries.length > 0) { + return libraries[0]; + } + final File[] groovyJars = GroovyUtils.getFilesInDirectoryByPattern(gradleHome + "/lib/", GroovyConfigUtils.GROOVY_ALL_JAR_PATTERN); + if (groovyJars == null || groovyJars.length <= 0) { + return null; + } + + return myLibraryImporter.importLibrary("groovy", Collections.singletonMap(OrderRootType.CLASSES, Arrays.asList(groovyJars)), myProject); + } + + private void applySdk(@NotNull Module module, @NotNull Library sdk) { + myDependencyImporter.importLibraryDependencies(module, Collections.singleton(sdk)); + } +} diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/config/GradleScriptType.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/config/GradleScriptType.java index d7def8e54110..2b81013aa6b5 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/config/GradleScriptType.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/config/GradleScriptType.java @@ -39,6 +39,7 @@ import com.intellij.psi.search.NonClasspathDirectoryScope; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.plugins.gradle.ui.GradleIcons; +import org.jetbrains.plugins.gradle.util.GradleBundle; import org.jetbrains.plugins.gradle.util.GradleConstants; import org.jetbrains.plugins.gradle.util.GradleLibraryManager; import org.jetbrains.plugins.groovy.config.GroovyConfigUtils; @@ -95,7 +96,6 @@ public class GradleScriptType extends GroovyScriptType { configuration.setScriptParameters(target); configuration.setName(configuration.getName() + "." + target); } - final CompileStepBeforeRun.MakeBeforeRunTask runTask = RunManagerEx.getInstanceEx(file.getProject()).getBeforeRunTask(configuration, CompileStepBeforeRun.ID); @@ -160,8 +160,8 @@ public class GradleScriptType extends GroovyScriptType { if (libraryManager.getGradleHome(module, project) == null) { // TODO den internationalise int result = Messages.showOkCancelDialog( - "Gradle is not configured. Do you want to configure it?", - "Configure Gradle SDK", + GradleBundle.message("gradle.run.no.sdk.text"), + GradleBundle.message("gradle.run.no.sdk.title"), GradleIcons.GRADLE_ICON ); if (result == 0) { diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/config/GradleSettings.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/config/GradleSettings.java index bb34e918c845..a970e5f1112d 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/config/GradleSettings.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/config/GradleSettings.java @@ -49,8 +49,8 @@ public class GradleSettings implements PersistentStateComponent, //private final AtomicReference> myAcceptedChanges // = new AtomicReference>(); - public String LINKED_PROJECT_FILE_PATH; - public String GRADLE_HOME; + private String myLinkedProjectPath; + private String myGradleHome; @Override public GradleSettings getState() { @@ -70,10 +70,37 @@ public class GradleSettings implements PersistentStateComponent, return ServiceManager.getService(project, GradleSettings.class); } - public static void setLinkedProjectPath(@Nullable String path, @NotNull Project project) { + @Nullable + public String getGradleHome() { + return myGradleHome; + } + + @SuppressWarnings("UnusedDeclaration") + public void setGradleHome(@Nullable String gradleHome) { // Necessary for the serialization. + myGradleHome = gradleHome; + } + + public static void applyGradleHome(@Nullable String newPath, @NotNull Project project) { final GradleSettings settings = getInstance(project); - final String oldPath = settings.LINKED_PROJECT_FILE_PATH; - settings.LINKED_PROJECT_FILE_PATH = path; + final String oldPath = settings.myGradleHome; + settings.myGradleHome = newPath; + project.getMessageBus().syncPublisher(GradleConfigNotifier.TOPIC).onGradleHomeChange(oldPath, newPath); + } + + @Nullable + public String getLinkedProjectPath() { + return myLinkedProjectPath; + } + + @SuppressWarnings("UnusedDeclaration") + public void setLinkedProjectPath(@Nullable String linkedProjectPath) { // Necessary for the serialization. + myLinkedProjectPath = linkedProjectPath; + } + + public static void applyLinkedProjectPath(@Nullable String path, @NotNull Project project) { + final GradleSettings settings = getInstance(project); + final String oldPath = settings.myLinkedProjectPath; + settings.myLinkedProjectPath = path; project.getMessageBus().syncPublisher(GradleConfigNotifier.TOPIC).onLinkedProjectPathChange(oldPath, path); } @@ -91,6 +118,6 @@ public class GradleSettings implements PersistentStateComponent, @Override public String toString() { - return "home: " + GRADLE_HOME + ", path: " + LINKED_PROJECT_FILE_PATH; + return "home: " + myGradleHome + ", path: " + myLinkedProjectPath; } } \ No newline at end of file diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/config/GradleToolWindowPanel.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/config/GradleToolWindowPanel.java index bc5247db68e6..b35f692e81f9 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/config/GradleToolWindowPanel.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/config/GradleToolWindowPanel.java @@ -55,7 +55,7 @@ public abstract class GradleToolWindowPanel extends SimpleToolWindowPanel { setContent(myContent); MessageBusConnection connection = project.getMessageBus().connect(project); - connection.subscribe(GradleConfigNotifier.TOPIC, new GradleConfigNotifier() { + connection.subscribe(GradleConfigNotifier.TOPIC, new GradleConfigNotifierAdapter() { @Override public void onLinkedProjectPathChange(@Nullable String oldPath, @Nullable String newPath) { update(); @@ -105,7 +105,7 @@ public abstract class GradleToolWindowPanel extends SimpleToolWindowPanel { */ public void update() { final GradleSettings settings = GradleSettings.getInstance(myProject); - String cardToShow = settings.LINKED_PROJECT_FILE_PATH == null ? NON_LINKED_CARD_NAME : CONTENT_CARD_NAME; + String cardToShow = settings.getLinkedProjectPath() == null ? NON_LINKED_CARD_NAME : CONTENT_CARD_NAME; myLayout.show(myContent, cardToShow); updateContent(); diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/importing/GradleModuleDependencyImporter.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/importing/GradleDependencyImporter.java similarity index 56% rename from plugins/gradle/src/org/jetbrains/plugins/gradle/importing/GradleModuleDependencyImporter.java rename to plugins/gradle/src/org/jetbrains/plugins/gradle/importing/GradleDependencyImporter.java index 8a4e99a7facd..d146f4167322 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/importing/GradleModuleDependencyImporter.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/importing/GradleDependencyImporter.java @@ -2,7 +2,10 @@ package org.jetbrains.plugins.gradle.importing; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.module.Module; -import com.intellij.openapi.roots.*; +import com.intellij.openapi.roots.DependencyScope; +import com.intellij.openapi.roots.LibraryOrderEntry; +import com.intellij.openapi.roots.ModifiableRootModel; +import com.intellij.openapi.roots.ModuleRootManager; import com.intellij.openapi.roots.libraries.Library; import com.intellij.openapi.roots.libraries.LibraryTable; import com.intellij.util.ui.UIUtil; @@ -10,9 +13,12 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.plugins.gradle.config.PlatformFacade; import org.jetbrains.plugins.gradle.model.gradle.*; import org.jetbrains.plugins.gradle.sync.GradleProjectStructureHelper; -import org.jetbrains.plugins.gradle.util.GradleLog; +import org.jetbrains.plugins.gradle.util.GradleUtil; -import java.util.*; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; /** * Thread-safe. @@ -20,11 +26,11 @@ import java.util.*; * @author Denis Zhdanov * @since 2/7/12 3:23 PM */ -public class GradleModuleDependencyImporter { +public class GradleDependencyImporter { @NotNull private final PlatformFacade myPlatformFacade; - public GradleModuleDependencyImporter(@NotNull PlatformFacade platformFacade) { + public GradleDependencyImporter(@NotNull PlatformFacade platformFacade) { myPlatformFacade = platformFacade; } @@ -91,61 +97,68 @@ public class GradleModuleDependencyImporter { } public void importLibraryDependencies(@NotNull final Iterable dependencies, @NotNull final Module module) { + final List infos = new ArrayList(); + final LibraryTable libraryTable = myPlatformFacade.getProjectLibraryTable(module.getProject()); + for (GradleLibraryDependency dependency : dependencies) { + final Library library = libraryTable.getLibraryByName(dependency.getName()); + if (library != null) { + infos.add(new LibraryDependencyInfo(library, dependency.getScope(), dependency.isExported())); + } + } + doImportLibraryDependencies(infos, module); + } + + @SuppressWarnings("MethodMayBeStatic") + public void importLibraryDependencies(@NotNull Module module, @NotNull Collection libraries) { + List infos = new ArrayList(); + for (Library library : libraries) { + infos.add(new LibraryDependencyInfo(library, DependencyScope.PROVIDED, true)); + } + doImportLibraryDependencies(infos, module); + } + + private static void doImportLibraryDependencies(@NotNull final Iterable infos, @NotNull final Module module) { UIUtil.invokeLaterIfNeeded(new Runnable() { @Override public void run() { - doImportLibraryDependencies(dependencies, module); + ApplicationManager.getApplication().runWriteAction(new Runnable() { + @Override + public void run() { + // Register library dependencies. + ModuleRootManager moduleRootManager = ModuleRootManager.getInstance(module); + final ModifiableRootModel moduleRootModel = moduleRootManager.getModifiableModel(); + final GradleProjectEntityImportListener publisher + = module.getProject().getMessageBus().syncPublisher(GradleProjectEntityImportListener.TOPIC); + try { + for (LibraryDependencyInfo info : infos) { + publisher.onImportStart(info.library); + LibraryOrderEntry orderEntry = moduleRootModel.addLibraryEntry(info.library); + orderEntry.setExported(info.exported); + orderEntry.setScope(info.scope); + } + } + finally { + moduleRootModel.commit(); + for (LibraryDependencyInfo info : infos) { + publisher.onImportEnd(info.library); + } + } + } + }); } }); } - - public void doImportLibraryDependencies(@NotNull final Iterable dependencies, @NotNull final Module module) { - // Is assumed to be called from EDT - final LibraryTable libraryTable = myPlatformFacade.getProjectLibraryTable(module.getProject()); - final Map gradle2intellij = new HashMap(); - for (final GradleLibraryDependency dependency : dependencies) { - // Try to find existing library in project libraries. - Library library = libraryTable.getLibraryByName(dependency.getName()); - if (library != null) { - gradle2intellij.put(dependency.getTarget(), library); - } - else { - GradleLog.LOG.warn(String.format( - "Detected situation when target library for the gradle-local library dependency doesn't exist. Dependency: %s", - dependency - )); - } - } - ApplicationManager.getApplication().runWriteAction(new Runnable() { - @Override - public void run() { - // Register library dependencies. - ModuleRootManager moduleRootManager = ModuleRootManager.getInstance(module); - final ModifiableRootModel moduleRootModel = moduleRootManager.getModifiableModel(); - final GradleProjectEntityImportListener publisher - = module.getProject().getMessageBus().syncPublisher(GradleProjectEntityImportListener.TOPIC); - try { - for (GradleLibraryDependency dependency : dependencies) { - final Library library = gradle2intellij.get(dependency.getTarget()); - if (library == null) { - continue; - } - publisher.onImportStart(library); - LibraryOrderEntry orderEntry = moduleRootModel.addLibraryEntry(library); - orderEntry.setExported(dependency.isExported()); - orderEntry.setScope(dependency.getScope()); - } - } - finally { - moduleRootModel.commit(); - for (GradleLibraryDependency dependency : dependencies) { - if (dependency != null) { - publisher.onImportEnd(dependency); - } - } - } - } - }); + private static class LibraryDependencyInfo { + + @NotNull public final Library library; + @NotNull public final DependencyScope scope; + public final boolean exported; + + LibraryDependencyInfo(@NotNull Library library, @NotNull DependencyScope scope, boolean exported) { + this.library = library; + this.scope = scope; + this.exported = exported; + } } } diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/importing/GradleLibraryImporter.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/importing/GradleLibraryImporter.java index 1f959c06899a..4dfb3f815b8e 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/importing/GradleLibraryImporter.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/importing/GradleLibraryImporter.java @@ -6,9 +6,12 @@ import com.intellij.openapi.roots.JavadocOrderRootType; import com.intellij.openapi.roots.OrderRootType; import com.intellij.openapi.roots.libraries.Library; import com.intellij.openapi.roots.libraries.LibraryTable; +import com.intellij.openapi.util.Ref; import com.intellij.openapi.vfs.JarFileSystem; import com.intellij.openapi.vfs.LocalFileSystem; import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.util.NotNullFunction; +import com.intellij.util.containers.ContainerUtil; import com.intellij.util.ui.UIUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.plugins.gradle.config.PlatformFacade; @@ -17,8 +20,7 @@ import org.jetbrains.plugins.gradle.model.gradle.LibraryPathType; import org.jetbrains.plugins.gradle.util.GradleLog; import java.io.File; -import java.util.EnumMap; -import java.util.Map; +import java.util.*; /** * @author Denis Zhdanov @@ -32,67 +34,104 @@ public class GradleLibraryImporter { myPlatformFacade = platformFacade; } - public void importLibrary(@NotNull final GradleLibrary library, @NotNull final Project project) { + @NotNull + public Library importLibrary(@NotNull final GradleLibrary library, @NotNull final Project project) { + Map> libraryFiles = new HashMap>(); + for (LibraryPathType pathType : LibraryPathType.values()) { + final Set paths = library.getPaths(pathType); + if (paths.isEmpty()) { + continue; + } + libraryFiles.put(Lazy.LIBRARY_ROOT_MAPPINGS.get(pathType), ContainerUtil.map(paths, new NotNullFunction() { + @NotNull + @Override + public File fun(String path) { + return new File(path); + } + })); + } + return importLibrary(library.getName(), libraryFiles, project); + } + + @NotNull + public Library importLibrary(@NotNull final String libraryName, + @NotNull final Map> libraryFiles, + @NotNull final Project project) + { + final Ref result = new Ref(); UIUtil.invokeLaterIfNeeded(new Runnable() { @Override public void run() { final GradleProjectEntityImportListener publisher = project.getMessageBus().syncPublisher(GradleProjectEntityImportListener.TOPIC); - publisher.onImportStart(library); + publisher.onImportStart(libraryName); try { - doImportLibrary(library, project); + result.set(doImportLibrary(libraryName, libraryFiles, project)); } finally { - publisher.onImportEnd(library); + publisher.onImportEnd(libraryName); } } }); + return result.get(); } - private void doImportLibrary(@NotNull final GradleLibrary gradleLibrary,@NotNull Project project) { + @NotNull + private Library doImportLibrary(@NotNull final String libraryName, + @NotNull final Map> libraryFiles, + @NotNull Project project) + { // Is assumed to be called from the EDT. final LibraryTable libraryTable = myPlatformFacade.getProjectLibraryTable(project); + final Ref result = new Ref(); ApplicationManager.getApplication().runWriteAction(new Runnable() { @Override public void run() { final LibraryTable.ModifiableModel projectLibraryModel = libraryTable.getModifiableModel(); final Library intellijLibrary; try { - intellijLibrary = projectLibraryModel.createLibrary(gradleLibrary.getName()); + intellijLibrary = projectLibraryModel.createLibrary(libraryName); + result.set(intellijLibrary); } finally { projectLibraryModel.commit(); } final Library.ModifiableModel libraryModel = intellijLibrary.getModifiableModel(); try { - registerPaths(gradleLibrary, libraryModel); + registerPaths(libraryFiles, libraryModel, libraryName); } finally { libraryModel.commit(); } } }); + return result.get(); } - private static void registerPaths(@NotNull GradleLibrary gradleLibrary, @NotNull Library.ModifiableModel model) { - for (LibraryPathType pathType : LibraryPathType.values()) { - for (String path : gradleLibrary.getPaths(pathType)) { - VirtualFile virtualFile = LocalFileSystem.getInstance().findFileByIoFile(new File(path)); + private static void registerPaths(@NotNull final Map> libraryFiles, + @NotNull Library.ModifiableModel model, + @NotNull String libraryName) + { + for (Map.Entry> entry : libraryFiles.entrySet()) { + for (File file : entry.getValue()) { + VirtualFile virtualFile = LocalFileSystem.getInstance().findFileByIoFile(file); if (virtualFile == null) { - GradleLog.LOG.warn(String.format("Can't find %s of the library '%s' at path '%s'", pathType, gradleLibrary.getName(), path)); + GradleLog.LOG.warn( + String.format("Can't find %s of the library '%s' at path '%s'", entry.getKey(), libraryName, file.getAbsolutePath()) + ); continue; } if (virtualFile.isDirectory()) { - model.addRoot(virtualFile, Lazy.LIBRARY_ROOT_MAPPINGS.get(pathType)); + model.addRoot(virtualFile, entry.getKey()); } else { VirtualFile jarRoot = JarFileSystem.getInstance().getJarRootForLocalFile(virtualFile); if (jarRoot == null) { GradleLog.LOG.warn(String.format( - "Can't parse contents of the jar file at path '%s' for the library '%s''", path, gradleLibrary.getName() + "Can't parse contents of the jar file at path '%s' for the library '%s''", file.getAbsolutePath(), libraryName )); continue; } - model.addRoot(jarRoot, Lazy.LIBRARY_ROOT_MAPPINGS.get(pathType)); + model.addRoot(jarRoot, entry.getKey()); } } } diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/importing/GradleLocalNodeImportHelper.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/importing/GradleLocalNodeImportHelper.java index b901cf96fd82..e87a378e8c7c 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/importing/GradleLocalNodeImportHelper.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/importing/GradleLocalNodeImportHelper.java @@ -52,14 +52,14 @@ public class GradleLocalNodeImportHelper { @NotNull private final GradleEntityIdMapper myIdMapper; @NotNull private final GradleModuleImporter myModuleImporter; @NotNull private final GradleLibraryImporter myLibraryImporter; - @NotNull private final GradleModuleDependencyImporter myModuleDependencyImporter; + @NotNull private final GradleDependencyImporter myModuleDependencyImporter; @NotNull private final GradleContentRootImporter myContentRootImporter; public GradleLocalNodeImportHelper(@NotNull GradleProjectStructureHelper projectStructureHelper, @NotNull GradleEntityIdMapper idMapper, @NotNull GradleModuleImporter moduleImporter, @NotNull GradleLibraryImporter libraryImporter, - @NotNull GradleModuleDependencyImporter moduleDependencyImporter, + @NotNull GradleDependencyImporter moduleDependencyImporter, @NotNull GradleContentRootImporter contentRootImporter) { myProjectStructureHelper = projectStructureHelper; diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/importing/GradleModuleImporter.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/importing/GradleModuleImporter.java index aadcd66faa85..7a95fa3ea2bc 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/importing/GradleModuleImporter.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/importing/GradleModuleImporter.java @@ -36,10 +36,10 @@ public class GradleModuleImporter { private final Alarm myAlarm = new Alarm(Alarm.ThreadToUse.SHARED_THREAD); @NotNull private final GradleContentRootImporter myContentRootImporter; - @NotNull private final GradleModuleDependencyImporter myDependencyImporter; + @NotNull private final GradleDependencyImporter myDependencyImporter; public GradleModuleImporter(@NotNull GradleContentRootImporter contentRootImporter, - @NotNull GradleModuleDependencyImporter dependencyImporter) + @NotNull GradleDependencyImporter dependencyImporter) { myContentRootImporter = contentRootImporter; myDependencyImporter = dependencyImporter; diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/importing/GradleModulesImporter.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/importing/GradleModulesImporter.java index 95e9e1d01124..41c0725e5078 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/importing/GradleModulesImporter.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/importing/GradleModulesImporter.java @@ -23,6 +23,8 @@ import com.intellij.util.containers.hash.HashMap; import com.intellij.util.ui.UIUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.jetbrains.plugins.gradle.config.GradleGroovyEnabler; +import org.jetbrains.plugins.gradle.config.GradleSettings; import org.jetbrains.plugins.gradle.model.gradle.*; import org.jetbrains.plugins.gradle.task.GradleResolveProjectTask; import org.jetbrains.plugins.gradle.util.GradleBundle; @@ -298,6 +300,7 @@ public class GradleModulesImporter { @NotNull final String gradleProjectPath) { final Ref gradleProjectRef = new Ref(); + final Ref libraryToPreserve = new Ref(); final Runnable setupExternalDependenciesTask = new Runnable() { @Override @@ -310,15 +313,15 @@ public class GradleModulesImporter { Application application = ApplicationManager.getApplication(); AccessToken writeLock = application.acquireWriteActionLock(getClass()); try { - doSetupLibraries(moduleMappings, gradleProject, intellijProject); + doSetupLibraries(moduleMappings, gradleProject, intellijProject, libraryToPreserve.get()); } finally { writeLock.finish(); - } + } } }; - Runnable resolveDependenciesTask = new Runnable() { + final Runnable resolveDependenciesTask = new Runnable() { @Override public void run() { ProgressManager.getInstance().run( @@ -335,12 +338,26 @@ public class GradleModulesImporter { } }; - UIUtil.invokeLaterIfNeeded(resolveDependenciesTask); + Runnable setupGroovyTask = new Runnable() { + @Override + public void run() { + final GradleSettings settings = GradleSettings.getInstance(intellijProject); + final String gradleHome = settings.getGradleHome(); + if (gradleHome != null) { + final GradleGroovyEnabler groovyEnabler = intellijProject.getComponent(GradleGroovyEnabler.class); + libraryToPreserve.set(groovyEnabler.setupGroovySdkIfNecessary(gradleHome)); + } + resolveDependenciesTask.run(); + } + }; + + UIUtil.invokeLaterIfNeeded(setupGroovyTask); } private static void doSetupLibraries(@NotNull Map moduleMappings, @NotNull GradleProject gradleProject, - @NotNull Project intellijProject) + @NotNull Project intellijProject, + @Nullable Library libraryToPreserve) { Application application = ApplicationManager.getApplication(); application.assertWriteAccessAllowed(); @@ -357,7 +374,9 @@ public class GradleModulesImporter { // Clean existing libraries (if any). try { for (Library library : model.getLibraries()) { - model.removeLibrary(library); + if (libraryToPreserve != library) { + model.removeLibrary(library); + } } } finally { diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/importing/GradleProjectImportBuilder.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/importing/GradleProjectImportBuilder.java index faaae1600c6a..fa12623f17ca 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/importing/GradleProjectImportBuilder.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/importing/GradleProjectImportBuilder.java @@ -80,13 +80,17 @@ public class GradleProjectImportBuilder extends ProjectImportBuilder mappings = diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/sync/GradleProjectStructureChangesPanel.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/sync/GradleProjectStructureChangesPanel.java index e647066e7d01..100f32edf451 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/sync/GradleProjectStructureChangesPanel.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/sync/GradleProjectStructureChangesPanel.java @@ -146,6 +146,7 @@ public class GradleProjectStructureChangesPanel extends GradleToolWindowPanel { @Override protected void updateContent() { + myTreeModel.rebuild(); } private void setupToolbar() { 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 2572281fecd2..fea46379ac88 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/sync/GradleProjectStructureTreeModel.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/sync/GradleProjectStructureTreeModel.java @@ -78,6 +78,7 @@ public class GradleProjectStructureTreeModel extends DefaultTreeModel { private Comparator myChangesComparator; private boolean myProcessChangesAtTheSameThread; + @SuppressWarnings("UnusedDeclaration") // Used implicitly by IoC public GradleProjectStructureTreeModel(@NotNull Project project, @NotNull GradleProjectStructureContext context) { this(project, context, true); } diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/util/GradleLibraryManager.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/util/GradleLibraryManager.java index cd1621f70b2b..b878565f40ca 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/util/GradleLibraryManager.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/util/GradleLibraryManager.java @@ -157,7 +157,7 @@ public class GradleLibraryManager { project = ProjectManager.getInstance().getDefaultProject(); } GradleSettings settings = GradleSettings.getInstance(project); - String path = settings.GRADLE_HOME; + String path = settings.getGradleHome(); if (path == null) { return null; } diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/util/GradleUtil.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/util/GradleUtil.java index 80f467e60117..d8cae7bcc2bb 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/util/GradleUtil.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/util/GradleUtil.java @@ -122,10 +122,11 @@ public class GradleUtil { */ public static void refreshProject(@NotNull Project project) { final GradleSettings settings = GradleSettings.getInstance(project); - final String linkedProjectPath = settings.LINKED_PROJECT_FILE_PATH; + final String linkedProjectPath = settings.getLinkedProjectPath(); if (StringUtil.isEmpty(linkedProjectPath)) { return; } + assert linkedProjectPath != null; Ref errorHolder = new Ref(); refreshProject(project, linkedProjectPath, errorHolder, true, false); final String error = errorHolder.get(); diff --git a/plugins/gradle/testSources/org/jetbrains/plugins/gradle/importing/GradleLocalNodeImportHelperTest.groovy b/plugins/gradle/testSources/org/jetbrains/plugins/gradle/importing/GradleLocalNodeImportHelperTest.groovy index 3bc05c2df535..2a8002c4d15a 100644 --- a/plugins/gradle/testSources/org/jetbrains/plugins/gradle/importing/GradleLocalNodeImportHelperTest.groovy +++ b/plugins/gradle/testSources/org/jetbrains/plugins/gradle/importing/GradleLocalNodeImportHelperTest.groovy @@ -23,7 +23,7 @@ public class GradleLocalNodeImportHelperTest extends AbstractGradleTest { container.registerComponentImplementation(GradleLocalNodeImportHelper) container.registerComponentImplementation(GradleModuleImporter) container.registerComponentImplementation(GradleLibraryImporter) - container.registerComponentImplementation(GradleModuleDependencyImporter) + container.registerComponentImplementation(GradleDependencyImporter) container.registerComponentImplementation(GradleContentRootImporter) }