Browse Source
* changes: Use BatchRefUpdate for tracking refs in FetchProcess Batch reference updates together for storage Expose ReceiveCommand.updateType to check for UPDATE_NONFASTFORWARD Reject non-fast-forwards earlier in BaseReceivePackstable-2.1
Shawn O. Pearce
13 years ago
committed by
Gerrit Code Review @ Eclipse.org
8 changed files with 606 additions and 112 deletions
@ -0,0 +1,317 @@ |
|||||||
|
/* |
||||||
|
* Copyright (C) 2008-2012, Google Inc. |
||||||
|
* Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org> |
||||||
|
* 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.lib; |
||||||
|
|
||||||
|
import static org.eclipse.jgit.transport.ReceiveCommand.Result.NOT_ATTEMPTED; |
||||||
|
import static org.eclipse.jgit.transport.ReceiveCommand.Result.REJECTED_OTHER_REASON; |
||||||
|
|
||||||
|
import java.io.IOException; |
||||||
|
import java.text.MessageFormat; |
||||||
|
import java.util.ArrayList; |
||||||
|
import java.util.Arrays; |
||||||
|
import java.util.Collection; |
||||||
|
import java.util.Collections; |
||||||
|
import java.util.List; |
||||||
|
|
||||||
|
import org.eclipse.jgit.internal.JGitText; |
||||||
|
import org.eclipse.jgit.revwalk.RevWalk; |
||||||
|
import org.eclipse.jgit.transport.ReceiveCommand; |
||||||
|
|
||||||
|
/** |
||||||
|
* Batch of reference updates to be applied to a repository. |
||||||
|
* <p> |
||||||
|
* The batch update is primarily useful in the transport code, where a client or |
||||||
|
* server is making changes to more than one reference at a time. |
||||||
|
*/ |
||||||
|
public class BatchRefUpdate { |
||||||
|
private final RefDatabase refdb; |
||||||
|
|
||||||
|
/** Commands to apply during this batch. */ |
||||||
|
private final List<ReceiveCommand> commands; |
||||||
|
|
||||||
|
/** Does the caller permit a forced update on a reference? */ |
||||||
|
private boolean allowNonFastForwards; |
||||||
|
|
||||||
|
/** Identity to record action as within the reflog. */ |
||||||
|
private PersonIdent refLogIdent; |
||||||
|
|
||||||
|
/** Message the caller wants included in the reflog. */ |
||||||
|
private String refLogMessage; |
||||||
|
|
||||||
|
/** Should the result value be appended to {@link #refLogMessage}. */ |
||||||
|
private boolean refLogIncludeResult; |
||||||
|
|
||||||
|
/** |
||||||
|
* Initialize a new batch update. |
||||||
|
* |
||||||
|
* @param refdb |
||||||
|
* the reference database of the repository to be updated. |
||||||
|
*/ |
||||||
|
protected BatchRefUpdate(RefDatabase refdb) { |
||||||
|
this.refdb = refdb; |
||||||
|
this.commands = new ArrayList<ReceiveCommand>(); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* @return true if the batch update will permit a non-fast-forward update to |
||||||
|
* an existing reference. |
||||||
|
*/ |
||||||
|
public boolean isAllowNonFastForwards() { |
||||||
|
return allowNonFastForwards; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Set if this update wants to permit a forced update. |
||||||
|
* |
||||||
|
* @param allow |
||||||
|
* true if this update batch should ignore merge tests. |
||||||
|
* @return {@code this}. |
||||||
|
*/ |
||||||
|
public BatchRefUpdate setAllowNonFastForwards(boolean allow) { |
||||||
|
allowNonFastForwards = allow; |
||||||
|
return this; |
||||||
|
} |
||||||
|
|
||||||
|
/** @return identity of the user making the change in the reflog. */ |
||||||
|
public PersonIdent getRefLogIdent() { |
||||||
|
return refLogIdent; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Set the identity of the user appearing in the reflog. |
||||||
|
* <p> |
||||||
|
* The timestamp portion of the identity is ignored. A new identity with the |
||||||
|
* current timestamp will be created automatically when the update occurs |
||||||
|
* and the log record is written. |
||||||
|
* |
||||||
|
* @param pi |
||||||
|
* identity of the user. If null the identity will be |
||||||
|
* automatically determined based on the repository |
||||||
|
* configuration. |
||||||
|
* @return {@code this}. |
||||||
|
*/ |
||||||
|
public BatchRefUpdate setRefLogIdent(final PersonIdent pi) { |
||||||
|
refLogIdent = pi; |
||||||
|
return this; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Get the message to include in the reflog. |
||||||
|
* |
||||||
|
* @return message the caller wants to include in the reflog; null if the |
||||||
|
* update should not be logged. |
||||||
|
*/ |
||||||
|
public String getRefLogMessage() { |
||||||
|
return refLogMessage; |
||||||
|
} |
||||||
|
|
||||||
|
/** @return {@code true} if the ref log message should show the result. */ |
||||||
|
public boolean isRefLogIncludingResult() { |
||||||
|
return refLogIncludeResult; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Set the message to include in the reflog. |
||||||
|
* |
||||||
|
* @param msg |
||||||
|
* the message to describe this change. It may be null if |
||||||
|
* appendStatus is null in order not to append to the reflog |
||||||
|
* @param appendStatus |
||||||
|
* true if the status of the ref change (fast-forward or |
||||||
|
* forced-update) should be appended to the user supplied |
||||||
|
* message. |
||||||
|
* @return {@code this}. |
||||||
|
*/ |
||||||
|
public BatchRefUpdate setRefLogMessage(String msg, boolean appendStatus) { |
||||||
|
if (msg == null && !appendStatus) |
||||||
|
disableRefLog(); |
||||||
|
else if (msg == null && appendStatus) { |
||||||
|
refLogMessage = ""; |
||||||
|
refLogIncludeResult = true; |
||||||
|
} else { |
||||||
|
refLogMessage = msg; |
||||||
|
refLogIncludeResult = appendStatus; |
||||||
|
} |
||||||
|
return this; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Don't record this update in the ref's associated reflog. |
||||||
|
* |
||||||
|
* @return {@code this}. |
||||||
|
*/ |
||||||
|
public BatchRefUpdate disableRefLog() { |
||||||
|
refLogMessage = null; |
||||||
|
refLogIncludeResult = false; |
||||||
|
return this; |
||||||
|
} |
||||||
|
|
||||||
|
/** @return true if log has been disabled by {@link #disableRefLog()}. */ |
||||||
|
public boolean isRefLogDisabled() { |
||||||
|
return refLogMessage == null; |
||||||
|
} |
||||||
|
|
||||||
|
/** @return commands this update will process. */ |
||||||
|
public List<ReceiveCommand> getCommands() { |
||||||
|
return Collections.unmodifiableList(commands); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Add a single command to this batch update. |
||||||
|
* |
||||||
|
* @param cmd |
||||||
|
* the command to add, must not be null. |
||||||
|
* @return {@code this}. |
||||||
|
*/ |
||||||
|
public BatchRefUpdate addCommand(ReceiveCommand cmd) { |
||||||
|
commands.add(cmd); |
||||||
|
return this; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Add commands to this batch update. |
||||||
|
* |
||||||
|
* @param cmd |
||||||
|
* the commands to add, must not be null. |
||||||
|
* @return {@code this}. |
||||||
|
*/ |
||||||
|
public BatchRefUpdate addCommand(ReceiveCommand... cmd) { |
||||||
|
return addCommand(Arrays.asList(cmd)); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Add commands to this batch update. |
||||||
|
* |
||||||
|
* @param cmd |
||||||
|
* the commands to add, must not be null. |
||||||
|
* @return {@code this}. |
||||||
|
*/ |
||||||
|
public BatchRefUpdate addCommand(Collection<ReceiveCommand> cmd) { |
||||||
|
commands.addAll(cmd); |
||||||
|
return this; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Execute this batch update. |
||||||
|
* <p> |
||||||
|
* The default implementation of this method performs a sequential reference |
||||||
|
* update over each reference. |
||||||
|
* |
||||||
|
* @param walk |
||||||
|
* a RevWalk to parse tags in case the storage system wants to |
||||||
|
* store them pre-peeled, a common performance optimization. |
||||||
|
* @param update |
||||||
|
* progress monitor to receive update status on. |
||||||
|
* @throws IOException |
||||||
|
* the database is unable to accept the update. Individual |
||||||
|
* command status must be tested to determine if there is a |
||||||
|
* partial failure, or a total failure. |
||||||
|
*/ |
||||||
|
public void execute(RevWalk walk, ProgressMonitor update) |
||||||
|
throws IOException { |
||||||
|
update.beginTask(JGitText.get().updatingReferences, commands.size()); |
||||||
|
for (ReceiveCommand cmd : commands) { |
||||||
|
try { |
||||||
|
update.update(1); |
||||||
|
|
||||||
|
if (cmd.getResult() == NOT_ATTEMPTED) { |
||||||
|
cmd.updateType(walk); |
||||||
|
RefUpdate ru = newUpdate(cmd); |
||||||
|
switch (cmd.getType()) { |
||||||
|
case DELETE: |
||||||
|
cmd.setResult(ru.delete(walk)); |
||||||
|
continue; |
||||||
|
|
||||||
|
case CREATE: |
||||||
|
case UPDATE: |
||||||
|
case UPDATE_NONFASTFORWARD: |
||||||
|
cmd.setResult(ru.update(walk)); |
||||||
|
continue; |
||||||
|
} |
||||||
|
} |
||||||
|
} catch (IOException err) { |
||||||
|
cmd.setResult(REJECTED_OTHER_REASON, MessageFormat.format( |
||||||
|
JGitText.get().lockError, err.getMessage())); |
||||||
|
} |
||||||
|
} |
||||||
|
update.endTask(); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Create a new RefUpdate copying the batch settings. |
||||||
|
* |
||||||
|
* @param cmd |
||||||
|
* specific command the update should be created to copy. |
||||||
|
* @return a single reference update command. |
||||||
|
* @throws IOException |
||||||
|
* the reference database cannot make a new update object for |
||||||
|
* the given reference. |
||||||
|
*/ |
||||||
|
protected RefUpdate newUpdate(ReceiveCommand cmd) throws IOException { |
||||||
|
RefUpdate ru = refdb.newUpdate(cmd.getRefName(), false); |
||||||
|
if (isRefLogDisabled()) |
||||||
|
ru.disableRefLog(); |
||||||
|
else { |
||||||
|
ru.setRefLogIdent(refLogIdent); |
||||||
|
ru.setRefLogMessage(refLogMessage, refLogIncludeResult); |
||||||
|
} |
||||||
|
switch (cmd.getType()) { |
||||||
|
case DELETE: |
||||||
|
if (!ObjectId.zeroId().equals(cmd.getOldId())) |
||||||
|
ru.setExpectedOldObjectId(cmd.getOldId()); |
||||||
|
ru.setForceUpdate(true); |
||||||
|
return ru; |
||||||
|
|
||||||
|
case CREATE: |
||||||
|
case UPDATE: |
||||||
|
case UPDATE_NONFASTFORWARD: |
||||||
|
default: |
||||||
|
ru.setForceUpdate(isAllowNonFastForwards()); |
||||||
|
ru.setExpectedOldObjectId(cmd.getOldId()); |
||||||
|
ru.setNewObjectId(cmd.getNewId()); |
||||||
|
return ru; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
Loading…
Reference in new issue