mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
IDEA-53476 Gradle integration (Maven's level - dependencies, modules, repositories)
1. 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;
This commit is contained in:
@@ -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")
|
||||
}
|
||||
|
||||
@@ -17,6 +17,15 @@
|
||||
<orderEntry type="module" module-name="execution-openapi" />
|
||||
<orderEntry type="module" module-name="openapi" />
|
||||
<orderEntry type="module" module-name="java-impl" />
|
||||
<orderEntry type="module-library">
|
||||
<library>
|
||||
<CLASSES>
|
||||
<root url="jar://$MODULE_DIR$/lib/gradle-tooling-api.jar!/" />
|
||||
</CLASSES>
|
||||
<JAVADOC />
|
||||
<SOURCES />
|
||||
</library>
|
||||
</orderEntry>
|
||||
</component>
|
||||
</module>
|
||||
|
||||
|
||||
Binary file not shown.
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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<GradleSettings> {
|
||||
public class GradleSettings implements PersistentStateComponent<GradleSettings>, Cloneable {
|
||||
|
||||
public String GRADLE_HOME;
|
||||
|
||||
@@ -48,4 +48,16 @@ public class GradleSettings implements PersistentStateComponent<GradleSettings>
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
package org.jetbrains.plugins.gradle.importing;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
/**
|
||||
* Application-level representation of the <code>'build.gradle'</code> file.
|
||||
*
|
||||
* @author Denis Zhdanov
|
||||
* @since 8/1/11 1:30 PM
|
||||
*/
|
||||
public class GradleProject {
|
||||
|
||||
private final File myFile;
|
||||
|
||||
/**
|
||||
* Creates new <code>GradleProject</code> object for the given gradle project file.
|
||||
*
|
||||
* @param projectFile target gradle project file
|
||||
*/
|
||||
public GradleProject(@NotNull File projectFile) {
|
||||
myFile = projectFile;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses underlying <code>'build.gradle'</code> file and populates current object within that information.
|
||||
*/
|
||||
public void build() {
|
||||
// TODO den implement
|
||||
}
|
||||
}
|
||||
+36
-15
@@ -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<GradleProje
|
||||
|
||||
private static final String GRADLE_IMPORT_ROOT_KEY = "gradle.import.root";
|
||||
|
||||
private final GradleProjectParser myProjectParser = new GradleProjectParser();
|
||||
private GradleProject myProject;
|
||||
private GradleProject myGradleProject;
|
||||
private File myProjectFile;
|
||||
|
||||
@Override
|
||||
@@ -82,9 +89,13 @@ public class GradleProjectImportBuilder extends ProjectImportBuilder<GradleProje
|
||||
* @return start path to use during importing gradle projects
|
||||
*/
|
||||
@NotNull
|
||||
public String getRootDirectoryPath(@Nullable WizardContext context) {
|
||||
public String getProjectPath(@Nullable WizardContext context) {
|
||||
String result = PropertiesComponent.getInstance().getValue(GRADLE_IMPORT_ROOT_KEY, "");
|
||||
if (new File(result).isDirectory()) {
|
||||
File file = new File(result);
|
||||
if (file.exists()) {
|
||||
if (myProjectFile == null) {
|
||||
myProjectFile = file;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
if (context == null) {
|
||||
@@ -106,17 +117,8 @@ public class GradleProjectImportBuilder extends ProjectImportBuilder<GradleProje
|
||||
}
|
||||
if (file == null) {
|
||||
return;
|
||||
}
|
||||
String pathToStore = null;
|
||||
if (file.isDirectory()) {
|
||||
pathToStore = file.getAbsolutePath();
|
||||
}
|
||||
else if (file.isFile()) {
|
||||
pathToStore = file.getParentFile().getAbsolutePath();
|
||||
}
|
||||
if (pathToStore != null) {
|
||||
PropertiesComponent.getInstance().setValue(GRADLE_IMPORT_ROOT_KEY, pathToStore);
|
||||
}
|
||||
PropertiesComponent.getInstance().setValue(GRADLE_IMPORT_ROOT_KEY, file.getAbsolutePath());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -132,10 +134,29 @@ public class GradleProjectImportBuilder extends ProjectImportBuilder<GradleProje
|
||||
throw new ConfigurationException(GradleBundle.message("gradle.import.text.error.directory.instead.file"));
|
||||
}
|
||||
try {
|
||||
myProject = myProjectParser.parse(myProjectFile);
|
||||
ProgressManager.getInstance().run(new Task.Modal(null, GradleBundle.message("gradle.import.progress.text"), true) {
|
||||
@Override
|
||||
public void run(@NotNull ProgressIndicator indicator) {
|
||||
GradleApiFacadeManager manager = ServiceManager.getService(GradleApiFacadeManager.class);
|
||||
try {
|
||||
GradleProjectResolver resolver = manager.getFacade().getResolver();
|
||||
myGradleProject = resolver.resolveProjectInfo(myProjectFile.getAbsolutePath());
|
||||
}
|
||||
catch (Exception e) {
|
||||
// Ignore here because it will be reported on method exit.
|
||||
GradleLog.LOG.warn("Can't resolve gradle project", e);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
catch (IllegalArgumentException e) {
|
||||
throw new ConfigurationException(e.getMessage(), GradleBundle.message("gradle.import.text.error.cannot.parse.project"));
|
||||
}
|
||||
if (myGradleProject == null) {
|
||||
throw new ConfigurationException(
|
||||
GradleBundle.message("gradle.import.text.error.resolve.generic", myProjectFile.getPath()),
|
||||
GradleBundle.message("gradle.import.title.error.resolve.generic")
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,32 +0,0 @@
|
||||
package org.jetbrains.plugins.gradle.importing;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
/**
|
||||
* Encapsulates functionality of performing <code>'build.gradle' -> {@link GradleProject}</code> conversion.
|
||||
* <p/>
|
||||
* 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);
|
||||
}
|
||||
}
|
||||
+22
-12
@@ -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()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
* <a href="http://gradle.org/current/docs/javadoc/org/gradle/tooling/package-summary.html">gradle tooling api</a>.
|
||||
* <p/>
|
||||
* 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 <code>'resolve gradle project'</code> service that works at another process.
|
||||
*
|
||||
* @return <code>'resolve gradle project'</code> 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;
|
||||
}
|
||||
@@ -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<Class<?>, RemoteGradleService> myRemotes = new ConcurrentHashMap<Class<?>, RemoteGradleService>();
|
||||
private final AtomicReference<RemoteGradleProcessSettings> mySettings = new AtomicReference<RemoteGradleProcessSettings>();
|
||||
|
||||
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.
|
||||
* <p/>
|
||||
* Uses cached value if it's found; creates new and caches it otherwise.
|
||||
*
|
||||
* @param clazz target service implementation class
|
||||
* @param <T> 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 extends Remote & RemoteGradleService> T getRemote(@NotNull Class<T> 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);
|
||||
}
|
||||
}
|
||||
@@ -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}.
|
||||
* <p/>
|
||||
* 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<Pair<GradleApiFacade, RemoteGradleProcessSettings>> myFacade
|
||||
= new AtomicReference<Pair<GradleApiFacade, RemoteGradleProcessSettings>>();
|
||||
|
||||
private final GradleLibraryManager myGradleLibraryManager = GradleLibraryManager.INSTANCE;
|
||||
|
||||
private final RemoteProcessSupport<Object, GradleApiFacade, Object> mySupport;
|
||||
private final GradleApiFacade myApiFacade;
|
||||
|
||||
public GradleApiFacadeManager() {
|
||||
mySupport = new RemoteProcessSupport<Object, GradleApiFacade, Object>(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<File> 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<String> classPath = new ArrayList<String>();
|
||||
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<GradleApiFacade, RemoteGradleProcessSettings> 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<GradleApiFacade, RemoteGradleProcessSettings> newPair
|
||||
= new Pair<GradleApiFacade, RemoteGradleProcessSettings>(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<GradleApiFacade, RemoteGradleProcessSettings> 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
+35
@@ -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.
|
||||
* <p/>
|
||||
* 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;
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package org.jetbrains.plugins.gradle.resolve;
|
||||
|
||||
/**
|
||||
* Defines IntelliJ module view to the application configured via gradle.
|
||||
* <p/>
|
||||
* Implementations of this interface are not obliged to be thread-safe.
|
||||
*
|
||||
* @author Denis Zhdanov
|
||||
* @since 8/8/11 12:10 PM
|
||||
*/
|
||||
public interface GradleModule {
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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.
|
||||
* <p/>
|
||||
* 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<? extends GradleModule> getModules();
|
||||
}
|
||||
@@ -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<GradleModuleImpl> myModules = new HashSet<GradleModuleImpl>();
|
||||
|
||||
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<? extends GradleModule> getModules() {
|
||||
return myModules;
|
||||
}
|
||||
}
|
||||
@@ -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 <code>'build.gradle'</code>.
|
||||
*
|
||||
* @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).
|
||||
* <p/>
|
||||
* <b>Note:</b> 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;
|
||||
}
|
||||
+108
@@ -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<ProjectConnection> myConnections = new LinkedBlockingQueue<ProjectConnection>();
|
||||
private final AtomicReference<RemoteGradleProcessSettings> mySettings = new AtomicReference<RemoteGradleProcessSettings>();
|
||||
|
||||
@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);
|
||||
}
|
||||
}
|
||||
@@ -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.
|
||||
* <p/>
|
||||
* Rationale: we want to import gradle project, i.e. setup IDE structure (project, modules, libraries etc) on the basis
|
||||
* of existing <code>'build.gradle'</code> file. We need to have object-level representation of the
|
||||
* <code>'build.gradle'</code> 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 <code>System.exit()</code> 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());
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
@@ -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() {
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user