This gives a chance to handle an exception for a user. For example, when an IOException is thrown while executing `walk.parseAny(cmd.getNewId())`, it's always handled as REJECTED_MISSING_OBJECT. However, IOException can mean a Git storage IO error. By introducing an error handler class, a user can add a custom error handler for these cases. Change-Id: I3e03a536e1d8e137cb0f6e596d71642e72adde9e Signed-off-by: Masaya Suzuki <masayasuzuki@google.com>tags/v5.7.0.202001151323-m1
@@ -0,0 +1,83 @@ | |||
/* | |||
* Copyright (c) 2019, Google LLC and others | |||
* | |||
* This program and the accompanying materials are made available under the | |||
* terms of the Eclipse Distribution License v. 1.0 which is available at | |||
* http://www.eclipse.org/org/documents/edl-v10.php. | |||
* | |||
* SPDX-License-Identifier: BSD-3-Clause | |||
*/ | |||
package org.eclipse.jgit.transport; | |||
import java.io.IOException; | |||
import java.util.List; | |||
import org.eclipse.jgit.errors.MissingObjectException; | |||
import org.eclipse.jgit.transport.ReceiveCommand.Result; | |||
/** | |||
* Exception handler for processing {@link ReceiveCommand}. | |||
* | |||
* @since 5.7 | |||
*/ | |||
public interface ReceiveCommandErrorHandler { | |||
/** | |||
* Handle an exception thrown while validating the new commit ID. | |||
* | |||
* @param cmd | |||
* offending command | |||
* @param e | |||
* exception thrown | |||
*/ | |||
default void handleNewIdValidationException(ReceiveCommand cmd, | |||
IOException e) { | |||
cmd.setResult(Result.REJECTED_MISSING_OBJECT, cmd.getNewId().name()); | |||
} | |||
/** | |||
* Handle an exception thrown while validating the old commit ID. | |||
* | |||
* @param cmd | |||
* offending command | |||
* @param e | |||
* exception thrown | |||
*/ | |||
default void handleOldIdValidationException(ReceiveCommand cmd, | |||
IOException e) { | |||
cmd.setResult(Result.REJECTED_MISSING_OBJECT, cmd.getOldId().name()); | |||
} | |||
/** | |||
* Handle an exception thrown while checking if the update is fast-forward. | |||
* | |||
* @param cmd | |||
* offending command | |||
* @param e | |||
* exception thrown | |||
*/ | |||
default void handleFastForwardCheckException(ReceiveCommand cmd, | |||
IOException e) { | |||
if (e instanceof MissingObjectException) { | |||
cmd.setResult(Result.REJECTED_MISSING_OBJECT, e.getMessage()); | |||
} else { | |||
cmd.setResult(Result.REJECTED_OTHER_REASON); | |||
} | |||
} | |||
/** | |||
* Handle an exception thrown while checking if the update is fast-forward. | |||
* | |||
* @param cmds | |||
* commands being processed | |||
* @param e | |||
* exception thrown | |||
*/ | |||
default void handleBatchRefUpdateException(List<ReceiveCommand> cmds, | |||
IOException e) { | |||
for (ReceiveCommand cmd : cmds) { | |||
if (cmd.getResult() == Result.NOT_ATTEMPTED) { | |||
cmd.reject(e); | |||
} | |||
} | |||
} | |||
} |
@@ -295,6 +295,10 @@ public class ReceivePack { | |||
/** Hook to validate the update commands before execution. */ | |||
private PreReceiveHook preReceive; | |||
private ReceiveCommandErrorHandler receiveCommandErrorHandler = new ReceiveCommandErrorHandler() { | |||
// Use the default implementation. | |||
}; | |||
/** Hook to report on the commands after execution. */ | |||
private PostReceiveHook postReceive; | |||
@@ -1020,6 +1024,17 @@ public class ReceivePack { | |||
return Collections.unmodifiableList(commands); | |||
} | |||
/** | |||
* Set an error handler for {@link ReceiveCommand}. | |||
* | |||
* @param receiveCommandErrorHandler | |||
* @since 5.7 | |||
*/ | |||
public void setReceiveCommandErrorHandler( | |||
ReceiveCommandErrorHandler receiveCommandErrorHandler) { | |||
this.receiveCommandErrorHandler = receiveCommandErrorHandler; | |||
} | |||
/** | |||
* Send an error message to the client. | |||
* <p> | |||
@@ -1726,16 +1741,16 @@ public class ReceivePack { | |||
try { | |||
oldObj = walk.parseAny(cmd.getOldId()); | |||
} catch (IOException e) { | |||
cmd.setResult(Result.REJECTED_MISSING_OBJECT, | |||
cmd.getOldId().name()); | |||
receiveCommandErrorHandler | |||
.handleOldIdValidationException(cmd, e); | |||
continue; | |||
} | |||
try { | |||
newObj = walk.parseAny(cmd.getNewId()); | |||
} catch (IOException e) { | |||
cmd.setResult(Result.REJECTED_MISSING_OBJECT, | |||
cmd.getNewId().name()); | |||
receiveCommandErrorHandler | |||
.handleNewIdValidationException(cmd, e); | |||
continue; | |||
} | |||
@@ -1743,16 +1758,14 @@ public class ReceivePack { | |||
&& newObj instanceof RevCommit) { | |||
try { | |||
if (walk.isMergedInto((RevCommit) oldObj, | |||
(RevCommit) newObj)) | |||
(RevCommit) newObj)) { | |||
cmd.setTypeFastForwardUpdate(); | |||
else | |||
cmd.setType( | |||
ReceiveCommand.Type.UPDATE_NONFASTFORWARD); | |||
} catch (MissingObjectException e) { | |||
cmd.setResult(Result.REJECTED_MISSING_OBJECT, | |||
e.getMessage()); | |||
} else { | |||
cmd.setType(ReceiveCommand.Type.UPDATE_NONFASTFORWARD); | |||
} | |||
} catch (IOException e) { | |||
cmd.setResult(Result.REJECTED_OTHER_REASON); | |||
receiveCommandErrorHandler | |||
.handleFastForwardCheckException(cmd, e); | |||
} | |||
} else { | |||
cmd.setType(ReceiveCommand.Type.UPDATE_NONFASTFORWARD); | |||
@@ -1831,11 +1844,9 @@ public class ReceivePack { | |||
try { | |||
batch.setPushCertificate(getPushCertificate()); | |||
batch.execute(walk, updating); | |||
} catch (IOException err) { | |||
for (ReceiveCommand cmd : toApply) { | |||
if (cmd.getResult() == Result.NOT_ATTEMPTED) | |||
cmd.reject(err); | |||
} | |||
} catch (IOException e) { | |||
receiveCommandErrorHandler.handleBatchRefUpdateException(toApply, | |||
e); | |||
} | |||
} | |||