From a91489f4a8c12214fcfda14f28326552b5293da5 Mon Sep 17 00:00:00 2001 From: Masaya Suzuki Date: Thu, 7 Nov 2019 18:22:17 -0800 Subject: [PATCH] transport: Add ReceiveCommandErrorHandler 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 --- .../transport/ReceiveCommandErrorHandler.java | 83 +++++++++++++++++++ .../eclipse/jgit/transport/ReceivePack.java | 45 ++++++---- 2 files changed, 111 insertions(+), 17 deletions(-) create mode 100644 org.eclipse.jgit/src/org/eclipse/jgit/transport/ReceiveCommandErrorHandler.java diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/ReceiveCommandErrorHandler.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/ReceiveCommandErrorHandler.java new file mode 100644 index 000000000..d9a148622 --- /dev/null +++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/ReceiveCommandErrorHandler.java @@ -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 cmds, + IOException e) { + for (ReceiveCommand cmd : cmds) { + if (cmd.getResult() == Result.NOT_ATTEMPTED) { + cmd.reject(e); + } + } + } +} diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/ReceivePack.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/ReceivePack.java index 8cafe775a..523dbecd2 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/ReceivePack.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/ReceivePack.java @@ -295,6 +295,10 @@ public Set getCapabilities() { /** 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 List getAllCommands() { 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. *

@@ -1726,16 +1741,16 @@ private void validateCommands() { 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 @@ private void validateCommands() { && 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 @@ private void executeCommands() { 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); } }