Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThomas Wolf2019-08-28 16:59:44 -0400
committerThomas Wolf2019-09-05 12:11:52 -0400
commit8bf986c31e2b7e97f3490f08993d11706d39c13d (patch)
tree03e8266d97871e92126e4f4b6d5ed2033b2db4d1 /org.eclipse.egit.ui
parentfb2fc5db7dd038e73af0bc8acfed1e4f96f8bbd3 (diff)
downloadegit-8bf986c31e2b7e97f3490f08993d11706d39c13d.tar.gz
egit-8bf986c31e2b7e97f3490f08993d11706d39c13d.tar.xz
egit-8bf986c31e2b7e97f3490f08993d11706d39c13d.zip
Cache more repository state for re-use in the UI thread
Many EGit commands depend on some repository state determining their enablement. Eclipse re-evaluates activation/enablement expressions or handlers' isEnabled() method very frequently. For globally available handlers, on every selection change; for others for instance when they are included in some (context) menu. JGit operations to determine repository state access the file system (typically config files, or the packed_refs file, or loose refs), and check every time whether the file has been changed since the last access. In the case of a repository config file, this check is even done for the user and system config files, too. If JGit determines that a file has been changed it reloads it, perhaps even multiple times depending on the file timestamp resolution. Thus accessing the repository config file or determining the currently checked out branch are expensive file system operations. Handler enablements are evaluated on the UI thread, so EGit did *a lot* of expensive file system accesses on the UI thread, which slows down Eclipse startup and context menus in particular. Introduce a cache for the most important values of a repository that are used in property testers and in handler activation and enablement code. The cache is cleared whenever the workbench selection or the "menu selection" changes to avoid serving stale values. When Eclipse then re-evaluates enablements, only the first expressions will actually access the file system, while all later re-evaluations due to a selection change will use the cached values. Caching values until the next selection change is a valid strategy. When a series of enablements is re-computed, these re-computations are all based on the same selection, thus using the repository state as it was at the beginning is fine. This greatly reduces the number of times EGit accesses the file system on the UI thread and generally makes the EGit UI *much* snappier. This cache should be used only for evaluations that are known to happen synchronously in the UI thread in response to a selection change. This includes property testers and isEnabled() on handlers. Bug: 544600 Change-Id: Idd369b50d8b4bd6dd68b30d640bbc13f5a5976c5 Signed-off-by: Thomas Wolf <thomas.wolf@paranor.ch>
Diffstat (limited to 'org.eclipse.egit.ui')
-rw-r--r--org.eclipse.egit.ui/META-INF/MANIFEST.MF3
-rwxr-xr-xorg.eclipse.egit.ui/src/org/eclipse/egit/ui/Activator.java3
-rw-r--r--org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/ResourcePropertyTester.java10
-rw-r--r--org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/actions/ConfigureFetchActionHandler.java2
-rw-r--r--org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/actions/ConfigurePushActionHandler.java2
-rw-r--r--org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/actions/DiscardChangesActionHandler.java5
-rw-r--r--org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/actions/MergeActionHandler.java4
-rw-r--r--org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/actions/PullFromUpstreamActionHandler.java26
-rw-r--r--org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/actions/PushActionHandler.java16
-rw-r--r--org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/actions/PushBranchActionHandler.java13
-rw-r--r--org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/actions/PushMenu.java41
-rw-r--r--org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/actions/PushUpstreamOrBranchActionHandler.java14
-rw-r--r--org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/actions/RebaseActionHandler.java4
-rw-r--r--org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/actions/RepositoryActionHandler.java22
-rw-r--r--org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/actions/SimpleFetchActionHandler.java2
-rw-r--r--org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/actions/SimplePushActionHandler.java2
-rw-r--r--org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/commands/shared/RebaseCurrentRefCommand.java16
-rw-r--r--org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/expressions/GitPropertyTester.java11
-rw-r--r--org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/fetch/SimpleConfigureFetchDialog.java63
-rw-r--r--org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/push/SimpleConfigurePushDialog.java57
-rw-r--r--org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/tree/RepositoriesViewPropertyTester.java61
-rw-r--r--org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/tree/command/FetchConfiguredRemoteCommand.java40
-rw-r--r--org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/tree/command/PushConfiguredRemoteCommand.java61
-rw-r--r--org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/tree/command/RepositoriesViewCommandHandler.java14
-rw-r--r--org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/selection/RepositoryStateCache.java316
-rw-r--r--org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/selection/SelectionUtils.java7
26 files changed, 597 insertions, 218 deletions
diff --git a/org.eclipse.egit.ui/META-INF/MANIFEST.MF b/org.eclipse.egit.ui/META-INF/MANIFEST.MF
index 8c366e2b0..ea9a1e251 100644
--- a/org.eclipse.egit.ui/META-INF/MANIFEST.MF
+++ b/org.eclipse.egit.ui/META-INF/MANIFEST.MF
@@ -28,7 +28,8 @@ Require-Bundle: org.eclipse.core.runtime;bundle-version="[3.12.0,4.0.0)",
org.eclipse.debug.ui;bundle-version="[3.11.200,4.0.0)";resolution:=optional,
org.eclipse.jdt.core;bundle-version="[3.12.0,4.0.0)";resolution:=optional,
org.eclipse.jdt.ui;bundle-version="[3.12.0,4.0.0)";resolution:=optional,
- org.eclipse.ui.views;bundle-version="[3.8.100,4.0.0)"
+ org.eclipse.ui.views;bundle-version="[3.8.100,4.0.0)",
+ org.eclipse.e4.core.contexts;bundle-version="[1.5.1,2.0.0)"
Bundle-ActivationPolicy: lazy
Bundle-RequiredExecutionEnvironment: JavaSE-1.8
Import-Package: org.eclipse.egit.core;version="[5.6.0,5.7.0)",
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/Activator.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/Activator.java
index 6e60a803c..92f720629 100755
--- a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/Activator.java
+++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/Activator.java
@@ -62,6 +62,7 @@ import org.eclipse.egit.ui.internal.RepositoryCacheRule;
import org.eclipse.egit.ui.internal.UIIcons;
import org.eclipse.egit.ui.internal.UIText;
import org.eclipse.egit.ui.internal.credentials.EGitCredentialsProvider;
+import org.eclipse.egit.ui.internal.selection.RepositoryStateCache;
import org.eclipse.egit.ui.internal.trace.GitTraceLocation;
import org.eclipse.egit.ui.internal.variables.GitTemplateVariableResolver;
import org.eclipse.jdt.internal.ui.JavaPlugin;
@@ -355,6 +356,7 @@ public class Activator extends AbstractUIPlugin implements DebugOptionsListener
context.registerService(DebugOptionsListener.class.getName(), this,
props);
+ RepositoryStateCache.INSTANCE.initialize();
setupRepoChangeScanner();
setupRepoIndexRefresh();
setupFocusHandling();
@@ -1118,6 +1120,7 @@ public class Activator extends AbstractUIPlugin implements DebugOptionsListener
@Override
public void stop(final BundleContext context) throws Exception {
+ RepositoryStateCache.INSTANCE.dispose();
if (refreshHandle != null) {
refreshHandle.remove();
refreshHandle = null;
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/ResourcePropertyTester.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/ResourcePropertyTester.java
index 7662ebfb5..2a0922cf4 100644
--- a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/ResourcePropertyTester.java
+++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/ResourcePropertyTester.java
@@ -23,6 +23,7 @@ import org.eclipse.core.resources.IResource;
import org.eclipse.egit.core.internal.gerrit.GerritUtil;
import org.eclipse.egit.core.project.RepositoryMapping;
import org.eclipse.egit.ui.internal.expressions.AbstractPropertyTester;
+import org.eclipse.egit.ui.internal.selection.RepositoryStateCache;
import org.eclipse.egit.ui.internal.trace.GitTraceLocation;
import org.eclipse.jgit.annotations.NonNull;
import org.eclipse.jgit.lib.Config;
@@ -115,7 +116,8 @@ public class ResourcePropertyTester extends AbstractPropertyTester {
if ("canPushToGerrit".equals(property)) { //$NON-NLS-1$
return canPushToGerrit(repository);
}
- RepositoryState state = repository.getRepositoryState();
+ RepositoryState state = RepositoryStateCache.INSTANCE
+ .getRepositoryState(repository);
if ("canAbortRebase".equals(property)) { //$NON-NLS-1$
return canAbortRebase(state);
@@ -153,7 +155,7 @@ public class ResourcePropertyTester extends AbstractPropertyTester {
*/
public static boolean hasGerritConfiguration(
@NonNull Repository repository) {
- Config config = repository.getConfig();
+ Config config = RepositoryStateCache.INSTANCE.getConfig(repository);
if (GerritUtil.getCreateChangeId(config)) {
return true;
}
@@ -178,7 +180,7 @@ public class ResourcePropertyTester extends AbstractPropertyTester {
* Gerrit
*/
public static boolean canFetchFromGerrit(@NonNull Repository repository) {
- Config config = repository.getConfig();
+ Config config = RepositoryStateCache.INSTANCE.getConfig(repository);
try {
List<RemoteConfig> remoteConfigs = RemoteConfig
.getAllRemoteConfigs(config);
@@ -199,7 +201,7 @@ public class ResourcePropertyTester extends AbstractPropertyTester {
* Gerrit
*/
public static boolean canPushToGerrit(@NonNull Repository repository) {
- Config config = repository.getConfig();
+ Config config = RepositoryStateCache.INSTANCE.getConfig(repository);
try {
List<RemoteConfig> remoteConfigs = RemoteConfig
.getAllRemoteConfigs(config);
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/actions/ConfigureFetchActionHandler.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/actions/ConfigureFetchActionHandler.java
index 6a3fa3de2..aa1ee7d45 100644
--- a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/actions/ConfigureFetchActionHandler.java
+++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/actions/ConfigureFetchActionHandler.java
@@ -34,7 +34,7 @@ public class ConfigureFetchActionHandler extends RepositoryActionHandler {
Repository repository = getRepository();
return repository != null
&& SimpleConfigureFetchDialog
- .getConfiguredRemote(repository) != null;
+ .getConfiguredRemoteCached(repository) != null;
}
}
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/actions/ConfigurePushActionHandler.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/actions/ConfigurePushActionHandler.java
index 01a1a35e6..b2040c92d 100644
--- a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/actions/ConfigurePushActionHandler.java
+++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/actions/ConfigurePushActionHandler.java
@@ -34,7 +34,7 @@ public class ConfigurePushActionHandler extends RepositoryActionHandler {
Repository repository = getRepository();
return repository != null
&& SimpleConfigurePushDialog
- .getConfiguredRemote(repository) != null;
+ .getConfiguredRemoteCached(repository) != null;
}
}
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/actions/DiscardChangesActionHandler.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/actions/DiscardChangesActionHandler.java
index 4c7205396..12cfb59f3 100644
--- a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/actions/DiscardChangesActionHandler.java
+++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/actions/DiscardChangesActionHandler.java
@@ -29,6 +29,7 @@ import org.eclipse.egit.ui.JobFamilies;
import org.eclipse.egit.ui.internal.UIText;
import org.eclipse.egit.ui.internal.dialogs.CommandConfirmation;
import org.eclipse.egit.ui.internal.operations.GitScopeUtil;
+import org.eclipse.egit.ui.internal.selection.RepositoryStateCache;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.lib.RepositoryState;
import org.eclipse.ui.IWorkbenchPart;
@@ -72,8 +73,10 @@ public class DiscardChangesActionHandler extends RepositoryActionHandler {
if (repositories.length == 0)
return false;
for (Repository repository : repositories) {
- if (!repository.getRepositoryState().equals(RepositoryState.SAFE))
+ if (!RepositoryState.SAFE.equals(RepositoryStateCache.INSTANCE
+ .getRepositoryState(repository))) {
return false;
+ }
}
return true;
}
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/actions/MergeActionHandler.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/actions/MergeActionHandler.java
index 85eb7b089..4cd750cff 100644
--- a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/actions/MergeActionHandler.java
+++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/actions/MergeActionHandler.java
@@ -31,6 +31,7 @@ import org.eclipse.egit.ui.internal.branch.LaunchFinder;
import org.eclipse.egit.ui.internal.dialogs.BasicConfigurationDialog;
import org.eclipse.egit.ui.internal.dialogs.MergeTargetSelectionDialog;
import org.eclipse.egit.ui.internal.merge.MergeResultDialog;
+import org.eclipse.egit.ui.internal.selection.RepositoryStateCache;
import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jgit.lib.Constants;
@@ -74,7 +75,8 @@ public class MergeActionHandler extends RepositoryActionHandler {
public boolean isEnabled() {
Repository repo = getRepository();
return repo != null
- && repo.getRepositoryState() == RepositoryState.SAFE
+ && RepositoryState.SAFE.equals(
+ RepositoryStateCache.INSTANCE.getRepositoryState(repo))
&& isLocalBranchCheckedout(repo);
}
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/actions/PullFromUpstreamActionHandler.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/actions/PullFromUpstreamActionHandler.java
index 3b875d0c9..caa1c0635 100644
--- a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/actions/PullFromUpstreamActionHandler.java
+++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/actions/PullFromUpstreamActionHandler.java
@@ -12,17 +12,15 @@
*******************************************************************************/
package org.eclipse.egit.ui.internal.actions;
-import java.io.IOException;
import java.util.Arrays;
import java.util.LinkedHashSet;
import java.util.Set;
import org.eclipse.core.commands.ExecutionEvent;
import org.eclipse.core.commands.ExecutionException;
-import org.eclipse.egit.ui.Activator;
import org.eclipse.egit.ui.internal.pull.PullOperationUI;
+import org.eclipse.egit.ui.internal.selection.RepositoryStateCache;
import org.eclipse.jgit.lib.Constants;
-import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.lib.Repository;
/**
@@ -45,21 +43,17 @@ public class PullFromUpstreamActionHandler extends RepositoryActionHandler {
// we don't do the full canMerge check here, but
// ensure that a branch is checked out
Repository[] repos = getRepositories();
- for (Repository repo : repos)
- try {
- String fullBranch = repo.getFullBranch();
- if (fullBranch == null
- || !fullBranch.startsWith(Constants.R_REFS)) {
- return false;
- }
- Ref head = repo.exactRef(Constants.HEAD);
- if (head == null || head.getObjectId() == null) {
- return false;
- }
- } catch (IOException e) {
- Activator.handleError(e.getMessage(), e, false);
+ for (Repository repo : repos) {
+ String fullBranch = RepositoryStateCache.INSTANCE
+ .getFullBranchName(repo);
+ if (fullBranch == null
+ || !fullBranch.startsWith(Constants.R_REFS)) {
return false;
}
+ if (RepositoryStateCache.INSTANCE.getHead(repo) == null) {
+ return false;
+ }
+ }
return repos.length > 0;
}
}
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/actions/PushActionHandler.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/actions/PushActionHandler.java
index ec56a1ed6..5d6cbe940 100644
--- a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/actions/PushActionHandler.java
+++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/actions/PushActionHandler.java
@@ -10,7 +10,6 @@
*******************************************************************************/
package org.eclipse.egit.ui.internal.actions;
-import java.io.IOException;
import java.net.URISyntaxException;
import org.eclipse.core.commands.ExecutionEvent;
@@ -20,10 +19,9 @@ import org.eclipse.core.runtime.Status;
import org.eclipse.egit.ui.Activator;
import org.eclipse.egit.ui.internal.UIText;
import org.eclipse.egit.ui.internal.push.PushWizard;
+import org.eclipse.egit.ui.internal.selection.RepositoryStateCache;
import org.eclipse.jface.dialogs.ErrorDialog;
import org.eclipse.jface.wizard.WizardDialog;
-import org.eclipse.jgit.lib.Constants;
-import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.lib.Repository;
/**
@@ -57,16 +55,10 @@ public class PushActionHandler extends RepositoryActionHandler {
@Override
public boolean isEnabled() {
- try {
- Repository repository = getRepository();
- if (repository == null) {
- return false;
- }
- Ref ref = repository.exactRef(Constants.HEAD);
- return ref != null && ref.getObjectId() != null;
- } catch (IOException e) {
- Activator.handleError(e.getMessage(), e, false);
+ Repository repository = getRepository();
+ if (repository == null) {
return false;
}
+ return RepositoryStateCache.INSTANCE.getHead(repository) != null;
}
}
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/actions/PushBranchActionHandler.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/actions/PushBranchActionHandler.java
index 9ac24b520..07faf8081 100644
--- a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/actions/PushBranchActionHandler.java
+++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/actions/PushBranchActionHandler.java
@@ -14,8 +14,9 @@ import java.io.IOException;
import org.eclipse.core.commands.ExecutionEvent;
import org.eclipse.core.commands.ExecutionException;
import org.eclipse.egit.ui.Activator;
-import org.eclipse.egit.ui.internal.push.PushWizardDialog;
import org.eclipse.egit.ui.internal.push.PushBranchWizard;
+import org.eclipse.egit.ui.internal.push.PushWizardDialog;
+import org.eclipse.egit.ui.internal.selection.RepositoryStateCache;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.Ref;
@@ -54,15 +55,7 @@ public class PushBranchActionHandler extends RepositoryActionHandler {
if (repository == null) {
return false;
}
- try {
- Ref head = repository.exactRef(Constants.HEAD);
- if (head != null && head.getObjectId() != null) {
- return true;
- }
- } catch (IOException e) {
- Activator.logError(e.getMessage(), e);
- }
- return false;
+ return RepositoryStateCache.INSTANCE.getHead(repository) != null;
}
private Ref getBranchRef(Repository repository) {
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/actions/PushMenu.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/actions/PushMenu.java
index cdc806193..b34abd100 100644
--- a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/actions/PushMenu.java
+++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/actions/PushMenu.java
@@ -13,13 +13,9 @@
*******************************************************************************/
package org.eclipse.egit.ui.internal.actions;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.List;
-
-import org.eclipse.egit.ui.Activator;
import org.eclipse.egit.ui.internal.CommonUtils;
import org.eclipse.egit.ui.internal.UIText;
+import org.eclipse.egit.ui.internal.selection.RepositoryStateCache;
import org.eclipse.egit.ui.internal.selection.SelectionUtils;
import org.eclipse.jface.action.IContributionItem;
import org.eclipse.jgit.lib.Constants;
@@ -68,33 +64,28 @@ public class PushMenu extends CompoundContributionItem implements
@Override
protected IContributionItem[] getContributionItems() {
- List<IContributionItem> res = new ArrayList<>();
-
if (this.handlerService != null) {
Repository repository = SelectionUtils.getRepository(handlerService
.getCurrentState());
if (repository != null) {
- try {
- String ref = repository.getFullBranch();
- String menuLabel = UIText.PushMenu_PushHEAD;
- if (ref != null && ref.startsWith(Constants.R_HEADS)) {
- menuLabel = NLS.bind(UIText.PushMenu_PushBranch,
- Repository.shortenRefName(ref));
- }
- CommandContributionItemParameter params = new CommandContributionItemParameter(
- this.serviceLocator, getClass().getName(),
- ActionCommands.PUSH_BRANCH_ACTION,
- CommandContributionItem.STYLE_PUSH);
- params.label = menuLabel;
- CommandContributionItem item = new CommandContributionItem(
- params);
- res.add(item);
- } catch (IOException ex) {
- Activator.handleError(ex.getLocalizedMessage(), ex, false);
+ String ref = RepositoryStateCache.INSTANCE
+ .getFullBranchName(repository);
+ String menuLabel = UIText.PushMenu_PushHEAD;
+ if (ref != null && ref.startsWith(Constants.R_HEADS)) {
+ menuLabel = NLS.bind(UIText.PushMenu_PushBranch,
+ Repository.shortenRefName(ref));
}
+ CommandContributionItemParameter params = new CommandContributionItemParameter(
+ this.serviceLocator, getClass().getName(),
+ ActionCommands.PUSH_BRANCH_ACTION,
+ CommandContributionItem.STYLE_PUSH);
+ params.label = menuLabel;
+ CommandContributionItem item = new CommandContributionItem(
+ params);
+ return new IContributionItem[] { item };
}
}
- return res.toArray(new IContributionItem[0]);
+ return new IContributionItem[0];
}
}
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/actions/PushUpstreamOrBranchActionHandler.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/actions/PushUpstreamOrBranchActionHandler.java
index 0eccf0d35..63f76004a 100644
--- a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/actions/PushUpstreamOrBranchActionHandler.java
+++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/actions/PushUpstreamOrBranchActionHandler.java
@@ -14,10 +14,11 @@ import java.io.IOException;
import org.eclipse.core.commands.ExecutionEvent;
import org.eclipse.core.commands.ExecutionException;
-import org.eclipse.egit.ui.internal.push.PushWizardDialog;
import org.eclipse.egit.ui.internal.push.PushBranchWizard;
import org.eclipse.egit.ui.internal.push.PushOperationUI;
+import org.eclipse.egit.ui.internal.push.PushWizardDialog;
import org.eclipse.egit.ui.internal.push.SimpleConfigurePushDialog;
+import org.eclipse.egit.ui.internal.selection.RepositoryStateCache;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.lib.Repository;
@@ -68,14 +69,11 @@ public class PushUpstreamOrBranchActionHandler extends RepositoryActionHandler {
@Override
public boolean isEnabled() {
final Repository repository = getRepository();
- if (repository == null)
+ if (repository == null) {
return false;
-
- Ref head = getHeadIfSymbolic(repository);
- if (head == null)
- return false;
-
- return true;
+ }
+ Ref head = RepositoryStateCache.INSTANCE.getHeadRef(repository);
+ return head != null && head.isSymbolic();
}
private static Ref getHeadIfSymbolic(Repository repository) {
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/actions/RebaseActionHandler.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/actions/RebaseActionHandler.java
index 1a2b92317..f7a0ba451 100644
--- a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/actions/RebaseActionHandler.java
+++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/actions/RebaseActionHandler.java
@@ -13,6 +13,7 @@ package org.eclipse.egit.ui.internal.actions;
import org.eclipse.core.commands.ExecutionEvent;
import org.eclipse.core.commands.ExecutionException;
import org.eclipse.egit.ui.internal.commands.shared.RebaseCurrentRefCommand;
+import org.eclipse.egit.ui.internal.selection.RepositoryStateCache;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.lib.RepositoryState;
@@ -49,7 +50,8 @@ public class RebaseActionHandler extends RepositoryActionHandler {
// (main action) or an active rebase can be continued, skipped or
// aborted (menu items). Even when the main action is not enabled we
// must enable this because otherwise the menu items cannot be opened.
- RepositoryState state = repo.getRepositoryState();
+ RepositoryState state = RepositoryStateCache.INSTANCE
+ .getRepositoryState(repo);
return state.isRebasing()
|| RebaseCurrentRefCommand.isEnabledForState(repo, state);
}
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/actions/RepositoryActionHandler.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/actions/RepositoryActionHandler.java
index 8e788eb3d..29b4efdc6 100644
--- a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/actions/RepositoryActionHandler.java
+++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/actions/RepositoryActionHandler.java
@@ -36,6 +36,7 @@ import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.IPath;
import org.eclipse.egit.core.internal.CompareCoreUtils;
import org.eclipse.egit.core.project.RepositoryMapping;
+import org.eclipse.egit.ui.internal.selection.RepositoryStateCache;
import org.eclipse.egit.ui.internal.selection.SelectionUtils;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredSelection;
@@ -321,26 +322,13 @@ abstract class RepositoryActionHandler extends AbstractHandler {
* {@code false} otherwise
*/
protected boolean containsHead(Repository repository) {
- try {
- return repository != null ? repository.resolve(Constants.HEAD) != null
- : false;
- } catch (Exception e) {
- // do nothing
- }
-
- return false;
+ return RepositoryStateCache.INSTANCE.getHead(repository) != null;
}
protected boolean isLocalBranchCheckedout(Repository repository) {
- try {
- String fullBranch = repository.getFullBranch();
- return fullBranch != null
- && fullBranch.startsWith(Constants.R_HEADS);
- } catch (Exception e) {
- // do nothing
- }
-
- return false;
+ String fullBranch = RepositoryStateCache.INSTANCE
+ .getFullBranchName(repository);
+ return fullBranch != null && fullBranch.startsWith(Constants.R_HEADS);
}
protected String getPreviousPath(Repository repository,
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/actions/SimpleFetchActionHandler.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/actions/SimpleFetchActionHandler.java
index d866c8822..bbd76a4f9 100644
--- a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/actions/SimpleFetchActionHandler.java
+++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/actions/SimpleFetchActionHandler.java
@@ -51,6 +51,6 @@ public class SimpleFetchActionHandler extends RepositoryActionHandler {
final Repository repository = getRepository();
return repository != null
&& SimpleConfigureFetchDialog
- .getConfiguredRemote(repository) != null;
+ .getConfiguredRemoteCached(repository) != null;
}
}
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/actions/SimplePushActionHandler.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/actions/SimplePushActionHandler.java
index 26cc0f222..c57c91eca 100644
--- a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/actions/SimplePushActionHandler.java
+++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/actions/SimplePushActionHandler.java
@@ -47,6 +47,6 @@ public class SimplePushActionHandler extends RepositoryActionHandler {
final Repository repository = getRepository();
return repository != null
&& SimpleConfigurePushDialog
- .getConfiguredRemote(repository) != null;
+ .getConfiguredRemoteCached(repository) != null;
}
}
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/commands/shared/RebaseCurrentRefCommand.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/commands/shared/RebaseCurrentRefCommand.java
index 23efebaae..2ae704bba 100644
--- a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/commands/shared/RebaseCurrentRefCommand.java
+++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/commands/shared/RebaseCurrentRefCommand.java
@@ -28,6 +28,7 @@ import org.eclipse.egit.ui.internal.branch.LaunchFinder;
import org.eclipse.egit.ui.internal.dialogs.BasicConfigurationDialog;
import org.eclipse.egit.ui.internal.dialogs.RebaseTargetSelectionDialog;
import org.eclipse.egit.ui.internal.rebase.RebaseInteractiveHandler;
+import org.eclipse.egit.ui.internal.selection.RepositoryStateCache;
import org.eclipse.egit.ui.internal.selection.SelectionUtils;
import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.jface.viewers.ISelection;
@@ -36,7 +37,6 @@ import org.eclipse.jgit.api.RebaseCommand.InteractiveHandler;
import org.eclipse.jgit.lib.BranchConfig.BranchRebaseMode;
import org.eclipse.jgit.lib.Config;
import org.eclipse.jgit.lib.ConfigConstants;
-import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.lib.RepositoryState;
@@ -129,7 +129,7 @@ public class RebaseCurrentRefCommand extends AbstractRebaseCommandHandler {
Repository repo = SelectionUtils.getRepository(ctx);
if (repo != null) {
boolean enabled = isEnabledForState(repo,
- repo.getRepositoryState());
+ RepositoryStateCache.INSTANCE.getRepositoryState(repo));
setBaseEnabled(enabled);
} else {
setBaseEnabled(false);
@@ -146,16 +146,8 @@ public class RebaseCurrentRefCommand extends AbstractRebaseCommandHandler {
*/
public static boolean isEnabledForState(Repository repo,
RepositoryState state) {
- return state == RepositoryState.SAFE && hasHead(repo);
- }
-
- private static boolean hasHead(Repository repo) {
- try {
- Ref headRef = repo.exactRef(Constants.HEAD);
- return headRef != null && headRef.getObjectId() != null;
- } catch (IOException e) {
- return false;
- }
+ return state == RepositoryState.SAFE
+ && RepositoryStateCache.INSTANCE.getHead(repo) != null;
}
private String getFullBranch(Repository repository)
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/expressions/GitPropertyTester.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/expressions/GitPropertyTester.java
index d27b12143..b8079a9ef 100644
--- a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/expressions/GitPropertyTester.java
+++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/expressions/GitPropertyTester.java
@@ -19,6 +19,7 @@ import org.eclipse.core.expressions.PropertyTester;
import org.eclipse.core.runtime.Adapters;
import org.eclipse.egit.core.internal.IRepositoryCommit;
import org.eclipse.egit.ui.internal.commit.RepositoryCommit;
+import org.eclipse.egit.ui.internal.selection.RepositoryStateCache;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.Ref;
@@ -90,14 +91,16 @@ public class GitPropertyTester extends AbstractPropertyTester {
} else if ("isSafe".equals(property)) { //$NON-NLS-1$
Repository repository = Adapters.adapt(receiver, Repository.class);
if (repository != null) {
- return computeResult(expectedValue, repository
- .getRepositoryState().equals(RepositoryState.SAFE));
+ return computeResult(expectedValue,
+ RepositoryState.SAFE.equals(RepositoryStateCache.INSTANCE
+ .getRepositoryState(repository)));
}
} else if ("canCommit".equals(property)) { //$NON-NLS-1$
Repository repository = Adapters.adapt(receiver, Repository.class);
if (repository != null) {
- return computeResult(expectedValue,
- repository.getRepositoryState().canCommit());
+ RepositoryState state = RepositoryStateCache.INSTANCE
+ .getRepositoryState(repository);
+ return computeResult(expectedValue, state.canCommit());
}
} else if ("hasMultipleRefs".equals(property)) { //$NON-NLS-1$
IRepositoryCommit commit = Adapters.adapt(receiver,
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/fetch/SimpleConfigureFetchDialog.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/fetch/SimpleConfigureFetchDialog.java
index 546e2d119..979e31da4 100644
--- a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/fetch/SimpleConfigureFetchDialog.java
+++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/fetch/SimpleConfigureFetchDialog.java
@@ -24,10 +24,12 @@ import org.eclipse.egit.ui.Activator;
import org.eclipse.egit.ui.UIPreferences;
import org.eclipse.egit.ui.internal.UIText;
import org.eclipse.egit.ui.internal.dialogs.AbstractConfigureRemoteDialog;
+import org.eclipse.egit.ui.internal.selection.RepositoryStateCache;
import org.eclipse.jface.dialogs.Dialog;
import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.jface.window.Window;
import org.eclipse.jface.wizard.WizardDialog;
+import org.eclipse.jgit.lib.Config;
import org.eclipse.jgit.lib.ConfigConstants;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.ObjectId;
@@ -91,31 +93,70 @@ public class SimpleConfigureFetchDialog extends AbstractConfigureRemoteDialog {
}
if (branch == null)
return null;
+ return getConfiguredRemote(branch, repository.getConfig());
+ }
+
+ /**
+ * Same as {@link #getConfiguredRemote(Repository)} but using cached
+ * repository state; intended for use in property testers or handler
+ * enablements.
+ *
+ * @param repository
+ * @return the configured remote for the current branch, or the default
+ * remote; <code>null</code> if a local branch is checked out that
+ * points to "." as remote
+ */
+ public static RemoteConfig getConfiguredRemoteCached(
+ Repository repository) {
+ String branch = RepositoryStateCache.INSTANCE
+ .getFullBranchName(repository);
+ if (branch == null) {
+ return null;
+ }
+ branch = Repository.shortenRefName(branch);
+ return getConfiguredRemote(branch,
+ RepositoryStateCache.INSTANCE.getConfig(repository));
+ }
+ /**
+ * @param branch
+ * currently checked out
+ * @param config
+ * of the repository
+ * @return the configured remote for the current branch, or the default
+ * remote; <code>null</code> if a local branch is checked out that
+ * points to "." as remote
+ */
+ private static RemoteConfig getConfiguredRemote(String branch,
+ Config config) {
+ if (branch == null) {
+ return null;
+ }
String remoteName;
- if (ObjectId.isId(branch))
+ if (ObjectId.isId(branch)) {
remoteName = Constants.DEFAULT_REMOTE_NAME;
- else
- remoteName = repository.getConfig().getString(
+ } else {
+ remoteName = config.getString(
ConfigConstants.CONFIG_BRANCH_SECTION, branch,
ConfigConstants.CONFIG_REMOTE_SECTION);
-
+ }
// check if we find the configured and default Remotes
List<RemoteConfig> allRemotes;
try {
- allRemotes = RemoteConfig.getAllRemoteConfigs(repository
- .getConfig());
+ allRemotes = RemoteConfig.getAllRemoteConfigs(config);
} catch (URISyntaxException e) {
allRemotes = new ArrayList<>();
}
RemoteConfig defaultConfig = null;
RemoteConfig configuredConfig = null;
- for (RemoteConfig config : allRemotes) {
- if (config.getName().equals(Constants.DEFAULT_REMOTE_NAME))
- defaultConfig = config;
- if (remoteName != null && config.getName().equals(remoteName))
- configuredConfig = config;
+ for (RemoteConfig cfg : allRemotes) {
+ if (cfg.getName().equals(Constants.DEFAULT_REMOTE_NAME)) {
+ defaultConfig = cfg;
+ }
+ if (remoteName != null && cfg.getName().equals(remoteName)) {
+ configuredConfig = cfg;
+ }
}
RemoteConfig configToUse = configuredConfig != null ? configuredConfig
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/push/SimpleConfigurePushDialog.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/push/SimpleConfigurePushDialog.java
index ebb9fd0b5..ad38fd701 100644
--- a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/push/SimpleConfigurePushDialog.java
+++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/push/SimpleConfigurePushDialog.java
@@ -25,6 +25,7 @@ import org.eclipse.egit.ui.Activator;
import org.eclipse.egit.ui.internal.UIText;
import org.eclipse.egit.ui.internal.dialogs.AbstractConfigureRemoteDialog;
import org.eclipse.egit.ui.internal.repository.SelectUriWizard;
+import org.eclipse.egit.ui.internal.selection.RepositoryStateCache;
import org.eclipse.jface.dialogs.Dialog;
import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.jface.layout.GridDataFactory;
@@ -34,6 +35,7 @@ import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.jface.window.Window;
import org.eclipse.jface.wizard.WizardDialog;
+import org.eclipse.jgit.lib.Config;
import org.eclipse.jgit.lib.ConfigConstants;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.ObjectId;
@@ -106,38 +108,65 @@ public class SimpleConfigurePushDialog extends AbstractConfigureRemoteDialog {
}
if (branch == null)
return null;
+ return getConfiguredRemote(branch, repository.getConfig());
+ }
+
+ /**
+ * Same as {@link #getConfiguredRemote(Repository)} but using cached
+ * repository state; intended for use in property testers or handler
+ * enablements.
+ *
+ * @param repository
+ * @return the configured remote for the current branch if any, or null
+ */
+ public static RemoteConfig getConfiguredRemoteCached(
+ Repository repository) {
+ String branch = RepositoryStateCache.INSTANCE
+ .getFullBranchName(repository);
+ if (branch == null) {
+ return null;
+ }
+ branch = Repository.shortenRefName(branch);
+ return getConfiguredRemote(branch,
+ RepositoryStateCache.INSTANCE.getConfig(repository));
+ }
+ private static RemoteConfig getConfiguredRemote(String branch,
+ Config config) {
+ if (branch == null) {
+ return null;
+ }
String remoteName = null;
if (!ObjectId.isId(branch))
- remoteName = repository.getConfig().getString(
+ remoteName = config.getString(
ConfigConstants.CONFIG_BRANCH_SECTION, branch,
ConfigConstants.CONFIG_REMOTE_SECTION);
// check if we find the configured and default Remotes
List<RemoteConfig> allRemotes;
try {
- allRemotes = RemoteConfig.getAllRemoteConfigs(repository
- .getConfig());
+ allRemotes = RemoteConfig.getAllRemoteConfigs(config);
} catch (URISyntaxException e) {
allRemotes = new ArrayList<>();
}
RemoteConfig configuredConfig = null;
RemoteConfig defaultConfig = null;
- for (RemoteConfig config : allRemotes) {
- if (remoteName != null && config.getName().equals(remoteName))
- configuredConfig = config;
- if (config.getName().equals(Constants.DEFAULT_REMOTE_NAME))
- defaultConfig = config;
+ for (RemoteConfig cfg : allRemotes) {
+ if (remoteName != null && cfg.getName().equals(remoteName)) {
+ configuredConfig = cfg;
+ }
+ if (cfg.getName().equals(Constants.DEFAULT_REMOTE_NAME)) {
+ defaultConfig = cfg;
+ }
}
- if (configuredConfig != null)
+ if (configuredConfig != null) {
return configuredConfig;
-
- if (defaultConfig != null)
- if (!defaultConfig.getPushRefSpecs().isEmpty())
- return defaultConfig;
-
+ }
+ if (defaultConfig != null && !defaultConfig.getPushRefSpecs().isEmpty()) {
+ return defaultConfig;
+ }
return null;
}
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/tree/RepositoriesViewPropertyTester.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/tree/RepositoriesViewPropertyTester.java
index 3a124bbf4..2405630be 100644
--- a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/tree/RepositoriesViewPropertyTester.java
+++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/tree/RepositoriesViewPropertyTester.java
@@ -17,6 +17,7 @@ import java.net.URISyntaxException;
import org.eclipse.egit.ui.internal.ResourcePropertyTester;
import org.eclipse.egit.ui.internal.expressions.AbstractPropertyTester;
+import org.eclipse.egit.ui.internal.selection.RepositoryStateCache;
import org.eclipse.egit.ui.internal.trace.GitTraceLocation;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.ObjectId;
@@ -101,7 +102,8 @@ public class RepositoriesViewPropertyTester extends AbstractPropertyTester {
RemoteConfig rconfig;
try {
- rconfig = new RemoteConfig(repository.getConfig(),
+ rconfig = new RemoteConfig(
+ RepositoryStateCache.INSTANCE.getConfig(repository),
configName);
} catch (URISyntaxException e2) {
return false;
@@ -117,7 +119,8 @@ public class RepositoriesViewPropertyTester extends AbstractPropertyTester {
RemoteConfig rconfig;
try {
- rconfig = new RemoteConfig(repository.getConfig(),
+ rconfig = new RemoteConfig(
+ RepositoryStateCache.INSTANCE.getConfig(repository),
configName);
} catch (URISyntaxException e2) {
return false;
@@ -129,21 +132,22 @@ public class RepositoriesViewPropertyTester extends AbstractPropertyTester {
}
}
if (property.equals("canStash")) { //$NON-NLS-1$
- return repository.getRepositoryState().canCommit();
+ RepositoryState state = RepositoryStateCache.INSTANCE
+ .getRepositoryState(repository);
+ return state.canCommit();
}
if (property.equals("canMerge")) { //$NON-NLS-1$
- if (repository.getRepositoryState() != RepositoryState.SAFE) {
+ RepositoryState state = RepositoryStateCache.INSTANCE
+ .getRepositoryState(repository);
+ if (state != RepositoryState.SAFE) {
return false;
}
- try {
- String branch = repository.getFullBranch();
- if (branch == null) {
- return false; // fail gracefully...
- }
- return branch.startsWith(Constants.R_HEADS);
- } catch (IOException e) {
- return false;
+ String branch = RepositoryStateCache.INSTANCE
+ .getFullBranchName(repository);
+ if (branch == null) {
+ return false; // fail gracefully...
}
+ return branch.startsWith(Constants.R_HEADS);
}
if ("isSubmodule".equals(property)) { //$NON-NLS-1$
@@ -162,33 +166,26 @@ public class RepositoriesViewPropertyTester extends AbstractPropertyTester {
}
private boolean isRefCheckedOut(Repository repository, Ref ref) {
- try {
- if (ref.getName().startsWith(Constants.R_REFS)) {
- return ref.getName().equals(repository.getFullBranch());
- } else if (ref.getName().equals(Constants.HEAD)) {
+ if (ref.getName().startsWith(Constants.R_REFS)) {
+ return ref.getName().equals(
+ RepositoryStateCache.INSTANCE.getFullBranchName(repository));
+ } else if (ref.getName().equals(Constants.HEAD)) {
+ return true;
+ } else {
+ String leafname = ref.getLeaf().getName();
+ if (leafname.startsWith(Constants.R_REFS) && leafname.equals(
+ RepositoryStateCache.INSTANCE.getFullBranchName(repository))) {
return true;
} else {
- String leafname = ref.getLeaf().getName();
- if (leafname.startsWith(Constants.R_REFS)
- && leafname.equals(repository.getFullBranch())) {
- return true;
- } else {
- ObjectId objectId = ref.getLeaf().getObjectId();
- return objectId != null && objectId
- .equals(repository.resolve(Constants.HEAD));
- }
+ ObjectId objectId = ref.getLeaf().getObjectId();
+ return objectId != null && objectId
+ .equals(RepositoryStateCache.INSTANCE.getHead(repository));
}
- } catch (IOException e) {
- return false;
}
}
private boolean containsHead(Repository repository) {
- try {
- return repository.resolve(Constants.HEAD) != null;
- } catch (IOException e) {
- return false;
- }
+ return RepositoryStateCache.INSTANCE.getHead(repository) != null;
}
}
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/tree/command/FetchConfiguredRemoteCommand.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/tree/command/FetchConfiguredRemoteCommand.java
index 881b5d01b..613b4397b 100644
--- a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/tree/command/FetchConfiguredRemoteCommand.java
+++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/tree/command/FetchConfiguredRemoteCommand.java
@@ -28,6 +28,7 @@ import org.eclipse.egit.ui.internal.repository.tree.FetchNode;
import org.eclipse.egit.ui.internal.repository.tree.RemoteNode;
import org.eclipse.egit.ui.internal.repository.tree.RepositoryNode;
import org.eclipse.egit.ui.internal.repository.tree.RepositoryTreeNode;
+import org.eclipse.egit.ui.internal.selection.RepositoryStateCache;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jgit.transport.RemoteConfig;
@@ -59,7 +60,7 @@ public class FetchConfiguredRemoteCommand extends
public boolean isEnabled() {
RepositoryTreeNode node = getSelectedNodes().get(0);
try {
- return getRemoteConfig(node) != null;
+ return getRemoteConfigCached(node) != null;
} catch (ExecutionException e) {
return false;
}
@@ -67,28 +68,43 @@ public class FetchConfiguredRemoteCommand extends
private RemoteConfig getRemoteConfig(RepositoryTreeNode node)
throws ExecutionException {
- if (node instanceof FetchNode)
+ if (node instanceof RepositoryNode) {
+ return SimpleConfigureFetchDialog
+ .getConfiguredRemote(node.getRepository());
+ }
+ if (node instanceof FetchNode) {
+ node = node.getParent();
+ }
+ if (node instanceof RemoteNode) {
try {
- RemoteNode remote = (RemoteNode) node.getParent();
- return new RemoteConfig(node.getRepository().getConfig(),
+ RemoteNode remote = (RemoteNode) node;
+ return new RemoteConfig(node.getRepository().getConfig(),
remote.getObject());
} catch (URISyntaxException e) {
throw new ExecutionException(e.getMessage());
}
+ }
+ return null;
+ }
- if (node instanceof RemoteNode)
+ private RemoteConfig getRemoteConfigCached(RepositoryTreeNode node)
+ throws ExecutionException {
+ if (node instanceof RepositoryNode) {
+ return SimpleConfigureFetchDialog
+ .getConfiguredRemoteCached(node.getRepository());
+ }
+ if (node instanceof FetchNode) {
+ node = node.getParent();
+ }
+ if (node instanceof RemoteNode) {
try {
RemoteNode remote = (RemoteNode) node;
- return new RemoteConfig(node.getRepository().getConfig(),
- remote.getObject());
+ return new RemoteConfig(RepositoryStateCache.INSTANCE
+ .getConfig(node.getRepository()), remote.getObject());
} catch (URISyntaxException e) {
throw new ExecutionException(e.getMessage());
}
-
- if (node instanceof RepositoryNode)
- return SimpleConfigureFetchDialog.getConfiguredRemote(node
- .getRepository());
-
+ }
return null;
}
}
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/tree/command/PushConfiguredRemoteCommand.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/tree/command/PushConfiguredRemoteCommand.java
index e260eb82e..7beaf5f88 100644
--- a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/tree/command/PushConfiguredRemoteCommand.java
+++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/tree/command/PushConfiguredRemoteCommand.java
@@ -27,6 +27,7 @@ import org.eclipse.egit.ui.internal.repository.tree.PushNode;
import org.eclipse.egit.ui.internal.repository.tree.RemoteNode;
import org.eclipse.egit.ui.internal.repository.tree.RepositoryNode;
import org.eclipse.egit.ui.internal.repository.tree.RepositoryTreeNode;
+import org.eclipse.egit.ui.internal.selection.RepositoryStateCache;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jgit.transport.RemoteConfig;
@@ -53,36 +54,60 @@ public class PushConfiguredRemoteCommand extends
@Override
public boolean isEnabled() {
RepositoryTreeNode<?> node = getSelectedNodes().get(0);
- return getRemoteConfig(node) != null;
+ return getRemoteConfigCached(node) != null;
}
private RemoteConfig getRemoteConfig(RepositoryTreeNode node) {
- if (node instanceof RepositoryNode)
+ if (node instanceof RepositoryNode) {
return SimpleConfigurePushDialog.getConfiguredRemote(node
.getRepository());
-
- if (node instanceof RemoteNode || node instanceof PushNode) {
- RemoteNode remoteNode;
- if (node instanceof PushNode)
- remoteNode = (RemoteNode) node.getParent();
- else
- remoteNode = (RemoteNode) node;
-
+ }
+ if (node instanceof PushNode) {
+ node = node.getParent();
+ }
+ if (node instanceof RemoteNode) {
try {
- RemoteConfig config = new RemoteConfig(remoteNode
- .getRepository().getConfig(), remoteNode.getObject());
- boolean fetchConfigured = !config.getFetchRefSpecs().isEmpty();
- boolean pushConfigured = !config.getPushRefSpecs().isEmpty();
- if (fetchConfigured || pushConfigured)
- return config;
- else
- return null;
+ RemoteNode remoteNode = (RemoteNode) node;
+ RemoteConfig config = new RemoteConfig(
+ remoteNode.getRepository().getConfig(),
+ remoteNode.getObject());
+ return withRefSpecs(config);
} catch (URISyntaxException e) {
return null;
}
}
+ return null;
+ }
+ private RemoteConfig getRemoteConfigCached(RepositoryTreeNode node) {
+ if (node instanceof RepositoryNode) {
+ return SimpleConfigurePushDialog
+ .getConfiguredRemoteCached(node.getRepository());
+ }
+ if (node instanceof PushNode) {
+ node = node.getParent();
+ }
+ if (node instanceof RemoteNode) {
+ try {
+ RemoteNode remoteNode = (RemoteNode) node;
+ RemoteConfig config = new RemoteConfig(
+ RepositoryStateCache.INSTANCE
+ .getConfig(node.getRepository()),
+ remoteNode.getObject());
+ return withRefSpecs(config);
+ } catch (URISyntaxException e) {
+ return null;
+ }
+ }
return null;
}
+ private RemoteConfig withRefSpecs(RemoteConfig config) {
+ boolean fetchConfigured = !config.getFetchRefSpecs().isEmpty();
+ boolean pushConfigured = !config.getPushRefSpecs().isEmpty();
+ if (fetchConfigured || pushConfigured) {
+ return config;
+ }
+ return null;
+ }
}
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/tree/command/RepositoriesViewCommandHandler.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/tree/command/RepositoriesViewCommandHandler.java
index 1b88701ed..c9e1f6929 100644
--- a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/tree/command/RepositoriesViewCommandHandler.java
+++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/tree/command/RepositoriesViewCommandHandler.java
@@ -17,7 +17,6 @@
package org.eclipse.egit.ui.internal.repository.tree.command;
import java.io.File;
-import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
@@ -35,10 +34,9 @@ import org.eclipse.egit.ui.internal.repository.tree.FileNode;
import org.eclipse.egit.ui.internal.repository.tree.FolderNode;
import org.eclipse.egit.ui.internal.repository.tree.RepositoryTreeNode;
import org.eclipse.egit.ui.internal.repository.tree.WorkingDirNode;
+import org.eclipse.egit.ui.internal.selection.RepositoryStateCache;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredSelection;
-import org.eclipse.jgit.lib.Constants;
-import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.ISources;
@@ -106,14 +104,8 @@ abstract class RepositoriesViewCommandHandler<T extends RepositoryTreeNode<?>>
}
private boolean repositoryHasHead(T treeNode) {
- Repository repo = treeNode.getRepository();
- try {
- Ref ref = repo.exactRef(Constants.HEAD);
- return ref != null && ref.getObjectId() != null;
- } catch (IOException e) {
- // ignore and report false
- return false;
- }
+ return RepositoryStateCache.INSTANCE
+ .getHead(treeNode.getRepository()) != null;
}
private boolean selectionHasHead(boolean all) {
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/selection/RepositoryStateCache.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/selection/RepositoryStateCache.java
new file mode 100644
index 000000000..ac70edace
--- /dev/null
+++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/selection/RepositoryStateCache.java
@@ -0,0 +1,316 @@
+/*******************************************************************************
+ * Copyright (C) 2019 Thomas Wolf <thomas.wolf@paranor.ch>
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *******************************************************************************/
+package org.eclipse.egit.ui.internal.selection;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import org.eclipse.e4.core.contexts.IEclipseContext;
+import org.eclipse.e4.core.contexts.RunAndTrack;
+import org.eclipse.egit.ui.Activator;
+import org.eclipse.jface.text.ITextSelection;
+import org.eclipse.jface.viewers.StructuredSelection;
+import org.eclipse.jgit.annotations.NonNull;
+import org.eclipse.jgit.lib.Constants;
+import org.eclipse.jgit.lib.ObjectId;
+import org.eclipse.jgit.lib.Ref;
+import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.lib.RepositoryState;
+import org.eclipse.jgit.lib.StoredConfig;
+import org.eclipse.ui.IEditorInput;
+import org.eclipse.ui.IEditorPart;
+import org.eclipse.ui.ISources;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.part.MultiPageEditorPart;
+
+/**
+ * A global cache of some state of repositories. The cache is automatically
+ * cleared whenever the workbench selection or the menu selection changes.
+ * <p>
+ * Intended for use in property testers and in other handler activation or
+ * enablement code, such as {@code isEnabled()} methods. Using this cache can
+ * massively reduce the number of file system accesses done in the UI thread to
+ * evaluate some git repository state. The first handler evaluations will fill
+ * the cache, and subsequent enablement expressions can then re-use these cached
+ * values.
+ * </p>
+ */
+public class RepositoryStateCache {
+
+ private enum RepositoryItem {
+ CONFIG, HEAD, HEAD_REF, FULL_BRANCH_NAME, STATE
+ }
+
+ /** The singleton instance of the {@link RepositoryStateCache}. */
+ public static final RepositoryStateCache INSTANCE = new RepositoryStateCache();
+
+ /** "null" marker in the maps. */
+ private static final Object NOTHING = new Object();
+
+ private final AtomicBoolean stopped = new AtomicBoolean();
+
+ private final Map<File, Map<RepositoryItem, Object>> cache = new ConcurrentHashMap<>();
+
+ private RepositoryStateCache() {
+ // No creation from outside
+ }
+
+ /**
+ * Initializes the {@link RepositoryStateCache} and makes it listen to changes
+ * that may affect the cache.
+ */
+ public void initialize() {
+ // Clear the cache whenever the selection changes.
+ IEclipseContext applicationContext = PlatformUI.getWorkbench()
+ .getService(IEclipseContext.class);
+ // A RunAndTrack on the workbench context runs *before* any E3 or E4
+ // selection listener on the selection service, which is how expression
+ // re-evaluations for expressions based on the current selection are
+ // triggered. So we can ensure here that re-evaluations don't use stale
+ // cached values.
+ applicationContext.runAndTrack(new ContextListener(stopped, cache));
+ }
+
+ /**
+ * Disposes the {@link RepositoryStateCache} and makes it stop listening to
+ * changes in the workbench context.
+ */
+ public void dispose() {
+ stopped.set(true);
+ }
+
+ private static class ContextListener extends RunAndTrack {
+
+ private AtomicBoolean stopped;
+
+ private Map<?, ?> cache;
+
+ ContextListener(AtomicBoolean stopped, Map<?, ?> cache) {
+ super();
+ this.stopped = stopped;
+ this.cache = cache;
+ }
+
+ private Object lastSelection;
+
+ private Object lastMenuSelection;
+
+ @Override
+ public boolean changed(IEclipseContext context) {
+ if (stopped.get()) {
+ cache.clear();
+ return false;
+ }
+ Object selection = context
+ .get(ISources.ACTIVE_CURRENT_SELECTION_NAME);
+ if (selection instanceof ITextSelection) {
+ selection = getInput(context);
+ }
+ Object menuSelection = context
+ .getActive(ISources.ACTIVE_MENU_SELECTION_NAME);
+ if (menuSelection instanceof ITextSelection) {
+ menuSelection = getInput(context);
+ }
+ // Clearing the cache on every workbench _or_ menu selection
+ // change is defensive. It might be possible to not clear the
+ // cache if the menuSelection == lastSelection.
+ if (selection != lastSelection
+ || menuSelection != lastMenuSelection) {
+ cache.clear();
+ }
+ lastSelection = selection;
+ lastMenuSelection = menuSelection;
+ return true;
+ }
+
+ private Object getInput(IEclipseContext context) {
+ Object[] input = { null };
+ runExternalCode(() -> {
+ IEditorInput e = getEditorInput(context);
+ input[0] = e != null ? e : StructuredSelection.EMPTY;
+ });
+ return input[0];
+ }
+
+ private IEditorInput getEditorInput(IEclipseContext context) {
+ Object part = context.get(ISources.ACTIVE_PART_NAME);
+ if (!(part instanceof IEditorPart)) {
+ return null;
+ }
+ Object object = context.get(ISources.ACTIVE_EDITOR_INPUT_NAME);
+ Object editor = context.get(ISources.ACTIVE_EDITOR_NAME);
+ if (editor instanceof MultiPageEditorPart) {
+ Object nestedEditor = ((MultiPageEditorPart) editor)
+ .getSelectedPage();
+ if (nestedEditor instanceof IEditorPart) {
+ object = ((IEditorPart) nestedEditor).getEditorInput();
+ }
+ }
+ if (!(object instanceof IEditorInput)
+ && (editor instanceof IEditorPart)) {
+ object = ((IEditorPart) editor).getEditorInput();
+ }
+ if (object instanceof IEditorInput) {
+ return (IEditorInput) object;
+ }
+ return null;
+ }
+ }
+
+ private Map<RepositoryItem, Object> getItems(Repository repository) {
+ return cache.computeIfAbsent(repository.getDirectory(),
+ gitDir -> new ConcurrentHashMap<>());
+ }
+
+ /**
+ * Retrieves the given repository's {@link StoredConfig}.
+ *
+ * @param repository
+ * @return the {@link StoredConfig} of the repository
+ */
+ public StoredConfig getConfig(Repository repository) {
+ Object value = getItems(repository).computeIfAbsent(
+ RepositoryItem.CONFIG, key -> repository.getConfig());
+ return (StoredConfig) value;
+ }
+
+ private ObjectId getHead(Repository repository,
+ String[] fullName, Ref[] ref) {
+ ObjectId head = ObjectId.zeroId();
+ String name = null;
+ Ref r = null;
+ try {
+ r = repository.exactRef(Constants.HEAD);
+ } catch (IOException e) {
+ Activator.logError(e.getLocalizedMessage(), e);
+ }
+ ref[0] = r;
+ if (r != null) {
+ if (r.isSymbolic()) {
+ name = r.getTarget().getName();
+ }
+ head = r.getObjectId();
+ if (head != null) {
+ if (name == null) {
+ name = head.name();
+ }
+ } else {
+ head = ObjectId.zeroId();
+ }
+ }
+ fullName[0] = name != null ? name : ""; //$NON-NLS-1$
+ return head;
+ }
+
+ /**
+ * Retrieves the {@link ObjectId} of the current HEAD.
+ *
+ * @param repository
+ * @return ObjectId of HEAD, or {@code null} if none
+ */
+ public ObjectId getHead(Repository repository) {
+ if (repository == null) {
+ return null;
+ }
+ Map<RepositoryItem, Object> items = getItems(repository);
+ Object value = items.get(RepositoryItem.HEAD);
+ if (value == null) {
+ String[] fullName = { null };
+ Ref[] headRef = { null };
+ value = items.computeIfAbsent(RepositoryItem.HEAD,
+ key -> getHead(repository, fullName, headRef));
+ items.computeIfAbsent(RepositoryItem.FULL_BRANCH_NAME,
+ key -> fullName[0]);
+ items.computeIfAbsent(RepositoryItem.HEAD_REF,
+ key -> headRef[0] == null ? NOTHING : headRef[0]);
+ }
+ ObjectId head = (ObjectId) value;
+ if (head == null || head.equals(ObjectId.zeroId())) {
+ return null;
+ }
+ return head;
+ }
+
+
+ /**
+ * Retrieves the current HEAD ref.
+ *
+ * @param repository
+ * @return the HEAD ref, or {@code null} if none
+ */
+ public Ref getHeadRef(Repository repository) {
+ if (repository == null) {
+ return null;
+ }
+ Map<RepositoryItem, Object> items = getItems(repository);
+ Object value = items.get(RepositoryItem.HEAD_REF);
+ if (value == null) {
+ String[] fullName = { null };
+ Ref[] headRef = { null };
+ items.computeIfAbsent(RepositoryItem.HEAD,
+ key -> getHead(repository, fullName, headRef));
+ items.computeIfAbsent(RepositoryItem.FULL_BRANCH_NAME,
+ key -> fullName[0]);
+ value = items.computeIfAbsent(RepositoryItem.HEAD_REF,
+ key -> headRef[0] == null ? NOTHING : headRef[0]);
+ }
+ if (value == null || value == NOTHING) {
+ return null;
+ }
+ return (Ref) value;
+ }
+
+ /**
+ * Retrieves the full name of the current branch.
+ *
+ * @param repository
+ * @return the full branch name
+ */
+ public String getFullBranchName(Repository repository) {
+ if (repository == null) {
+ return null;
+ }
+ Map<RepositoryItem, Object> items = getItems(repository);
+ Object fullBranchName = items.get(RepositoryItem.FULL_BRANCH_NAME);
+ if (fullBranchName == null) {
+ String[] fullName = { null };
+ Ref[] headRef = { null };
+ items.computeIfAbsent(RepositoryItem.HEAD,
+ key -> getHead(repository, fullName, headRef));
+ fullBranchName = items.computeIfAbsent(
+ RepositoryItem.FULL_BRANCH_NAME, key -> fullName[0]);
+ items.computeIfAbsent(RepositoryItem.HEAD_REF,
+ key -> headRef[0] == null ? NOTHING : headRef[0]);
+ }
+ String name = (String) fullBranchName;
+ if (name == null || name.isEmpty()) {
+ return null;
+ }
+ return name;
+ }
+
+ /**
+ * Retrieves the repository state.
+ *
+ * @param repository
+ * @return the {@link RepositoryState}
+ */
+ public @NonNull RepositoryState getRepositoryState(Repository repository) {
+ Object value = getItems(repository).computeIfAbsent(
+ RepositoryItem.STATE, key -> repository.getRepositoryState());
+ assert value != null; // Keep the compiler happy.
+ return (RepositoryState) value;
+ }
+
+}
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/selection/SelectionUtils.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/selection/SelectionUtils.java
index a550cfd48..f769df785 100644
--- a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/selection/SelectionUtils.java
+++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/selection/SelectionUtils.java
@@ -514,15 +514,14 @@ public class SelectionUtils {
}
private static IEvaluationContext getEvaluationContext() {
- IEvaluationContext ctx;
IWorkbenchWindow activeWorkbenchWindow = PlatformUI.getWorkbench()
.getActiveWorkbenchWindow();
// no active window during Eclipse shutdown
- if (activeWorkbenchWindow == null)
+ if (activeWorkbenchWindow == null) {
return null;
+ }
IHandlerService hsr = CommonUtils.getService(activeWorkbenchWindow, IHandlerService.class);
- ctx = hsr.getCurrentState();
- return ctx;
+ return hsr != null ? hsr.getCurrentState() : null;
}
/**

Back to the top