aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJens Baumgart2010-05-06 11:28:23 (EDT)
committerChris Aniszczyk2010-05-07 01:52:42 (EDT)
commit3643937dec912c8da636e659c75b587b2bcd3d19 (patch)
treedfc73acdac0d2c74cebf52334cf605fd9e772d79
parentde6da8e38d81eba100149e2d9e37326d2e0f9f43 (diff)
downloadegit-3643937dec912c8da636e659c75b587b2bcd3d19.zip
egit-3643937dec912c8da636e659c75b587b2bcd3d19.tar.gz
egit-3643937dec912c8da636e659c75b587b2bcd3d19.tar.bz2
Improve DiscardChangesActionrefs/changes/50/650/3
Currently DiscardChangesAction (Trigger: Replace With->File in Git Index) runs in the UI thread. This might block the UI. Furthermore the discard operation is located in the action. Now DiscardChangesAction uses a Job to execute. The discard operation was moved in a new class DiscardChangesOperation. Change-Id: I06fe4efa096ae4ca6b1110c2f7259243e1d2c99d Signed-off-by: Jens Baumgart <jens.baumgart@sap.com> Signed-off-by: Chris Aniszczyk <caniszczyk@gmail.com>
-rw-r--r--org.eclipse.egit.core/src/org/eclipse/egit/core/CoreText.java21
-rw-r--r--org.eclipse.egit.core/src/org/eclipse/egit/core/coretext.properties7
-rw-r--r--org.eclipse.egit.core/src/org/eclipse/egit/core/internal/util/ProjectUtil.java29
-rw-r--r--org.eclipse.egit.core/src/org/eclipse/egit/core/op/DiscardChangesOperation.java212
-rw-r--r--org.eclipse.egit.ui/src/org/eclipse/egit/ui/UIText.java3
-rw-r--r--org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/actions/DiscardChangesAction.java117
-rw-r--r--org.eclipse.egit.ui/src/org/eclipse/egit/ui/uitext.properties1
7 files changed, 298 insertions, 92 deletions
diff --git a/org.eclipse.egit.core/src/org/eclipse/egit/core/CoreText.java b/org.eclipse.egit.core/src/org/eclipse/egit/core/CoreText.java
index 1624d60..9de35c9 100644
--- a/org.eclipse.egit.core/src/org/eclipse/egit/core/CoreText.java
+++ b/org.eclipse.egit.core/src/org/eclipse/egit/core/CoreText.java
@@ -47,6 +47,24 @@ public class CoreText extends NLS {
public static String ConnectProviderOperation_ConnectingProject;
/** */
+ public static String DiscardChangesOperation_discardFailed;
+
+ /** */
+ public static String DiscardChangesOperation_discardFailedSeeLog;
+
+ /** */
+ public static String DiscardChangesOperation_discardingChanges;
+
+ /** */
+ public static String DiscardChangesOperation_refreshFailed;
+
+ /** */
+ public static String DiscardChangesOperation_repoNotFound;
+
+ /** */
+ public static String DiscardChangesOperation_writeIndexFailed;
+
+ /** */
public static String DisconnectProviderOperation_disconnecting;
/** */
@@ -191,6 +209,9 @@ public class CoreText extends NLS {
public static String ProjectUtil_refreshingProjects;
/** */
+ public static String ProjectUtil_refreshing;
+
+ /** */
public static String PushOperation_resultCancelled;
/** */
diff --git a/org.eclipse.egit.core/src/org/eclipse/egit/core/coretext.properties b/org.eclipse.egit.core/src/org/eclipse/egit/core/coretext.properties
index 576d730..1076c64 100644
--- a/org.eclipse.egit.core/src/org/eclipse/egit/core/coretext.properties
+++ b/org.eclipse.egit.core/src/org/eclipse/egit/core/coretext.properties
@@ -12,6 +12,12 @@ CommitFileRevision_errorLookingUpPath=IO error looking up path {1} in {0}.
ConnectProviderOperation_connecting=Connecting Git team provider.
ConnectProviderOperation_ConnectingProject=Connecting project {0}
+DiscardChangesOperation_discardFailed=Discarding changes of {0} failed
+DiscardChangesOperation_discardFailedSeeLog=Discarding changes failed. See log for details
+DiscardChangesOperation_discardingChanges=Discarding changes
+DiscardChangesOperation_refreshFailed=Refreshing resources failed
+DiscardChangesOperation_repoNotFound=Repository not found
+DiscardChangesOperation_writeIndexFailed=Writing index failed
DisconnectProviderOperation_disconnecting=Disconnecting Git team provider.
UpdateJob_updatingIndex=Update index
@@ -79,6 +85,7 @@ IndexFileRevision_indexEntryNotFound=Git index entry for path {1} not found
ListRemoteOperation_title=Getting remote branches information
ProjectUtil_refreshingProjects=Refreshing projects
+ProjectUtil_refreshing=Refreshing
PushOperation_resultCancelled=Operation was cancelled.
PushOperation_resultNotSupported=Can't push to {0}
PushOperation_resultTransportError=Transport error occured during push operation: {0}
diff --git a/org.eclipse.egit.core/src/org/eclipse/egit/core/internal/util/ProjectUtil.java b/org.eclipse.egit.core/src/org/eclipse/egit/core/internal/util/ProjectUtil.java
index 246b504..8585f19 100644
--- a/org.eclipse.egit.core/src/org/eclipse/egit/core/internal/util/ProjectUtil.java
+++ b/org.eclipse.egit.core/src/org/eclipse/egit/core/internal/util/ProjectUtil.java
@@ -21,7 +21,7 @@ import org.eclipse.jgit.lib.Repository;
/**
* This class contains utility methods related to projects
- *
+ * TODO: rename to RefreshUtil or ResourceUtil?
*/
public class ProjectUtil {
/**
@@ -53,4 +53,31 @@ public class ProjectUtil {
monitor.done();
}
}
+
+ /**
+ * The method refreshes resources
+ *
+ * @param resources
+ * resources to refresh
+ * @param monitor
+ * @throws CoreException
+ */
+ public static void refreshResources(IResource[] resources,
+ IProgressMonitor monitor) throws CoreException {
+ try {
+ monitor.beginTask(CoreText.ProjectUtil_refreshing,
+ resources.length);
+ for (IResource resource : resources) {
+ if (monitor.isCanceled())
+ break;
+ resource.refreshLocal(IResource.DEPTH_INFINITE,
+ new SubProgressMonitor(monitor, 1));
+ monitor.worked(1);
+ }
+ } finally {
+ monitor.done();
+ }
+
+ }
+
}
diff --git a/org.eclipse.egit.core/src/org/eclipse/egit/core/op/DiscardChangesOperation.java b/org.eclipse.egit.core/src/org/eclipse/egit/core/op/DiscardChangesOperation.java
new file mode 100644
index 0000000..8dd576e
--- /dev/null
+++ b/org.eclipse.egit.core/src/org/eclipse/egit/core/op/DiscardChangesOperation.java
@@ -0,0 +1,212 @@
+/*******************************************************************************
+ * Copyright (C) 2010, Jens Baumgart <jens.baumgart@sap.com>
+ * Copyright (C) 2010, Roland Grunberg <rgrunber@redhat.com>
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Code extracted from org.eclipse.egit.ui.internal.actions.DiscardChangesAction
+ * and reworked.
+ *******************************************************************************/
+package org.eclipse.egit.core.op;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.eclipse.core.resources.IContainer;
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.resources.IResourceRuleFactory;
+import org.eclipse.core.resources.IWorkspace;
+import org.eclipse.core.resources.IWorkspaceRunnable;
+import org.eclipse.core.resources.ResourcesPlugin;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.SubProgressMonitor;
+import org.eclipse.core.runtime.jobs.ISchedulingRule;
+import org.eclipse.core.runtime.jobs.MultiRule;
+import org.eclipse.egit.core.Activator;
+import org.eclipse.egit.core.CoreText;
+import org.eclipse.egit.core.internal.util.ProjectUtil;
+import org.eclipse.egit.core.project.RepositoryMapping;
+import org.eclipse.jgit.lib.GitIndex;
+import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.lib.GitIndex.Entry;
+import org.eclipse.osgi.util.NLS;
+
+/**
+ * The operation discards changes on a set of resources. In case of a folder
+ * resource all file resources in the sub tree are processed.
+ */
+public class DiscardChangesOperation implements IEGitOperation {
+
+ IResource[] files;
+
+ ISchedulingRule schedulingRule;
+
+ /**
+ * Construct a {@link DiscardChangesOperation} object.
+ *
+ * @param files
+ */
+ public DiscardChangesOperation(IResource[] files) {
+ this.files = files;
+ schedulingRule = calcRefreshRule(files);
+ }
+
+ /**
+ * @return the rule needed to execute this operation
+ */
+ public ISchedulingRule getSchedulingRule() {
+ return schedulingRule;
+ }
+
+ private static ISchedulingRule calcRefreshRule(IResource[] resources) {
+ List<ISchedulingRule> rules = new ArrayList<ISchedulingRule>();
+ IResourceRuleFactory ruleFactory = ResourcesPlugin.getWorkspace()
+ .getRuleFactory();
+ for (IResource resource : resources) {
+ ISchedulingRule rule = ruleFactory.refreshRule(resource);
+ if (rule != null)
+ rules.add(rule);
+ }
+ if (rules.size() == 0)
+ return null;
+ else
+ return new MultiRule(rules.toArray(new IResource[rules.size()]));
+ }
+
+ public void execute(IProgressMonitor monitor) throws CoreException {
+ IWorkspaceRunnable action = new IWorkspaceRunnable() {
+ public void run(IProgressMonitor monitor) throws CoreException {
+ discardChanges(monitor);
+ }
+ };
+ ResourcesPlugin.getWorkspace().run(action, getSchedulingRule(),
+ IWorkspace.AVOID_UPDATE, monitor);
+ }
+
+ private void discardChanges(IProgressMonitor monitor) throws CoreException {
+ monitor.beginTask(CoreText.DiscardChangesOperation_discardingChanges, 3);
+ boolean errorOccured = false;
+ List<IResource> allFiles = new ArrayList<IResource>();
+ // find all files
+ for (IResource res : files) {
+ allFiles.addAll(getAllMembers(res));
+ }
+ Set<GitIndex> modifiedIndexes = new HashSet<GitIndex>();
+ for (IResource res : allFiles) {
+ Repository repo = getRepository(res);
+ if (repo == null) {
+ IStatus status = Activator.error(
+ CoreText.DiscardChangesOperation_repoNotFound, null);
+ throw new CoreException(status);
+ }
+ try {
+ discardChange(res, repo, modifiedIndexes);
+ } catch (IOException e) {
+ errorOccured = true;
+ String message = NLS.bind(
+ CoreText.DiscardChangesOperation_discardFailed, res
+ .getFullPath());
+ Activator.logError(message, e);
+ }
+ }
+ monitor.worked(1);
+ for (GitIndex index : modifiedIndexes) {
+ try {
+ index.write();
+ } catch (IOException e) {
+ errorOccured = true;
+ Activator.logError(
+ CoreText.DiscardChangesOperation_writeIndexFailed, e);
+ }
+ }
+ monitor.worked(1);
+ try {
+ ProjectUtil.refreshResources(files, new SubProgressMonitor(monitor,
+ 1));
+ } catch (CoreException e) {
+ errorOccured = true;
+ Activator.logError(CoreText.DiscardChangesOperation_refreshFailed,
+ e);
+ }
+ monitor.worked(1);
+ monitor.done();
+ if (errorOccured) {
+ IStatus status = Activator.error(
+ CoreText.DiscardChangesOperation_discardFailedSeeLog, null);
+ throw new CoreException(status);
+ }
+ }
+
+ private static Repository getRepository(IResource resource) {
+ IProject project = resource.getProject();
+ RepositoryMapping repositoryMapping = RepositoryMapping
+ .getMapping(project);
+ if (repositoryMapping != null)
+ return repositoryMapping.getRepository();
+ else
+ return null;
+ }
+
+ private void discardChange(IResource res, Repository repository,
+ Set<GitIndex> modifiedIndexes) throws IOException {
+ String resRelPath = RepositoryMapping.getMapping(res)
+ .getRepoRelativePath(res);
+
+ Entry e = repository.getIndex().getEntry(resRelPath);
+ // resource must exist in the index and be dirty
+ if (e != null && e.getStage() == 0
+ && e.isModified(repository.getWorkDir())) {
+ GitIndex index = repository.getIndex();
+ index.checkoutEntry(repository.getWorkDir(), e);
+ modifiedIndexes.add(index);
+ }
+ }
+
+ /**
+ * @param res
+ * an IResource
+ * @return An ArrayList with all members of this IResource of arbitrary
+ * depth. This will return just the argument res if it is a file.
+ */
+ private ArrayList<IResource> getAllMembers(IResource res) {
+ ArrayList<IResource> ret = new ArrayList<IResource>();
+ if (res.getLocation().toFile().isFile()) {
+ ret.add(res);
+ } else {
+ getAllMembersHelper(res, ret);
+ }
+ return ret;
+ }
+
+ private void getAllMembersHelper(IResource res, ArrayList<IResource> ret) {
+ if (res instanceof IContainer) {
+ ArrayList<IResource> tmp = new ArrayList<IResource>();
+ IContainer cont = (IContainer) res;
+ try {
+ for (IResource r : cont.members()) {
+ if (r.getLocation().toFile().isFile()) {
+ tmp.add(r);
+ } else {
+ getAllMembersHelper(r, tmp);
+ }
+ }
+ } catch (CoreException e) {
+ // thrown by members()
+ // ignore children in case parent resource no longer accessible
+ return;
+ }
+
+ ret.addAll(tmp);
+ }
+ }
+
+}
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/UIText.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/UIText.java
index 2ce6989..1c20907 100644
--- a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/UIText.java
+++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/UIText.java
@@ -1723,6 +1723,9 @@ public class UIText extends NLS {
public static String DiscardChangesAction_confirmActionMessage;
/** */
+ public static String DiscardChangesAction_discardChanges;
+
+ /** */
public static String DiscardChangesAction_unexpectedErrorTitle;
/** */
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/actions/DiscardChangesAction.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/actions/DiscardChangesAction.java
index a169a7d..c2ca63e 100644
--- a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/actions/DiscardChangesAction.java
+++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/actions/DiscardChangesAction.java
@@ -8,27 +8,25 @@
*******************************************************************************/
package org.eclipse.egit.ui.internal.actions;
-import java.io.IOException;
-import java.util.ArrayList;
-
-import org.eclipse.core.resources.IContainer;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.CoreException;
-import org.eclipse.core.runtime.NullProgressMonitor;
-import org.eclipse.egit.core.project.RepositoryMapping;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.core.runtime.jobs.Job;
+import org.eclipse.egit.core.op.DiscardChangesOperation;
import org.eclipse.egit.ui.Activator;
import org.eclipse.egit.ui.UIText;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.lib.RepositoryState;
-import org.eclipse.jgit.lib.GitIndex.Entry;
/**
* Checkout all selected dirty files.
*/
-public class DiscardChangesAction extends RepositoryAction{
+public class DiscardChangesAction extends RepositoryAction {
@Override
public void execute(IAction action) {
@@ -36,50 +34,26 @@ public class DiscardChangesAction extends RepositoryAction{
boolean performAction = MessageDialog.openConfirm(getShell(),
UIText.DiscardChangesAction_confirmActionTitle,
UIText.DiscardChangesAction_confirmActionMessage);
- if (performAction) {
- performDiscardChanges();
- }
- }
-
- private void performDiscardChanges() {
- ArrayList<IResource> allFiles = new ArrayList<IResource>();
-
- // find all files
- for (IResource res : getSelectedResources()) {
- allFiles.addAll(getAllMembers(res));
- }
-
- for (IResource res : allFiles) {
- try {
- discardChange(res);
- } catch (IOException e1) {
- Activator.handleError(UIText.DiscardChangesAction_unexpectedErrorMessage, e1, true);
- }catch (RuntimeException e2) {
- Activator.handleError(UIText.DiscardChangesAction_unexpectedIndexErrorMessage, e2, true);
- }
- }
-
- }
-
- private void discardChange(IResource res) throws IOException {
- IProject[] proj = new IProject[] { res.getProject() };
- Repository repository = getRepositoriesFor(proj)[0];
-
- String resRelPath = RepositoryMapping.getMapping(res).getRepoRelativePath(res);
- Entry e = repository.getIndex().getEntry(resRelPath);
-
- // resource must exist in the index and be dirty
- if (e != null && e.getStage() == 0 && e.isModified(repository.getWorkDir())) {
- repository.getIndex().checkoutEntry(repository.getWorkDir(), e);
-
- try {
- res.refreshLocal(0, new NullProgressMonitor());
- } catch (CoreException e1) {
- Activator.handleError(UIText.DiscardChangesAction_refreshErrorMessage, e1, true);
+ if (!performAction)
+ return;
+ final DiscardChangesOperation operation = new DiscardChangesOperation(
+ getSelectedResources());
+ String jobname = UIText.DiscardChangesAction_discardChanges;
+ Job job = new Job(jobname) {
+ @Override
+ protected IStatus run(IProgressMonitor monitor) {
+ try {
+ operation.execute(monitor);
+ } catch (CoreException e) {
+ return Activator.createErrorStatus(e.getStatus()
+ .getMessage(), e);
+ }
+ return Status.OK_STATUS;
}
-
- repository.getIndex().write();
- }
+ };
+ job.setUser(true);
+ job.setRule(operation.getSchedulingRule());
+ job.schedule();
}
@Override
@@ -87,50 +61,11 @@ public class DiscardChangesAction extends RepositoryAction{
for (IResource res : getSelectedResources()) {
IProject[] proj = new IProject[] { res.getProject() };
Repository repository = getRepositoriesFor(proj)[0];
- if (! repository.getRepositoryState().equals(RepositoryState.SAFE)){
+ if (!repository.getRepositoryState().equals(RepositoryState.SAFE)) {
return false;
}
}
return true;
}
- /**
- * @param res an IResource
- * @return An ArrayList with all members of this IResource
- * of arbitrary depth. This will return just the argument
- * res if it is a file.
- */
- private ArrayList<IResource> getAllMembers(IResource res) {
- ArrayList<IResource> ret = new ArrayList<IResource>();
- if (res.getLocation().toFile().isFile()) {
- ret.add(res);
- } else {
- getAllMembersHelper(res, ret);
- }
- return ret;
- }
-
-
- private void getAllMembersHelper(IResource res, ArrayList<IResource> ret) {
- ArrayList<IResource> tmp = new ArrayList<IResource> ();
- if (res instanceof IContainer) {
- IContainer cont = (IContainer) res;
- try {
- for (IResource r : cont.members()) {
- if (r.getLocation().toFile().isFile()) {
- tmp.add(r);
- } else {
- getAllMembersHelper(r, tmp);
- }
- }
- } catch (CoreException e) {
- // thrown by members()
- // ignore children in case parent resource no longer accessible
- return;
- }
-
- ret.addAll(tmp);
- }
- }
-
}
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/uitext.properties b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/uitext.properties
index f91a848..6139155 100644
--- a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/uitext.properties
+++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/uitext.properties
@@ -616,6 +616,7 @@ RepositoriesViewLabelProvider_TagsNodeText=Tags
DiscardChangesAction_confirmActionTitle=Discard Local Changes
DiscardChangesAction_confirmActionMessage=This will discard all local changes for the selected resources. Are you sure you want to do this ?
+DiscardChangesAction_discardChanges=Discard Changes
DiscardChangesAction_unexpectedErrorTitle=Unexpected Error
DiscardChangesAction_unexpectedErrorMessage=An unexpected error occured while attempting to checkout resources.
DiscardChangesAction_unexpectedIndexErrorMessage=An unexpected error occured while attempting to interact with the Git Index.