Fix sharing projects
[egit.git] / org.eclipse.egit.core / src / org / eclipse / egit / core / op / PushOperationResult.java
blob520951d213e79a15c9104479b4c3358d9d4339ab
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 v1.0
6 * which accompanies this distribution, and is available at
7 * http://www.eclipse.org/legal/epl-v10.html
8 *******************************************************************************/
9 package org.eclipse.egit.core.op;
11 import java.io.IOException;
12 import java.util.ArrayList;
13 import java.util.Collection;
14 import java.util.Collections;
15 import java.util.LinkedHashMap;
16 import java.util.Set;
18 import org.eclipse.jgit.lib.ObjectId;
19 import org.eclipse.jgit.lib.Ref;
20 import org.eclipse.jgit.transport.PushResult;
21 import org.eclipse.jgit.transport.RemoteRefUpdate;
22 import org.eclipse.jgit.transport.URIish;
24 /**
25 * Data class for storing push operation results for each remote repository/URI
26 * being part of push operation.
27 * <p>
28 * One instance of this class is dedicated for result of one push operation:
29 * either to one URI or to many URIs.
31 * @see PushOperation
33 public class PushOperationResult {
34 private LinkedHashMap<URIish, Entry> urisEntries;
36 /**
37 * Construct empty push operation result.
39 PushOperationResult() {
40 this.urisEntries = new LinkedHashMap<URIish, Entry>();
43 /**
44 * Add push result for the repository (URI) with successful connection.
46 * @param uri
47 * remote repository URI.
48 * @param result
49 * push result.
51 public void addOperationResult(final URIish uri, final PushResult result) {
52 urisEntries.put(uri, new Entry(result));
55 /**
56 * Add error message for the repository (URI) with unsuccessful connection.
58 * @param uri
59 * remote repository URI.
60 * @param errorMessage
61 * failure error message.
63 public void addOperationResult(final URIish uri, final String errorMessage) {
64 urisEntries.put(uri, new Entry(errorMessage));
67 /**
68 * @return set of remote repositories URIish. Set is ordered in addition
69 * sequence, which is usually the same as that from
70 * {@link PushOperationSpecification}.
72 public Set<URIish> getURIs() {
73 return Collections.unmodifiableSet(urisEntries.keySet());
76 /**
77 * @param uri
78 * remote repository URI.
79 * @return true if connection was successful for this repository (URI),
80 * false if this operation ended with unsuccessful connection.
82 public boolean isSuccessfulConnection(final URIish uri) {
83 return urisEntries.get(uri).isSuccessfulConnection();
86 /**
87 * @return true if connection was successful for any repository (URI), false
88 * otherwise.
90 public boolean isSuccessfulConnectionForAnyURI() {
91 for (final URIish uri : getURIs()) {
92 if (isSuccessfulConnection(uri))
93 return true;
95 return false;
98 /**
99 * @param uri
100 * remote repository URI.
101 * @return push result for this repository (URI) or null if operation ended
102 * with unsuccessful connection for this URI.
104 public PushResult getPushResult(final URIish uri) {
105 return urisEntries.get(uri).getResult();
109 * @param uri
110 * remote repository URI.
111 * @return error message for this repository (URI) or null if operation
112 * ended with successful connection for this URI.
114 public String getErrorMessage(final URIish uri) {
115 return urisEntries.get(uri).getErrorMessage();
119 * @return string being list of failed URIs with their error messages.
121 public String getErrorStringForAllURis() {
122 final StringBuilder sb = new StringBuilder();
123 boolean first = true;
124 for (final URIish uri : getURIs()) {
125 if (first)
126 first = false;
127 else
128 sb.append(", ");
129 sb.append(uri);
130 sb.append(" (");
131 sb.append(getErrorMessage(uri));
132 sb.append(")");
134 return sb.toString();
138 * Derive push operation specification from this push operation result.
139 * <p>
140 * Specification is created basing on URIs of remote repositories in this
141 * result that completed without connection errors, and remote ref updates
142 * from push results.
143 * <p>
144 * This method is targeted to provide support for 2-stage push, where first
145 * operation is dry run for user confirmation and second one is a real
146 * operation.
148 * @param requireUnchanged
149 * if true, newly created copies of remote ref updates have
150 * expected old object id set to previously advertised ref value
151 * (remote ref won't be updated if it change in the mean time),
152 * if false, newly create copies of remote ref updates have
153 * expected object id set up as in this result source
154 * specification.
155 * @return derived specification for another push operation.
156 * @throws IOException
157 * when some previously locally available source ref is not
158 * available anymore, or some error occurred during creation
159 * locally tracking ref update.
162 public PushOperationSpecification deriveSpecification(
163 final boolean requireUnchanged) throws IOException {
164 final PushOperationSpecification spec = new PushOperationSpecification();
165 for (final URIish uri : getURIs()) {
166 final PushResult pr = getPushResult(uri);
167 if (pr == null)
168 continue;
170 final Collection<RemoteRefUpdate> oldUpdates = pr
171 .getRemoteUpdates();
172 final ArrayList<RemoteRefUpdate> newUpdates = new ArrayList<RemoteRefUpdate>(
173 oldUpdates.size());
174 for (final RemoteRefUpdate rru : oldUpdates) {
175 final ObjectId expectedOldObjectId;
176 if (requireUnchanged) {
177 final Ref advertisedRef = getPushResult(uri)
178 .getAdvertisedRef(rru.getRemoteName());
179 if (advertisedRef == null)
180 expectedOldObjectId = ObjectId.zeroId();
181 else
182 expectedOldObjectId = advertisedRef.getObjectId();
183 } else
184 expectedOldObjectId = rru.getExpectedOldObjectId();
185 final RemoteRefUpdate newRru = new RemoteRefUpdate(rru,
186 expectedOldObjectId);
187 newUpdates.add(newRru);
189 spec.addURIRefUpdates(uri, newUpdates);
191 return spec;
195 * This implementation returns true if all following conditions are met:
196 * <ul>
197 * <li>both objects result have the same set successfully connected
198 * repositories (URIs) - unsuccessful connections are discarded, AND <li>
199 * remote ref updates must match for each successful connection in sense of
200 * equal remoteName, equal status and equal newObjectId value.</li>
201 * </ul>
203 * @see Object#equals(Object)
204 * @param obj
205 * other push operation result to compare to.
206 * @return true if object is equal to this one in terms of conditions
207 * described above, false otherwise.
209 @Override
210 public boolean equals(final Object obj) {
211 if (!(obj instanceof PushOperationResult))
212 return false;
214 final PushOperationResult other = (PushOperationResult) obj;
216 // Check successful connections/URIs two-ways:
217 final Set<URIish> otherURIs = other.getURIs();
218 for (final URIish uri : getURIs()) {
219 if (isSuccessfulConnection(uri)
220 && (!otherURIs.contains(uri) || !other
221 .isSuccessfulConnection(uri)))
222 return false;
224 for (final URIish uri : other.getURIs()) {
225 if (other.isSuccessfulConnection(uri)
226 && (!urisEntries.containsKey(uri) || !isSuccessfulConnection(uri)))
227 return false;
230 for (final URIish uri : getURIs()) {
231 if (!isSuccessfulConnection(uri))
232 continue;
234 final PushResult otherPushResult = other.getPushResult(uri);
235 for (final RemoteRefUpdate rru : getPushResult(uri)
236 .getRemoteUpdates()) {
237 final RemoteRefUpdate otherRru = otherPushResult
238 .getRemoteUpdate(rru.getRemoteName());
239 if (otherRru == null)
240 return false;
241 if (otherRru.getStatus() != rru.getStatus()
242 || otherRru.getNewObjectId() != rru.getNewObjectId())
243 return false;
246 return true;
249 private static class Entry {
250 private String errorMessage;
252 private PushResult result;
254 Entry(final PushResult result) {
255 this.result = result;
258 Entry(final String errorMessage) {
259 this.errorMessage = errorMessage;
262 boolean isSuccessfulConnection() {
263 return result != null;
266 String getErrorMessage() {
267 return errorMessage;
270 PushResult getResult() {
271 return result;