From 7d142c1de7fca26f0921fc3db509d98bc96ea2a2 Mon Sep 17 00:00:00 2001 From: "Denis.Zhdanov" Date: Tue, 9 Aug 2011 17:55:27 +0400 Subject: [PATCH] IDEA-53476 Gradle integration (Maven's level - dependencies, modules, repositories) 1. Moved functional that works with gradle api to the separate process; 2. Setup infrastructure for communication with that remote process; 3. Started implemented 'import' functionality; --- build/scripts/layouts.gant | 6 + plugins/gradle/gradle.iml | 9 + plugins/gradle/lib/gradle-tooling-api.jar | Bin 0 -> 101173 bytes .../resources/i18n/GradleBundle.properties | 9 +- .../gradle/config/GradleConfigurable.java | 6 +- .../plugins/gradle/config/GradleSettings.java | 14 +- .../gradle/importing/GradleProject.java | 32 --- .../importing/GradleProjectImportBuilder.java | 51 ++-- .../gradle/importing/GradleProjectParser.java | 32 --- .../importing/GradleSelectProjectStep.java | 34 ++- .../gradle/remote/GradleApiFacade.java | 38 +++ .../gradle/remote/GradleApiFacadeImpl.java | 85 +++++++ .../gradle/remote/GradleApiFacadeManager.java | 238 ++++++++++++++++++ .../remote/RemoteGradleProcessSettings.java | 35 +++ .../gradle/remote/RemoteGradleService.java | 19 ++ .../plugins/gradle/resolve/GradleModule.java | 12 + .../gradle/resolve/GradleModuleImpl.java | 12 + .../plugins/gradle/resolve/GradleProject.java | 26 ++ .../gradle/resolve/GradleProjectImpl.java | 60 +++++ .../gradle/resolve/GradleProjectResolver.java | 31 +++ .../resolve/GradleProjectResolverImpl.java | 108 ++++++++ .../resolve/RemoteResolveEntryPoint.java | 21 ++ .../gradle/util/GradleLibraryManager.java | 16 +- .../plugins/gradle/util/GradleLog.java | 15 ++ 24 files changed, 813 insertions(+), 96 deletions(-) create mode 100644 plugins/gradle/lib/gradle-tooling-api.jar delete mode 100644 plugins/gradle/src/org/jetbrains/plugins/gradle/importing/GradleProject.java delete mode 100644 plugins/gradle/src/org/jetbrains/plugins/gradle/importing/GradleProjectParser.java create mode 100644 plugins/gradle/src/org/jetbrains/plugins/gradle/remote/GradleApiFacade.java create mode 100644 plugins/gradle/src/org/jetbrains/plugins/gradle/remote/GradleApiFacadeImpl.java create mode 100644 plugins/gradle/src/org/jetbrains/plugins/gradle/remote/GradleApiFacadeManager.java create mode 100644 plugins/gradle/src/org/jetbrains/plugins/gradle/remote/RemoteGradleProcessSettings.java create mode 100644 plugins/gradle/src/org/jetbrains/plugins/gradle/remote/RemoteGradleService.java create mode 100644 plugins/gradle/src/org/jetbrains/plugins/gradle/resolve/GradleModule.java create mode 100644 plugins/gradle/src/org/jetbrains/plugins/gradle/resolve/GradleModuleImpl.java create mode 100644 plugins/gradle/src/org/jetbrains/plugins/gradle/resolve/GradleProject.java create mode 100644 plugins/gradle/src/org/jetbrains/plugins/gradle/resolve/GradleProjectImpl.java create mode 100644 plugins/gradle/src/org/jetbrains/plugins/gradle/resolve/GradleProjectResolver.java create mode 100644 plugins/gradle/src/org/jetbrains/plugins/gradle/resolve/GradleProjectResolverImpl.java create mode 100644 plugins/gradle/src/org/jetbrains/plugins/gradle/resolve/RemoteResolveEntryPoint.java create mode 100644 plugins/gradle/src/org/jetbrains/plugins/gradle/util/GradleLog.java 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 0000000000000000000000000000000000000000..2b38bc80a0556d00b2bbebf4ac8a1d80bb1b26f5 GIT binary patch literal 101173 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 literal 0 HcmV?d00001 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 mySupport; + private final GradleApiFacade myApiFacade; + + public GradleApiFacadeManager() { + mySupport = new RemoteProcessSupport(GradleApiFacade.class) { + @Override + protected void fireModificationCountChanged() { + } + + @Override + protected String getName(Object o) { + return GradleApiFacade.class.getName(); + } + + @Override + protected RunProfileState getRunProfileState(Object o, Object configuration, Executor executor) throws ExecutionException { + return createRunProfileState(); + } + }; + myApiFacade = (GradleApiFacade)Proxy.newProxyInstance( + GradleApiFacadeManager.class.getClassLoader(), new Class[]{GradleApiFacade.class}, new MyHandler() + ); + + ShutDownTracker.getInstance().registerShutdownTask(new Runnable() { + public void run() { + shutdown(false); + } + }); + } + + private RunProfileState createRunProfileState() { + return new CommandLineState(null) { + private SimpleJavaParameters createJavaParameters() throws ExecutionException { + Collection gradleLibraries = myGradleLibraryManager.getAllLibraries(null); + GradleLog.LOG.assertTrue(gradleLibraries != null, GradleBundle.message("gradle.generic.text.error.sdk.undefined")); + if (gradleLibraries == null) { + return null; + } + + final SimpleJavaParameters params = new SimpleJavaParameters(); + params.setJdk(new SimpleJavaSdkType().createJdk("tmp", SystemProperties.getJavaHome())); + + params.setWorkingDirectory(PathManager.getBinPath()); + final ArrayList classPath = new ArrayList(); + ContainerUtil.addIfNotNull(PathUtil.getJarPathForClass(NotNull.class), classPath); + ContainerUtil.addIfNotNull(PathUtil.getJarPathForClass(StringUtil.class), classPath); + ContainerUtil.addIfNotNull(PathUtil.getJarPathForClass(THashSet.class), classPath); + ContainerUtil.addIfNotNull(PathUtil.getJarPathForClass(LanguageLevel.class), classPath); + ContainerUtil.addIfNotNull(PathUtil.getJarPathForClass(PsiBundle.class), classPath); + ContainerUtil.addIfNotNull(PathUtil.getJarPathForClass(getClass()), classPath); + for (File library : gradleLibraries) { + classPath.add(library.getAbsolutePath()); + } + params.getClassPath().addAll(classPath); + params.getClassPath().add(PathManager.getResourceRoot(getClass(), "/messages/CommonBundle.properties")); + + params.setMainClass(MAIN_CLASS_NAME); + + params.getVMParametersList().addParametersString("-Djava.awt.headless=true -Xmx512m"); + //params.getVMParametersList().addParametersString("-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=5009"); + return params; + } + + @Override + public ExecutionResult execute(@NotNull Executor executor, @NotNull ProgramRunner runner) throws ExecutionException { + ProcessHandler processHandler = startProcess(); + return new DefaultExecutionResult(null, processHandler, AnAction.EMPTY_ARRAY); + } + + protected OSProcessHandler startProcess() throws ExecutionException { + SimpleJavaParameters params = createJavaParameters(); + Sdk sdk = params.getJdk(); + if (sdk == null) { + throw new ExecutionException("No sdk is defined. Params: " + params); + } + + final GeneralCommandLine commandLine = JdkUtil.setupJVMCommandLine( + ((JavaSdkType)sdk.getSdkType()).getVMExecutablePath(sdk), + params, + false // TODO den check + ); + final OSProcessHandler processHandler = new OSProcessHandler(commandLine.createProcess(), commandLine.getCommandLineString()) { + @Override + public Charset getCharset() { + return commandLine.getCharset(); + } + }; + ProcessTerminatedListener.attach(processHandler); + return processHandler; + } + }; + } + + public synchronized void shutdown(boolean wait) { + mySupport.stopAll(wait); + } + + /** + * @return gradle api facade to use + * @throws Exception in case of inability to return the facade + */ + @NotNull + public GradleApiFacade getFacade() throws Exception { + return myApiFacade; + } + + public Object doInvoke(Method method, Object[] args, int invocationNumber) throws Throwable { + GradleApiFacade facade = doGetFacade(); + try { + return method.invoke(facade, args); + } + catch (InvocationTargetException e) { + if (e.getTargetException() instanceof RemoteException && invocationNumber > 0) { + Thread.sleep(1000); + return doInvoke(method, args, invocationNumber - 1); + } + else { + throw e; + } + } + } + + @NotNull + private GradleApiFacade doGetFacade() throws Exception { + Pair pair = myFacade.get(); + if (pair != null) { + if (isValid(pair)) { + return pair.first; + } + mySupport.stopAll(true); + } + + GradleApiFacade result = mySupport.acquire(this, ""); + if (result == null) { + throw new IllegalStateException("Can't obtain facade to working with gradle api at the remote process"); + } + Pair newPair + = new Pair(result, getRemoteSettings()); + if (!myFacade.compareAndSet(null, newPair)) { + GradleLog.LOG.warn("Detected unexpected duplicate tooling api facade instance creation"); + return myFacade.get().first; + } + result.applySettings(getRemoteSettings()); + return result; + } + + private boolean isValid(@NotNull Pair pair) { + // Check remote process is alive. + try { + pair.first.getResolver(); + } + catch (RemoteException e) { + return false; + } + + // Check that significant settings are not changed + RemoteGradleProcessSettings oldSettings = pair.second; + RemoteGradleProcessSettings currentSettings = getRemoteSettings(); + return StringUtil.equals(oldSettings.getGradleHome(), currentSettings.getGradleHome()); + } + + @NotNull + private RemoteGradleProcessSettings getRemoteSettings() { + File gradleHome = myGradleLibraryManager.getGradleHome(); + return new RemoteGradleProcessSettings(gradleHome.getAbsolutePath()); + } + + private class MyHandler implements InvocationHandler { + @Override + public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { + return doInvoke(method, args, REMOTE_FAIL_RECOVERY_ATTEMPTS_NUMBER); + } + } +} diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/remote/RemoteGradleProcessSettings.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/remote/RemoteGradleProcessSettings.java new file mode 100644 index 000000000000..0f8df656f684 --- /dev/null +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/remote/RemoteGradleProcessSettings.java @@ -0,0 +1,35 @@ +package org.jetbrains.plugins.gradle.remote; + +import org.jetbrains.annotations.NotNull; + +import java.io.Serializable; + +/** + * Encapsulates settings important for the process that works with gradle tooling api. + *

+ * The main idea is that we don't want to use the tooling api at intellij process (avoid heap/cpu pollution) + * and run separate process instead. Current class encapsulates settings significant for it. + * + * @author Denis Zhdanov + * @since 8/9/11 12:12 PM + */ +public class RemoteGradleProcessSettings implements Serializable { + + private static final long serialVersionUID = 1L; + + private final String myGradleHome; + + public RemoteGradleProcessSettings(@NotNull String gradleHome) { + myGradleHome = gradleHome; + } + + @NotNull + public String getGradleHome() { + return myGradleHome; + } + + @Override + public String toString() { + return "home: " + myGradleHome; + } +} diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/remote/RemoteGradleService.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/remote/RemoteGradleService.java new file mode 100644 index 000000000000..f81a5b8ce77a --- /dev/null +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/remote/RemoteGradleService.java @@ -0,0 +1,19 @@ +package org.jetbrains.plugins.gradle.remote; + +import org.jetbrains.annotations.NotNull; + +/** + * Generic interface with common functionality for all remote services that work with gradle tooling api. + * + * @author Denis Zhdanov + * @since 8/9/11 3:19 PM + */ +public interface RemoteGradleService { + + /** + * Provides the service with settings to use. + * + * @param settings settings to use + */ + void setSettings(@NotNull RemoteGradleProcessSettings settings); +} diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/resolve/GradleModule.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/resolve/GradleModule.java new file mode 100644 index 000000000000..13dcbc7c9f96 --- /dev/null +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/resolve/GradleModule.java @@ -0,0 +1,12 @@ +package org.jetbrains.plugins.gradle.resolve; + +/** + * Defines IntelliJ module view to the application configured via gradle. + *

+ * Implementations of this interface are not obliged to be thread-safe. + * + * @author Denis Zhdanov + * @since 8/8/11 12:10 PM + */ +public interface GradleModule { +} diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/resolve/GradleModuleImpl.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/resolve/GradleModuleImpl.java new file mode 100644 index 000000000000..7a359c178cd4 --- /dev/null +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/resolve/GradleModuleImpl.java @@ -0,0 +1,12 @@ +package org.jetbrains.plugins.gradle.resolve; + +import java.io.Serializable; + +/** + * @author Denis Zhdanov + * @since 8/8/11 12:11 PM + */ +public class GradleModuleImpl implements GradleModule, Serializable { + + // TODO den implement +} diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/resolve/GradleProject.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/resolve/GradleProject.java new file mode 100644 index 000000000000..f8af423f7b74 --- /dev/null +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/resolve/GradleProject.java @@ -0,0 +1,26 @@ +package org.jetbrains.plugins.gradle.resolve; + +import com.intellij.pom.java.LanguageLevel; +import org.jetbrains.annotations.NotNull; + +import java.util.Set; + +/** + * Defines IntelliJ project view to the application configured via gradle. + *

+ * Implementations of this interface are not obliged to be thread-safe. + * + * @author Denis Zhdanov + * @since 8/8/11 12:05 PM + */ +public interface GradleProject { + + @NotNull + String getJdkName(); + + @NotNull + LanguageLevel getLanguageLevel(); + + @NotNull + Set getModules(); +} diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/resolve/GradleProjectImpl.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/resolve/GradleProjectImpl.java new file mode 100644 index 000000000000..2c5a133564aa --- /dev/null +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/resolve/GradleProjectImpl.java @@ -0,0 +1,60 @@ +package org.jetbrains.plugins.gradle.resolve; + +import com.intellij.pom.java.LanguageLevel; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.io.Serializable; +import java.util.HashSet; +import java.util.Set; + +/** + * Not thread-safe. + * + * @author Denis Zhdanov + * @since 8/1/11 1:30 PM + */ +public class GradleProjectImpl implements Serializable, GradleProject { + + private static final long serialVersionUID = 1L; + private static final LanguageLevel DEFAULT_LANGUAGE_LEVEL = LanguageLevel.JDK_1_6; + private static final String DEFAULT_JDK = "1.6"; + + private final Set myModules = new HashSet(); + + private String myJdk = DEFAULT_JDK; + private LanguageLevel myLanguageLevel = DEFAULT_LANGUAGE_LEVEL; + + @NotNull + @Override + public String getJdkName() { + return myJdk; + } + + public void setJdk(@NotNull String jdk) { + myJdk = jdk; + } + + @NotNull + @Override + public LanguageLevel getLanguageLevel() { + return myLanguageLevel; + } + + public void setLanguageLevel(@Nullable String languageLevel) { + LanguageLevel level = LanguageLevel.parse(languageLevel); + if (level != null) { + myLanguageLevel = level; + } + } + + public void addModule(@NotNull GradleModuleImpl module) { + myModules.add(module); + } + + @NotNull + @Override + public Set getModules() { + return myModules; + } +} diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/resolve/GradleProjectResolver.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/resolve/GradleProjectResolver.java new file mode 100644 index 000000000000..0042e3b99580 --- /dev/null +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/resolve/GradleProjectResolver.java @@ -0,0 +1,31 @@ +package org.jetbrains.plugins.gradle.resolve; + +import org.jetbrains.annotations.NotNull; + +import java.rmi.Remote; +import java.rmi.RemoteException; + +/** + * Defines common interface for resolving gradle project, i.e. building object-level representation of 'build.gradle'. + * + * @author Denis Zhdanov + * @since 8/8/11 10:58 AM + */ +public interface GradleProjectResolver extends Remote { + + /** + * Builds object-level representation of the gradle project file contained at the target directory (dependencies are not resolved + * during that). + *

+ * Note: gradle api doesn't allow to explicitly define project file to use though it's possible to do that via + * command-line switch. So, we want to treat the argument as a target project file name when that is supported. + * + * @param projectPath absolute path to the gradle project file + * @return object-level representation of the target gradle project + * @throws RemoteException in case of unexpected exception during remote communications + * @throws IllegalArgumentException if given path doesn't point to directory that contains gradle project + * @throws IllegalStateException if it's not possible to resolve target project info + */ + @NotNull + GradleProject resolveProjectInfo(@NotNull String projectPath) throws RemoteException, IllegalArgumentException, IllegalStateException; +} diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/resolve/GradleProjectResolverImpl.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/resolve/GradleProjectResolverImpl.java new file mode 100644 index 000000000000..a495b7e0f8ff --- /dev/null +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/resolve/GradleProjectResolverImpl.java @@ -0,0 +1,108 @@ +package org.jetbrains.plugins.gradle.resolve; + +import com.intellij.execution.rmi.RemoteObject; +import org.gradle.tooling.GradleConnector; +import org.gradle.tooling.ProjectConnection; +import org.gradle.tooling.model.idea.OfflineIdeaProject; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.plugins.gradle.remote.RemoteGradleProcessSettings; +import org.jetbrains.plugins.gradle.remote.RemoteGradleService; +import org.jetbrains.plugins.gradle.util.GradleBundle; +import org.jetbrains.plugins.gradle.util.GradleLog; + +import java.io.File; +import java.rmi.RemoteException; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicReference; + +/** + * @author Denis Zhdanov + * @since 8/8/11 11:09 AM + */ +public class GradleProjectResolverImpl extends RemoteObject implements GradleProjectResolver, RemoteGradleService { + + private final BlockingQueue myConnections = new LinkedBlockingQueue(); + private final AtomicReference mySettings = new AtomicReference(); + + @NotNull + @Override + public GradleProject resolveProjectInfo(@NotNull String projectPath) throws RemoteException { + try { + return doResolve(projectPath); + } + catch (Throwable e) { + throw new IllegalStateException(GradleBundle.message("gradle.import.text.error.resolve.generic", projectPath), e); + } + } + + @NotNull + private GradleProject doResolve(@NotNull String projectPath) { + ProjectConnection connection = getConnection(projectPath); + OfflineIdeaProject project = connection.getModel(OfflineIdeaProject.class); + GradleProjectImpl result = new GradleProjectImpl(); + result.setJdk(project.getJdkName()); + result.setLanguageLevel(project.getLanguageLevel().getLevel()); + // TODO den build modules here + return result; + } + + /** + * Allows to retrieve gradle api connection to use for the given project. + * + * @param projectPath target project path + * @return connection to use + * @throws IllegalStateException if it's not possible to create the connection + */ + @NotNull + private ProjectConnection getConnection(@NotNull String projectPath) throws IllegalStateException { + File projectFile = new File(projectPath); + if (!projectFile.isFile()) { + throw new IllegalArgumentException(GradleBundle.message("gradle.import.text.error.invalid.path", projectPath)); + } + File projectDir = projectFile.getParentFile(); + GradleConnector connector = GradleConnector.newConnector(); + RemoteGradleProcessSettings settings = mySettings.get(); + if (settings != null) { + connector.useInstallation(new File(settings.getGradleHome())); + } + connector.forProjectDirectory(projectDir); + ProjectConnection connection = connector.connect(); + if (connection == null) { + throw new IllegalStateException(String.format( + "Can't create connection to the target project via gradle tooling api. Project path: '%s'", projectPath + )); + } + myConnections.add(connection); + return connection; + } + + @SuppressWarnings("NonSynchronizedMethodOverridesSynchronizedMethod") + @Override + public void unreferenced() { + releaseConnectionIfPossible(); + super.unreferenced(); + } + + private void releaseConnectionIfPossible() { + while (!myConnections.isEmpty()) { + try { + ProjectConnection connection = myConnections.poll(1, TimeUnit.SECONDS); + connection.close(); + } + catch (InterruptedException e) { + GradleLog.LOG.warn("Detected unexpected thread interruption on releasing gradle connections", e); + Thread.currentThread().interrupt(); + } + catch (Throwable e) { + GradleLog.LOG.warn("Got unexpected exception on closing project connection created by the gradle tooling api", e); + } + } + } + + @Override + public void setSettings(@NotNull RemoteGradleProcessSettings settings) { + mySettings.set(settings); + } +} diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/resolve/RemoteResolveEntryPoint.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/resolve/RemoteResolveEntryPoint.java new file mode 100644 index 000000000000..eb0de9ff6366 --- /dev/null +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/resolve/RemoteResolveEntryPoint.java @@ -0,0 +1,21 @@ +package org.jetbrains.plugins.gradle.resolve; + +import com.intellij.execution.rmi.RemoteServer; + +/** + * Entry point to the processing that resolves gradle project via its tooling api and exposes the result to IntelliJ process. + *

+ * Rationale: we want to import gradle project, i.e. setup IDE structure (project, modules, libraries etc) on the basis + * of existing 'build.gradle' file. We need to have object-level representation of the + * 'build.gradle' file data then. That is done via gradle api, i.e. it should be initialised and asked to + * perform the job. The thing is that we don't want to have that done at IJ process. The reason is that that is not our + * codebase, so, we can't be sure that it doesn't leaks memory, consumes perm gen, calls System.exit() etc. + * + * @author Denis Zhdanov + * @since 8/5/11 11:50 AM + */ +public class RemoteResolveEntryPoint extends RemoteServer { + public static void main(String[] args) throws Exception { + start(new GradleProjectResolverImpl()); + } +} 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 8670f9f01d62..c27bed2df53f 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/util/GradleLibraryManager.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/util/GradleLibraryManager.java @@ -1,6 +1,7 @@ package org.jetbrains.plugins.gradle.util; import com.intellij.openapi.project.Project; +import com.intellij.openapi.project.ProjectManager; import com.intellij.openapi.vfs.VirtualFile; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.Nullable; @@ -52,7 +53,7 @@ public class GradleLibraryManager { // Manually defined gradle home File gradleHome = getGradleHome(project); - if (gradleHome == null || gradleHome.isDirectory()) { + if (gradleHome == null || !gradleHome.isDirectory()) { return null; } @@ -70,6 +71,17 @@ public class GradleLibraryManager { return result; } + /** + * Performs the same job as {@link #getGradleHome(Project)} but tries to deduce project to use. + * + * @return file handle that points to the gradle installation home (if any) + */ + public File getGradleHome() { + ProjectManager projectManager = ProjectManager.getInstance(); + Project[] openProjects = projectManager.getOpenProjects(); + return openProjects.length == 1 ? getGradleHome(openProjects[0]) : getGradleHome(projectManager.getDefaultProject()); + } + /** * Tries to return file handle that points to the gradle installation home. * @@ -96,7 +108,7 @@ public class GradleLibraryManager { @Nullable public File getManuallyDefinedGradleHome(@Nullable Project project) { if (project == null) { - return null; + project = ProjectManager.getInstance().getDefaultProject(); } GradleSettings settings = GradleSettings.getInstance(project); String path = settings.GRADLE_HOME; diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/util/GradleLog.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/util/GradleLog.java new file mode 100644 index 000000000000..3eaf8b22485d --- /dev/null +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/util/GradleLog.java @@ -0,0 +1,15 @@ +package org.jetbrains.plugins.gradle.util; + +import com.intellij.openapi.diagnostic.Logger; + +/** + * @author Denis Zhdanov + * @since 8/8/11 11:44 AM + */ +public class GradleLog { + + public static final Logger LOG = Logger.getInstance("#" + GradleLog.class.getName()); + + private GradleLog() { + } +}