Avoid refresh on up-to-date pull operation
[egit/eclipse.git] / org.eclipse.egit.core / src / org / eclipse / egit / core / op / PushOperationResult.java
blobd8633bb5f292936e997d59db35c7392ec27c30f3
1 /*******************************************************************************
2 * Copyright (C) 2008, Marek Zawirski <marek.zawirski@gmail.com>
4 * All rights reserved. This program and the accompanying materials
5 * are made available under the terms of the Eclipse Public License 2.0
6 * which accompanies this distribution, and is available at
7 * https://www.eclipse.org/legal/epl-2.0/
9 * SPDX-License-Identifier: EPL-2.0
10 *******************************************************************************/
11 package org.eclipse.egit.core.op;
13 import java.io.IOException;
14 import java.util.ArrayList;
15 import java.util.Collection;
16 import java.util.Collections;
17 import java.util.LinkedHashMap;
18 import java.util.Set;
20 import org.eclipse.jgit.lib.ObjectId;
21 import org.eclipse.jgit.lib.Ref;
22 import org.eclipse.jgit.transport.PushResult;
23 import org.eclipse.jgit.transport.RemoteRefUpdate;
24 import org.eclipse.jgit.transport.URIish;
26 /**
27 * Data class for storing push operation results for each remote repository/URI
28 * being part of push operation.
29 * <p>
30 * One instance of this class is dedicated for result of one push operation:
31 * either to one URI or to many URIs.
33 * @see PushOperation
35 public class PushOperationResult {
36 private LinkedHashMap<URIish, Entry> urisEntries;
38 /**
39 * Construct empty push operation result.
41 public PushOperationResult() {
42 this.urisEntries = new LinkedHashMap<URIish, Entry>();
45 /**
46 * Add push result for the repository (URI) with successful connection.
48 * @param uri
49 * remote repository URI.
50 * @param result
51 * push result.
53 public void addOperationResult(final URIish uri, final PushResult result) {
54 urisEntries.put(uri, new Entry(result));
57 /**
58 * Add error message for the repository (URI) with unsuccessful connection.
60 * @param uri
61 * remote repository URI.
62 * @param errorMessage
63 * failure error message.
65 public void addOperationResult(final URIish uri, final String errorMessage) {
66 urisEntries.put(uri, new Entry(errorMessage));
69 /**
70 * @return set of remote repositories URIish. Set is ordered in addition
71 * sequence, which is usually the same as that from
72 * {@link PushOperationSpecification}.
74 public Set<URIish> getURIs() {
75 return Collections.unmodifiableSet(urisEntries.keySet());
78 /**
79 * @param uri
80 * remote repository URI.
81 * @return true if connection was successful for this repository (URI),
82 * false if this operation ended with unsuccessful connection.
84 public boolean isSuccessfulConnection(final URIish uri) {
85 return urisEntries.get(uri).isSuccessfulConnection();
88 /**
89 * @return true if connection was successful for any repository (URI), false
90 * otherwise.
92 public boolean isSuccessfulConnectionForAnyURI() {
93 for (final URIish uri : getURIs()) {
94 if (isSuccessfulConnection(uri))
95 return true;
97 return false;
101 * @param uri
102 * remote repository URI.
103 * @return push result for this repository (URI) or null if operation ended
104 * with unsuccessful connection for this URI.
106 public PushResult getPushResult(final URIish uri) {
107 return urisEntries.get(uri).getResult();
111 * @param uri
112 * remote repository URI.
113 * @return error message for this repository (URI) or null if operation
114 * ended with successful connection for this URI.
116 public String getErrorMessage(final URIish uri) {
117 return urisEntries.get(uri).getErrorMessage();
121 * @return string being list of failed URIs with their error messages.
123 public String getErrorStringForAllURis() {
124 final StringBuilder sb = new StringBuilder();
125 boolean first = true;
126 for (final URIish uri : getURIs()) {
127 if (first)
128 first = false;
129 else
130 sb.append(", "); //$NON-NLS-1$
131 sb.append(uri);
132 sb.append(" ("); //$NON-NLS-1$
133 sb.append(getErrorMessage(uri));
134 sb.append(")"); //$NON-NLS-1$
136 return sb.toString();
140 * Derive push operation specification from this push operation result.
141 * <p>
142 * Specification is created basing on URIs of remote repositories in this
143 * result that completed without connection errors, and remote ref updates
144 * from push results.
145 * <p>
146 * This method is targeted to provide support for 2-stage push, where first
147 * operation is dry run for user confirmation and second one is a real
148 * operation.
150 * @param requireUnchanged
151 * if true, newly created copies of remote ref updates have
152 * expected old object id set to previously advertised ref value
153 * (remote ref won't be updated if it change in the mean time),
154 * if false, newly create copies of remote ref updates have
155 * expected object id set up as in this result source
156 * specification.
157 * @return derived specification for another push operation.
158 * @throws IOException
159 * when some previously locally available source ref is not
160 * available anymore, or some error occurred during creation
161 * locally tracking ref update.
164 public PushOperationSpecification deriveSpecification(
165 final boolean requireUnchanged) throws IOException {
166 final PushOperationSpecification spec = new PushOperationSpecification();
167 for (final URIish uri : getURIs()) {
168 final PushResult pr = getPushResult(uri);
169 if (pr == null)
170 continue;
172 final Collection<RemoteRefUpdate> oldUpdates = pr
173 .getRemoteUpdates();
174 final ArrayList<RemoteRefUpdate> newUpdates = new ArrayList<RemoteRefUpdate>(
175 oldUpdates.size());
176 for (final RemoteRefUpdate rru : oldUpdates) {
177 final ObjectId expectedOldObjectId;
178 if (requireUnchanged) {
179 final Ref advertisedRef = getPushResult(uri)
180 .getAdvertisedRef(rru.getRemoteName());
181 if (advertisedRef == null)
182 expectedOldObjectId = ObjectId.zeroId();
183 else
184 expectedOldObjectId = advertisedRef.getObjectId();
185 } else
186 expectedOldObjectId = rru.getExpectedOldObjectId();
187 final RemoteRefUpdate newRru = new RemoteRefUpdate(rru,
188 expectedOldObjectId);
189 newUpdates.add(newRru);
191 spec.addURIRefUpdates(uri, newUpdates);
193 return spec;
197 * This implementation returns true if all following conditions are met:
198 * <ul>
199 * <li>both objects result have the same set successfully connected
200 * repositories (URIs) - unsuccessful connections are discarded, AND <li>
201 * remote ref updates must match for each successful connection in sense of
202 * equal remoteName, equal status and equal newObjectId value.</li>
203 * </ul>
205 * @see Object#equals(Object)
206 * @param obj
207 * other push operation result to compare to.
208 * @return true if object is equal to this one in terms of conditions
209 * described above, false otherwise.
211 @Override
212 public boolean equals(final Object obj) {
213 if (obj == this)
214 return true;
216 if (!(obj instanceof PushOperationResult))
217 return false;
219 final PushOperationResult other = (PushOperationResult) obj;
221 // Check successful connections/URIs two-ways:
222 final Set<URIish> otherURIs = other.getURIs();
223 for (final URIish uri : getURIs()) {
224 if (isSuccessfulConnection(uri)
225 && (!otherURIs.contains(uri) || !other
226 .isSuccessfulConnection(uri)))
227 return false;
229 for (final URIish uri : other.getURIs()) {
230 if (other.isSuccessfulConnection(uri)
231 && (!urisEntries.containsKey(uri) || !isSuccessfulConnection(uri)))
232 return false;
235 for (final URIish uri : getURIs()) {
236 if (!isSuccessfulConnection(uri))
237 continue;
239 final PushResult otherPushResult = other.getPushResult(uri);
240 for (final RemoteRefUpdate rru : getPushResult(uri)
241 .getRemoteUpdates()) {
242 final RemoteRefUpdate otherRru = otherPushResult
243 .getRemoteUpdate(rru.getRemoteName());
244 if (otherRru == null)
245 return false;
246 if (otherRru.getStatus() != rru.getStatus()
247 || otherRru.getNewObjectId() != rru.getNewObjectId())
248 return false;
251 return true;
254 @Override
255 public int hashCode() {
256 return urisEntries.hashCode();
259 private static class Entry {
260 private String errorMessage;
262 private PushResult result;
264 Entry(final PushResult result) {
265 this.result = result;
268 Entry(final String errorMessage) {
269 this.errorMessage = errorMessage;
272 boolean isSuccessfulConnection() {
273 return result != null;
276 String getErrorMessage() {
277 return errorMessage;
280 PushResult getResult() {
281 return result;