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 * See LICENSE for the full license text, also available.
7 *******************************************************************************/
8 package org
.spearce
.egit
.core
.op
;
10 import java
.io
.IOException
;
11 import java
.util
.ArrayList
;
12 import java
.util
.Collection
;
13 import java
.util
.Collections
;
14 import java
.util
.LinkedHashMap
;
17 import org
.spearce
.jgit
.lib
.ObjectId
;
18 import org
.spearce
.jgit
.lib
.Ref
;
19 import org
.spearce
.jgit
.transport
.PushResult
;
20 import org
.spearce
.jgit
.transport
.RemoteRefUpdate
;
21 import org
.spearce
.jgit
.transport
.URIish
;
24 * Data class for storing push operation results for each remote repository/URI
25 * being part of push operation.
27 * One instance of this class is dedicated for result of one push operation:
28 * either to one URI or to many URIs.
32 public class PushOperationResult
{
33 private LinkedHashMap
<URIish
, Entry
> urisEntries
;
36 * Construct empty push operation result.
38 PushOperationResult() {
39 this.urisEntries
= new LinkedHashMap
<URIish
, Entry
>();
43 * Add push result for the repository (URI) with successful connection.
46 * remote repository URI.
50 public void addOperationResult(final URIish uri
, final PushResult result
) {
51 urisEntries
.put(uri
, new Entry(result
));
55 * Add error message for the repository (URI) with unsuccessful connection.
58 * remote repository URI.
60 * failure error message.
62 public void addOperationResult(final URIish uri
, final String errorMessage
) {
63 urisEntries
.put(uri
, new Entry(errorMessage
));
67 * @return set of remote repositories URIish. Set is ordered in addition
68 * sequence, which is usually the same as that from
69 * {@link PushOperationSpecification}.
71 public Set
<URIish
> getURIs() {
72 return Collections
.unmodifiableSet(urisEntries
.keySet());
77 * remote repository URI.
78 * @return true if connection was successful for this repository (URI),
79 * false if this operation ended with unsuccessful connection.
81 public boolean isSuccessfulConnection(final URIish uri
) {
82 return urisEntries
.get(uri
).isSuccessfulConnection();
86 * @return true if connection was successful for any repository (URI), false
89 public boolean isSuccessfulConnectionForAnyURI() {
90 for (final URIish uri
: getURIs()) {
91 if (isSuccessfulConnection(uri
))
99 * remote repository URI.
100 * @return push result for this repository (URI) or null if operation ended
101 * with unsuccessful connection for this URI.
103 public PushResult
getPushResult(final URIish uri
) {
104 return urisEntries
.get(uri
).getResult();
109 * remote repository URI.
110 * @return error message for this repository (URI) or null if operation
111 * ended with successful connection for this URI.
113 public String
getErrorMessage(final URIish uri
) {
114 return urisEntries
.get(uri
).getErrorMessage();
118 * @return string being list of failed URIs with their error messages.
120 public String
getErrorStringForAllURis() {
121 final StringBuilder sb
= new StringBuilder();
122 boolean first
= true;
123 for (final URIish uri
: getURIs()) {
130 sb
.append(getErrorMessage(uri
));
133 return sb
.toString();
137 * Derive push operation specification from this push operation result.
139 * Specification is created basing on URIs of remote repositories in this
140 * result that completed without connection errors, and remote ref updates
143 * This method is targeted to provide support for 2-stage push, where first
144 * operation is dry run for user confirmation and second one is a real
147 * @param requireUnchanged
148 * if true, newly created copies of remote ref updates have
149 * expected old object id set to previously advertised ref value
150 * (remote ref won't be updated if it change in the mean time),
151 * if false, newly create copies of remote ref updates have
152 * expected object id set up as in this result source
154 * @return derived specification for another push operation.
155 * @throws IOException
156 * when some previously locally available source ref is not
157 * available anymore, or some error occurred during creation
158 * locally tracking ref update.
161 public PushOperationSpecification
deriveSpecification(
162 final boolean requireUnchanged
) throws IOException
{
163 final PushOperationSpecification spec
= new PushOperationSpecification();
164 for (final URIish uri
: getURIs()) {
165 final PushResult pr
= getPushResult(uri
);
169 final Collection
<RemoteRefUpdate
> oldUpdates
= pr
171 final ArrayList
<RemoteRefUpdate
> newUpdates
= new ArrayList
<RemoteRefUpdate
>(
173 for (final RemoteRefUpdate rru
: oldUpdates
) {
174 final ObjectId expectedOldObjectId
;
175 if (requireUnchanged
) {
176 final Ref advertisedRef
= getPushResult(uri
)
177 .getAdvertisedRef(rru
.getRemoteName());
178 if (advertisedRef
== null)
179 expectedOldObjectId
= ObjectId
.zeroId();
181 expectedOldObjectId
= advertisedRef
.getObjectId();
183 expectedOldObjectId
= rru
.getExpectedOldObjectId();
184 final RemoteRefUpdate newRru
= new RemoteRefUpdate(rru
,
185 expectedOldObjectId
);
186 newUpdates
.add(newRru
);
188 spec
.addURIRefUpdates(uri
, newUpdates
);
194 * This implementation returns true if all following conditions are met:
196 * <li>both objects result have the same set successfully connected
197 * repositories (URIs) - unsuccessful connections are discarded, AND <li>
198 * remote ref updates must match for each successful connection in sense of
199 * equal remoteName, equal status and equal newObjectId value.</li>
202 * @see Object#equals(Object)
204 * other push operation result to compare to.
205 * @return true if object is equal to this one in terms of conditions
206 * described above, false otherwise.
209 public boolean equals(final Object obj
) {
210 if (!(obj
instanceof PushOperationResult
))
213 final PushOperationResult other
= (PushOperationResult
) obj
;
215 // Check successful connections/URIs two-ways:
216 final Set
<URIish
> otherURIs
= other
.getURIs();
217 for (final URIish uri
: getURIs()) {
218 if (isSuccessfulConnection(uri
)
219 && (!otherURIs
.contains(uri
) || !other
220 .isSuccessfulConnection(uri
)))
223 for (final URIish uri
: other
.getURIs()) {
224 if (other
.isSuccessfulConnection(uri
)
225 && (!urisEntries
.containsKey(uri
) || !isSuccessfulConnection(uri
)))
229 for (final URIish uri
: getURIs()) {
230 if (!isSuccessfulConnection(uri
))
233 final PushResult otherPushResult
= other
.getPushResult(uri
);
234 for (final RemoteRefUpdate rru
: getPushResult(uri
)
235 .getRemoteUpdates()) {
236 final RemoteRefUpdate otherRru
= otherPushResult
237 .getRemoteUpdate(rru
.getRemoteName());
238 if (otherRru
== null)
240 if (otherRru
.getStatus() != rru
.getStatus()
241 || otherRru
.getNewObjectId() != rru
.getNewObjectId())
248 private static class Entry
{
249 private String errorMessage
;
251 private PushResult result
;
253 Entry(final PushResult result
) {
254 this.result
= result
;
257 Entry(final String errorMessage
) {
258 this.errorMessage
= errorMessage
;
261 boolean isSuccessfulConnection() {
262 return result
!= null;
265 String
getErrorMessage() {
269 PushResult
getResult() {