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
;
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
;
27 * Data class for storing push operation results for each remote repository/URI
28 * being part of push operation.
30 * One instance of this class is dedicated for result of one push operation:
31 * either to one URI or to many URIs.
35 public class PushOperationResult
{
36 private LinkedHashMap
<URIish
, Entry
> urisEntries
;
39 * Construct empty push operation result.
41 public PushOperationResult() {
42 this.urisEntries
= new LinkedHashMap
<URIish
, Entry
>();
46 * Add push result for the repository (URI) with successful connection.
49 * remote repository URI.
53 public void addOperationResult(final URIish uri
, final PushResult result
) {
54 urisEntries
.put(uri
, new Entry(result
));
58 * Add error message for the repository (URI) with unsuccessful connection.
61 * remote repository URI.
63 * failure error message.
65 public void addOperationResult(final URIish uri
, final String errorMessage
) {
66 urisEntries
.put(uri
, new Entry(errorMessage
));
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());
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();
89 * @return true if connection was successful for any repository (URI), false
92 public boolean isSuccessfulConnectionForAnyURI() {
93 for (final URIish uri
: getURIs()) {
94 if (isSuccessfulConnection(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();
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()) {
130 sb
.append(", "); //$NON-NLS-1$
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.
142 * Specification is created basing on URIs of remote repositories in this
143 * result that completed without connection errors, and remote ref updates
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
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
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
);
172 final Collection
<RemoteRefUpdate
> oldUpdates
= pr
174 final ArrayList
<RemoteRefUpdate
> newUpdates
= new ArrayList
<RemoteRefUpdate
>(
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();
184 expectedOldObjectId
= advertisedRef
.getObjectId();
186 expectedOldObjectId
= rru
.getExpectedOldObjectId();
187 final RemoteRefUpdate newRru
= new RemoteRefUpdate(rru
,
188 expectedOldObjectId
);
189 newUpdates
.add(newRru
);
191 spec
.addURIRefUpdates(uri
, newUpdates
);
197 * This implementation returns true if all following conditions are met:
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>
205 * @see Object#equals(Object)
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.
212 public boolean equals(final Object obj
) {
216 if (!(obj
instanceof PushOperationResult
))
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
)))
229 for (final URIish uri
: other
.getURIs()) {
230 if (other
.isSuccessfulConnection(uri
)
231 && (!urisEntries
.containsKey(uri
) || !isSuccessfulConnection(uri
)))
235 for (final URIish uri
: getURIs()) {
236 if (!isSuccessfulConnection(uri
))
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)
246 if (otherRru
.getStatus() != rru
.getStatus()
247 || otherRru
.getNewObjectId() != rru
.getNewObjectId())
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() {
280 PushResult
getResult() {