Fix RemoteRefUpdate to delete local tracking ref upon successful deletion
[egit/zawir.git] / org.spearce.jgit / src / org / spearce / jgit / transport / RemoteRefUpdate.java
blobc79f7dc033c4e47b6c35b6e26a36a719835138fd
1 /*
2 * Copyright (C) 2008, Marek Zawirski <marek.zawirski@gmail.com>
4 * All rights reserved.
6 * Redistribution and use in source and binary forms, with or
7 * without modification, are permitted provided that the following
8 * conditions are met:
10 * - Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
13 * - Redistributions in binary form must reproduce the above
14 * copyright notice, this list of conditions and the following
15 * disclaimer in the documentation and/or other materials provided
16 * with the distribution.
18 * - Neither the remoteName of the Git Development Community nor the
19 * names of its contributors may be used to endorse or promote
20 * products derived from this software without specific prior
21 * written permission.
23 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
24 * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
25 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
26 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
28 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
29 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
30 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
31 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
32 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
33 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
34 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
35 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
38 package org.spearce.jgit.transport;
40 import java.io.IOException;
42 import org.spearce.jgit.lib.ObjectId;
43 import org.spearce.jgit.lib.Repository;
44 import org.spearce.jgit.revwalk.RevWalk;
46 /**
47 * Represent request and status of a remote ref update. Specification is
48 * provided by client, while status is handled by {@link PushProcess} class,
49 * being read-only for client.
50 * <p>
51 * Client can create instances of this class directly, basing on user
52 * specification and advertised refs ({@link Connection} or through
53 * {@link Transport} helper methods. Apply this specification on remote
54 * repository using
55 * {@link Transport#push(org.spearce.jgit.lib.ProgressMonitor, java.util.Collection)}
56 * method.
57 * </p>
60 public class RemoteRefUpdate {
61 /**
62 * Represent current status of a remote ref update.
64 public static enum Status {
65 /**
66 * Push process hasn't yet attempted to update this ref. This is the
67 * default status, prior to push process execution.
69 NOT_ATTEMPTED,
71 /**
72 * Remote ref was up to date, there was no need to update anything.
74 UP_TO_DATE,
76 /**
77 * Remote ref update was rejected, as it would cause non fast-forward
78 * update.
80 REJECTED_NONFASTFORWARD,
82 /**
83 * Remote ref update was rejected, because remote side doesn't
84 * support/allow deleting refs.
86 REJECTED_NODELETE,
88 /**
89 * Remote ref update was rejected, because old object id on remote
90 * repository wasn't the same as defined expected old object.
92 REJECTED_REMOTE_CHANGED,
94 /**
95 * Remote ref update was rejected for other reason, possibly described
96 * in {@link RemoteRefUpdate#getMessage()}.
98 REJECTED_OTHER_REASON,
101 * Remote ref didn't exist. Can occur on delete request of a non
102 * existing ref.
104 NON_EXISTING,
107 * Push process is awaiting update report from remote repository. This
108 * is a temporary state or state after critical error in push process.
110 AWAITING_REPORT,
113 * Remote ref was successfully updated.
118 private final ObjectId expectedOldObjectId;
120 private final ObjectId newObjectId;
122 private final String remoteName;
124 private final TrackingRefUpdate trackingRefUpdate;
126 private final String srcRef;
128 private final boolean forceUpdate;
130 private Status status;
132 private boolean fastForward;
134 private String message;
136 private final Repository localDb;
139 * Construct remote ref update request by providing an update specification.
140 * Object is created with default {@link Status#NOT_ATTEMPTED} status and no
141 * message.
143 * @param localDb
144 * local repository to push from.
145 * @param srcRef
146 * source revision - any string resolvable by
147 * {@link Repository#resolve(String)}. This resolves to the new
148 * object that the caller want remote ref to be after update. Use
149 * null or {@link ObjectId#zeroId()} string for delete request.
150 * @param remoteName
151 * full name of a remote ref to update, e.g. "refs/heads/master"
152 * (no wildcard, no short name).
153 * @param forceUpdate
154 * true when caller want remote ref to be updated regardless
155 * whether it is fast-forward update (old object is ancestor of
156 * new object).
157 * @param localName
158 * optional full name of a local stored tracking branch, to
159 * update after push, e.g. "refs/remotes/zawir/dirty" (no
160 * wildcard, no short name); null if no local tracking branch
161 * should be updated.
162 * @param expectedOldObjectId
163 * optional object id that caller is expecting, requiring to be
164 * advertised by remote side before update; update will take
165 * place ONLY if remote side advertise exactly this expected id;
166 * null if caller doesn't care what object id remote side
167 * advertise. Use {@link ObjectId#zeroId()} when expecting no
168 * remote ref with this name.
169 * @throws IOException
170 * when I/O error occurred during creating
171 * {@link TrackingRefUpdate} for local tracking branch or srcRef
172 * can't be resolved to any object.
173 * @throws IllegalArgumentException
174 * if some required parameter was null
176 public RemoteRefUpdate(final Repository localDb, final String srcRef,
177 final String remoteName, final boolean forceUpdate,
178 final String localName, final ObjectId expectedOldObjectId)
179 throws IOException {
180 if (remoteName == null)
181 throw new IllegalArgumentException("Remote name can't be null.");
182 this.srcRef = srcRef;
183 this.newObjectId = (srcRef == null ? ObjectId.zeroId() : localDb
184 .resolve(srcRef));
185 if (newObjectId == null)
186 throw new IOException("Source ref " + srcRef
187 + " doesn't resolve to any object.");
188 this.remoteName = remoteName;
189 this.forceUpdate = forceUpdate;
190 if (localName != null && localDb != null)
191 trackingRefUpdate = new TrackingRefUpdate(localDb, localName,
192 remoteName, true, newObjectId, "push");
193 else
194 trackingRefUpdate = null;
195 this.localDb = localDb;
196 this.expectedOldObjectId = expectedOldObjectId;
197 this.status = Status.NOT_ATTEMPTED;
201 * Create a new instance of this object basing on existing instance for
202 * configuration. State (like {@link #getMessage()}, {@link #getStatus()})
203 * of base object is not shared. Expected old object id is set up from
204 * scratch, as this constructor may be used for 2-stage push: first one
205 * being dry run, second one being actual push.
207 * @param base
208 * configuration base.
209 * @param newExpectedOldObjectId
210 * new expected object id value.
211 * @throws IOException
212 * when I/O error occurred during creating
213 * {@link TrackingRefUpdate} for local tracking branch or srcRef
214 * of base object no longer can be resolved to any object.
216 public RemoteRefUpdate(final RemoteRefUpdate base,
217 final ObjectId newExpectedOldObjectId) throws IOException {
218 this(base.localDb, base.srcRef, base.remoteName, base.forceUpdate,
219 (base.trackingRefUpdate == null ? null : base.trackingRefUpdate
220 .getLocalName()), newExpectedOldObjectId);
224 * @return expectedOldObjectId required to be advertised by remote side, as
225 * set in constructor; may be null.
227 public ObjectId getExpectedOldObjectId() {
228 return expectedOldObjectId;
232 * @return true if some object is required to be advertised by remote side,
233 * as set in constructor; false otherwise.
235 public boolean isExpectingOldObjectId() {
236 return expectedOldObjectId != null;
240 * @return newObjectId for remote ref, as set in constructor.
242 public ObjectId getNewObjectId() {
243 return newObjectId;
247 * @return true if this update is deleting update; false otherwise.
249 public boolean isDelete() {
250 return ObjectId.zeroId().equals(newObjectId);
254 * @return name of remote ref to update, as set in constructor.
256 public String getRemoteName() {
257 return remoteName;
261 * @return local tracking branch update if localName was set in constructor.
263 public TrackingRefUpdate getTrackingRefUpdate() {
264 return trackingRefUpdate;
268 * @return source revision as specified by user (in constructor), could be
269 * any string parseable by {@link Repository#resolve(String)}; can
270 * be null if specified that way in constructor - this stands for
271 * delete request.
273 public String getSrcRef() {
274 return srcRef;
278 * @return true if user specified a local tracking branch for remote update;
279 * false otherwise.
281 public boolean hasTrackingRefUpdate() {
282 return trackingRefUpdate != null;
286 * @return true if this update is forced regardless of old remote ref
287 * object; false otherwise.
289 public boolean isForceUpdate() {
290 return forceUpdate;
294 * @return status of remote ref update operation.
296 public Status getStatus() {
297 return status;
301 * Check whether update was fast-forward. Note that this result is
302 * meaningful only after successful update (when status is {@link Status#OK}).
304 * @return true if update was fast-forward; false otherwise.
306 public boolean isFastForward() {
307 return fastForward;
311 * @return message describing reasons of status when needed/possible; may be
312 * null.
314 public String getMessage() {
315 return message;
318 protected void setStatus(final Status status) {
319 this.status = status;
322 protected void setFastForward(boolean fastForward) {
323 this.fastForward = fastForward;
326 protected void setMessage(final String message) {
327 this.message = message;
331 * Update locally stored tracking branch with the new object.
333 * @param walk
334 * walker used for checking update properties.
335 * @throws IOException
336 * when I/O error occurred during update
338 protected void updateTrackingRef(final RevWalk walk) throws IOException {
339 if (isDelete())
340 trackingRefUpdate.delete(walk);
341 else
342 trackingRefUpdate.update(walk);