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
;
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
;
25 * Data class for storing push operation results for each remote repository/URI
26 * being part of push operation.
28 * One instance of this class is dedicated for result of one push operation:
29 * either to one URI or to many URIs.
33 public class PushOperationResult
{
34 private LinkedHashMap
<URIish
, Entry
> urisEntries
;
37 * Construct empty push operation result.
39 PushOperationResult() {
40 this.urisEntries
= new LinkedHashMap
<URIish
, Entry
>();
44 * Add push result for the repository (URI) with successful connection.
47 * remote repository URI.
51 public void addOperationResult(final URIish uri
, final PushResult result
) {
52 urisEntries
.put(uri
, new Entry(result
));
56 * Add error message for the repository (URI) with unsuccessful connection.
59 * remote repository URI.
61 * failure error message.
63 public void addOperationResult(final URIish uri
, final String errorMessage
) {
64 urisEntries
.put(uri
, new Entry(errorMessage
));
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());
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();
87 * @return true if connection was successful for any repository (URI), false
90 public boolean isSuccessfulConnectionForAnyURI() {
91 for (final URIish uri
: getURIs()) {
92 if (isSuccessfulConnection(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();
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()) {
131 sb
.append(getErrorMessage(uri
));
134 return sb
.toString();
138 * Derive push operation specification from this push operation result.
140 * Specification is created basing on URIs of remote repositories in this
141 * result that completed without connection errors, and remote ref updates
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
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
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
);
170 final Collection
<RemoteRefUpdate
> oldUpdates
= pr
172 final ArrayList
<RemoteRefUpdate
> newUpdates
= new ArrayList
<RemoteRefUpdate
>(
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();
182 expectedOldObjectId
= advertisedRef
.getObjectId();
184 expectedOldObjectId
= rru
.getExpectedOldObjectId();
185 final RemoteRefUpdate newRru
= new RemoteRefUpdate(rru
,
186 expectedOldObjectId
);
187 newUpdates
.add(newRru
);
189 spec
.addURIRefUpdates(uri
, newUpdates
);
195 * This implementation returns true if all following conditions are met:
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>
203 * @see Object#equals(Object)
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.
210 public boolean equals(final Object obj
) {
211 if (!(obj
instanceof PushOperationResult
))
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
)))
224 for (final URIish uri
: other
.getURIs()) {
225 if (other
.isSuccessfulConnection(uri
)
226 && (!urisEntries
.containsKey(uri
) || !isSuccessfulConnection(uri
)))
230 for (final URIish uri
: getURIs()) {
231 if (!isSuccessfulConnection(uri
))
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)
241 if (otherRru
.getStatus() != rru
.getStatus()
242 || otherRru
.getNewObjectId() != rru
.getNewObjectId())
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() {
270 PushResult
getResult() {