import java.util.concurrent.locks.ReadWriteLock; | import java.util.concurrent.locks.ReadWriteLock; | ||||
import java.util.concurrent.locks.ReentrantReadWriteLock; | import java.util.concurrent.locks.ReentrantReadWriteLock; | ||||
import org.eclipse.jgit.internal.JGitText; | |||||
import org.eclipse.jgit.internal.storage.pack.PackExt; | import org.eclipse.jgit.internal.storage.pack.PackExt; | ||||
import org.eclipse.jgit.lib.BatchRefUpdate; | import org.eclipse.jgit.lib.BatchRefUpdate; | ||||
import org.eclipse.jgit.lib.ObjectId; | import org.eclipse.jgit.lib.ObjectId; | ||||
try (RevWalk rw = new RevWalk(getRepository())) { | try (RevWalk rw = new RevWalk(getRepository())) { | ||||
for (ReceiveCommand c : cmds) { | for (ReceiveCommand c : cmds) { | ||||
if (c.getResult() != ReceiveCommand.Result.NOT_ATTEMPTED) { | if (c.getResult() != ReceiveCommand.Result.NOT_ATTEMPTED) { | ||||
reject(cmds); | |||||
ReceiveCommand.abort(cmds); | |||||
return; | return; | ||||
} | } | ||||
} | } | ||||
} catch (IOException e) { | } catch (IOException e) { | ||||
c.setResult(ReceiveCommand.Result.REJECTED_MISSING_OBJECT); | c.setResult(ReceiveCommand.Result.REJECTED_MISSING_OBJECT); | ||||
reject(cmds); | |||||
ReceiveCommand.abort(cmds); | |||||
return; | return; | ||||
} | } | ||||
} | } | ||||
if (r == null) { | if (r == null) { | ||||
if (c.getType() != ReceiveCommand.Type.CREATE) { | if (c.getType() != ReceiveCommand.Type.CREATE) { | ||||
c.setResult(ReceiveCommand.Result.LOCK_FAILURE); | c.setResult(ReceiveCommand.Result.LOCK_FAILURE); | ||||
reject(cmds); | |||||
ReceiveCommand.abort(cmds); | |||||
return; | return; | ||||
} | } | ||||
} else { | } else { | ||||
if (r.isSymbolic() || objectId == null | if (r.isSymbolic() || objectId == null | ||||
|| !objectId.equals(c.getOldId())) { | || !objectId.equals(c.getOldId())) { | ||||
c.setResult(ReceiveCommand.Result.LOCK_FAILURE); | c.setResult(ReceiveCommand.Result.LOCK_FAILURE); | ||||
reject(cmds); | |||||
ReceiveCommand.abort(cmds); | |||||
return; | return; | ||||
} | } | ||||
} | } | ||||
clearCache(); | clearCache(); | ||||
} | } | ||||
private void reject(List<ReceiveCommand> cmds) { | |||||
for (ReceiveCommand c : cmds) { | |||||
if (c.getResult() == ReceiveCommand.Result.NOT_ATTEMPTED) { | |||||
c.setResult(ReceiveCommand.Result.REJECTED_OTHER_REASON, | |||||
JGitText.get().transactionAborted); | |||||
} | |||||
} | |||||
} | |||||
@Override | @Override | ||||
protected boolean compareAndPut(Ref oldRef, Ref newRef) | protected boolean compareAndPut(Ref oldRef, Ref newRef) | ||||
throws IOException { | throws IOException { |
import static org.eclipse.jgit.lib.FileMode.TYPE_SYMLINK; | import static org.eclipse.jgit.lib.FileMode.TYPE_SYMLINK; | ||||
import static org.eclipse.jgit.lib.Ref.Storage.NETWORK; | import static org.eclipse.jgit.lib.Ref.Storage.NETWORK; | ||||
import static org.eclipse.jgit.transport.ReceiveCommand.Result.NOT_ATTEMPTED; | 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.io.IOException; | ||||
import org.eclipse.jgit.annotations.Nullable; | import org.eclipse.jgit.annotations.Nullable; | ||||
import org.eclipse.jgit.dircache.DirCacheEntry; | import org.eclipse.jgit.dircache.DirCacheEntry; | ||||
import org.eclipse.jgit.errors.MissingObjectException; | import org.eclipse.jgit.errors.MissingObjectException; | ||||
import org.eclipse.jgit.internal.JGitText; | |||||
import org.eclipse.jgit.lib.ObjectId; | import org.eclipse.jgit.lib.ObjectId; | ||||
import org.eclipse.jgit.lib.ObjectIdRef; | import org.eclipse.jgit.lib.ObjectIdRef; | ||||
import org.eclipse.jgit.lib.ObjectInserter; | import org.eclipse.jgit.lib.ObjectInserter; | ||||
* for processing. | * for processing. | ||||
*/ | */ | ||||
public class Command { | public class Command { | ||||
/** | |||||
* Set unprocessed commands as failed due to transaction aborted. | |||||
* <p> | |||||
* If a command is still {@link Result#NOT_ATTEMPTED} it will be set to | |||||
* {@link Result#REJECTED_OTHER_REASON}. If {@code why} is non-null its | |||||
* contents will be used as the message for the first command status. | |||||
* | |||||
* @param commands | |||||
* commands to mark as failed. | |||||
* @param why | |||||
* optional message to set on the first aborted command. | |||||
*/ | |||||
public static void abort(Iterable<Command> commands, @Nullable String why) { | |||||
if (why == null || why.isEmpty()) { | |||||
why = JGitText.get().transactionAborted; | |||||
} | |||||
for (Command c : commands) { | |||||
if (c.getResult() == NOT_ATTEMPTED) { | |||||
c.setResult(REJECTED_OTHER_REASON, why); | |||||
why = JGitText.get().transactionAborted; | |||||
} | |||||
} | |||||
} | |||||
private final Ref oldRef; | private final Ref oldRef; | ||||
private final Ref newRef; | private final Ref newRef; | ||||
private final ReceiveCommand cmd; | private final ReceiveCommand cmd; |
import static org.eclipse.jgit.lib.Ref.Storage.PACKED; | import static org.eclipse.jgit.lib.Ref.Storage.PACKED; | ||||
import static org.eclipse.jgit.lib.RefDatabase.MAX_SYMBOLIC_REF_DEPTH; | import static org.eclipse.jgit.lib.RefDatabase.MAX_SYMBOLIC_REF_DEPTH; | ||||
import static org.eclipse.jgit.transport.ReceiveCommand.Result.LOCK_FAILURE; | import static org.eclipse.jgit.transport.ReceiveCommand.Result.LOCK_FAILURE; | ||||
import static org.eclipse.jgit.transport.ReceiveCommand.Result.NOT_ATTEMPTED; | |||||
import static org.eclipse.jgit.transport.ReceiveCommand.Result.REJECTED_OTHER_REASON; | import static org.eclipse.jgit.transport.ReceiveCommand.Result.REJECTED_OTHER_REASON; | ||||
import java.io.IOException; | import java.io.IOException; | ||||
if (!isValidRef(cmd)) { | if (!isValidRef(cmd)) { | ||||
cmd.setResult(REJECTED_OTHER_REASON, | cmd.setResult(REJECTED_OTHER_REASON, | ||||
JGitText.get().funnyRefname); | JGitText.get().funnyRefname); | ||||
return abort(cmdList); | |||||
Command.abort(cmdList, null); | |||||
return false; | |||||
} | } | ||||
apply(ed, cmd); | apply(ed, cmd); | ||||
} | } | ||||
break; | break; | ||||
} | } | ||||
} | } | ||||
return abort(cmdList); | |||||
Command.abort(cmdList, null); | |||||
return false; | |||||
} catch (LockFailureException e) { | } catch (LockFailureException e) { | ||||
return abort(cmdList); | |||||
Command.abort(cmdList, null); | |||||
return false; | |||||
} | } | ||||
} | } | ||||
} | } | ||||
} | } | ||||
private static boolean abort(Iterable<Command> cmdList) { | |||||
for (Command cmd : cmdList) { | |||||
if (cmd.getResult() == NOT_ATTEMPTED) { | |||||
reject(cmd, JGitText.get().transactionAborted); | |||||
} | |||||
} | |||||
return false; | |||||
} | |||||
private static void reject(Command cmd, String msg) { | |||||
cmd.setResult(REJECTED_OTHER_REASON, msg); | |||||
} | |||||
/** | /** | ||||
* Convert a path name in a RefTree to the reference name known by Git. | * Convert a path name in a RefTree to the reference name known by Git. | ||||
* | * |
} | } | ||||
if (c.getType() == UPDATE_NONFASTFORWARD) { | if (c.getType() == UPDATE_NONFASTFORWARD) { | ||||
c.setResult(REJECTED_NONFASTFORWARD); | c.setResult(REJECTED_NONFASTFORWARD); | ||||
reject(); | |||||
ReceiveCommand.abort(getCommands()); | |||||
return; | return; | ||||
} | } | ||||
} | } | ||||
execute(rw, todo); | execute(rw, todo); | ||||
} | } | ||||
private void reject() { | |||||
String aborted = JGitText.get().transactionAborted; | |||||
for (ReceiveCommand c : getCommands()) { | |||||
if (c.getResult() == NOT_ATTEMPTED) { | |||||
c.setResult(REJECTED_OTHER_REASON, aborted); | |||||
} | |||||
} | |||||
} | |||||
void init(RevWalk rw) throws IOException { | void init(RevWalk rw) throws IOException { | ||||
src = refdb.getBootstrap().exactRef(refdb.getTxnCommitted()); | src = refdb.getBootstrap().exactRef(refdb.getTxnCommitted()); | ||||
if (src != null && src.getObjectId() != null) { | if (src != null && src.getObjectId() != null) { | ||||
void execute(RevWalk rw, List<Command> todo) throws IOException { | void execute(RevWalk rw, List<Command> todo) throws IOException { | ||||
for (Command c : todo) { | for (Command c : todo) { | ||||
if (c.getResult() != NOT_ATTEMPTED) { | if (c.getResult() != NOT_ATTEMPTED) { | ||||
reject(todo, JGitText.get().transactionAborted); | |||||
Command.abort(todo, null); | |||||
return; | return; | ||||
} | } | ||||
if (refdb.conflictsWithBootstrap(c.getRefName())) { | if (refdb.conflictsWithBootstrap(c.getRefName())) { | ||||
c.setResult(REJECTED_OTHER_REASON, MessageFormat | c.setResult(REJECTED_OTHER_REASON, MessageFormat | ||||
.format(JGitText.get().invalidRefName, c.getRefName())); | .format(JGitText.get().invalidRefName, c.getRefName())); | ||||
reject(todo, JGitText.get().transactionAborted); | |||||
Command.abort(todo, null); | |||||
return; | return; | ||||
} | } | ||||
} | } | ||||
c.setResult(OK); | c.setResult(OK); | ||||
} | } | ||||
} else { | } else { | ||||
reject(todo, commit.getResult().name()); | |||||
Command.abort(todo, commit.getResult().name()); | |||||
} | } | ||||
} | } | ||||
u.addCommand(commit); | u.addCommand(commit); | ||||
u.execute(rw, NullProgressMonitor.INSTANCE); | u.execute(rw, NullProgressMonitor.INSTANCE); | ||||
} | } | ||||
private static void reject(List<Command> todo, String msg) { | |||||
for (Command c : todo) { | |||||
if (c.getResult() == NOT_ATTEMPTED) { | |||||
c.setResult(REJECTED_OTHER_REASON, msg); | |||||
msg = JGitText.get().transactionAborted; | |||||
} | |||||
} | |||||
} | |||||
} | } |
* @since 3.6 | * @since 3.6 | ||||
*/ | */ | ||||
protected void failPendingCommands() { | protected void failPendingCommands() { | ||||
for (ReceiveCommand cmd : commands) { | |||||
if (cmd.getResult() == Result.NOT_ATTEMPTED) | |||||
cmd.setResult(Result.REJECTED_OTHER_REASON, JGitText.get().transactionAborted); | |||||
} | |||||
ReceiveCommand.abort(commands); | |||||
} | } | ||||
/** | /** |
package org.eclipse.jgit.transport; | package org.eclipse.jgit.transport; | ||||
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.io.IOException; | ||||
import java.text.MessageFormat; | import java.text.MessageFormat; | ||||
import java.util.ArrayList; | import java.util.ArrayList; | ||||
return filter((Iterable<ReceiveCommand>) commands, want); | return filter((Iterable<ReceiveCommand>) commands, want); | ||||
} | } | ||||
/** | |||||
* Set unprocessed commands as failed due to transaction aborted. | |||||
* <p> | |||||
* If a command is still {@link Result#NOT_ATTEMPTED} it will be set to | |||||
* {@link Result#REJECTED_OTHER_REASON}. | |||||
* | |||||
* @param commands | |||||
* commands to mark as failed. | |||||
* @since 4.2 | |||||
*/ | |||||
public static void abort(Iterable<ReceiveCommand> commands) { | |||||
for (ReceiveCommand c : commands) { | |||||
if (c.getResult() == NOT_ATTEMPTED) { | |||||
c.setResult(REJECTED_OTHER_REASON, | |||||
JGitText.get().transactionAborted); | |||||
} | |||||
} | |||||
} | |||||
private final ObjectId oldId; | private final ObjectId oldId; | ||||
private final ObjectId newId; | private final ObjectId newId; |