diff --git a/build/scripts/layouts.gant b/build/scripts/layouts.gant
index a74b08b2f039..aa510e3be835 100644
--- a/build/scripts/layouts.gant
+++ b/build/scripts/layouts.gant
@@ -177,6 +177,12 @@ public def layoutCommunityPlugins(String home) {
fileset(dir: "$home/plugins/maven/maven2-server-impl/lib")
}
+ layoutPlugin("gradle") {
+ jar("gradle.jar") {
+ module("gradle")
+ }
+ }
+
layoutPlugin("git4idea") {
fileset(dir: "$home/plugins/git4idea/lib", excludes: "**/trilead-ssh2-src.zip")
}
diff --git a/plugins/gradle/gradle.iml b/plugins/gradle/gradle.iml
index 4ba3c58beb15..c9bf1c328807 100644
--- a/plugins/gradle/gradle.iml
+++ b/plugins/gradle/gradle.iml
@@ -17,6 +17,15 @@
+
+
+
+
+
+
+
+
+
diff --git a/plugins/gradle/lib/gradle-tooling-api.jar b/plugins/gradle/lib/gradle-tooling-api.jar
new file mode 100644
index 000000000000..2b38bc80a055
Binary files /dev/null and b/plugins/gradle/lib/gradle-tooling-api.jar differ
diff --git a/plugins/gradle/resources/i18n/GradleBundle.properties b/plugins/gradle/resources/i18n/GradleBundle.properties
index 2fc00d71000f..12d0a07c6b10 100644
--- a/plugins/gradle/resources/i18n/GradleBundle.properties
+++ b/plugins/gradle/resources/i18n/GradleBundle.properties
@@ -1,8 +1,15 @@
gradle.name=Gradle
-gradle.import.label.select.project=Gradle &project
+gradle.import.label.select.project=Gradle project:
gradle.import.title.select.project=Select project to import
gradle.import.text.home.path=Gradle home:
+gradle.import.progress.text=Building gradle project info
+
+gradle.import.title.error.resolve.generic=Resolve error
+gradle.import.text.error.resolve.generic=Can't resolve target gradle project at '{0}'
gradle.import.text.error.project.undefined=No project file is defined
gradle.import.text.error.directory.instead.file=Given path points to directory instead of gradle build file
+gradle.import.text.error.invalid.path=Can't resolve gradle project. Reason: given path ({0}) doesn't point to a file
gradle.import.text.error.cannot.parse.project=Can not parse gradle project
+
+gradle.generic.text.error.sdk.undefined=Gradle installation is unknown
\ No newline at end of file
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 13a6a3b869c6..21bdd1b3125c 100644
--- a/plugins/gradle/src/org/jetbrains/plugins/gradle/config/GradleConfigurable.java
+++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/config/GradleConfigurable.java
@@ -94,7 +94,11 @@ public class GradleConfigurable implements SearchableConfigurable {
}
String newPath = myPathComponent.getPath();
String oldPath = GradleSettings.getInstance(myProject).GRADLE_HOME;
- return newPath == null ? oldPath == null : newPath.equals(oldPath);
+ boolean modified = newPath == null ? oldPath == null : !newPath.equals(oldPath);
+ if (modified) {
+ useNormalColorForPath();
+ }
+ return modified;
}
@Override
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 d147a24af95f..cf01402eb8da 100644
--- a/plugins/gradle/src/org/jetbrains/plugins/gradle/config/GradleSettings.java
+++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/config/GradleSettings.java
@@ -30,7 +30,7 @@ import org.jetbrains.annotations.NotNull;
@Storage( file = "$PROJECT_CONFIG_DIR$/gradle.xml", scheme = StorageScheme.DIRECTORY_BASED)
}
)
-public class GradleSettings implements PersistentStateComponent {
+public class GradleSettings implements PersistentStateComponent, Cloneable {
public String GRADLE_HOME;
@@ -48,4 +48,16 @@ public class GradleSettings implements PersistentStateComponent
public static GradleSettings getInstance(@NotNull Project project) {
return ServiceManager.getService(project, GradleSettings.class);
}
+
+ @Override
+ protected GradleSettings clone() throws CloneNotSupportedException {
+ GradleSettings result = new GradleSettings();
+ result.GRADLE_HOME = GRADLE_HOME;
+ return result;
+ }
+
+ @Override
+ public String toString() {
+ return "home: " + GRADLE_HOME;
+ }
}
\ No newline at end of file
diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/importing/GradleProject.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/importing/GradleProject.java
deleted file mode 100644
index a16c3764af62..000000000000
--- a/plugins/gradle/src/org/jetbrains/plugins/gradle/importing/GradleProject.java
+++ /dev/null
@@ -1,32 +0,0 @@
-package org.jetbrains.plugins.gradle.importing;
-
-import org.jetbrains.annotations.NotNull;
-
-import java.io.File;
-
-/**
- * Application-level representation of the 'build.gradle' file.
- *
- * @author Denis Zhdanov
- * @since 8/1/11 1:30 PM
- */
-public class GradleProject {
-
- private final File myFile;
-
- /**
- * Creates new GradleProject object for the given gradle project file.
- *
- * @param projectFile target gradle project file
- */
- public GradleProject(@NotNull File projectFile) {
- myFile = projectFile;
- }
-
- /**
- * Parses underlying 'build.gradle' file and populates current object within that information.
- */
- public void build() {
- // TODO den implement
- }
-}
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 55b68a321f35..46bb92b4ec9c 100644
--- a/plugins/gradle/src/org/jetbrains/plugins/gradle/importing/GradleProjectImportBuilder.java
+++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/importing/GradleProjectImportBuilder.java
@@ -2,17 +2,25 @@ package org.jetbrains.plugins.gradle.importing;
import com.intellij.ide.util.PropertiesComponent;
import com.intellij.ide.util.projectWizard.WizardContext;
+import com.intellij.openapi.components.ServiceManager;
import com.intellij.openapi.module.ModifiableModuleModel;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.options.ConfigurationException;
+import com.intellij.openapi.progress.ProgressIndicator;
+import com.intellij.openapi.progress.ProgressManager;
+import com.intellij.openapi.progress.Task;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.ui.configuration.ModulesProvider;
import com.intellij.packaging.artifacts.ModifiableArtifactModel;
import com.intellij.projectImport.ProjectImportBuilder;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
+import org.jetbrains.plugins.gradle.remote.GradleApiFacadeManager;
+import org.jetbrains.plugins.gradle.resolve.GradleProject;
+import org.jetbrains.plugins.gradle.resolve.GradleProjectResolver;
import org.jetbrains.plugins.gradle.util.GradleBundle;
import org.jetbrains.plugins.gradle.util.GradleIcons;
+import org.jetbrains.plugins.gradle.util.GradleLog;
import javax.swing.*;
import java.io.File;
@@ -29,8 +37,7 @@ public class GradleProjectImportBuilder extends ProjectImportBuilder'build.gradle' -> {@link GradleProject} conversion.
- *
- * Thread-safe.
- *
- * @author Denis Zhdanov
- * @since 8/3/11 12:04 PM
- */
-public class GradleProjectParser {
-
- /**
- * // TODO den add doc
- *
- * @param file
- * @return
- * @throws IllegalArgumentException if given file handle doesn't point to valid gradle project
- */
- @NotNull
- public GradleProject parse(@NotNull File file) throws IllegalArgumentException{
- if (!file.isFile()) {
-
- }
- // TODO den implement
- return new GradleProject(file);
- }
-}
diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/importing/GradleSelectProjectStep.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/importing/GradleSelectProjectStep.java
index de091d774efc..364c3b056a89 100644
--- a/plugins/gradle/src/org/jetbrains/plugins/gradle/importing/GradleSelectProjectStep.java
+++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/importing/GradleSelectProjectStep.java
@@ -1,8 +1,10 @@
package org.jetbrains.plugins.gradle.importing;
-import com.intellij.ide.util.projectWizard.NamePathComponent;
import com.intellij.ide.util.projectWizard.WizardContext;
+import com.intellij.openapi.fileChooser.FileTypeDescriptor;
import com.intellij.openapi.options.ConfigurationException;
+import com.intellij.openapi.ui.TextFieldWithBrowseButton;
+import com.intellij.openapi.util.text.StringUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.plugins.gradle.util.GradleBundle;
@@ -24,23 +26,27 @@ import java.awt.*;
public class GradleSelectProjectStep extends GradleImportWizardStep {
private final JPanel myComponent = new JPanel(new GridBagLayout());
- private final NamePathComponent myRootPathComponent;
+ private final TextFieldWithBrowseButton myProjectPathComponent;
public GradleSelectProjectStep(@NotNull WizardContext context) {
super(context);
GridBagConstraints constraints = new GridBagConstraints();
+ JLabel label = new JLabel(GradleBundle.message("gradle.import.label.select.project"));
+ myComponent.add(label);
+
constraints.gridwidth = GridBagConstraints.REMAINDER;
constraints.weightx = 1;
constraints.fill = GridBagConstraints.HORIZONTAL;
- myRootPathComponent = new NamePathComponent(
- "", GradleBundle.message("gradle.import.label.select.project"), GradleBundle.message("gradle.import.title.select.project"), "",
- false,
- false
+ myProjectPathComponent = new TextFieldWithBrowseButton();
+ myProjectPathComponent.addBrowseFolderListener(
+ "",
+ GradleBundle.message("gradle.import.title.select.project"),
+ null,
+ new FileTypeDescriptor(GradleBundle.message("gradle.import.label.select.project"), "gradle")
);
- myRootPathComponent.setNameComponentVisible(false);
- myComponent.add(myRootPathComponent, constraints);
+ myComponent.add(myProjectPathComponent, constraints);
myComponent.add(Box.createVerticalGlue());
}
@@ -51,8 +57,8 @@ public class GradleSelectProjectStep extends GradleImportWizardStep {
@Override
public void updateStep() {
- if (!myRootPathComponent.isPathChangedByUser()) {
- myRootPathComponent.setPath(getBuilder().getRootDirectoryPath(getWizardContext()));
+ if (isPathChanged()) {
+ myProjectPathComponent.setText(getBuilder().getProjectPath(getWizardContext()));
}
}
@@ -73,8 +79,12 @@ public class GradleSelectProjectStep extends GradleImportWizardStep {
}
private void storeCurrentSettings() {
- if (myRootPathComponent.isPathChangedByUser()) {
- getBuilder().setCurrentProjectPath(myRootPathComponent.getPath());
+ if (isPathChanged()) {
+ getBuilder().setCurrentProjectPath(myProjectPathComponent.getText());
}
}
+
+ private boolean isPathChanged() {
+ return !StringUtil.equals(myProjectPathComponent.getText(), getBuilder().getProjectPath(getWizardContext()));
+ }
}
diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/remote/GradleApiFacade.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/remote/GradleApiFacade.java
new file mode 100644
index 000000000000..f140f35676b0
--- /dev/null
+++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/remote/GradleApiFacade.java
@@ -0,0 +1,38 @@
+package org.jetbrains.plugins.gradle.remote;
+
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.plugins.gradle.resolve.GradleProjectResolver;
+
+import java.rmi.Remote;
+import java.rmi.RemoteException;
+
+/**
+ * Serves as a facade for working with
+ * gradle tooling api.
+ *
+ * The main idea is that we don't want to use it directly from IntelliJ IDEA process (to avoid unnecessary heap/perm gen pollution,
+ * memory leaks etc). So, we use it at external process and current class works as a facade to it from IntelliJ process.
+ *
+ * @author Denis Zhdanov
+ * @since 8/8/11 10:52 AM
+ */
+public interface GradleApiFacade extends Remote {
+
+ /**
+ * Exposes 'resolve gradle project' service that works at another process.
+ *
+ * @return 'resolve gradle project' service
+ * @throws RemoteException in case of unexpected I/O exception during processing
+ * @throws IllegalStateException in case of inability to create the service
+ */
+ @NotNull
+ GradleProjectResolver getResolver() throws RemoteException, IllegalStateException;
+
+ /**
+ * Asks remote gradle process to apply given settings.
+ *
+ * @param settings settings to apply
+ * @throws RemoteException in case of unexpected I/O exception during processing
+ */
+ void applySettings(@NotNull RemoteGradleProcessSettings settings) throws RemoteException;
+}
diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/remote/GradleApiFacadeImpl.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/remote/GradleApiFacadeImpl.java
new file mode 100644
index 000000000000..27205b2d37c2
--- /dev/null
+++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/remote/GradleApiFacadeImpl.java
@@ -0,0 +1,85 @@
+package org.jetbrains.plugins.gradle.remote;
+
+import com.intellij.execution.rmi.RemoteServer;
+import com.intellij.util.containers.ConcurrentHashMap;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.plugins.gradle.resolve.GradleProjectResolver;
+import org.jetbrains.plugins.gradle.resolve.GradleProjectResolverImpl;
+
+import java.rmi.Remote;
+import java.rmi.RemoteException;
+import java.rmi.server.UnicastRemoteObject;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.atomic.AtomicReference;
+
+/**
+ * @author Denis Zhdanov
+ * @since 8/8/11 12:51 PM
+ */
+public class GradleApiFacadeImpl extends RemoteServer implements GradleApiFacade {
+
+ private final ConcurrentMap, RemoteGradleService> myRemotes = new ConcurrentHashMap, RemoteGradleService>();
+ private final AtomicReference mySettings = new AtomicReference();
+
+ public static void main(String[] args) throws Exception {
+ start(new GradleApiFacadeImpl());
+ }
+
+ @NotNull
+ @Override
+ public GradleProjectResolver getResolver() throws RemoteException, IllegalStateException {
+ try {
+ return getRemote(GradleProjectResolverImpl.class);
+ }
+ catch (Exception e) {
+ throw new IllegalStateException(String.format("Can't create '%s' service", GradleProjectResolver.class.getName()), e);
+ }
+ }
+
+ /**
+ * Generic method to retrieve exposed implementations of the target interface.
+ *
+ * Uses cached value if it's found; creates new and caches it otherwise.
+ *
+ * @param clazz target service implementation class
+ * @param service implementation class
+ * @return implementation of the target service
+ * @throws IllegalAccessException in case of incorrect assumptions about server class interface
+ * @throws InstantiationException in case of incorrect assumptions about server class interface
+ * @throws ClassNotFoundException in case of incorrect assumptions about server class interface
+ */
+ @SuppressWarnings("unchecked")
+ private T getRemote(@NotNull Class clazz)
+ throws ClassNotFoundException, IllegalAccessException, InstantiationException
+ {
+ Object cachedResult = myRemotes.get(clazz);
+ if (cachedResult != null) {
+ return (T)cachedResult;
+ }
+ T result = clazz.newInstance();
+ RemoteGradleProcessSettings settings = mySettings.get();
+ if (settings != null) {
+ result.setSettings(settings);
+ }
+ try {
+ UnicastRemoteObject.exportObject(result, 0);
+ T stored = (T)myRemotes.putIfAbsent(clazz, result);
+ return stored == null ? result : stored;
+ }
+ catch (RemoteException e) {
+ Object raceResult = myRemotes.get(clazz);
+ if (raceResult != null) {
+ // Race condition occurred
+ return (T)raceResult;
+ }
+ else {
+ throw new IllegalStateException(String.format("Can't prepare remote service for interface '%s'", clazz), e);
+ }
+ }
+ }
+
+ @Override
+ public void applySettings(@NotNull RemoteGradleProcessSettings settings) throws RemoteException {
+ mySettings.set(settings);
+ }
+}
diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/remote/GradleApiFacadeManager.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/remote/GradleApiFacadeManager.java
new file mode 100644
index 000000000000..eaca740d36c9
--- /dev/null
+++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/remote/GradleApiFacadeManager.java
@@ -0,0 +1,238 @@
+package org.jetbrains.plugins.gradle.remote;
+
+import com.intellij.execution.DefaultExecutionResult;
+import com.intellij.execution.ExecutionException;
+import com.intellij.execution.ExecutionResult;
+import com.intellij.execution.Executor;
+import com.intellij.execution.configurations.CommandLineState;
+import com.intellij.execution.configurations.GeneralCommandLine;
+import com.intellij.execution.configurations.RunProfileState;
+import com.intellij.execution.configurations.SimpleJavaParameters;
+import com.intellij.execution.process.OSProcessHandler;
+import com.intellij.execution.process.ProcessHandler;
+import com.intellij.execution.process.ProcessTerminatedListener;
+import com.intellij.execution.rmi.RemoteProcessSupport;
+import com.intellij.execution.runners.ProgramRunner;
+import com.intellij.openapi.actionSystem.AnAction;
+import com.intellij.openapi.application.PathManager;
+import com.intellij.openapi.projectRoots.JavaSdkType;
+import com.intellij.openapi.projectRoots.JdkUtil;
+import com.intellij.openapi.projectRoots.Sdk;
+import com.intellij.openapi.projectRoots.SimpleJavaSdkType;
+import com.intellij.openapi.util.Pair;
+import com.intellij.openapi.util.ShutDownTracker;
+import com.intellij.openapi.util.text.StringUtil;
+import com.intellij.pom.java.LanguageLevel;
+import com.intellij.psi.PsiBundle;
+import com.intellij.util.PathUtil;
+import com.intellij.util.SystemProperties;
+import com.intellij.util.containers.ContainerUtil;
+import gnu.trove.THashSet;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.plugins.gradle.util.GradleBundle;
+import org.jetbrains.plugins.gradle.util.GradleLibraryManager;
+import org.jetbrains.plugins.gradle.util.GradleLog;
+
+import java.io.File;
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+import java.nio.charset.Charset;
+import java.rmi.RemoteException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.concurrent.atomic.AtomicReference;
+
+/**
+ * Entry point to work with remote {@link GradleApiFacade}.
+ *
+ * Thread-safe.
+ *
+ * @author Denis Zhdanov
+ * @since 8/8/11 1:08 PM
+ */
+public class GradleApiFacadeManager {
+
+ private static final String MAIN_CLASS_NAME = GradleApiFacadeImpl.class.getName();
+ private static final int REMOTE_FAIL_RECOVERY_ATTEMPTS_NUMBER = 3;
+
+ private final AtomicReference> myFacade
+ = new AtomicReference>();
+
+ private final GradleLibraryManager myGradleLibraryManager = GradleLibraryManager.INSTANCE;
+
+ private final RemoteProcessSupport