mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
IDEA-76142: Gradle support - cannot update IDEA projects once one of build.gradle files changes
1. Refreshing gradle project on intellij module root change; 2. 'Refresh gradle action' is disabled if there is a refresh in progress; 3. Gradle tasks have 'queued' status now;
This commit is contained in:
@@ -49,6 +49,7 @@
|
||||
<!--Generic application services-->
|
||||
<applicationService serviceImplementation="org.jetbrains.plugins.gradle.remote.GradleApiFacadeManager"/>
|
||||
<applicationService serviceImplementation="org.jetbrains.plugins.gradle.util.GradleLibraryManager"/>
|
||||
<applicationService serviceImplementation="org.jetbrains.plugins.gradle.task.GradleTaskManager"/>
|
||||
<applicationService serviceInterface="org.jetbrains.plugins.gradle.notification.GradleProgressNotificationManager"
|
||||
serviceImplementation="org.jetbrains.plugins.gradle.notification.GradleProgressNotificationManagerImpl"/>
|
||||
<applicationService serviceInterface="org.jetbrains.plugins.gradle.diff.PlatformFacade"
|
||||
@@ -74,6 +75,9 @@
|
||||
<component>
|
||||
<implementation-class>org.jetbrains.plugins.gradle.sync.GradleProjectStructureHelper</implementation-class>
|
||||
</component>
|
||||
<component>
|
||||
<implementation-class>org.jetbrains.plugins.gradle.sync.GradleProjectStructureChangesDetector</implementation-class>
|
||||
</component>
|
||||
</project-components>
|
||||
|
||||
<actions>
|
||||
|
||||
+13
-9
@@ -2,6 +2,7 @@ package org.jetbrains.plugins.gradle.action;
|
||||
|
||||
import com.intellij.openapi.actionSystem.*;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
@@ -21,13 +22,13 @@ public abstract class AbstractGradleLinkedProjectAction extends AnAction {
|
||||
|
||||
@Override
|
||||
public void update(AnActionEvent e) {
|
||||
final String path = getLinkedProjectPath(e.getDataContext());
|
||||
final boolean visible = path != null;
|
||||
final Pair<Project, String> pair = deriveProjects(e.getDataContext());
|
||||
final boolean visible = pair != null;
|
||||
e.getPresentation().setVisible(visible);
|
||||
if (!visible) {
|
||||
return;
|
||||
}
|
||||
doUpdate(e.getPresentation(), path);
|
||||
doUpdate(e.getPresentation(), pair.first, pair.second);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -36,16 +37,16 @@ public abstract class AbstractGradleLinkedProjectAction extends AnAction {
|
||||
if (project == null) {
|
||||
return;
|
||||
}
|
||||
final String path = getLinkedProjectPath(e.getDataContext());
|
||||
if (path == null) {
|
||||
final Pair<Project, String> pair = deriveProjects(e.getDataContext());
|
||||
if (pair == null) {
|
||||
e.getPresentation().setVisible(false);
|
||||
return;
|
||||
}
|
||||
doActionPerformed(project, path);
|
||||
doActionPerformed(project, pair.second);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
protected static String getLinkedProjectPath(@Nullable DataContext context) {
|
||||
private static Pair<Project, String> deriveProjects(@Nullable DataContext context) {
|
||||
if (context == null) {
|
||||
return null;
|
||||
}
|
||||
@@ -56,9 +57,12 @@ public abstract class AbstractGradleLinkedProjectAction extends AnAction {
|
||||
}
|
||||
|
||||
final String path = GradleSettings.getInstance(project).LINKED_PROJECT_FILE_PATH;
|
||||
return (StringUtil.isEmpty(path) || !new File(path).isFile()) ? null : path;
|
||||
if (StringUtil.isEmpty(path) || !new File(path).isFile()) {
|
||||
return null;
|
||||
}
|
||||
return new Pair<Project, String>(project, path);
|
||||
}
|
||||
|
||||
protected abstract void doUpdate(@NotNull Presentation presentation, @NotNull String linkedProjectPath);
|
||||
protected abstract void doUpdate(@NotNull Presentation presentation, @NotNull Project project, @NotNull String linkedProjectPath);
|
||||
protected abstract void doActionPerformed(@NotNull Project project, @NotNull String linkedProjectPath);
|
||||
}
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
package org.jetbrains.plugins.gradle.action;
|
||||
|
||||
import com.intellij.openapi.actionSystem.AnAction;
|
||||
import com.intellij.openapi.actionSystem.AnActionEvent;
|
||||
import com.intellij.openapi.actionSystem.Presentation;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.fileEditor.FileEditorManager;
|
||||
@@ -32,7 +30,7 @@ public class GradleOpenScriptAction extends AbstractGradleLinkedProjectAction im
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doUpdate(@NotNull Presentation presentation, @NotNull String linkedProjectPath) {
|
||||
protected void doUpdate(@NotNull Presentation presentation, @NotNull Project project, @NotNull String linkedProjectPath) {
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+14
-24
@@ -1,17 +1,16 @@
|
||||
package org.jetbrains.plugins.gradle.action;
|
||||
|
||||
import com.intellij.openapi.actionSystem.AnAction;
|
||||
import com.intellij.openapi.actionSystem.Presentation;
|
||||
import com.intellij.openapi.progress.ProgressIndicator;
|
||||
import com.intellij.openapi.progress.ProgressManager;
|
||||
import com.intellij.openapi.progress.Task;
|
||||
import com.intellij.openapi.components.ServiceManager;
|
||||
import com.intellij.openapi.project.DumbAware;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.plugins.gradle.config.GradleSettings;
|
||||
import org.jetbrains.plugins.gradle.task.GradleResolveProjectTask;
|
||||
import org.jetbrains.plugins.gradle.task.GradleTaskManager;
|
||||
import org.jetbrains.plugins.gradle.task.GradleTaskType;
|
||||
import org.jetbrains.plugins.gradle.util.GradleBundle;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import org.jetbrains.plugins.gradle.util.GradleUtil;
|
||||
|
||||
/**
|
||||
* Forces the 'gradle' plugin to retrieve the most up-to-date info about the
|
||||
@@ -21,34 +20,25 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
||||
* @author Denis Zhdanov
|
||||
* @since 1/23/12 3:48 PM
|
||||
*/
|
||||
public class GradleRefreshProjectAction extends AbstractGradleLinkedProjectAction implements DumbAware {
|
||||
public class GradleRefreshProjectAction extends AbstractGradleLinkedProjectAction implements DumbAware, AnAction.TransparentUpdate {
|
||||
|
||||
private final AtomicBoolean myInProgress = new AtomicBoolean();
|
||||
|
||||
public GradleRefreshProjectAction() {
|
||||
getTemplatePresentation().setText(GradleBundle.message("gradle.action.refresh.project.text"));
|
||||
getTemplatePresentation().setDescription(GradleBundle.message("gradle.action.refresh.project.description"));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doUpdate(@NotNull Presentation presentation, @NotNull String linkedProjectPath) {
|
||||
presentation.setEnabled(!myInProgress.get());
|
||||
protected void doUpdate(@NotNull Presentation presentation, @NotNull Project project, @NotNull String linkedProjectPath) {
|
||||
boolean enabled = false;
|
||||
final GradleTaskManager taskManager = ServiceManager.getService(GradleTaskManager.class);
|
||||
if (taskManager != null) {
|
||||
enabled = !taskManager.hasTaskOfTypeInProgress(GradleTaskType.RESOLVE_PROJECT);
|
||||
}
|
||||
presentation.setEnabled(enabled);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doActionPerformed(@NotNull final Project project, @NotNull final String linkedProjectPath) {
|
||||
myInProgress.set(true);
|
||||
ProgressManager.getInstance().run(new Task.Backgroundable(project, GradleBundle.message("gradle.sync.progress.text")) {
|
||||
@Override
|
||||
public void run(@NotNull final ProgressIndicator indicator) {
|
||||
try {
|
||||
GradleResolveProjectTask task = new GradleResolveProjectTask(project, linkedProjectPath, true);
|
||||
task.execute(indicator);
|
||||
}
|
||||
finally {
|
||||
myInProgress.set(false);
|
||||
}
|
||||
}
|
||||
});
|
||||
GradleUtil.refreshProject(project);
|
||||
}
|
||||
}
|
||||
|
||||
+2
-40
@@ -1,14 +1,10 @@
|
||||
package org.jetbrains.plugins.gradle.importing;
|
||||
|
||||
import com.intellij.execution.rmi.RemoteUtil;
|
||||
import com.intellij.ide.util.PropertiesComponent;
|
||||
import com.intellij.ide.util.projectWizard.WizardContext;
|
||||
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.project.ProjectManager;
|
||||
import com.intellij.openapi.projectRoots.JavaSdk;
|
||||
@@ -17,7 +13,6 @@ import com.intellij.openapi.projectRoots.Sdk;
|
||||
import com.intellij.openapi.roots.ui.configuration.ModulesProvider;
|
||||
import com.intellij.openapi.startup.StartupManager;
|
||||
import com.intellij.openapi.util.Ref;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.packaging.artifacts.ModifiableArtifactModel;
|
||||
import com.intellij.projectImport.ProjectImportBuilder;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@@ -26,11 +21,9 @@ import org.jetbrains.plugins.gradle.config.GradleSettings;
|
||||
import org.jetbrains.plugins.gradle.model.GradleEntity;
|
||||
import org.jetbrains.plugins.gradle.model.GradleModule;
|
||||
import org.jetbrains.plugins.gradle.model.GradleProject;
|
||||
import org.jetbrains.plugins.gradle.remote.GradleApiException;
|
||||
import org.jetbrains.plugins.gradle.task.GradleResolveProjectTask;
|
||||
import org.jetbrains.plugins.gradle.ui.GradleIcons;
|
||||
import org.jetbrains.plugins.gradle.util.GradleBundle;
|
||||
import org.jetbrains.plugins.gradle.util.GradleLog;
|
||||
import org.jetbrains.plugins.gradle.util.GradleUtil;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.io.File;
|
||||
@@ -156,38 +149,7 @@ public class GradleProjectImportBuilder extends ProjectImportBuilder<GradleProje
|
||||
final Ref<String> errorReason = new Ref<String>();
|
||||
try {
|
||||
final Project project = getProject(wizardContext);
|
||||
ProgressManager.getInstance().run(new Task.Modal(project, GradleBundle.message("gradle.import.progress.text"), true) {
|
||||
@SuppressWarnings("ThrowableResultOfMethodCallIgnored")
|
||||
@Override
|
||||
public void run(@NotNull final ProgressIndicator indicator) {
|
||||
GradleResolveProjectTask task = new GradleResolveProjectTask(project, myProjectFile.getAbsolutePath(), false);
|
||||
task.execute(indicator);
|
||||
myGradleProject = task.getProject();
|
||||
if (myGradleProject != null) {
|
||||
return;
|
||||
}
|
||||
final Throwable error = task.getError();
|
||||
if (error == null) {
|
||||
return;
|
||||
}
|
||||
Throwable unwrapped = RemoteUtil.unwrap(error);
|
||||
String reason = unwrapped.getLocalizedMessage();
|
||||
if (!StringUtil.isEmpty(reason)) {
|
||||
errorReason.set(reason);
|
||||
}
|
||||
if (unwrapped.getClass() == NoClassDefFoundError.class) {
|
||||
errorReason.set(GradleBundle.message("gradle.import.text.incomplete.tooling.api"));
|
||||
}
|
||||
else if (unwrapped.getClass() == GradleApiException.class) {
|
||||
GradleLog.LOG.warn("Can't resolve gradle project. Reason: gradle api threw an exception:\n"
|
||||
+ ((GradleApiException)unwrapped).getOriginalReason()
|
||||
);
|
||||
}
|
||||
else {
|
||||
GradleLog.LOG.warn("Can't resolve gradle project", unwrapped);
|
||||
}
|
||||
}
|
||||
});
|
||||
myGradleProject = GradleUtil.refreshProject(project, myProjectFile.getAbsolutePath(), errorReason, false, true);
|
||||
}
|
||||
catch (IllegalArgumentException e) {
|
||||
throw new ConfigurationException(e.getMessage(), GradleBundle.message("gradle.import.text.error.cannot.parse.project"));
|
||||
|
||||
+9
@@ -9,6 +9,15 @@ import org.jetbrains.plugins.gradle.task.GradleTaskId;
|
||||
*/
|
||||
public interface GradleProgressNotificationManager {
|
||||
|
||||
/**
|
||||
* Allows to register given listener to listen events from all tasks.
|
||||
*
|
||||
* @param listener listener to register
|
||||
* @return <code>true</code> if given listener was not registered before for the given key;
|
||||
* <code>false</code> otherwise
|
||||
*/
|
||||
boolean addNotificationListener(@NotNull GradleTaskNotificationListener listener);
|
||||
|
||||
/**
|
||||
* Allows to register given listener within the current manager for listening events from the task with the target id.
|
||||
*
|
||||
|
||||
+25
-4
@@ -7,6 +7,7 @@ import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.plugins.gradle.remote.RemoteGradleProgressNotificationManager;
|
||||
import org.jetbrains.plugins.gradle.task.GradleTaskId;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
@@ -19,9 +20,15 @@ public class GradleProgressNotificationManagerImpl extends RemoteObject
|
||||
implements GradleProgressNotificationManager, RemoteGradleProgressNotificationManager
|
||||
{
|
||||
|
||||
private final ConcurrentMap<GradleTaskNotificationListener, Set<GradleTaskId>> myListeners
|
||||
private final ConcurrentMap<GradleTaskNotificationListener, Set<GradleTaskId>/* EMPTY_SET as a sign of 'all ids' */> myListeners
|
||||
= new ConcurrentHashMap<GradleTaskNotificationListener, Set<GradleTaskId>>();
|
||||
|
||||
@Override
|
||||
public boolean addNotificationListener(@NotNull GradleTaskNotificationListener listener) {
|
||||
Set<GradleTaskId> dummy = Collections.emptySet();
|
||||
return myListeners.put(listener, dummy) == null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean addNotificationListener(@NotNull GradleTaskId taskId, @NotNull GradleTaskNotificationListener listener) {
|
||||
Set<GradleTaskId> ids = null;
|
||||
@@ -41,10 +48,22 @@ public class GradleProgressNotificationManagerImpl extends RemoteObject
|
||||
return myListeners.remove(listener) != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onQueued(@NotNull GradleTaskId id) {
|
||||
for (Map.Entry<GradleTaskNotificationListener, Set<GradleTaskId>> entry : myListeners.entrySet()) {
|
||||
final Set<GradleTaskId> ids = entry.getValue();
|
||||
if (Collections.EMPTY_SET == ids || ids.contains(id)) {
|
||||
entry.getKey().onQueued(id);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStart(@NotNull GradleTaskId id) {
|
||||
for (Map.Entry<GradleTaskNotificationListener, Set<GradleTaskId>> entry : myListeners.entrySet()) {
|
||||
if (entry.getValue().contains(id)) {
|
||||
final Set<GradleTaskId> ids = entry.getValue();
|
||||
if (Collections.EMPTY_SET == ids || ids.contains(id)) {
|
||||
entry.getKey().onStart(id);
|
||||
}
|
||||
}
|
||||
@@ -53,7 +72,8 @@ public class GradleProgressNotificationManagerImpl extends RemoteObject
|
||||
@Override
|
||||
public void onStatusChange(@NotNull GradleTaskNotificationEvent event) {
|
||||
for (Map.Entry<GradleTaskNotificationListener, Set<GradleTaskId>> entry : myListeners.entrySet()) {
|
||||
if (entry.getValue().contains(event.getId())) {
|
||||
final Set<GradleTaskId> ids = entry.getValue();
|
||||
if (Collections.EMPTY_SET == ids || ids.contains(event.getId())) {
|
||||
entry.getKey().onStatusChange(event);
|
||||
}
|
||||
}
|
||||
@@ -62,7 +82,8 @@ public class GradleProgressNotificationManagerImpl extends RemoteObject
|
||||
@Override
|
||||
public void onEnd(@NotNull GradleTaskId id) {
|
||||
for (Map.Entry<GradleTaskNotificationListener, Set<GradleTaskId>> entry : myListeners.entrySet()) {
|
||||
if (entry.getValue().contains(id)) {
|
||||
final Set<GradleTaskId> ids = entry.getValue();
|
||||
if (Collections.EMPTY_SET == ids || ids.contains(id)) {
|
||||
entry.getKey().onEnd(id);
|
||||
}
|
||||
}
|
||||
|
||||
+10
@@ -11,6 +11,16 @@ import org.jetbrains.plugins.gradle.task.GradleTaskId;
|
||||
*/
|
||||
public interface GradleTaskNotificationListener {
|
||||
|
||||
/**
|
||||
* Notifies that task with the given id is queued for the execution.
|
||||
* <p/>
|
||||
* 'Queued' here means that intellij process-local codebase receives request to execute the target task and even has not been
|
||||
* sent it to the slave gradle api process.
|
||||
*
|
||||
* @param id target task's id
|
||||
*/
|
||||
void onQueued(@NotNull GradleTaskId id);
|
||||
|
||||
/**
|
||||
* Notifies that task with the given id is about to be started.
|
||||
*
|
||||
|
||||
+5
@@ -8,6 +8,11 @@ import org.jetbrains.plugins.gradle.task.GradleTaskId;
|
||||
* @since 11/10/11 12:18 PM
|
||||
*/
|
||||
public class GradleTaskNotificationListenerAdapter implements GradleTaskNotificationListener {
|
||||
|
||||
@Override
|
||||
public void onQueued(@NotNull GradleTaskId id) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStart(@NotNull GradleTaskId id) {
|
||||
}
|
||||
|
||||
@@ -1,12 +1,10 @@
|
||||
package org.jetbrains.plugins.gradle.remote;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.plugins.gradle.task.GradleTaskId;
|
||||
import org.jetbrains.plugins.gradle.task.GradleTaskType;
|
||||
import org.jetbrains.plugins.gradle.task.GradleTaskAware;
|
||||
|
||||
import java.rmi.Remote;
|
||||
import java.rmi.RemoteException;
|
||||
import java.util.Collection;
|
||||
|
||||
/**
|
||||
* Serves as a facade for working with
|
||||
@@ -18,7 +16,7 @@ import java.util.Collection;
|
||||
* @author Denis Zhdanov
|
||||
* @since 8/8/11 10:52 AM
|
||||
*/
|
||||
public interface GradleApiFacade extends Remote {
|
||||
public interface GradleApiFacade extends Remote, GradleTaskAware {
|
||||
|
||||
/**
|
||||
* Exposes <code>'resolve gradle project'</code> service that works at another process.
|
||||
@@ -45,23 +43,4 @@ public interface GradleApiFacade extends Remote {
|
||||
* @throws RemoteException in case of unexpected I/O exception during processing
|
||||
*/
|
||||
void applyProgressManager(@NotNull RemoteGradleProgressNotificationManager progressManager) throws RemoteException;
|
||||
|
||||
/**
|
||||
* Asks remote gradle process to check if a task with the given id is being executed right now.
|
||||
*
|
||||
* @param id target task's id
|
||||
* @return <code>true</code> if a task with the given id is executed at the moment; <code>false</code> otherwise
|
||||
* @throws RemoteException in case of unexpected I/O exception during processing
|
||||
*/
|
||||
boolean isTaskInProgress(@NotNull GradleTaskId id) throws RemoteException;
|
||||
|
||||
/**
|
||||
* Allows to ask remote gradle process for the ids of the tasks with the given type being executed now.
|
||||
*
|
||||
* @param type target task type
|
||||
* @return ids of the tasks of the target type being executed at the moment (if any)
|
||||
* @throws RemoteException in case of unexpected I/O exception during processing
|
||||
*/
|
||||
@NotNull
|
||||
Collection<GradleTaskId> getTasksInProgress(@NotNull GradleTaskType type) throws RemoteException;
|
||||
}
|
||||
|
||||
@@ -31,7 +31,9 @@ import com.intellij.util.containers.ContainerUtil;
|
||||
import gnu.trove.THashSet;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.plugins.gradle.notification.GradleProgressNotificationManager;
|
||||
import org.jetbrains.plugins.gradle.notification.GradleProgressNotificationManagerImpl;
|
||||
import org.jetbrains.plugins.gradle.remote.impl.GradleApiFacadeImpl;
|
||||
import org.jetbrains.plugins.gradle.remote.wrapper.GradleApiFacadeWrapper;
|
||||
import org.jetbrains.plugins.gradle.util.GradleBundle;
|
||||
import org.jetbrains.plugins.gradle.util.GradleLibraryManager;
|
||||
import org.jetbrains.plugins.gradle.util.GradleLog;
|
||||
@@ -69,8 +71,8 @@ public class GradleApiFacadeManager {
|
||||
private final AtomicReference<RemoteGradleProgressNotificationManager> myExportedProgressManager
|
||||
= new AtomicReference<RemoteGradleProgressNotificationManager>();
|
||||
|
||||
private final GradleLibraryManager myGradleLibraryManager;
|
||||
private final RemoteGradleProgressNotificationManager myProgressManager;
|
||||
@NotNull private final GradleLibraryManager myGradleLibraryManager;
|
||||
@NotNull private final GradleProgressNotificationManagerImpl myProgressManager;
|
||||
|
||||
// Please note that we don't use RemoteGradleProcessSettings as the 'Configuration' type parameter here because we need
|
||||
// to apply the settings to the newly created process. I.e. every time new process is created we need to call
|
||||
@@ -80,7 +82,7 @@ public class GradleApiFacadeManager {
|
||||
|
||||
public GradleApiFacadeManager(@NotNull GradleLibraryManager gradleLibraryManager, @NotNull GradleProgressNotificationManager manager) {
|
||||
myGradleLibraryManager = gradleLibraryManager;
|
||||
myProgressManager = (RemoteGradleProgressNotificationManager)manager;
|
||||
myProgressManager = (GradleProgressNotificationManagerImpl)manager;
|
||||
mySupport = new RemoteProcessSupport<Object, GradleApiFacade, Object>(GradleApiFacade.class) {
|
||||
@Override
|
||||
protected void fireModificationCountChanged() {
|
||||
@@ -223,10 +225,11 @@ public class GradleApiFacadeManager {
|
||||
myFacade.compareAndSet(pair, null);
|
||||
}
|
||||
|
||||
GradleApiFacade result = mySupport.acquire(this, "");
|
||||
if (result == null) {
|
||||
final GradleApiFacade facade = mySupport.acquire(this, "");
|
||||
if (facade == null) {
|
||||
throw new IllegalStateException("Can't obtain facade to working with gradle api at the remote process");
|
||||
}
|
||||
final GradleApiFacade result = new GradleApiFacadeWrapper(facade, myProgressManager);
|
||||
Pair<GradleApiFacade, RemoteGradleProcessSettings> newPair
|
||||
= new Pair<GradleApiFacade, RemoteGradleProcessSettings>(result, getRemoteSettings());
|
||||
if (!myFacade.compareAndSet(null, newPair)) {
|
||||
|
||||
+6
-1
@@ -18,6 +18,9 @@ import java.rmi.RemoteException;
|
||||
public interface RemoteGradleProgressNotificationManager extends Remote {
|
||||
|
||||
RemoteGradleProgressNotificationManager NULL_OBJECT = new RemoteGradleProgressNotificationManager() {
|
||||
@Override
|
||||
public void onQueued(@NotNull GradleTaskId id) throws RemoteException {
|
||||
}
|
||||
@Override
|
||||
public void onStart(@NotNull GradleTaskId id) {
|
||||
}
|
||||
@@ -28,7 +31,9 @@ public interface RemoteGradleProgressNotificationManager extends Remote {
|
||||
public void onEnd(@NotNull GradleTaskId id) {
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
void onQueued(@NotNull GradleTaskId id) throws RemoteException;
|
||||
|
||||
void onStart(@NotNull GradleTaskId id) throws RemoteException;
|
||||
|
||||
void onStatusChange(@NotNull GradleTaskNotificationEvent event) throws RemoteException;
|
||||
|
||||
@@ -2,12 +2,10 @@ package org.jetbrains.plugins.gradle.remote;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.plugins.gradle.notification.GradleTaskNotificationListener;
|
||||
import org.jetbrains.plugins.gradle.task.GradleTaskId;
|
||||
import org.jetbrains.plugins.gradle.task.GradleTaskType;
|
||||
import org.jetbrains.plugins.gradle.task.GradleTaskAware;
|
||||
|
||||
import java.rmi.Remote;
|
||||
import java.rmi.RemoteException;
|
||||
import java.util.Collection;
|
||||
|
||||
/**
|
||||
* Generic interface with common functionality for all remote services that work with gradle tooling api.
|
||||
@@ -15,28 +13,8 @@ import java.util.Collection;
|
||||
* @author Denis Zhdanov
|
||||
* @since 8/9/11 3:19 PM
|
||||
*/
|
||||
public interface RemoteGradleService extends Remote {
|
||||
public interface RemoteGradleService extends Remote, GradleTaskAware {
|
||||
|
||||
/**
|
||||
* Allows to check if current service executes the target task.
|
||||
*
|
||||
* @param id target task's id
|
||||
* @return <code>true</code> if a task with the given id is executed at the moment by the current service;
|
||||
* <code>false</code> otherwise
|
||||
* @throws RemoteException as required by RMI
|
||||
*/
|
||||
boolean isTaskInProgress(@NotNull GradleTaskId id) throws RemoteException;
|
||||
|
||||
/**
|
||||
* Allows to ask current service for the ids of the tasks with the given type being executed now.
|
||||
*
|
||||
* @param type target task type
|
||||
* @return ids of the tasks of the target type being executed at the moment by the current service (if any)
|
||||
* @throws RemoteException as required by RMI
|
||||
*/
|
||||
@NotNull
|
||||
Collection<GradleTaskId> getTasksInProgress(@NotNull GradleTaskType type) throws RemoteException;
|
||||
|
||||
/**
|
||||
* Provides the service settings to use.
|
||||
*
|
||||
|
||||
+20
-7
@@ -142,21 +142,30 @@ public class GradleApiFacadeImpl extends RemoteServer implements GradleApiFacade
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Collection<GradleTaskId> getTasksInProgress(@NotNull GradleTaskType type) throws RemoteException {
|
||||
Set<GradleTaskId> result = null;
|
||||
public Map<GradleTaskType, Set<GradleTaskId>> getTasksInProgress() throws RemoteException {
|
||||
Map<GradleTaskType, Set<GradleTaskId>> result = null;
|
||||
for (RemoteGradleService service : myRemotes.values()) {
|
||||
final Collection<GradleTaskId> tasks = service.getTasksInProgress(type);
|
||||
final Map<GradleTaskType, Set<GradleTaskId>> tasks = service.getTasksInProgress();
|
||||
if (tasks.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
if (result == null) {
|
||||
result = new HashSet<GradleTaskId>();
|
||||
result = new HashMap<GradleTaskType, Set<GradleTaskId>>();
|
||||
}
|
||||
for (Map.Entry<GradleTaskType, Set<GradleTaskId>> entry : tasks.entrySet()) {
|
||||
Set<GradleTaskId> ids = result.get(entry.getKey());
|
||||
if (ids == null) {
|
||||
result.put(entry.getKey(), ids = new HashSet<GradleTaskId>());
|
||||
}
|
||||
ids.addAll(entry.getValue());
|
||||
}
|
||||
result.addAll(tasks);
|
||||
}
|
||||
return result == null ? Collections.<GradleTaskId>emptySet() : result;
|
||||
if (result == null) {
|
||||
result = Collections.emptyMap();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void applySettings(@NotNull RemoteGradleProcessSettings settings) throws RemoteException {
|
||||
mySettings.set(settings);
|
||||
@@ -208,6 +217,10 @@ public class GradleApiFacadeImpl extends RemoteServer implements GradleApiFacade
|
||||
myManager = manager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onQueued(@NotNull GradleTaskId id) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStart(@NotNull GradleTaskId id) {
|
||||
try {
|
||||
|
||||
+4
-5
@@ -81,11 +81,10 @@ public class GradleProjectResolverImpl extends RemoteObject implements GradlePro
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Collection<GradleTaskId> getTasksInProgress(@NotNull GradleTaskType type) {
|
||||
if (type != GradleTaskType.RESOLVE_PROJECT || myTasksInProgress.isEmpty()) {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
return new HashSet<GradleTaskId>(myTasksInProgress);
|
||||
public Map<GradleTaskType, Set<GradleTaskId>> getTasksInProgress() throws RemoteException {
|
||||
Map<GradleTaskType, Set<GradleTaskId>> result = new HashMap<GradleTaskType, Set<GradleTaskId>>();
|
||||
result.put(GradleTaskType.RESOLVE_PROJECT, new HashSet<GradleTaskId>(myTasksInProgress));
|
||||
return result;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
|
||||
+62
@@ -0,0 +1,62 @@
|
||||
package org.jetbrains.plugins.gradle.remote.wrapper;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.plugins.gradle.notification.GradleProgressNotificationManagerImpl;
|
||||
import org.jetbrains.plugins.gradle.remote.GradleApiFacade;
|
||||
import org.jetbrains.plugins.gradle.remote.GradleProjectResolver;
|
||||
import org.jetbrains.plugins.gradle.remote.RemoteGradleProcessSettings;
|
||||
import org.jetbrains.plugins.gradle.remote.RemoteGradleProgressNotificationManager;
|
||||
import org.jetbrains.plugins.gradle.task.GradleTaskId;
|
||||
import org.jetbrains.plugins.gradle.task.GradleTaskType;
|
||||
|
||||
import java.rmi.RemoteException;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* This class acts as a point where target remote gradle services are proxied.
|
||||
* <p/>
|
||||
* Check service wrapper contracts for more details.
|
||||
* <p/>
|
||||
* Thread-safe.
|
||||
*
|
||||
* @author Denis Zhdanov
|
||||
* @since 2/8/12 7:21 PM
|
||||
*/
|
||||
public class GradleApiFacadeWrapper implements GradleApiFacade {
|
||||
|
||||
@NotNull private final GradleApiFacade myDelegate;
|
||||
@NotNull private final GradleProgressNotificationManagerImpl myNotificationManager;
|
||||
|
||||
public GradleApiFacadeWrapper(@NotNull GradleApiFacade delegate, @NotNull GradleProgressNotificationManagerImpl notificationManager) {
|
||||
myDelegate = delegate;
|
||||
myNotificationManager = notificationManager;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public GradleProjectResolver getResolver() throws RemoteException, IllegalStateException {
|
||||
return new GradleProjectResolverWrapper(myDelegate.getResolver(), myNotificationManager);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applySettings(@NotNull RemoteGradleProcessSettings settings) throws RemoteException {
|
||||
myDelegate.applySettings(settings);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applyProgressManager(@NotNull RemoteGradleProgressNotificationManager progressManager) throws RemoteException {
|
||||
myDelegate.applyProgressManager(progressManager);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isTaskInProgress(@NotNull GradleTaskId id) throws RemoteException {
|
||||
return myDelegate.isTaskInProgress(id);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Map<GradleTaskType, Set<GradleTaskId>> getTasksInProgress() throws RemoteException {
|
||||
return myDelegate.getTasksInProgress();
|
||||
}
|
||||
}
|
||||
+68
@@ -0,0 +1,68 @@
|
||||
package org.jetbrains.plugins.gradle.remote.wrapper;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.plugins.gradle.model.GradleProject;
|
||||
import org.jetbrains.plugins.gradle.notification.GradleProgressNotificationManagerImpl;
|
||||
import org.jetbrains.plugins.gradle.notification.GradleTaskNotificationListener;
|
||||
import org.jetbrains.plugins.gradle.remote.GradleApiException;
|
||||
import org.jetbrains.plugins.gradle.remote.GradleProjectResolver;
|
||||
import org.jetbrains.plugins.gradle.remote.RemoteGradleProcessSettings;
|
||||
import org.jetbrains.plugins.gradle.task.GradleTaskId;
|
||||
import org.jetbrains.plugins.gradle.task.GradleTaskManager;
|
||||
import org.jetbrains.plugins.gradle.task.GradleTaskType;
|
||||
|
||||
import java.rmi.RemoteException;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Intercepts calls to the target {@link GradleProjectResolver} and
|
||||
* {@link GradleTaskManager#onQueued(GradleTaskId) updates 'queued' task status}.
|
||||
* <p/>
|
||||
* Thread-safe.
|
||||
*
|
||||
* @author Denis Zhdanov
|
||||
* @since 2/8/12 7:21 PM
|
||||
*/
|
||||
public class GradleProjectResolverWrapper implements GradleProjectResolver {
|
||||
|
||||
@NotNull private final GradleProjectResolver myResolver;
|
||||
@NotNull private final GradleProgressNotificationManagerImpl myNotificationManager;
|
||||
|
||||
public GradleProjectResolverWrapper(@NotNull GradleProjectResolver resolver,
|
||||
@NotNull GradleProgressNotificationManagerImpl notificationManager)
|
||||
{
|
||||
myResolver = resolver;
|
||||
myNotificationManager = notificationManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public GradleProject resolveProjectInfo(@NotNull GradleTaskId id, @NotNull String projectPath, boolean downloadLibraries)
|
||||
throws RemoteException, GradleApiException, IllegalArgumentException, IllegalStateException
|
||||
{
|
||||
myNotificationManager.onQueued(id);
|
||||
return myResolver.resolveProjectInfo(id, projectPath, downloadLibraries);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSettings(@NotNull RemoteGradleProcessSettings settings) throws RemoteException {
|
||||
myResolver.setSettings(settings);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setNotificationListener(@NotNull GradleTaskNotificationListener notificationListener) throws RemoteException {
|
||||
myResolver.setNotificationListener(notificationListener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isTaskInProgress(@NotNull GradleTaskId id) throws RemoteException {
|
||||
return myResolver.isTaskInProgress(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public Map<GradleTaskType, Set<GradleTaskId>> getTasksInProgress() throws RemoteException {
|
||||
return myResolver.getTasksInProgress();
|
||||
}
|
||||
}
|
||||
+60
-2
@@ -1,10 +1,68 @@
|
||||
package org.jetbrains.plugins.gradle.sync;
|
||||
|
||||
import com.intellij.ProjectTopics;
|
||||
import com.intellij.openapi.components.AbstractProjectComponent;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.roots.ModuleRootEvent;
|
||||
import com.intellij.openapi.roots.ModuleRootListener;
|
||||
import com.intellij.util.Alarm;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.plugins.gradle.util.GradleUtil;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
|
||||
/**
|
||||
* // TODO den add doc
|
||||
* Detects project structure changes and triggers linked gradle project update.
|
||||
*
|
||||
* @author Denis Zhdanov
|
||||
* @since 11/3/11 3:57 PM
|
||||
*/
|
||||
public class GradleProjectStructureChangesDetector {
|
||||
public class GradleProjectStructureChangesDetector extends AbstractProjectComponent {
|
||||
|
||||
private static final int REFRESH_DELAY_MILLIS = (int)TimeUnit.SECONDS.toMillis(2);
|
||||
|
||||
private final Alarm myAlarm = new Alarm(Alarm.ThreadToUse.SHARED_THREAD);
|
||||
private final AtomicLong myStartRefreshTime = new AtomicLong();
|
||||
private final RefreshRequest myRequest = new RefreshRequest();
|
||||
|
||||
public GradleProjectStructureChangesDetector(@NotNull Project project) {
|
||||
super(project);
|
||||
subscribeToRootChanges(project);
|
||||
}
|
||||
|
||||
private void subscribeToRootChanges(@NotNull Project project) {
|
||||
project.getMessageBus().connect(project).subscribe(ProjectTopics.PROJECT_ROOTS, new ModuleRootListener() {
|
||||
@Override
|
||||
public void beforeRootsChange(ModuleRootEvent event) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void rootsChanged(ModuleRootEvent event) {
|
||||
scheduleUpdate();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void scheduleUpdate() {
|
||||
myStartRefreshTime.set(System.currentTimeMillis() + REFRESH_DELAY_MILLIS);
|
||||
myAlarm.cancelAllRequests();
|
||||
myAlarm.addRequest(myRequest, REFRESH_DELAY_MILLIS + 16);
|
||||
}
|
||||
|
||||
private class RefreshRequest implements Runnable {
|
||||
@Override
|
||||
public void run() {
|
||||
if (!myProject.isInitialized()) {
|
||||
return;
|
||||
}
|
||||
myAlarm.cancelAllRequests();
|
||||
final long diff = System.currentTimeMillis() - myStartRefreshTime.get();
|
||||
if (diff < 0) {
|
||||
myAlarm.addRequest(this, (int)-diff);
|
||||
return;
|
||||
}
|
||||
GradleUtil.refreshProject(myProject);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -96,7 +96,7 @@ public abstract class AbstractGradleTask implements GradleTask {
|
||||
}
|
||||
finally {
|
||||
for (GradleTaskNotificationListener listener : listeners) {
|
||||
progressManager.addNotificationListener(getId(), listener);
|
||||
progressManager.removeNotificationListener(listener);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
package org.jetbrains.plugins.gradle.task;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.rmi.RemoteException;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Represents service that exposes information about the tasks being processed.
|
||||
*
|
||||
* @author Denis Zhdanov
|
||||
* @since 2/8/12 1:46 PM
|
||||
*/
|
||||
public interface GradleTaskAware {
|
||||
|
||||
/**
|
||||
* Allows to check if current service executes the target task.
|
||||
*
|
||||
* @param id target task's id
|
||||
* @return <code>true</code> if a task with the given id is executed at the moment by the current service;
|
||||
* <code>false</code> otherwise
|
||||
* @throws RemoteException as required by RMI
|
||||
*/
|
||||
boolean isTaskInProgress(@NotNull GradleTaskId id) throws RemoteException;
|
||||
|
||||
/**
|
||||
* Allows to ask current service for all tasks being executed at the moment.
|
||||
*
|
||||
* @return ids of all tasks being executed at the moment grouped by type
|
||||
* @throws RemoteException as required by RMI
|
||||
*/
|
||||
@NotNull
|
||||
Map<GradleTaskType, Set<GradleTaskId>> getTasksInProgress() throws RemoteException;
|
||||
}
|
||||
@@ -0,0 +1,121 @@
|
||||
package org.jetbrains.plugins.gradle.task;
|
||||
|
||||
import com.intellij.util.Alarm;
|
||||
import com.intellij.util.containers.ConcurrentHashMap;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.plugins.gradle.notification.GradleProgressNotificationManager;
|
||||
import org.jetbrains.plugins.gradle.notification.GradleTaskNotificationEvent;
|
||||
import org.jetbrains.plugins.gradle.notification.GradleTaskNotificationListener;
|
||||
import org.jetbrains.plugins.gradle.remote.GradleApiFacadeManager;
|
||||
import org.jetbrains.plugins.gradle.util.GradleLog;
|
||||
import org.jetbrains.plugins.gradle.util.GradleUtil;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* Provides gradle tasks monitoring and management facilities.
|
||||
* <p/>
|
||||
* Thread-safe.
|
||||
*
|
||||
* @author Denis Zhdanov
|
||||
* @since 2/8/12 1:52 PM
|
||||
*/
|
||||
public class GradleTaskManager implements GradleTaskNotificationListener {
|
||||
|
||||
/**
|
||||
* We receive information about the tasks being enqueued to the slave gradle projects here. However, there is a possible
|
||||
* situation when particular task has been sent to execution but remote side has not been responding for a while. There at least
|
||||
* two possible explanations then:
|
||||
* <pre>
|
||||
* <ul>
|
||||
* <li>The task is still in progress (e.g. great number of libraries is being downloaded);</li>
|
||||
* <li>Remote side has fallen (uncaught exception; manual slave gradle process kill etc);</li>
|
||||
* </ul>
|
||||
* </pre>
|
||||
* We need to distinguish between them, so, we perform 'task pings' if any task is executed too long. Current constant holds
|
||||
* criteria of 'too long execution'.
|
||||
*/
|
||||
private static final long REFRESH_DELAY_MILLIS = TimeUnit.SECONDS.toMillis(10);
|
||||
private static final int DETECT_HANGED_TASKS_FREQUENCY_MILLIS = (int)TimeUnit.SECONDS.toMillis(5);
|
||||
|
||||
@NotNull private final ConcurrentMap<GradleTaskId, Long> myTasksInProgress = new ConcurrentHashMap<GradleTaskId, Long>();
|
||||
@NotNull private final Alarm myAlarm = new Alarm(Alarm.ThreadToUse.SHARED_THREAD);
|
||||
|
||||
@NotNull private final GradleApiFacadeManager myFacadeManager;
|
||||
|
||||
public GradleTaskManager(@NotNull GradleApiFacadeManager facadeManager, @NotNull GradleProgressNotificationManager notificationManager) {
|
||||
myFacadeManager = facadeManager;
|
||||
notificationManager.addNotificationListener(this);
|
||||
myAlarm.addRequest(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
for (Long limit : myTasksInProgress.values()) {
|
||||
if (limit <= System.currentTimeMillis()) {
|
||||
update();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
finally {
|
||||
myAlarm.cancelAllRequests();
|
||||
myAlarm.addRequest(this, DETECT_HANGED_TASKS_FREQUENCY_MILLIS);
|
||||
}
|
||||
}
|
||||
}, DETECT_HANGED_TASKS_FREQUENCY_MILLIS);
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows to check if any task of the given type is being executed at the moment.
|
||||
*
|
||||
* @param type target task type
|
||||
* @return <code>true</code> if any task of the given type is being executed at the moment;
|
||||
* <code>false</code> otherwise
|
||||
*/
|
||||
public boolean hasTaskOfTypeInProgress(@NotNull GradleTaskType type) {
|
||||
for (GradleTaskId id : myTasksInProgress.keySet()) {
|
||||
if (type.equals(id.getType())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onQueued(@NotNull GradleTaskId id) {
|
||||
myTasksInProgress.put(id, System.currentTimeMillis() + REFRESH_DELAY_MILLIS);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStart(@NotNull GradleTaskId id) {
|
||||
myTasksInProgress.put(id, System.currentTimeMillis() + REFRESH_DELAY_MILLIS);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStatusChange(@NotNull GradleTaskNotificationEvent event) {
|
||||
myTasksInProgress.put(event.getId(), System.currentTimeMillis() + REFRESH_DELAY_MILLIS);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEnd(@NotNull GradleTaskId id) {
|
||||
myTasksInProgress.remove(id);
|
||||
}
|
||||
|
||||
public void update() {
|
||||
try {
|
||||
final Map<GradleTaskType, Set<GradleTaskId>> currentState = myFacadeManager.getFacade().getTasksInProgress();
|
||||
myTasksInProgress.clear();
|
||||
for (Set<GradleTaskId> ids : currentState.values()) {
|
||||
for (GradleTaskId id : ids) {
|
||||
myTasksInProgress.put(id, System.currentTimeMillis() + REFRESH_DELAY_MILLIS);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
GradleLog.LOG.warn(String.format("Can't refresh active tasks. Reason: %s", GradleUtil.buildErrorMessage(e)));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,21 +1,36 @@
|
||||
package org.jetbrains.plugins.gradle.util;
|
||||
|
||||
import com.intellij.execution.rmi.RemoteUtil;
|
||||
import com.intellij.ide.actions.OpenProjectFileChooserDescriptor;
|
||||
import com.intellij.openapi.fileChooser.FileChooserDescriptor;
|
||||
import com.intellij.openapi.fileChooser.FileTypeDescriptor;
|
||||
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.ui.MessageType;
|
||||
import com.intellij.openapi.ui.popup.Balloon;
|
||||
import com.intellij.openapi.ui.popup.BalloonBuilder;
|
||||
import com.intellij.openapi.ui.popup.JBPopupFactory;
|
||||
import com.intellij.openapi.util.Ref;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.ui.awt.RelativePoint;
|
||||
import com.intellij.util.PathUtil;
|
||||
import com.intellij.util.ui.UIUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.plugins.gradle.config.GradleSettings;
|
||||
import org.jetbrains.plugins.gradle.model.GradleProject;
|
||||
import org.jetbrains.plugins.gradle.remote.GradleApiException;
|
||||
import org.jetbrains.plugins.gradle.task.GradleResolveProjectTask;
|
||||
import org.jetbrains.plugins.gradle.ui.GradleIcons;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
import java.io.File;
|
||||
import java.io.PrintWriter;
|
||||
import java.io.StringWriter;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
@@ -26,27 +41,6 @@ import java.util.concurrent.TimeUnit;
|
||||
*/
|
||||
public class GradleUtil {
|
||||
|
||||
/**
|
||||
* We use this class in order to avoid static initialisation of the wrapped object - it loads number of pico container-based
|
||||
* dependencies that are unavailable to the slave gradle project, so, we don't want to get unexpected NPE there.
|
||||
*/
|
||||
private static class DescriptorHolder {
|
||||
public static final FileChooserDescriptor GRADLE_BUILD_FILE_CHOOSER_DESCRIPTOR = new OpenProjectFileChooserDescriptor(true) {
|
||||
@Override
|
||||
public boolean isFileSelectable(VirtualFile file) {
|
||||
return GradleConstants.DEFAULT_SCRIPT_NAME.equals(file.getName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isFileVisible(VirtualFile file, boolean showHiddenFiles) {
|
||||
if (!super.isFileVisible(file, showHiddenFiles)) {
|
||||
return false;
|
||||
}
|
||||
return file.isDirectory() || GradleConstants.EXTENSION.equals(file.getExtension());
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private GradleUtil() {
|
||||
}
|
||||
|
||||
@@ -96,4 +90,133 @@ public class GradleUtil {
|
||||
}
|
||||
balloon.show(new RelativePoint(component, new Point(x, y)), position);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delegates to the {@link #refreshProject(Project, String, Ref, boolean, boolean)} with the following defaults:
|
||||
* <pre>
|
||||
* <ul>
|
||||
* <li>target gradle project path is retrieved from the {@link GradleSettings gradle settings} associated with the given project;</li>
|
||||
* <li>refresh process is run in background;</li>
|
||||
* <li>any problem occurred during the refresh is reported to the {@link GradleLog#LOG};</li>
|
||||
* </ul>
|
||||
* </pre>
|
||||
*
|
||||
* @param project target intellij project to use
|
||||
*/
|
||||
public static void refreshProject(@NotNull Project project) {
|
||||
final GradleSettings settings = GradleSettings.getInstance(project);
|
||||
final String linkedProjectPath = settings.LINKED_PROJECT_FILE_PATH;
|
||||
if (StringUtil.isEmpty(linkedProjectPath)) {
|
||||
return;
|
||||
}
|
||||
Ref<String> errorHolder = new Ref<String>();
|
||||
refreshProject(project, linkedProjectPath, errorHolder, true, false);
|
||||
final String error = errorHolder.get();
|
||||
if (!StringUtil.isEmpty(error)) {
|
||||
GradleLog.LOG.warn(error);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link RemoteUtil#unwrap(Throwable) unwraps} given exception if possible and builds error message for it.
|
||||
*
|
||||
* @param e exception to process
|
||||
* @return error message for the given exception
|
||||
*/
|
||||
@SuppressWarnings({"ThrowableResultOfMethodCallIgnored", "IOResourceOpenedButNotSafelyClosed"})
|
||||
public static String buildErrorMessage(@NotNull Throwable e) {
|
||||
Throwable unwrapped = RemoteUtil.unwrap(e);
|
||||
String reason = unwrapped.getLocalizedMessage();
|
||||
if (!StringUtil.isEmpty(reason)) {
|
||||
return reason;
|
||||
}
|
||||
else if (unwrapped.getClass() == GradleApiException.class) {
|
||||
return String.format("gradle api threw an exception: %s", ((GradleApiException)unwrapped).getOriginalReason());
|
||||
}
|
||||
else {
|
||||
StringWriter writer = new StringWriter();
|
||||
unwrapped.printStackTrace(new PrintWriter(writer));
|
||||
return writer.toString();
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Queries slave gradle process to refresh target gradle project.
|
||||
*
|
||||
* @param project target intellij project to use
|
||||
* @param gradleProjectPath path of the target gradle project's file
|
||||
* @param errorHolder holder for the error message that describes a problem occurred during the refresh (if any)
|
||||
* @param resolveLibraries flag that identifies whether gradle libraries should be resolved during the refresh
|
||||
* @return the most up-to-date gradle project (if any)
|
||||
*/
|
||||
@Nullable
|
||||
public static GradleProject refreshProject(@NotNull final Project project,
|
||||
@NotNull final String gradleProjectPath,
|
||||
@NotNull final Ref<String> errorHolder,
|
||||
final boolean resolveLibraries,
|
||||
final boolean modal)
|
||||
{
|
||||
final Ref<GradleProject> gradleProject = new Ref<GradleProject>();
|
||||
final TaskUnderProgress task = new TaskUnderProgress() {
|
||||
@SuppressWarnings({"ThrowableResultOfMethodCallIgnored", "IOResourceOpenedButNotSafelyClosed"})
|
||||
@Override
|
||||
public void execute(@NotNull ProgressIndicator indicator) {
|
||||
GradleResolveProjectTask task = new GradleResolveProjectTask(project, gradleProjectPath, resolveLibraries);
|
||||
task.execute(indicator);
|
||||
gradleProject.set(task.getProject());
|
||||
final Throwable error = task.getError();
|
||||
if (error == null) {
|
||||
return;
|
||||
}
|
||||
final String message = buildErrorMessage(error);
|
||||
errorHolder.set(String.format("Can't resolve gradle project at '%s'. Reason: %s", gradleProjectPath, message));
|
||||
}
|
||||
};
|
||||
UIUtil.invokeAndWaitIfNeeded(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (modal) {
|
||||
ProgressManager.getInstance().run(new Task.Modal(project, GradleBundle.message("gradle.import.progress.text"), true) {
|
||||
@Override
|
||||
public void run(@NotNull ProgressIndicator indicator) {
|
||||
task.execute(indicator);
|
||||
}
|
||||
});
|
||||
}
|
||||
else {
|
||||
ProgressManager.getInstance().run(new Task.Backgroundable(project, GradleBundle.message("gradle.sync.progress.text")) {
|
||||
@Override
|
||||
public void run(@NotNull ProgressIndicator indicator) {
|
||||
task.execute(indicator);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
return gradleProject.get();
|
||||
}
|
||||
|
||||
private interface TaskUnderProgress {
|
||||
void execute(@NotNull ProgressIndicator indicator);
|
||||
}
|
||||
|
||||
/**
|
||||
* We use this class in order to avoid static initialisation of the wrapped object - it loads number of pico container-based
|
||||
* dependencies that are unavailable to the slave gradle project, so, we don't want to get unexpected NPE there.
|
||||
*/
|
||||
private static class DescriptorHolder {
|
||||
public static final FileChooserDescriptor GRADLE_BUILD_FILE_CHOOSER_DESCRIPTOR = new OpenProjectFileChooserDescriptor(true) {
|
||||
@Override
|
||||
public boolean isFileSelectable(VirtualFile file) {
|
||||
return GradleConstants.DEFAULT_SCRIPT_NAME.equals(file.getName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isFileVisible(VirtualFile file, boolean showHiddenFiles) {
|
||||
if (!super.isFileVisible(file, showHiddenFiles)) {
|
||||
return false;
|
||||
}
|
||||
return file.isDirectory() || GradleConstants.EXTENSION.equals(file.getExtension());
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user