1 /*******************************************************************************
2 * Copyright (c) 2011, 2020 SAP AG and others.
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License 2.0
5 * which accompanies this distribution, and is available at
6 * https://www.eclipse.org/legal/epl-2.0/
8 * SPDX-License-Identifier: EPL-2.0
11 * Mathias Kinzler (SAP AG) - initial implementation
12 * Dariusz Luksza <dariusz@luksza.org> - add 'isSafe' implementation
13 * Thomas Wolf <thomas.wolf@paranor.ch> - Bug 493352
14 *******************************************************************************/
15 package org
.eclipse
.egit
.ui
.internal
;
17 import java
.lang
.reflect
.Method
;
18 import java
.net
.URISyntaxException
;
19 import java
.util
.List
;
20 import java
.util
.Locale
;
22 import org
.eclipse
.core
.resources
.IResource
;
23 import org
.eclipse
.egit
.core
.internal
.gerrit
.GerritUtil
;
24 import org
.eclipse
.egit
.core
.internal
.hosts
.GitHosts
;
25 import org
.eclipse
.egit
.core
.project
.RepositoryMapping
;
26 import org
.eclipse
.egit
.ui
.internal
.expressions
.AbstractPropertyTester
;
27 import org
.eclipse
.egit
.ui
.internal
.selection
.SelectionRepositoryStateCache
;
28 import org
.eclipse
.egit
.ui
.internal
.trace
.GitTraceLocation
;
29 import org
.eclipse
.jgit
.annotations
.NonNull
;
30 import org
.eclipse
.jgit
.lib
.Config
;
31 import org
.eclipse
.jgit
.lib
.Repository
;
32 import org
.eclipse
.jgit
.lib
.RepositoryState
;
33 import org
.eclipse
.jgit
.transport
.RemoteConfig
;
36 * Resource-based property tester.
38 * Supported properties:
40 * <li>isShared <code>true</code> if the resource is mapped to EGit. EGit may
41 * still affect a resource if it belongs to the workspace of some shared
43 * <li>isContainer <code>true</code> if the resource is a project or a
45 * <li>hasHead <code>true</code> if the repository has a HEAD</li>
46 * <li>is<em>repository state</em>
48 * <li>isSafe - see {@link RepositoryState#SAFE}</li>
49 * <li>isReverting - see {@link RepositoryState#REVERTING}</li>
50 * <li>isRevertingResolved - see {@link RepositoryState#REVERTING_RESOLVED}</li>
51 * <li>isCherryPicking - see {@link RepositoryState#CHERRY_PICKING}</li>
52 * <li>isCherryPickingResolved - see
53 * {@link RepositoryState#CHERRY_PICKING_RESOLVED}</li>
54 * <li>isMerging - see {@link RepositoryState#MERGING}</li>
55 * <li>isMergingResolved - see {@link RepositoryState#MERGING_RESOLVED}</li>
56 * <li>isRebasing - see {@link RepositoryState#REBASING}</li>
57 * <li>isRebasingRebasing - see {@link RepositoryState#REBASING_REBASING}</li>
58 * <li>isRebasingMerge - see {@link RepositoryState#REBASING_MERGE}</li>
59 * <li>isRebasingInteractive - see
60 * {@link RepositoryState#REBASING_INTERACTIVE}</li>
61 * <li>isApply - see {@link RepositoryState#APPLY}</li>
62 * <li>isBisecting - see {@link RepositoryState#BISECTING}</li>
65 * <li>Capabilities/properties of the current state:
67 * <li>canCheckout - see {@link RepositoryState#canCheckout()}</li>
68 * <li>canAmend - see {@link RepositoryState#canAmend()}</li>
69 * <li>canCommit - see {@link RepositoryState#canCommit()}</li>
70 * <li>canResetHead - see {@link RepositoryState#canResetHead()}</li>
75 public class ResourcePropertyTester
extends AbstractPropertyTester
{
78 public boolean test(Object receiver
, String property
, Object
[] args
,
79 Object expectedValue
) {
80 if (!(receiver
instanceof IResource
)) {
83 boolean value
= internalTest((IResource
) receiver
, property
);
84 boolean trace
= GitTraceLocation
.PROPERTIESTESTER
.isActive();
88 .trace(GitTraceLocation
.PROPERTIESTESTER
.getLocation(),
89 "prop " + property
+ " of " + receiver
+ " = " + value
+ ", expected = " + expectedValue
); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
90 return computeResult(expectedValue
, value
);
93 private boolean internalTest(@NonNull IResource res
, String property
) {
94 if ("isContainer".equals(property
)) { //$NON-NLS-1$
95 int type
= res
.getType();
96 return type
== IResource
.FOLDER
|| type
== IResource
.PROJECT
;
99 RepositoryMapping mapping
= RepositoryMapping
.getMapping(res
);
100 if (mapping
!= null) {
101 Repository repository
= mapping
.getRepository();
102 return testRepositoryState(repository
, property
);
110 * @return true if the repository is in an appropriate state. See
111 * {@link ResourcePropertyTester}
113 public static boolean testRepositoryState(Repository repository
, String property
) {
114 if ("isShared".equals(property
)) { //$NON-NLS-1$
115 return repository
!= null;
117 if (repository
!= null) {
118 if ("hasHead".equals(property
)) { //$NON-NLS-1$
119 return SelectionRepositoryStateCache
.INSTANCE
120 .getHead(repository
) != null;
122 if ("hasGitHubConfiguration".equals(property
)) { //$NON-NLS-1$
123 return hasServerConfiguration(repository
,
124 GitHosts
.ServerType
.GITHUB
);
126 if ("hasGitLabConfiguration".equals(property
)) { //$NON-NLS-1$
127 return hasServerConfiguration(repository
,
128 GitHosts
.ServerType
.GITLAB
);
130 if ("hasGiteaConfiguration".equals(property
)) { //$NON-NLS-1$
131 return hasServerConfiguration(repository
,
132 GitHosts
.ServerType
.GITEA
);
134 if ("hasGerritConfiguration".equals(property
)) { //$NON-NLS-1$
135 return hasGerritConfiguration(repository
);
137 if ("canFetchFromGerrit".equals(property
)) { //$NON-NLS-1$
138 return canFetchFromGerrit(repository
);
140 if ("canPushToGerrit".equals(property
)) { //$NON-NLS-1$
141 return canPushToGerrit(repository
);
143 RepositoryState state
= SelectionRepositoryStateCache
.INSTANCE
144 .getRepositoryState(repository
);
146 if ("canAbortRebase".equals(property
)) { //$NON-NLS-1$
147 return canAbortRebase(state
);
149 if ("canContinueRebase".equals(property
)) { //$NON-NLS-1$
150 return canContinueRebase(state
);
152 // isSTATE checks repository state where STATE is the CamelCase version
153 // of the RepositoryState enum values.
154 if (property
.length() > 3 && property
.startsWith("is")) { //$NON-NLS-1$
155 // e.g. isCherryPickingResolved => CHERRY_PICKING_RESOLVED
156 String lookFor
= property
.substring(2, 3)
157 + property
.substring(3).replaceAll("([A-Z])", "_$1") //$NON-NLS-1$//$NON-NLS-2$
158 .toUpperCase(Locale
.ROOT
);
159 if (state
.toString().equals(lookFor
))
162 // invokes test methods of RepositoryState, canCommit etc
164 Method method
= RepositoryState
.class.getMethod(property
);
165 if (method
.getReturnType() == boolean.class) {
166 Boolean ret
= (Boolean
) method
.invoke(state
);
167 return ret
.booleanValue();
169 } catch (Exception e
) {
176 private static boolean hasServerConfiguration(Repository repository
,
177 GitHosts
.ServerType server
) {
180 .hasServerConfig(SelectionRepositoryStateCache
.INSTANCE
181 .getConfig(repository
), server
);
182 } catch (URISyntaxException e
) {
183 // Assume no matching config.
190 * @return {@code true} if repository has been configured for Gerrit
192 public static boolean hasGerritConfiguration(
193 @NonNull Repository repository
) {
194 Config config
= SelectionRepositoryStateCache
.INSTANCE
.getConfig(repository
);
195 if (GerritUtil
.getCreateChangeId(config
)) {
199 List
<RemoteConfig
> remoteConfigs
= RemoteConfig
.getAllRemoteConfigs(config
);
200 for (RemoteConfig remoteConfig
: remoteConfigs
) {
201 if (GerritUtil
.isGerritPush(remoteConfig
)
202 || GerritUtil
.isGerritFetch(remoteConfig
)) {
206 } catch (URISyntaxException e
) {
207 // Assume it doesn't contain Gerrit configuration
215 * @return {@code true} if repository has been configured to fetch from
218 public static boolean canFetchFromGerrit(@NonNull Repository repository
) {
219 Config config
= SelectionRepositoryStateCache
.INSTANCE
.getConfig(repository
);
221 List
<RemoteConfig
> remoteConfigs
= RemoteConfig
222 .getAllRemoteConfigs(config
);
223 for (RemoteConfig remoteConfig
: remoteConfigs
) {
224 if (GerritUtil
.isGerritFetch(remoteConfig
)) {
228 } catch (URISyntaxException e
) {
236 * @return {@code true} if repository has been configured for pushing to
239 public static boolean canPushToGerrit(@NonNull Repository repository
) {
240 Config config
= SelectionRepositoryStateCache
.INSTANCE
.getConfig(repository
);
242 List
<RemoteConfig
> remoteConfigs
= RemoteConfig
243 .getAllRemoteConfigs(config
);
244 for (RemoteConfig remoteConfig
: remoteConfigs
) {
245 if (GerritUtil
.isGerritPush(remoteConfig
)) {
249 } catch (URISyntaxException e
) {
257 * @return {@code true} if the repository state permits a rebase to be
260 public static boolean canAbortRebase(@NonNull RepositoryState state
) {
262 case REBASING_INTERACTIVE
:
264 case REBASING_REBASING
:
275 * @return {@code true} if the repository state permits a rebase to be
278 public static boolean canContinueRebase(@NonNull RepositoryState state
) {
280 case REBASING_INTERACTIVE
: