1 /* 2 * Copyright (C) 2015 Obeo. 3 * and other copyright owners as documented in the project's IP log. 4 * 5 * This program and the accompanying materials are made available 6 * under the terms of the Eclipse Distribution License v1.0 which 7 * accompanies this distribution, is reproduced below, and is 8 * available at http://www.eclipse.org/org/documents/edl-v10.php 9 * 10 * All rights reserved. 11 * 12 * Redistribution and use in source and binary forms, with or 13 * without modification, are permitted provided that the following 14 * conditions are met: 15 * 16 * - Redistributions of source code must retain the above copyright 17 * notice, this list of conditions and the following disclaimer. 18 * 19 * - Redistributions in binary form must reproduce the above 20 * copyright notice, this list of conditions and the following 21 * disclaimer in the documentation and/or other materials provided 22 * with the distribution. 23 * 24 * - Neither the name of the Eclipse Foundation, Inc. nor the 25 * names of its contributors may be used to endorse or promote 26 * products derived from this software without specific prior 27 * written permission. 28 * 29 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 30 * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, 31 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 32 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 33 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 34 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 35 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 36 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 37 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 38 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 39 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 40 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 41 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 42 */ 43 package org.eclipse.jgit.hooks; 44 45 import java.io.ByteArrayOutputStream; 46 import java.io.IOException; 47 import java.io.PrintStream; 48 import java.util.concurrent.Callable; 49 50 import org.eclipse.jgit.api.errors.AbortedByHookException; 51 import org.eclipse.jgit.lib.Repository; 52 import org.eclipse.jgit.util.FS; 53 import org.eclipse.jgit.util.ProcessResult; 54 55 /** 56 * Git can fire off custom scripts when certain important actions occur. These 57 * custom scripts are called "hooks". There are two groups of hooks: client-side 58 * (that run on local operations such as committing and merging), and 59 * server-side (that run on network operations such as receiving pushed 60 * commits). This is the abstract super-class of the different hook 61 * implementations in JGit. 62 * 63 * @param <T> 64 * the return type which is expected from {@link #call()} 65 * @see <a href="http://git-scm.com/book/en/v2/Customizing-Git-Git-Hooks">Git 66 * Hooks on the git-scm official site</a> 67 * @since 4.0 68 */ 69 abstract class GitHook<T> implements Callable<T> { 70 71 private final Repository repo; 72 73 /** 74 * The output stream to be used by the hook. 75 */ 76 protected final PrintStream outputStream; 77 78 /** 79 * @param repo 80 * @param outputStream 81 * The output stream the hook must use. {@code null} is allowed, 82 * in which case the hook will use {@code System.out}. 83 */ 84 protected GitHook(Repository repo, PrintStream outputStream) { 85 this.repo = repo; 86 this.outputStream = outputStream; 87 } 88 89 /** 90 * Run the hook. 91 * 92 * @throws IOException 93 * if IO goes wrong. 94 * @throws AbortedByHookException 95 * If the hook has been run and a returned an exit code 96 * different from zero. 97 */ 98 public abstract T call() throws IOException, AbortedByHookException; 99 100 /** 101 * @return The name of the hook, which must not be {@code null}. 102 */ 103 public abstract String getHookName(); 104 105 /** 106 * @return The repository. 107 */ 108 protected Repository getRepository() { 109 return repo; 110 } 111 112 /** 113 * Override this method when needed to provide relevant parameters to the 114 * underlying hook script. The default implementation returns an empty 115 * array. 116 * 117 * @return The parameters the hook receives. 118 */ 119 protected String[] getParameters() { 120 return new String[0]; 121 } 122 123 /** 124 * Override to provide relevant arguments via stdin to the underlying hook 125 * script. The default implementation returns {@code null}. 126 * 127 * @return The parameters the hook receives. 128 */ 129 protected String getStdinArgs() { 130 return null; 131 } 132 133 /** 134 * @return The output stream the hook must use. Never {@code null}, 135 * {@code System.out} is returned by default. 136 */ 137 protected PrintStream getOutputStream() { 138 return outputStream == null ? System.out : outputStream; 139 } 140 141 /** 142 * Runs the hook, without performing any validity checks. 143 * 144 * @throws AbortedByHookException 145 * If the underlying hook script exited with non-zero. 146 */ 147 protected void doRun() throws AbortedByHookException { 148 final ByteArrayOutputStream errorByteArray = new ByteArrayOutputStream(); 149 final PrintStream hookErrRedirect = new PrintStream(errorByteArray); 150 ProcessResult result = FS.DETECTED.runHookIfPresent(getRepository(), 151 getHookName(), getParameters(), getOutputStream(), 152 hookErrRedirect, getStdinArgs()); 153 if (result.isExecutedWithError()) { 154 throw new AbortedByHookException(errorByteArray.toString(), 155 getHookName(), result.getExitCode()); 156 } 157 } 158 159 }