Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThomas Wolf2019-10-13 17:14:35 -0400
committerThomas Wolf2019-11-12 02:34:49 -0500
commit0a2a6a4a54d0a7b3507641a261499566d80e1ae9 (patch)
treead48ad8473535b30833efcda8f8b23f2f3cacda0
parent528a53b2793a5f86c3f372e4b36e0933a0c481d6 (diff)
downloadegit-0a2a6a4a54d0a7b3507641a261499566d80e1ae9.tar.gz
egit-0a2a6a4a54d0a7b3507641a261499566d80e1ae9.tar.xz
egit-0a2a6a4a54d0a7b3507641a261499566d80e1ae9.zip
Decorators: cache more repository state
Generalize the mechanism previously only used for the branch state in the DecoratableResourceHelper. This cached the branch state per repository and relied on the label providers clearing that cache when needed. Use the same mechanism for more repository state, similar to what had been done in commit 8bf986c3 for handler enabling. Make RepositoryStateCache abstract; move the clearing on selection changes into a separate subclass and use that instead. Give decorators their own cache instance, and make sure they use it instead of computing things themselves over and over again. Bug: 550878 Change-Id: I988905103ad86e18c696269dd54d525fcdbc5cbc Signed-off-by: Thomas Wolf <thomas.wolf@paranor.ch>
-rw-r--r--org.eclipse.egit.gitflow.ui/META-INF/MANIFEST.MF1
-rw-r--r--org.eclipse.egit.gitflow.ui/src/org/eclipse/egit/gitflow/ui/internal/decorators/GitFlowLightweightDecorator.java87
-rw-r--r--org.eclipse.egit.gitflow.ui/src/org/eclipse/egit/gitflow/ui/internal/properties/RepositoryPropertyTester.java6
-rw-r--r--org.eclipse.egit.ui.test/src/org/eclipse/egit/ui/internal/decorators/GitLightweightDecoratorTest.java3
-rw-r--r--org.eclipse.egit.ui/META-INF/MANIFEST.MF2
-rwxr-xr-xorg.eclipse.egit.ui/src/org/eclipse/egit/ui/Activator.java6
-rw-r--r--org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/RepositoryStateCache.java (renamed from org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/selection/RepositoryStateCache.java)176
-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/DiscardChangesActionHandler.java4
-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.java6
-rw-r--r--org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/actions/PushActionHandler.java4
-rw-r--r--org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/actions/PushBranchActionHandler.java4
-rw-r--r--org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/actions/PushMenu.java4
-rw-r--r--org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/actions/PushUpstreamOrBranchActionHandler.java4
-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.java6
-rw-r--r--org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/commands/shared/RebaseCurrentRefCommand.java6
-rw-r--r--org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/decorators/DecoratableResourceAdapter.java17
-rw-r--r--org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/decorators/DecoratableResourceHelper.java89
-rw-r--r--org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/decorators/DecoratableResourceMapping.java14
-rw-r--r--org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/decorators/DecoratorRepositoryStateCache.java151
-rw-r--r--org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/decorators/GitLightweightDecorator.java14
-rw-r--r--org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/expressions/GitPropertyTester.java6
-rw-r--r--org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/fetch/SimpleConfigureFetchDialog.java6
-rw-r--r--org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/push/SimpleConfigurePushDialog.java6
-rw-r--r--org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/RepositoryTreeNodeDecorator.java57
-rw-r--r--org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/RepositoryTreeNodeWorkbenchAdapter.java22
-rw-r--r--org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/tree/RepositoriesViewPropertyTester.java20
-rw-r--r--org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/tree/command/FetchConfiguredRemoteCommand.java4
-rw-r--r--org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/tree/command/PushConfiguredRemoteCommand.java4
-rw-r--r--org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/tree/command/RepositoriesViewCommandHandler.java4
-rw-r--r--org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/selection/SelectionRepositoryStateCache.java146
33 files changed, 495 insertions, 402 deletions
diff --git a/org.eclipse.egit.gitflow.ui/META-INF/MANIFEST.MF b/org.eclipse.egit.gitflow.ui/META-INF/MANIFEST.MF
index 4e56f1e2a..df721f0c6 100644
--- a/org.eclipse.egit.gitflow.ui/META-INF/MANIFEST.MF
+++ b/org.eclipse.egit.gitflow.ui/META-INF/MANIFEST.MF
@@ -21,6 +21,7 @@ Import-Package: org.eclipse.egit.core;version="[5.6.0,5.7.0)",
org.eclipse.egit.ui.internal.actions;version="[5.6.0,5.7.0)",
org.eclipse.egit.ui.internal.branch;version="[5.6.0,5.7.0)",
org.eclipse.egit.ui.internal.commit;version="[5.6.0,5.7.0)",
+ org.eclipse.egit.ui.internal.decorators;version="[5.6.0,5.7.0)",
org.eclipse.egit.ui.internal.expressions;version="[5.6.0,5.7.0)",
org.eclipse.egit.ui.internal.rebase;version="[5.6.0,5.7.0)",
org.eclipse.egit.ui.internal.repository.tree;version="[5.6.0,5.7.0)",
diff --git a/org.eclipse.egit.gitflow.ui/src/org/eclipse/egit/gitflow/ui/internal/decorators/GitFlowLightweightDecorator.java b/org.eclipse.egit.gitflow.ui/src/org/eclipse/egit/gitflow/ui/internal/decorators/GitFlowLightweightDecorator.java
index f5ee7876b..ef0fad4f9 100644
--- a/org.eclipse.egit.gitflow.ui/src/org/eclipse/egit/gitflow/ui/internal/decorators/GitFlowLightweightDecorator.java
+++ b/org.eclipse.egit.gitflow.ui/src/org/eclipse/egit/gitflow/ui/internal/decorators/GitFlowLightweightDecorator.java
@@ -13,16 +13,16 @@ package org.eclipse.egit.gitflow.ui.internal.decorators;
import java.io.IOException;
import org.eclipse.core.runtime.ILog;
+import org.eclipse.egit.gitflow.GitFlowConfig;
import org.eclipse.egit.gitflow.GitFlowRepository;
import org.eclipse.egit.gitflow.ui.Activator;
import org.eclipse.egit.gitflow.ui.internal.UIIcons;
+import org.eclipse.egit.ui.internal.decorators.DecoratorRepositoryStateCache;
import org.eclipse.egit.ui.internal.repository.tree.RepositoryNode;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.jface.viewers.IDecoration;
import org.eclipse.jface.viewers.ILightweightLabelDecorator;
import org.eclipse.jface.viewers.LabelProvider;
-import org.eclipse.jgit.annotations.Nullable;
-import org.eclipse.jgit.lib.Repository;
import org.eclipse.swt.graphics.ImageData;
import org.eclipse.ui.PlatformUI;
@@ -53,57 +53,39 @@ public class GitFlowLightweightDecorator extends LabelProvider implements
*/
@Override
public void decorate(Object element, IDecoration decoration) {
- // Don't decorate if UI plugin is not running
- if (Activator.getDefault() == null) {
+ if (!PlatformUI.isWorkbenchRunning() || Activator.getDefault() == null) {
return;
}
- // Don't decorate if the workbench is not running
- if (!PlatformUI.isWorkbenchRunning()) {
- return;
+ GitFlowConfig config = null;
+ if (element instanceof GitFlowRepository) {
+ config = ((GitFlowRepository) element).getConfig();
+ } else if (element instanceof RepositoryNode) {
+ config = new GitFlowConfig(DecoratorRepositoryStateCache.INSTANCE
+ .getConfig(((RepositoryNode) element).getRepository()));
}
-
-
- final GitFlowRepository repository = getRepository(element);
try {
- if (repository != null) {
- decorateRepository(repository, decoration);
+ if (config != null) {
+ decorateRepository(config, decoration);
}
} catch (Exception e) {
- handleException(repository, e);
- }
- }
-
- private static @Nullable GitFlowRepository getRepository(Object element) {
- GitFlowRepository repository = null;
- if (element instanceof GitFlowRepository) {
- repository = (GitFlowRepository) element;
- }
-
- if (element instanceof RepositoryNode) {
- RepositoryNode node = (RepositoryNode) element;
- Repository repo = node.getObject();
- if (repo != null) {
- repository = new GitFlowRepository(repo);
- }
+ log.log(Activator.error(e.getMessage(), e));
}
-
- return repository;
}
/**
* Decorates a single repository.
*
- * @param repository
- * the repository to decorate
+ * @param config
+ * of the repository to decorate
* @param decoration
* the decoration
* @throws IOException
*/
- private void decorateRepository(GitFlowRepository repository,
+ private void decorateRepository(GitFlowConfig config,
IDecoration decoration) throws IOException {
final DecorationHelper helper = new DecorationHelper();
- helper.decorate(decoration, repository);
+ helper.decorate(decoration, config);
}
@@ -137,11 +119,8 @@ public class GitFlowLightweightDecorator extends LabelProvider implements
}
}
- private final static ImageDescriptor INITIALIZED_IMAGE;
-
- static {
- INITIALIZED_IMAGE = new CachedImageDescriptor(UIIcons.OVR_GITFLOW);
- }
+ private final static ImageDescriptor INITIALIZED_IMAGE = new CachedImageDescriptor(
+ UIIcons.OVR_GITFLOW);
/**
* Decorates the given <code>decoration</code> based on the state of the
@@ -149,20 +128,20 @@ public class GitFlowLightweightDecorator extends LabelProvider implements
*
* @param decoration
* the decoration to decorate
- * @param repository
- * the repository to retrieve state from
+ * @param config
+ * the config to retrieve state from
* @throws IOException
*/
- public void decorate(IDecoration decoration, GitFlowRepository repository)
+ public void decorate(IDecoration decoration, GitFlowConfig config)
throws IOException {
- decorateIcons(decoration, repository);
+ decorateIcons(decoration, config);
}
private void decorateIcons(IDecoration decoration,
- GitFlowRepository repository) throws IOException {
+ GitFlowConfig config) {
ImageDescriptor overlay = null;
- if (repository.getConfig().isInitialized()) {
+ if (config.isInitialized()) {
overlay = INITIALIZED_IMAGE;
}
@@ -170,22 +149,10 @@ public class GitFlowLightweightDecorator extends LabelProvider implements
// for feature branch
// Overlays can only be added once, so do it at the end
- decoration.addOverlay(overlay);
+ if (overlay != null) {
+ decoration.addOverlay(overlay);
+ }
}
}
-
- /**
- * Handle exceptions that occur in the decorator.
- *
- * @param repository
- * The repository that triggered the exception
- * @param e
- * The exception that occurred
- */
- private void handleException(GitFlowRepository repository, Exception e) {
- if (repository != null) {
- log.log(Activator.error(e.getMessage(), e));
- }
- }
}
diff --git a/org.eclipse.egit.gitflow.ui/src/org/eclipse/egit/gitflow/ui/internal/properties/RepositoryPropertyTester.java b/org.eclipse.egit.gitflow.ui/src/org/eclipse/egit/gitflow/ui/internal/properties/RepositoryPropertyTester.java
index ad7e9886c..cf06ba9fb 100644
--- a/org.eclipse.egit.gitflow.ui/src/org/eclipse/egit/gitflow/ui/internal/properties/RepositoryPropertyTester.java
+++ b/org.eclipse.egit.gitflow.ui/src/org/eclipse/egit/gitflow/ui/internal/properties/RepositoryPropertyTester.java
@@ -17,7 +17,7 @@ import java.io.File;
import org.eclipse.egit.gitflow.GitFlowConfig;
import org.eclipse.egit.ui.internal.expressions.AbstractPropertyTester;
-import org.eclipse.egit.ui.internal.selection.RepositoryStateCache;
+import org.eclipse.egit.ui.internal.selection.SelectionRepositoryStateCache;
import org.eclipse.jgit.lib.Repository;
/**
@@ -60,13 +60,13 @@ public class RepositoryPropertyTester extends AbstractPropertyTester {
private boolean internalTest(Repository repository, String property) {
GitFlowConfig config = new GitFlowConfig(
- RepositoryStateCache.INSTANCE.getConfig(repository));
+ SelectionRepositoryStateCache.INSTANCE.getConfig(repository));
if (IS_INITIALIZED.equals(property)) {
return config.isInitialized();
} else if (HAS_DEFAULT_REMOTE.equals(property)) {
return config.hasDefaultRemote();
} else {
- String branch = RepositoryStateCache.INSTANCE
+ String branch = SelectionRepositoryStateCache.INSTANCE
.getFullBranchName(repository);
if (branch == null) {
return false;
diff --git a/org.eclipse.egit.ui.test/src/org/eclipse/egit/ui/internal/decorators/GitLightweightDecoratorTest.java b/org.eclipse.egit.ui.test/src/org/eclipse/egit/ui/internal/decorators/GitLightweightDecoratorTest.java
index 2f41bf256..527f57b5d 100644
--- a/org.eclipse.egit.ui.test/src/org/eclipse/egit/ui/internal/decorators/GitLightweightDecoratorTest.java
+++ b/org.eclipse.egit.ui.test/src/org/eclipse/egit/ui/internal/decorators/GitLightweightDecoratorTest.java
@@ -260,8 +260,7 @@ public abstract class GitLightweightDecoratorTest
}
protected static DecoratableResource newDecoratableResource(
- IndexDiffData indexDiffData, IResource resource)
- throws IOException {
+ IndexDiffData indexDiffData, IResource resource) {
return new DecoratableResourceAdapter(indexDiffData, resource);
}
diff --git a/org.eclipse.egit.ui/META-INF/MANIFEST.MF b/org.eclipse.egit.ui/META-INF/MANIFEST.MF
index e263e4ce6..daf28b100 100644
--- a/org.eclipse.egit.ui/META-INF/MANIFEST.MF
+++ b/org.eclipse.egit.ui/META-INF/MANIFEST.MF
@@ -85,7 +85,7 @@ Export-Package: org.eclipse.egit.ui;version="5.6.0";x-friends:="org.eclipse.egit
org.eclipse.egit.ui.internal.commit.command;version="5.6.0";x-internal:=true,
org.eclipse.egit.ui.internal.components;version="5.6.0";x-friends:="org.eclipse.mylyn.github.ui",
org.eclipse.egit.ui.internal.credentials;version="5.6.0";x-internal:=true,
- org.eclipse.egit.ui.internal.decorators;version="5.6.0";x-internal:=true,
+ org.eclipse.egit.ui.internal.decorators;version="5.6.0";x-friends:="org.eclipse.egit.gitflow.ui",
org.eclipse.egit.ui.internal.dialogs;version="5.6.0";x-friends:="org.eclipse.egit.gitflow.ui",
org.eclipse.egit.ui.internal.expressions;version="5.6.0";x-friends:="org.eclipse.egit.gitflow.ui",
org.eclipse.egit.ui.internal.factories;version="5.6.0";x-internal:=true,
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 e1402f888..6e909515d 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
@@ -51,7 +51,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.selection.SelectionRepositoryStateCache;
import org.eclipse.egit.ui.internal.trace.GitTraceLocation;
import org.eclipse.egit.ui.internal.variables.GitTemplateVariableResolver;
import org.eclipse.jdt.internal.ui.JavaPlugin;
@@ -344,7 +344,7 @@ public class Activator extends AbstractUIPlugin implements DebugOptionsListener
context.registerService(DebugOptionsListener.class.getName(), this,
props);
- RepositoryStateCache.INSTANCE.initialize();
+ SelectionRepositoryStateCache.INSTANCE.initialize();
setupRepoChangeScanner();
setupFocusHandling();
setupCredentialsProvider();
@@ -900,7 +900,7 @@ public class Activator extends AbstractUIPlugin implements DebugOptionsListener
@Override
public void stop(final BundleContext context) throws Exception {
- RepositoryStateCache.INSTANCE.dispose();
+ SelectionRepositoryStateCache.INSTANCE.dispose();
if (focusListener != null) {
if (PlatformUI.isWorkbenchRunning()) {
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/RepositoryStateCache.java
index ac70edace..016791413 100644
--- 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/RepositoryStateCache.java
@@ -8,19 +8,14 @@
*
* SPDX-License-Identifier: EPL-2.0
*******************************************************************************/
-package org.eclipse.egit.ui.internal.selection;
+package org.eclipse.egit.ui.internal;
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;
@@ -28,144 +23,52 @@ 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;
+import org.eclipse.jgit.revwalk.RevCommit;
+import org.eclipse.jgit.revwalk.RevWalk;
/**
- * 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>
+ * A cache of some state of repositories. Concrete subclasses are responsible
+ * for clearing this cache in response to some event.
*/
-public class RepositoryStateCache {
+public abstract class RepositoryStateCache {
private enum RepositoryItem {
- CONFIG, HEAD, HEAD_REF, FULL_BRANCH_NAME, STATE
+ CONFIG, HEAD, HEAD_REF, HEAD_COMMIT, 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));
- }
+ public abstract void initialize();
/**
- * Disposes the {@link RepositoryStateCache} and makes it stop listening to
- * changes in the workbench context.
+ * Disposes the {@link RepositoryStateCache}.
*/
public void dispose() {
- stopped.set(true);
+ clear();
}
- 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];
- }
+ /**
+ * Completely clears the cache.
+ */
+ public void clear() {
+ cache.clear();
+ }
- 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;
- }
+ /**
+ * Clears all cached entries for the given {@link Repository}.
+ *
+ * @param repository
+ * to remove cached items of
+ */
+ public void clear(Repository repository) {
+ cache.remove(repository.getDirectory());
}
private Map<RepositoryItem, Object> getItems(Repository repository) {
@@ -272,6 +175,37 @@ public class RepositoryStateCache {
}
/**
+ * Retrieves the current HEAD commit of the repository.
+ *
+ * @param repository
+ * @return the commit, or {@code null} if none could be determined
+ */
+ public RevCommit getHeadCommit(Repository repository) {
+ if (repository == null) {
+ return null;
+ }
+ Map<RepositoryItem, Object> items = getItems(repository);
+ Object value = items.get(RepositoryItem.HEAD_COMMIT);
+ if (value == null) {
+ ObjectId headId = getHead(repository);
+ if (headId != null) {
+ try (RevWalk w = new RevWalk(repository)) {
+ RevCommit commit = w.parseCommit(headId);
+ items.put(RepositoryItem.HEAD_COMMIT, commit);
+ return commit;
+ } catch (IOException e) {
+ // Ignore here
+ }
+ }
+ items.put(RepositoryItem.HEAD_COMMIT, NOTHING);
+ return null;
+ } else if (value == NOTHING) {
+ return null;
+ }
+ return (RevCommit) value;
+ }
+
+ /**
* Retrieves the full name of the current branch.
*
* @param repository
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 2a0922cf4..229af9d0c 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,7 +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.selection.SelectionRepositoryStateCache;
import org.eclipse.egit.ui.internal.trace.GitTraceLocation;
import org.eclipse.jgit.annotations.NonNull;
import org.eclipse.jgit.lib.Config;
@@ -116,7 +116,7 @@ public class ResourcePropertyTester extends AbstractPropertyTester {
if ("canPushToGerrit".equals(property)) { //$NON-NLS-1$
return canPushToGerrit(repository);
}
- RepositoryState state = RepositoryStateCache.INSTANCE
+ RepositoryState state = SelectionRepositoryStateCache.INSTANCE
.getRepositoryState(repository);
if ("canAbortRebase".equals(property)) { //$NON-NLS-1$
@@ -155,7 +155,7 @@ public class ResourcePropertyTester extends AbstractPropertyTester {
*/
public static boolean hasGerritConfiguration(
@NonNull Repository repository) {
- Config config = RepositoryStateCache.INSTANCE.getConfig(repository);
+ Config config = SelectionRepositoryStateCache.INSTANCE.getConfig(repository);
if (GerritUtil.getCreateChangeId(config)) {
return true;
}
@@ -180,7 +180,7 @@ public class ResourcePropertyTester extends AbstractPropertyTester {
* Gerrit
*/
public static boolean canFetchFromGerrit(@NonNull Repository repository) {
- Config config = RepositoryStateCache.INSTANCE.getConfig(repository);
+ Config config = SelectionRepositoryStateCache.INSTANCE.getConfig(repository);
try {
List<RemoteConfig> remoteConfigs = RemoteConfig
.getAllRemoteConfigs(config);
@@ -201,7 +201,7 @@ public class ResourcePropertyTester extends AbstractPropertyTester {
* Gerrit
*/
public static boolean canPushToGerrit(@NonNull Repository repository) {
- Config config = RepositoryStateCache.INSTANCE.getConfig(repository);
+ Config config = SelectionRepositoryStateCache.INSTANCE.getConfig(repository);
try {
List<RemoteConfig> remoteConfigs = RemoteConfig
.getAllRemoteConfigs(config);
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 12cfb59f3..ef9a30f36 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,7 +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.egit.ui.internal.selection.SelectionRepositoryStateCache;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.lib.RepositoryState;
import org.eclipse.ui.IWorkbenchPart;
@@ -73,7 +73,7 @@ public class DiscardChangesActionHandler extends RepositoryActionHandler {
if (repositories.length == 0)
return false;
for (Repository repository : repositories) {
- if (!RepositoryState.SAFE.equals(RepositoryStateCache.INSTANCE
+ if (!RepositoryState.SAFE.equals(SelectionRepositoryStateCache.INSTANCE
.getRepositoryState(repository))) {
return false;
}
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 4cd750cff..fabec6d6f 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,7 +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.egit.ui.internal.selection.SelectionRepositoryStateCache;
import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jgit.lib.Constants;
@@ -76,7 +76,7 @@ public class MergeActionHandler extends RepositoryActionHandler {
Repository repo = getRepository();
return repo != null
&& RepositoryState.SAFE.equals(
- RepositoryStateCache.INSTANCE.getRepositoryState(repo))
+ SelectionRepositoryStateCache.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 caa1c0635..97955986d 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
@@ -19,7 +19,7 @@ import java.util.Set;
import org.eclipse.core.commands.ExecutionEvent;
import org.eclipse.core.commands.ExecutionException;
import org.eclipse.egit.ui.internal.pull.PullOperationUI;
-import org.eclipse.egit.ui.internal.selection.RepositoryStateCache;
+import org.eclipse.egit.ui.internal.selection.SelectionRepositoryStateCache;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.Repository;
@@ -44,13 +44,13 @@ public class PullFromUpstreamActionHandler extends RepositoryActionHandler {
// ensure that a branch is checked out
Repository[] repos = getRepositories();
for (Repository repo : repos) {
- String fullBranch = RepositoryStateCache.INSTANCE
+ String fullBranch = SelectionRepositoryStateCache.INSTANCE
.getFullBranchName(repo);
if (fullBranch == null
|| !fullBranch.startsWith(Constants.R_REFS)) {
return false;
}
- if (RepositoryStateCache.INSTANCE.getHead(repo) == null) {
+ if (SelectionRepositoryStateCache.INSTANCE.getHead(repo) == null) {
return false;
}
}
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 5d6cbe940..6294b2496 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
@@ -19,7 +19,7 @@ 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.egit.ui.internal.selection.SelectionRepositoryStateCache;
import org.eclipse.jface.dialogs.ErrorDialog;
import org.eclipse.jface.wizard.WizardDialog;
import org.eclipse.jgit.lib.Repository;
@@ -59,6 +59,6 @@ public class PushActionHandler extends RepositoryActionHandler {
if (repository == null) {
return false;
}
- return RepositoryStateCache.INSTANCE.getHead(repository) != null;
+ return SelectionRepositoryStateCache.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 07faf8081..a6fadacfc 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
@@ -16,7 +16,7 @@ import org.eclipse.core.commands.ExecutionException;
import org.eclipse.egit.ui.Activator;
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.egit.ui.internal.selection.SelectionRepositoryStateCache;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.Ref;
@@ -55,7 +55,7 @@ public class PushBranchActionHandler extends RepositoryActionHandler {
if (repository == null) {
return false;
}
- return RepositoryStateCache.INSTANCE.getHead(repository) != null;
+ return SelectionRepositoryStateCache.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 b34abd100..35f7744cf 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
@@ -15,7 +15,7 @@ package org.eclipse.egit.ui.internal.actions;
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.SelectionRepositoryStateCache;
import org.eclipse.egit.ui.internal.selection.SelectionUtils;
import org.eclipse.jface.action.IContributionItem;
import org.eclipse.jgit.lib.Constants;
@@ -69,7 +69,7 @@ public class PushMenu extends CompoundContributionItem implements
.getCurrentState());
if (repository != null) {
- String ref = RepositoryStateCache.INSTANCE
+ String ref = SelectionRepositoryStateCache.INSTANCE
.getFullBranchName(repository);
String menuLabel = UIText.PushMenu_PushHEAD;
if (ref != null && ref.startsWith(Constants.R_HEADS)) {
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 63f76004a..322d52a9c 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
@@ -18,7 +18,7 @@ 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.egit.ui.internal.selection.SelectionRepositoryStateCache;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.lib.Repository;
@@ -72,7 +72,7 @@ public class PushUpstreamOrBranchActionHandler extends RepositoryActionHandler {
if (repository == null) {
return false;
}
- Ref head = RepositoryStateCache.INSTANCE.getHeadRef(repository);
+ Ref head = SelectionRepositoryStateCache.INSTANCE.getHeadRef(repository);
return head != null && head.isSymbolic();
}
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 f7a0ba451..9a4dbf3a6 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,7 +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.egit.ui.internal.selection.SelectionRepositoryStateCache;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.lib.RepositoryState;
@@ -50,7 +50,7 @@ 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 = RepositoryStateCache.INSTANCE
+ RepositoryState state = SelectionRepositoryStateCache.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 29b4efdc6..6db47e6d0 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,7 +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.SelectionRepositoryStateCache;
import org.eclipse.egit.ui.internal.selection.SelectionUtils;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredSelection;
@@ -322,11 +322,11 @@ abstract class RepositoryActionHandler extends AbstractHandler {
* {@code false} otherwise
*/
protected boolean containsHead(Repository repository) {
- return RepositoryStateCache.INSTANCE.getHead(repository) != null;
+ return SelectionRepositoryStateCache.INSTANCE.getHead(repository) != null;
}
protected boolean isLocalBranchCheckedout(Repository repository) {
- String fullBranch = RepositoryStateCache.INSTANCE
+ String fullBranch = SelectionRepositoryStateCache.INSTANCE
.getFullBranchName(repository);
return fullBranch != null && fullBranch.startsWith(Constants.R_HEADS);
}
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 2ae704bba..50c5bcb05 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,7 +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.SelectionRepositoryStateCache;
import org.eclipse.egit.ui.internal.selection.SelectionUtils;
import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.jface.viewers.ISelection;
@@ -129,7 +129,7 @@ public class RebaseCurrentRefCommand extends AbstractRebaseCommandHandler {
Repository repo = SelectionUtils.getRepository(ctx);
if (repo != null) {
boolean enabled = isEnabledForState(repo,
- RepositoryStateCache.INSTANCE.getRepositoryState(repo));
+ SelectionRepositoryStateCache.INSTANCE.getRepositoryState(repo));
setBaseEnabled(enabled);
} else {
setBaseEnabled(false);
@@ -147,7 +147,7 @@ public class RebaseCurrentRefCommand extends AbstractRebaseCommandHandler {
public static boolean isEnabledForState(Repository repo,
RepositoryState state) {
return state == RepositoryState.SAFE
- && RepositoryStateCache.INSTANCE.getHead(repo) != null;
+ && SelectionRepositoryStateCache.INSTANCE.getHead(repo) != null;
}
private String getFullBranch(Repository repository)
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/decorators/DecoratableResourceAdapter.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/decorators/DecoratableResourceAdapter.java
index eccb99fb5..c0adcb424 100644
--- a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/decorators/DecoratableResourceAdapter.java
+++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/decorators/DecoratableResourceAdapter.java
@@ -22,8 +22,6 @@
package org.eclipse.egit.ui.internal.decorators;
-import java.io.IOException;
-
import org.eclipse.core.resources.IResource;
import org.eclipse.egit.core.internal.indexdiff.IndexDiffData;
import org.eclipse.egit.core.project.RepositoryMapping;
@@ -37,8 +35,7 @@ import org.eclipse.jgit.revwalk.RevCommit;
class DecoratableResourceAdapter extends DecoratableResource {
public DecoratableResourceAdapter(@NonNull IndexDiffData indexDiffData,
- @NonNull IResource resourceToWrap)
- throws IOException {
+ @NonNull IResource resourceToWrap) {
super(resourceToWrap);
boolean trace = GitTraceLocation.DECORATION.isActive();
long start = 0;
@@ -71,11 +68,13 @@ class DecoratableResourceAdapter extends DecoratableResource {
// We only need this very expensive info for for decorating
// projects and folders that are submodule or nested repository
// roots
- repositoryName = DecoratableResourceHelper
- .getRepositoryName(repository);
- branch = DecoratableResourceHelper.getShortBranch(repository);
- branchStatus = DecoratableResourceHelper.getBranchStatus(repository);
- RevCommit headCommit = DecoratableResourceHelper
+ repositoryName = DecoratorRepositoryStateCache.INSTANCE
+ .getRepositoryNameAndState(repository);
+ branch = DecoratorRepositoryStateCache.INSTANCE
+ .getCurrentBranchLabel(repository);
+ branchStatus = DecoratorRepositoryStateCache.INSTANCE
+ .getBranchStatus(repository);
+ RevCommit headCommit = DecoratorRepositoryStateCache.INSTANCE
.getHeadCommit(repository);
if (headCommit != null) {
commitMessage = headCommit.getShortMessage();
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/decorators/DecoratableResourceHelper.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/decorators/DecoratableResourceHelper.java
deleted file mode 100644
index 8098085fe..000000000
--- a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/decorators/DecoratableResourceHelper.java
+++ /dev/null
@@ -1,89 +0,0 @@
-/*******************************************************************************
- * Copyright (C) 2011, Philipp Thun <philipp.thun@sap.com>
- * Copyright (C) 2011, Dariusz Luksza <dariusz@luksza.org>
- * Copyright (C) 2011, Christian Halstrick <christian.halstrick@sap.com>
- *
- * 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.decorators;
-
-import java.io.IOException;
-import java.util.Collections;
-import java.util.Map;
-import java.util.WeakHashMap;
-
-import org.eclipse.egit.core.internal.indexdiff.IndexDiffData;
-import org.eclipse.egit.ui.Activator;
-import org.eclipse.egit.ui.internal.GitLabels;
-import org.eclipse.jgit.lib.BranchTrackingStatus;
-import org.eclipse.jgit.lib.Repository;
-import org.eclipse.jgit.lib.RepositoryState;
-import org.eclipse.jgit.revwalk.RevCommit;
-
-/**
- * Helper class to create decoratable resources
- *
- * @see IDecoratableResource
- */
-public class DecoratableResourceHelper {
-
- /**
- * Maps repository to the branch state. The entries are removed each time
- * {@link IndexDiffData} changes
- *
- * @see GitLightweightDecorator#indexDiffChanged(Repository,
- * org.eclipse.egit.core.internal.indexdiff.IndexDiffData)
- */
- private static Map<Repository, String> branchState = Collections
- .synchronizedMap(new WeakHashMap<Repository, String>());
-
- static String getRepositoryName(Repository repository) {
- String repoName = Activator.getDefault().getRepositoryUtil()
- .getRepositoryName(repository);
- RepositoryState state = repository.getRepositoryState();
- if (state != RepositoryState.SAFE)
- return repoName + '|' + state.getDescription();
- else
- return repoName;
- }
-
- static String getShortBranch(Repository repository) throws IOException {
- return Activator.getDefault().getRepositoryUtil()
- .getShortBranch(repository);
- }
-
- static RevCommit getHeadCommit(Repository repository) {
- return Activator.getDefault().getRepositoryUtil()
- .parseHeadCommit(repository);
- }
-
- static String getBranchStatus(Repository repo) throws IOException {
- String cachedStatus = branchState.get(repo);
- if (cachedStatus != null)
- return cachedStatus;
-
- String branchName = repo.getBranch();
- if (branchName == null)
- return null;
-
- BranchTrackingStatus status = BranchTrackingStatus.of(repo, branchName);
- if (status == null)
- return null;
-
- if (status.getAheadCount() == 0 && status.getBehindCount() == 0)
- return null;
-
- String formattedStatus = GitLabels.formatBranchTrackingStatus(status);
- branchState.put(repo, formattedStatus);
- return formattedStatus;
- }
-
- static void clearState(Repository repo) {
- branchState.remove(repo);
- }
-}
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/decorators/DecoratableResourceMapping.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/decorators/DecoratableResourceMapping.java
index 70282f320..e0a992412 100644
--- a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/decorators/DecoratableResourceMapping.java
+++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/decorators/DecoratableResourceMapping.java
@@ -133,18 +133,18 @@ public class DecoratableResourceMapping extends DecoratableResourceGroup {
if (repositories.size() == 1) {
// single repo, single branch --> [repo branch]
Repository repository = repositories.iterator().next();
- resource.repositoryName = DecoratableResourceHelper
- .getRepositoryName(repository);
- resource.branch = DecoratableResourceHelper
- .getShortBranch(repository);
- resource.branchStatus = DecoratableResourceHelper
+ resource.repositoryName = DecoratorRepositoryStateCache.INSTANCE
+ .getRepositoryNameAndState(repository);
+ resource.branch = DecoratorRepositoryStateCache.INSTANCE
+ .getCurrentBranchLabel(repository);
+ resource.branchStatus = DecoratorRepositoryStateCache.INSTANCE
.getBranchStatus(repository);
} else if (repositories.size() > 1) {
// collect branch names but skip branch status (doesn't make sense)
Set<String> branches = new HashSet<>(2);
for (Repository repository : repositories) {
- branches.add(
- DecoratableResourceHelper.getShortBranch(repository));
+ branches.add(DecoratorRepositoryStateCache.INSTANCE
+ .getCurrentBranchLabel(repository));
if (branches.size() > 1)
break;
}
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/decorators/DecoratorRepositoryStateCache.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/decorators/DecoratorRepositoryStateCache.java
new file mode 100644
index 000000000..934bf1b25
--- /dev/null
+++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/decorators/DecoratorRepositoryStateCache.java
@@ -0,0 +1,151 @@
+/*******************************************************************************
+ * 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.decorators;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+import org.eclipse.egit.core.internal.CoreText;
+import org.eclipse.egit.ui.Activator;
+import org.eclipse.egit.ui.internal.GitLabels;
+import org.eclipse.egit.ui.internal.RepositoryStateCache;
+import org.eclipse.jgit.lib.BranchTrackingStatus;
+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.util.StringUtils;
+
+/**
+ * A {@link RepositoryStateCache} for decorators.
+ */
+public class DecoratorRepositoryStateCache extends RepositoryStateCache {
+
+ /**
+ * The singleton {@link DecoratorRepositoryStateCache}.
+ */
+ public static final DecoratorRepositoryStateCache INSTANCE = new DecoratorRepositoryStateCache();
+
+ private final Map<File, String> branchLabels = new ConcurrentHashMap<>();
+
+ private final Map<File, String> branchStateLabels = new ConcurrentHashMap<>();
+
+ private DecoratorRepositoryStateCache() {
+ // No public instantiation
+ }
+
+ @Override
+ public void initialize() {
+ // Nothing. Instead the label providers or decorators that listen to
+ // events will clear their instance of this cache as appropriate.
+ }
+
+ @Override
+ public void clear() {
+ super.clear();
+ branchLabels.clear();
+ branchStateLabels.clear();
+ }
+
+ @Override
+ public void clear(Repository repository) {
+ super.clear(repository);
+ branchLabels.remove(repository.getDirectory());
+ branchStateLabels.remove(repository.getDirectory());
+ }
+
+ /**
+ * Retrieves a display name for the {@link Repository}, possibly augmented
+ * with state information.
+ *
+ * @param repository
+ * to get the name of
+ * @return the name
+ */
+ public String getRepositoryNameAndState(Repository repository) {
+ String repoName = Activator.getDefault().getRepositoryUtil()
+ .getRepositoryName(repository);
+ RepositoryState state = getRepositoryState(repository);
+ if (state != RepositoryState.SAFE) {
+ return repoName + '|' + state.getDescription();
+ } else {
+ return repoName;
+ }
+ }
+
+ /**
+ * Retrieves a label for the current HEAD of a {@link Repository}.
+ *
+ * @param repository
+ * to get the label of the current HEAD of
+ * @return the label
+ */
+ public String getCurrentBranchLabel(Repository repository) {
+ return branchLabels.computeIfAbsent(repository.getDirectory(), dir -> {
+ Ref head = getHeadRef(repository);
+ if (head == null) {
+ return CoreText.RepositoryUtil_noHead;
+ }
+ if (head.isSymbolic()) {
+ String branchName = getFullBranchName(repository);
+ return Repository.shortenRefName(branchName);
+ }
+ ObjectId objectId = head.getObjectId();
+ if (objectId == null) {
+ return CoreText.RepositoryUtil_noHead;
+ }
+ String ref = Activator.getDefault().getRepositoryUtil()
+ .mapCommitToRef(repository, objectId.name(), false);
+ if (ref != null) {
+ return Repository.shortenRefName(ref) + ' '
+ + objectId.abbreviate(7).name();
+ } else {
+ return objectId.abbreviate(7).name();
+ }
+ });
+ }
+
+ /**
+ * Retrieves a label for the {@link BranchTrackingStatus} of the current
+ * HEAD.
+ *
+ * @param repository
+ * to get the status label for
+ * @return the label, or {@code null} if none
+ */
+ public String getBranchStatus(Repository repository) {
+ String label = branchStateLabels
+ .computeIfAbsent(repository.getDirectory(), dir -> {
+ String branchName = getFullBranchName(repository);
+ if (branchName == null) {
+ return ""; //$NON-NLS-1$
+ }
+ BranchTrackingStatus status = null;
+ try {
+ status = BranchTrackingStatus.of(repository,
+ branchName);
+ } catch (IOException e) {
+ // Ignore here; return null below.
+ }
+ if (status == null) {
+ return ""; //$NON-NLS-1$
+ }
+ if (status.getAheadCount() == 0
+ && status.getBehindCount() == 0) {
+ return ""; //$NON-NLS-1$
+ }
+ return GitLabels.formatBranchTrackingStatus(status);
+ });
+ return StringUtils.isEmptyOrNull(label) ? null : label;
+ }
+}
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/decorators/GitLightweightDecorator.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/decorators/GitLightweightDecorator.java
index e53efd5a1..d8425772b 100644
--- a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/decorators/GitLightweightDecorator.java
+++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/decorators/GitLightweightDecorator.java
@@ -213,10 +213,9 @@ public class GitLightweightDecorator extends GitDecorator
*
* @param resource the resource to decorate
* @param decoration the decoration
- * @throws CoreException
*/
private void decorateResource(@NonNull IResource resource,
- IDecoration decoration) throws CoreException {
+ IDecoration decoration) {
if (resource.getType() == IResource.ROOT || !resource.isAccessible()) {
return;
}
@@ -226,13 +225,8 @@ public class GitLightweightDecorator extends GitDecorator
if (indexDiffData == null) {
return;
}
- IDecoratableResource decoratableResource = null;
- try {
- decoratableResource = new DecoratableResourceAdapter(indexDiffData, resource);
- } catch (IOException e) {
- throw new CoreException(Activator.createErrorStatus(
- NLS.bind(UIText.Decorator_exceptionMessage, resource), e));
- }
+ IDecoratableResource decoratableResource = new DecoratableResourceAdapter(
+ indexDiffData, resource);
helper.decorate(decoration, decoratableResource);
}
@@ -697,7 +691,7 @@ public class GitLightweightDecorator extends GitDecorator
public void indexDiffChanged(Repository repository,
IndexDiffData indexDiffData) {
// clear calculated repo data
- DecoratableResourceHelper.clearState(repository);
+ DecoratorRepositoryStateCache.INSTANCE.clear(repository);
super.indexDiffChanged(repository, indexDiffData);
}
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 b8079a9ef..e1a8b3333 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,7 +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.egit.ui.internal.selection.SelectionRepositoryStateCache;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.Ref;
@@ -92,13 +92,13 @@ public class GitPropertyTester extends AbstractPropertyTester {
Repository repository = Adapters.adapt(receiver, Repository.class);
if (repository != null) {
return computeResult(expectedValue,
- RepositoryState.SAFE.equals(RepositoryStateCache.INSTANCE
+ RepositoryState.SAFE.equals(SelectionRepositoryStateCache.INSTANCE
.getRepositoryState(repository)));
}
} else if ("canCommit".equals(property)) { //$NON-NLS-1$
Repository repository = Adapters.adapt(receiver, Repository.class);
if (repository != null) {
- RepositoryState state = RepositoryStateCache.INSTANCE
+ RepositoryState state = SelectionRepositoryStateCache.INSTANCE
.getRepositoryState(repository);
return computeResult(expectedValue, state.canCommit());
}
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 979e31da4..c117a29bc 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,7 +24,7 @@ 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.egit.ui.internal.selection.SelectionRepositoryStateCache;
import org.eclipse.jface.dialogs.Dialog;
import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.jface.window.Window;
@@ -108,14 +108,14 @@ public class SimpleConfigureFetchDialog extends AbstractConfigureRemoteDialog {
*/
public static RemoteConfig getConfiguredRemoteCached(
Repository repository) {
- String branch = RepositoryStateCache.INSTANCE
+ String branch = SelectionRepositoryStateCache.INSTANCE
.getFullBranchName(repository);
if (branch == null) {
return null;
}
branch = Repository.shortenRefName(branch);
return getConfiguredRemote(branch,
- RepositoryStateCache.INSTANCE.getConfig(repository));
+ SelectionRepositoryStateCache.INSTANCE.getConfig(repository));
}
/**
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 ad38fd701..f14ae688a 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,7 +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.egit.ui.internal.selection.SelectionRepositoryStateCache;
import org.eclipse.jface.dialogs.Dialog;
import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.jface.layout.GridDataFactory;
@@ -121,14 +121,14 @@ public class SimpleConfigurePushDialog extends AbstractConfigureRemoteDialog {
*/
public static RemoteConfig getConfiguredRemoteCached(
Repository repository) {
- String branch = RepositoryStateCache.INSTANCE
+ String branch = SelectionRepositoryStateCache.INSTANCE
.getFullBranchName(repository);
if (branch == null) {
return null;
}
branch = Repository.shortenRefName(branch);
return getConfiguredRemote(branch,
- RepositoryStateCache.INSTANCE.getConfig(repository));
+ SelectionRepositoryStateCache.INSTANCE.getConfig(repository));
}
private static RemoteConfig getConfiguredRemote(String branch,
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/RepositoryTreeNodeDecorator.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/RepositoryTreeNodeDecorator.java
index 4420db0b2..be27a72d3 100644
--- a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/RepositoryTreeNodeDecorator.java
+++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/RepositoryTreeNodeDecorator.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2018 Thomas Wolf <thomas.wolf@paranor.ch>
+ * Copyright (c) 2018, 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
@@ -11,7 +11,6 @@
package org.eclipse.egit.ui.internal.repository;
import java.io.IOException;
-import java.text.MessageFormat;
import java.util.Set;
import org.eclipse.core.commands.IStateListener;
@@ -23,8 +22,8 @@ import org.eclipse.egit.core.internal.indexdiff.IndexDiffCacheEntry;
import org.eclipse.egit.core.internal.indexdiff.IndexDiffData;
import org.eclipse.egit.ui.Activator;
import org.eclipse.egit.ui.internal.CommonUtils;
-import org.eclipse.egit.ui.internal.GitLabels;
import org.eclipse.egit.ui.internal.UIText;
+import org.eclipse.egit.ui.internal.decorators.DecoratorRepositoryStateCache;
import org.eclipse.egit.ui.internal.decorators.GitDecorator;
import org.eclipse.egit.ui.internal.repository.tree.AdditionalRefNode;
import org.eclipse.egit.ui.internal.repository.tree.RefNode;
@@ -35,8 +34,6 @@ import org.eclipse.egit.ui.internal.repository.tree.TagNode;
import org.eclipse.egit.ui.internal.repository.tree.command.ToggleBranchCommitCommand;
import org.eclipse.jface.viewers.IDecoration;
import org.eclipse.jgit.annotations.NonNull;
-import org.eclipse.jgit.lib.BranchTrackingStatus;
-import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.lib.Repository;
@@ -85,6 +82,13 @@ public class RepositoryTreeNodeDecorator extends GitDecorator
}
@Override
+ public void indexDiffChanged(Repository repository,
+ IndexDiffData indexDiffData) {
+ DecoratorRepositoryStateCache.INSTANCE.clear(repository);
+ super.indexDiffChanged(repository, indexDiffData);
+ }
+
+ @Override
public void handleStateChange(State state, Object oldValue) {
try {
boolean newValue = ((Boolean) state.getValue())
@@ -103,19 +107,12 @@ public class RepositoryTreeNodeDecorator extends GitDecorator
RepositoryTreeNode<?> node = (RepositoryTreeNode) element;
Repository repository = node.getRepository();
if (repository != null) {
- try {
- decorateText(node, repository, decoration);
- } catch (IOException e) {
- Activator.logError(MessageFormat.format(
- UIText.GitLabelProvider_UnableToRetrieveLabel,
- element.toString()), e);
- }
+ decorateText(node, repository, decoration);
}
}
private void decorateText(RepositoryTreeNode<?> node,
- @NonNull Repository repository, IDecoration decoration)
- throws IOException {
+ @NonNull Repository repository, IDecoration decoration) {
boolean decorated = false;
switch (node.getType()) {
case REPO:
@@ -183,8 +180,7 @@ public class RepositoryTreeNodeDecorator extends GitDecorator
}
private boolean decorateRepository(RepositoryTreeNode<?> node,
- @NonNull Repository repository, IDecoration decoration)
- throws IOException {
+ @NonNull Repository repository, IDecoration decoration) {
boolean isSubModule = node.getParent() != null && node.getParent()
.getType() == RepositoryTreeNodeType.SUBMODULES;
if (RepositoryUtil.hasChanges(repository)) {
@@ -192,7 +188,8 @@ public class RepositoryTreeNodeDecorator extends GitDecorator
}
StringBuilder suffix = new StringBuilder();
if (isSubModule) {
- Ref head = repository.exactRef(Constants.HEAD);
+ Ref head = DecoratorRepositoryStateCache.INSTANCE
+ .getHeadRef(repository);
if (head == null) {
return false;
}
@@ -205,33 +202,29 @@ public class RepositoryTreeNodeDecorator extends GitDecorator
}
suffix.append(']');
if (verboseBranchMode && head.getObjectId() != null) {
- try (RevWalk walk = new RevWalk(repository)) {
- RevCommit commit = walk.parseCommit(head.getObjectId());
+ RevCommit commit = DecoratorRepositoryStateCache.INSTANCE
+ .getHeadCommit(repository);
+ if (commit != null) {
suffix.append(' ').append(commit.getShortMessage());
- } catch (IOException ignored) {
- // Ignored
}
}
} else {
// Not a submodule
- String branch = Activator.getDefault().getRepositoryUtil()
- .getShortBranch(repository);
+ String branch = DecoratorRepositoryStateCache.INSTANCE
+ .getCurrentBranchLabel(repository);
if (branch == null) {
return false;
}
suffix.append(" ["); //$NON-NLS-1$
suffix.append(branch);
- BranchTrackingStatus trackingStatus = BranchTrackingStatus
- .of(repository, branch);
- if (trackingStatus != null && (trackingStatus.getAheadCount() != 0
- || trackingStatus.getBehindCount() != 0)) {
- String formattedTrackingStatus = GitLabels
- .formatBranchTrackingStatus(trackingStatus);
- suffix.append(' ').append(formattedTrackingStatus);
+ String trackingStatus = DecoratorRepositoryStateCache.INSTANCE
+ .getBranchStatus(repository);
+ if (trackingStatus != null) {
+ suffix.append(' ').append(trackingStatus);
}
-
- RepositoryState repositoryState = repository.getRepositoryState();
+ RepositoryState repositoryState = DecoratorRepositoryStateCache.INSTANCE
+ .getRepositoryState(repository);
if (repositoryState != RepositoryState.SAFE) {
suffix.append(" - ") //$NON-NLS-1$
.append(repositoryState.getDescription());
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/RepositoryTreeNodeWorkbenchAdapter.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/RepositoryTreeNodeWorkbenchAdapter.java
index 598c16381..5be2e5772 100644
--- a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/RepositoryTreeNodeWorkbenchAdapter.java
+++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/repository/RepositoryTreeNodeWorkbenchAdapter.java
@@ -11,7 +11,6 @@
package org.eclipse.egit.ui.internal.repository;
import java.io.File;
-import java.io.IOException;
import java.text.MessageFormat;
import org.eclipse.core.runtime.IPath;
@@ -20,6 +19,7 @@ import org.eclipse.egit.ui.internal.GitLabels;
import org.eclipse.egit.ui.internal.ResourcePropertyTester;
import org.eclipse.egit.ui.internal.UIIcons;
import org.eclipse.egit.ui.internal.UIText;
+import org.eclipse.egit.ui.internal.decorators.DecoratorRepositoryStateCache;
import org.eclipse.egit.ui.internal.repository.tree.RepositoryTreeNode;
import org.eclipse.egit.ui.internal.repository.tree.RepositoryTreeNodeType;
import org.eclipse.egit.ui.internal.repository.tree.StashedCommitNode;
@@ -67,13 +67,9 @@ public class RepositoryTreeNodeWorkbenchAdapter extends WorkbenchAdapter {
return null;
}
// We have to decorate here: if we let an asynchronous lightweight
- // decorator do it, image decorations may flicker in the repositories
- // view and elsewhere where we'd refresh viewers.
- try {
- return decorateImageDescriptor(base, node);
- } catch (IOException e) {
- return base;
- }
+ // decorator do it, image decorations may flicker in the
+ // repositories view and elsewhere where we'd refresh viewers.
+ return decorateImageDescriptor(base, node);
}
private ImageDescriptor getBaseImageDescriptor(
@@ -107,8 +103,8 @@ public class RepositoryTreeNodeWorkbenchAdapter extends WorkbenchAdapter {
}
private ImageDescriptor decorateImageDescriptor(
- @NonNull ImageDescriptor base, @NonNull RepositoryTreeNode<?> node)
- throws IOException {
+ @NonNull ImageDescriptor base,
+ @NonNull RepositoryTreeNode<?> node) {
switch (node.getType()) {
case TAG:
case ADDITIONALREF:
@@ -121,7 +117,8 @@ public class RepositoryTreeNodeWorkbenchAdapter extends WorkbenchAdapter {
String compareString = null;
Repository repository = node.getRepository();
- String branchName = repository.getFullBranch();
+ String branchName = DecoratorRepositoryStateCache.INSTANCE
+ .getFullBranchName(repository);
if (branchName == null) {
return base;
}
@@ -156,7 +153,8 @@ public class RepositoryTreeNodeWorkbenchAdapter extends WorkbenchAdapter {
}
ObjectId objectId = leaf.getObjectId();
if (objectId != null && objectId
- .equals(repository.resolve(Constants.HEAD))) {
+ .equals(DecoratorRepositoryStateCache.INSTANCE
+ .getHead(repository))) {
return new DecorationOverlayDescriptor(base,
UIIcons.OVR_CHECKEDOUT, IDecoration.TOP_LEFT);
}
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 2405630be..010704530 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,7 +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.selection.SelectionRepositoryStateCache;
import org.eclipse.egit.ui.internal.trace.GitTraceLocation;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.ObjectId;
@@ -103,7 +103,7 @@ public class RepositoriesViewPropertyTester extends AbstractPropertyTester {
RemoteConfig rconfig;
try {
rconfig = new RemoteConfig(
- RepositoryStateCache.INSTANCE.getConfig(repository),
+ SelectionRepositoryStateCache.INSTANCE.getConfig(repository),
configName);
} catch (URISyntaxException e2) {
return false;
@@ -120,7 +120,7 @@ public class RepositoriesViewPropertyTester extends AbstractPropertyTester {
RemoteConfig rconfig;
try {
rconfig = new RemoteConfig(
- RepositoryStateCache.INSTANCE.getConfig(repository),
+ SelectionRepositoryStateCache.INSTANCE.getConfig(repository),
configName);
} catch (URISyntaxException e2) {
return false;
@@ -132,17 +132,17 @@ public class RepositoriesViewPropertyTester extends AbstractPropertyTester {
}
}
if (property.equals("canStash")) { //$NON-NLS-1$
- RepositoryState state = RepositoryStateCache.INSTANCE
+ RepositoryState state = SelectionRepositoryStateCache.INSTANCE
.getRepositoryState(repository);
return state.canCommit();
}
if (property.equals("canMerge")) { //$NON-NLS-1$
- RepositoryState state = RepositoryStateCache.INSTANCE
+ RepositoryState state = SelectionRepositoryStateCache.INSTANCE
.getRepositoryState(repository);
if (state != RepositoryState.SAFE) {
return false;
}
- String branch = RepositoryStateCache.INSTANCE
+ String branch = SelectionRepositoryStateCache.INSTANCE
.getFullBranchName(repository);
if (branch == null) {
return false; // fail gracefully...
@@ -168,24 +168,24 @@ public class RepositoriesViewPropertyTester extends AbstractPropertyTester {
private boolean isRefCheckedOut(Repository repository, Ref ref) {
if (ref.getName().startsWith(Constants.R_REFS)) {
return ref.getName().equals(
- RepositoryStateCache.INSTANCE.getFullBranchName(repository));
+ SelectionRepositoryStateCache.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))) {
+ SelectionRepositoryStateCache.INSTANCE.getFullBranchName(repository))) {
return true;
} else {
ObjectId objectId = ref.getLeaf().getObjectId();
return objectId != null && objectId
- .equals(RepositoryStateCache.INSTANCE.getHead(repository));
+ .equals(SelectionRepositoryStateCache.INSTANCE.getHead(repository));
}
}
}
private boolean containsHead(Repository repository) {
- return RepositoryStateCache.INSTANCE.getHead(repository) != null;
+ return SelectionRepositoryStateCache.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 613b4397b..1c4052196 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,7 +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.egit.ui.internal.selection.SelectionRepositoryStateCache;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jgit.transport.RemoteConfig;
@@ -99,7 +99,7 @@ public class FetchConfiguredRemoteCommand extends
if (node instanceof RemoteNode) {
try {
RemoteNode remote = (RemoteNode) node;
- return new RemoteConfig(RepositoryStateCache.INSTANCE
+ return new RemoteConfig(SelectionRepositoryStateCache.INSTANCE
.getConfig(node.getRepository()), remote.getObject());
} catch (URISyntaxException e) {
throw new ExecutionException(e.getMessage());
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 7beaf5f88..8ec3dbc67 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,7 +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.egit.ui.internal.selection.SelectionRepositoryStateCache;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jgit.transport.RemoteConfig;
@@ -91,7 +91,7 @@ public class PushConfiguredRemoteCommand extends
try {
RemoteNode remoteNode = (RemoteNode) node;
RemoteConfig config = new RemoteConfig(
- RepositoryStateCache.INSTANCE
+ SelectionRepositoryStateCache.INSTANCE
.getConfig(node.getRepository()),
remoteNode.getObject());
return withRefSpecs(config);
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 c9e1f6929..52a970dee 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
@@ -34,7 +34,7 @@ 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.egit.ui.internal.selection.SelectionRepositoryStateCache;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jgit.lib.Repository;
@@ -104,7 +104,7 @@ abstract class RepositoriesViewCommandHandler<T extends RepositoryTreeNode<?>>
}
private boolean repositoryHasHead(T treeNode) {
- return RepositoryStateCache.INSTANCE
+ return SelectionRepositoryStateCache.INSTANCE
.getHead(treeNode.getRepository()) != null;
}
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/selection/SelectionRepositoryStateCache.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/selection/SelectionRepositoryStateCache.java
new file mode 100644
index 000000000..aae0b671f
--- /dev/null
+++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/selection/SelectionRepositoryStateCache.java
@@ -0,0 +1,146 @@
+/*******************************************************************************
+ * 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.util.concurrent.atomic.AtomicBoolean;
+
+import org.eclipse.e4.core.contexts.IEclipseContext;
+import org.eclipse.e4.core.contexts.RunAndTrack;
+import org.eclipse.egit.ui.internal.RepositoryStateCache;
+import org.eclipse.jface.text.ITextSelection;
+import org.eclipse.jface.viewers.StructuredSelection;
+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 SelectionRepositoryStateCache extends RepositoryStateCache {
+
+ /** The singleton instance of the {@link SelectionRepositoryStateCache}. */
+ public static final SelectionRepositoryStateCache INSTANCE = new SelectionRepositoryStateCache();
+
+ private final AtomicBoolean stopped = new AtomicBoolean();
+
+ private SelectionRepositoryStateCache() {
+ // No creation from outside
+ }
+
+ @Override
+ 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, this::clear));
+ }
+
+ @Override
+ public void dispose() {
+ stopped.set(true);
+ super.dispose();
+ }
+
+ private static class ContextListener extends RunAndTrack {
+
+ private AtomicBoolean stopped;
+
+ private final Runnable clearCache;
+
+ ContextListener(AtomicBoolean stopped, Runnable clearCache) {
+ super();
+ this.stopped = stopped;
+ this.clearCache = clearCache;
+ }
+
+ private Object lastSelection;
+
+ private Object lastMenuSelection;
+
+ @Override
+ public boolean changed(IEclipseContext context) {
+ if (stopped.get()) {
+ clearCache.run();
+ 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) {
+ clearCache.run();
+ }
+ 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;
+ }
+ }
+}

Back to the top