/*
 * Copyright (C) 2008, Marek Zawirski <marek.zawirski@gmail.com>
 * and other copyright owners as documented in the project's IP log.
 *
 * This program and the accompanying materials are made available
 * under the terms of the Eclipse Distribution License v1.0 which
 * accompanies this distribution, is reproduced below, and is
 * available at http://www.eclipse.org/org/documents/edl-v10.php
 *
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or
 * without modification, are permitted provided that the following
 * conditions are met:
 *
 * - Redistributions of source code must retain the above copyright
 *   notice, this list of conditions and the following disclaimer.
 *
 * - Redistributions in binary form must reproduce the above
 *   copyright notice, this list of conditions and the following
 *   disclaimer in the documentation and/or other materials provided
 *   with the distribution.
 *
 * - Neither the name of the Eclipse Foundation, Inc. nor the
 *   names of its contributors may be used to endorse or promote
 *   products derived from this software without specific prior
 *   written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
 * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

package org.eclipse.jgit.transport;

import java.io.IOException;
import java.text.MessageFormat;

import org.eclipse.jgit.internal.JGitText;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.lib.RefUpdate;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.revwalk.RevWalk;

Represent request and status of a remote ref update. Specification is provided by client, while status is handled by PushProcess class, being read-only for client.

Client can create instances of this class directly, basing on user specification and advertised refs (Connection or through Transport helper methods. Apply this specification on remote repository using Transport.push(ProgressMonitor, Collection<RemoteRefUpdate>) method.

/** * Represent request and status of a remote ref update. Specification is * provided by client, while status is handled by * {@link org.eclipse.jgit.transport.PushProcess} class, being read-only for * client. * <p> * Client can create instances of this class directly, basing on user * specification and advertised refs * ({@link org.eclipse.jgit.transport.Connection} or through * {@link org.eclipse.jgit.transport.Transport} helper methods. Apply this * specification on remote repository using * {@link org.eclipse.jgit.transport.Transport#push(org.eclipse.jgit.lib.ProgressMonitor, java.util.Collection)} * method. * </p> */
public class RemoteRefUpdate {
Represent current status of a remote ref update.
/** * Represent current status of a remote ref update. */
public static enum Status {
Push process hasn't yet attempted to update this ref. This is the default status, prior to push process execution.
/** * Push process hasn't yet attempted to update this ref. This is the * default status, prior to push process execution. */
NOT_ATTEMPTED,
Remote ref was up to date, there was no need to update anything.
/** * Remote ref was up to date, there was no need to update anything. */
UP_TO_DATE,
Remote ref update was rejected, as it would cause non fast-forward update.
/** * Remote ref update was rejected, as it would cause non fast-forward * update. */
REJECTED_NONFASTFORWARD,
Remote ref update was rejected, because remote side doesn't support/allow deleting refs.
/** * Remote ref update was rejected, because remote side doesn't * support/allow deleting refs. */
REJECTED_NODELETE,
Remote ref update was rejected, because old object id on remote repository wasn't the same as defined expected old object.
/** * Remote ref update was rejected, because old object id on remote * repository wasn't the same as defined expected old object. */
REJECTED_REMOTE_CHANGED,
Remote ref update was rejected for other reason, possibly described in RemoteRefUpdate.getMessage().
/** * Remote ref update was rejected for other reason, possibly described * in {@link RemoteRefUpdate#getMessage()}. */
REJECTED_OTHER_REASON,
Remote ref didn't exist. Can occur on delete request of a non existing ref.
/** * Remote ref didn't exist. Can occur on delete request of a non * existing ref. */
NON_EXISTING,
Push process is awaiting update report from remote repository. This is a temporary state or state after critical error in push process.
/** * Push process is awaiting update report from remote repository. This * is a temporary state or state after critical error in push process. */
AWAITING_REPORT,
Remote ref was successfully updated.
/** * Remote ref was successfully updated. */
OK; } private ObjectId expectedOldObjectId; private final ObjectId newObjectId; private final String remoteName; private final TrackingRefUpdate trackingRefUpdate; private final String srcRef; private final boolean forceUpdate; private Status status; private boolean fastForward; private String message; private final Repository localDb; private RefUpdate localUpdate;
Construct remote ref update request by providing an update specification. Object is created with default Status.NOT_ATTEMPTED status and no message.
Params:
  • localDb – local repository to push from.
  • srcRef – source revision - any string resolvable by Repository.resolve(String). This resolves to the new object that the caller want remote ref to be after update. Use null or ObjectId.zeroId() string for delete request.
  • remoteName – full name of a remote ref to update, e.g. "refs/heads/master" (no wildcard, no short name).
  • forceUpdate – true when caller want remote ref to be updated regardless whether it is fast-forward update (old object is ancestor of new object).
  • localName – optional full name of a local stored tracking branch, to update after push, e.g. "refs/remotes/zawir/dirty" (no wildcard, no short name); null if no local tracking branch should be updated.
  • expectedOldObjectId – optional object id that caller is expecting, requiring to be advertised by remote side before update; update will take place ONLY if remote side advertise exactly this expected id; null if caller doesn't care what object id remote side advertise. Use ObjectId.zeroId() when expecting no remote ref with this name.
Throws:
/** * Construct remote ref update request by providing an update specification. * Object is created with default * {@link org.eclipse.jgit.transport.RemoteRefUpdate.Status#NOT_ATTEMPTED} * status and no message. * * @param localDb * local repository to push from. * @param srcRef * source revision - any string resolvable by * {@link org.eclipse.jgit.lib.Repository#resolve(String)}. This * resolves to the new object that the caller want remote ref to * be after update. Use null or * {@link org.eclipse.jgit.lib.ObjectId#zeroId()} string for * delete request. * @param remoteName * full name of a remote ref to update, e.g. "refs/heads/master" * (no wildcard, no short name). * @param forceUpdate * true when caller want remote ref to be updated regardless * whether it is fast-forward update (old object is ancestor of * new object). * @param localName * optional full name of a local stored tracking branch, to * update after push, e.g. "refs/remotes/zawir/dirty" (no * wildcard, no short name); null if no local tracking branch * should be updated. * @param expectedOldObjectId * optional object id that caller is expecting, requiring to be * advertised by remote side before update; update will take * place ONLY if remote side advertise exactly this expected id; * null if caller doesn't care what object id remote side * advertise. Use {@link org.eclipse.jgit.lib.ObjectId#zeroId()} * when expecting no remote ref with this name. * @throws java.io.IOException * when I/O error occurred during creating * {@link org.eclipse.jgit.transport.TrackingRefUpdate} for * local tracking branch or srcRef can't be resolved to any * object. * @throws java.lang.IllegalArgumentException * if some required parameter was null */
public RemoteRefUpdate(final Repository localDb, final String srcRef, final String remoteName, final boolean forceUpdate, final String localName, final ObjectId expectedOldObjectId) throws IOException { this(localDb, srcRef, srcRef != null ? localDb.resolve(srcRef) : ObjectId.zeroId(), remoteName, forceUpdate, localName, expectedOldObjectId); }
Construct remote ref update request by providing an update specification. Object is created with default Status.NOT_ATTEMPTED status and no message.
Params:
  • localDb – local repository to push from.
  • srcRef – source revision. Use null to delete.
  • remoteName – full name of a remote ref to update, e.g. "refs/heads/master" (no wildcard, no short name).
  • forceUpdate – true when caller want remote ref to be updated regardless whether it is fast-forward update (old object is ancestor of new object).
  • localName – optional full name of a local stored tracking branch, to update after push, e.g. "refs/remotes/zawir/dirty" (no wildcard, no short name); null if no local tracking branch should be updated.
  • expectedOldObjectId – optional object id that caller is expecting, requiring to be advertised by remote side before update; update will take place ONLY if remote side advertise exactly this expected id; null if caller doesn't care what object id remote side advertise. Use ObjectId.zeroId() when expecting no remote ref with this name.
Throws:
/** * Construct remote ref update request by providing an update specification. * Object is created with default * {@link org.eclipse.jgit.transport.RemoteRefUpdate.Status#NOT_ATTEMPTED} * status and no message. * * @param localDb * local repository to push from. * @param srcRef * source revision. Use null to delete. * @param remoteName * full name of a remote ref to update, e.g. "refs/heads/master" * (no wildcard, no short name). * @param forceUpdate * true when caller want remote ref to be updated regardless * whether it is fast-forward update (old object is ancestor of * new object). * @param localName * optional full name of a local stored tracking branch, to * update after push, e.g. "refs/remotes/zawir/dirty" (no * wildcard, no short name); null if no local tracking branch * should be updated. * @param expectedOldObjectId * optional object id that caller is expecting, requiring to be * advertised by remote side before update; update will take * place ONLY if remote side advertise exactly this expected id; * null if caller doesn't care what object id remote side * advertise. Use {@link org.eclipse.jgit.lib.ObjectId#zeroId()} * when expecting no remote ref with this name. * @throws java.io.IOException * when I/O error occurred during creating * {@link org.eclipse.jgit.transport.TrackingRefUpdate} for * local tracking branch or srcRef can't be resolved to any * object. * @throws java.lang.IllegalArgumentException * if some required parameter was null */
public RemoteRefUpdate(final Repository localDb, final Ref srcRef, final String remoteName, final boolean forceUpdate, final String localName, final ObjectId expectedOldObjectId) throws IOException { this(localDb, srcRef != null ? srcRef.getName() : null, srcRef != null ? srcRef.getObjectId() : null, remoteName, forceUpdate, localName, expectedOldObjectId); }
Construct remote ref update request by providing an update specification. Object is created with default Status.NOT_ATTEMPTED status and no message.
Params:
  • localDb – local repository to push from.
  • srcRef – source revision to label srcId with. If null srcId.name() will be used instead.
  • srcId – The new object that the caller wants remote ref to be after update. Use null or ObjectId.zeroId() for delete request.
  • remoteName – full name of a remote ref to update, e.g. "refs/heads/master" (no wildcard, no short name).
  • forceUpdate – true when caller want remote ref to be updated regardless whether it is fast-forward update (old object is ancestor of new object).
  • localName – optional full name of a local stored tracking branch, to update after push, e.g. "refs/remotes/zawir/dirty" (no wildcard, no short name); null if no local tracking branch should be updated.
  • expectedOldObjectId – optional object id that caller is expecting, requiring to be advertised by remote side before update; update will take place ONLY if remote side advertise exactly this expected id; null if caller doesn't care what object id remote side advertise. Use ObjectId.zeroId() when expecting no remote ref with this name.
Throws:
/** * Construct remote ref update request by providing an update specification. * Object is created with default * {@link org.eclipse.jgit.transport.RemoteRefUpdate.Status#NOT_ATTEMPTED} * status and no message. * * @param localDb * local repository to push from. * @param srcRef * source revision to label srcId with. If null srcId.name() will * be used instead. * @param srcId * The new object that the caller wants remote ref to be after * update. Use null or * {@link org.eclipse.jgit.lib.ObjectId#zeroId()} for delete * request. * @param remoteName * full name of a remote ref to update, e.g. "refs/heads/master" * (no wildcard, no short name). * @param forceUpdate * true when caller want remote ref to be updated regardless * whether it is fast-forward update (old object is ancestor of * new object). * @param localName * optional full name of a local stored tracking branch, to * update after push, e.g. "refs/remotes/zawir/dirty" (no * wildcard, no short name); null if no local tracking branch * should be updated. * @param expectedOldObjectId * optional object id that caller is expecting, requiring to be * advertised by remote side before update; update will take * place ONLY if remote side advertise exactly this expected id; * null if caller doesn't care what object id remote side * advertise. Use {@link org.eclipse.jgit.lib.ObjectId#zeroId()} * when expecting no remote ref with this name. * @throws java.io.IOException * when I/O error occurred during creating * {@link org.eclipse.jgit.transport.TrackingRefUpdate} for * local tracking branch or srcRef can't be resolved to any * object. * @throws java.lang.IllegalArgumentException * if some required parameter was null */
public RemoteRefUpdate(final Repository localDb, final String srcRef, final ObjectId srcId, final String remoteName, final boolean forceUpdate, final String localName, final ObjectId expectedOldObjectId) throws IOException { if (remoteName == null) throw new IllegalArgumentException(JGitText.get().remoteNameCannotBeNull); if (srcId == null && srcRef != null) throw new IOException(MessageFormat.format( JGitText.get().sourceRefDoesntResolveToAnyObject, srcRef)); if (srcRef != null) this.srcRef = srcRef; else if (srcId != null && !srcId.equals(ObjectId.zeroId())) this.srcRef = srcId.name(); else this.srcRef = null; if (srcId != null) this.newObjectId = srcId; else this.newObjectId = ObjectId.zeroId(); this.remoteName = remoteName; this.forceUpdate = forceUpdate; if (localName != null && localDb != null) { localUpdate = localDb.updateRef(localName); localUpdate.setForceUpdate(true); localUpdate.setRefLogMessage("push", true); //$NON-NLS-1$ localUpdate.setNewObjectId(newObjectId); trackingRefUpdate = new TrackingRefUpdate( true, remoteName, localName, localUpdate.getOldObjectId() != null ? localUpdate.getOldObjectId() : ObjectId.zeroId(), newObjectId); } else trackingRefUpdate = null; this.localDb = localDb; this.expectedOldObjectId = expectedOldObjectId; this.status = Status.NOT_ATTEMPTED; }
Create a new instance of this object basing on existing instance for configuration. State (like getMessage(), getStatus()) of base object is not shared. Expected old object id is set up from scratch, as this constructor may be used for 2-stage push: first one being dry run, second one being actual push.
Params:
  • base – configuration base.
  • newExpectedOldObjectId – new expected object id value.
Throws:
  • IOException – when I/O error occurred during creating TrackingRefUpdate for local tracking branch or srcRef of base object no longer can be resolved to any object.
/** * Create a new instance of this object basing on existing instance for * configuration. State (like {@link #getMessage()}, {@link #getStatus()}) * of base object is not shared. Expected old object id is set up from * scratch, as this constructor may be used for 2-stage push: first one * being dry run, second one being actual push. * * @param base * configuration base. * @param newExpectedOldObjectId * new expected object id value. * @throws java.io.IOException * when I/O error occurred during creating * {@link org.eclipse.jgit.transport.TrackingRefUpdate} for * local tracking branch or srcRef of base object no longer can * be resolved to any object. */
public RemoteRefUpdate(final RemoteRefUpdate base, final ObjectId newExpectedOldObjectId) throws IOException { this(base.localDb, base.srcRef, base.remoteName, base.forceUpdate, (base.trackingRefUpdate == null ? null : base.trackingRefUpdate .getLocalName()), newExpectedOldObjectId); }
Get expected old object id
Returns:expectedOldObjectId required to be advertised by remote side, as set in constructor; may be null.
/** * Get expected old object id * * @return expectedOldObjectId required to be advertised by remote side, as * set in constructor; may be null. */
public ObjectId getExpectedOldObjectId() { return expectedOldObjectId; }
Whether some object is required to be advertised by remote side, as set in constructor
Returns:true if some object is required to be advertised by remote side, as set in constructor; false otherwise.
/** * Whether some object is required to be advertised by remote side, as set * in constructor * * @return true if some object is required to be advertised by remote side, * as set in constructor; false otherwise. */
public boolean isExpectingOldObjectId() { return expectedOldObjectId != null; }
Get new object id
Returns:newObjectId for remote ref, as set in constructor.
/** * Get new object id * * @return newObjectId for remote ref, as set in constructor. */
public ObjectId getNewObjectId() { return newObjectId; }
Whether this update is a deleting update
Returns:true if this update is deleting update; false otherwise.
/** * Whether this update is a deleting update * * @return true if this update is deleting update; false otherwise. */
public boolean isDelete() { return ObjectId.zeroId().equals(newObjectId); }
Get name of remote ref to update
Returns:name of remote ref to update, as set in constructor.
/** * Get name of remote ref to update * * @return name of remote ref to update, as set in constructor. */
public String getRemoteName() { return remoteName; }
Get tracking branch update if localName was set in constructor.
Returns:local tracking branch update if localName was set in constructor.
/** * Get tracking branch update if localName was set in constructor. * * @return local tracking branch update if localName was set in constructor. */
public TrackingRefUpdate getTrackingRefUpdate() { return trackingRefUpdate; }
Get source revision as specified by user (in constructor)
Returns:source revision as specified by user (in constructor), could be any string parseable by Repository.resolve(String); can be null if specified that way in constructor - this stands for delete request.
/** * Get source revision as specified by user (in constructor) * * @return source revision as specified by user (in constructor), could be * any string parseable by * {@link org.eclipse.jgit.lib.Repository#resolve(String)}; can be * null if specified that way in constructor - this stands for * delete request. */
public String getSrcRef() { return srcRef; }
Whether user specified a local tracking branch for remote update
Returns:true if user specified a local tracking branch for remote update; false otherwise.
/** * Whether user specified a local tracking branch for remote update * * @return true if user specified a local tracking branch for remote update; * false otherwise. */
public boolean hasTrackingRefUpdate() { return trackingRefUpdate != null; }
Whether this update is forced regardless of old remote ref object
Returns:true if this update is forced regardless of old remote ref object; false otherwise.
/** * Whether this update is forced regardless of old remote ref object * * @return true if this update is forced regardless of old remote ref * object; false otherwise. */
public boolean isForceUpdate() { return forceUpdate; }
Get status of remote ref update operation.
Returns:status of remote ref update operation.
/** * Get status of remote ref update operation. * * @return status of remote ref update operation. */
public Status getStatus() { return status; }
Check whether update was fast-forward. Note that this result is meaningful only after successful update (when status is Status.OK).
Returns:true if update was fast-forward; false otherwise.
/** * Check whether update was fast-forward. Note that this result is * meaningful only after successful update (when status is * {@link org.eclipse.jgit.transport.RemoteRefUpdate.Status#OK}). * * @return true if update was fast-forward; false otherwise. */
public boolean isFastForward() { return fastForward; }
Get message describing reasons of status when needed/possible; may be null.
Returns:message describing reasons of status when needed/possible; may be null.
/** * Get message describing reasons of status when needed/possible; may be * null. * * @return message describing reasons of status when needed/possible; may be * null. */
public String getMessage() { return message; } void setExpectedOldObjectId(ObjectId id) { expectedOldObjectId = id; } void setStatus(Status status) { this.status = status; } void setFastForward(boolean fastForward) { this.fastForward = fastForward; } void setMessage(String message) { this.message = message; }
Update locally stored tracking branch with the new object.
Params:
  • walk – walker used for checking update properties.
Throws:
/** * Update locally stored tracking branch with the new object. * * @param walk * walker used for checking update properties. * @throws java.io.IOException * when I/O error occurred during update */
protected void updateTrackingRef(RevWalk walk) throws IOException { if (isDelete()) trackingRefUpdate.setResult(localUpdate.delete(walk)); else trackingRefUpdate.setResult(localUpdate.update(walk)); }
{@inheritDoc}
/** {@inheritDoc} */
@SuppressWarnings("nls") @Override public String toString() { return "RemoteRefUpdate[remoteName=" + remoteName + ", " + status + ", " + (expectedOldObjectId != null ? expectedOldObjectId.name() : "(null)") + "..." + (newObjectId != null ? newObjectId.name() : "(null)") + (fastForward ? ", fastForward" : "") + ", srcRef=" + srcRef + (forceUpdate ? ", forceUpdate" : "") + ", message=" + (message != null ? "\"" + message + "\"" : "null") + "]"; } }