org.codice.git.hook.GitHooks.java Source code

Java tutorial

Introduction

Here is the source code for org.codice.git.hook.GitHooks.java

Source

/**
 * Copyright (c) Codice Foundation
 * <p/>
 * This is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser
 * General Public License as published by the Free Software Foundation, either version 3 of the
 * License, or any later version.
 * <p/>
 * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
 * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details. A copy of the GNU Lesser General Public License
 * is distributed along with this program and can be found at
 * <http://www.gnu.org/licenses/lgpl.html>.
 */
package org.codice.git.hook;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;

import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.text.StrSubstitutor;
import org.codice.git.RepositoryHandler;

import com.google.common.base.Charsets;

/**
 * Handles the installation and updating of the git hooks in a current repository.
 */
public class GitHooks {
    public static final String[] HOOKS = new String[] { "applypatch-msg", "commit-msg", "pre-applypatch",
            "pre-commit" };

    public static final String HOOK_DIR = "hooks";

    public static final String HOOK_BASE_DIR = "/" + HOOK_DIR + "/";

    private static final Logger LOGGER = Logger.getLogger(GitHooks.class.getName());

    public static void install(RepositoryHandler handler, String settings) throws IOException {
        if (handler == null) {
            LOGGER.warning("No Repository handler specified; git hooks not installed");
            return;
        }
        final File hdir = new File(handler.getMetadir(), HOOK_DIR);
        final Map<String, String> vars = new HashMap<String, String>(8);
        final StrSubstitutor substitutor = new StrSubstitutor(vars, "@{", "}", '@');
        boolean filesCopiedOK = true;

        // because the paths are being expanded in the bash scripts for the hooks, we will be safe
        // on Windows as long as we replace all \ for / since some of those paths will be concatenated
        // with others inside the scripts
        vars.put("BASEDIR", handler.getBasedir().getAbsolutePath().replace('\\', '/'));
        vars.put("POMPATH", new File(handler.getBasedir(), "pom.xml").getAbsolutePath().replace('\\', '/'));
        vars.put("SETTINGS", settings.replace('\\', '/'));
        LOGGER.log(Level.INFO, "Installing hooks into directory: {0}", hdir);
        System.out.println("[INFO] Installing git hooks.");
        for (String hookName : HOOKS) {
            filesCopiedOK = filesCopiedOK
                    && copyFromJar(HOOK_BASE_DIR + hookName, new File(hdir, hookName), substitutor, true);
        }
        LOGGER.log(Level.INFO, "Hook files copied successfully: {0}", filesCopiedOK);
    }

    public static void clean(RepositoryHandler handler) throws IOException {
        if (handler == null) {
            LOGGER.warning("No Repository handler specified; git hooks not cleaned.");
            return;
        }
        final File bdir = handler.getBasedir();
        final File hdir = new File(handler.getMetadir(), HOOK_DIR);
        final File cpath = new File(bdir, "classpath.txt");

        LOGGER.log(Level.INFO, "Cleaning cached classpath from directory: {0}", bdir);
        System.out.println("[INFO] Removing git hooks cached classpath.");
        boolean filesDeletedOK = !cpath.exists() || cpath.delete();

        LOGGER.log(Level.INFO, "Cleaning hooks from directory: {0}", hdir);
        System.out.println("[INFO] Removing git hooks.");
        for (String hookName : HOOKS) {
            final File hfile = new File(hdir, hookName);

            filesDeletedOK = filesDeletedOK && (!hfile.exists() || hfile.delete());
        }
        LOGGER.log(Level.INFO, "Hook files deleted successfully: {0}", filesDeletedOK);
    }

    /**
     * Downloads the blacklist either dynamically (if already done in the past) or by prompting for
     * the maven artifact info (if at install time).
     *
     * @param handler  the repository handler
     * @param settings the maven settings file or "" if using the default one
     * @param install  <code>true</code> if we are at install time; <code>false</code> if this is from a hook
     * @throws IOException if an error occurs
     */
    public static void downloadBlacklist(RepositoryHandler handler, String settings, boolean install)
            throws IOException {
        // use stderr instead of stdout to allow the stdout to be piped without impacting the querying
        new Artifact(handler, "blacklist words", handler.getBlacklistFile(),
                new File(handler.getBasedir(), "blacklist-words.mvn"), install).download(settings,
                        install ? System.err : System.out);
    }

    /**
     * Copied/expanded from org.apache.commons.io.IOUtils
     * Takes the name of an input file and the name of an output file and copies the input file to the
     * output file.
     *
     * @param fromName       the name of the input file to read from
     * @param output         the name of the output file to write to
     * @param substitutor    the optional string substitutor to use when processing files (can be <code>null</code>)
     * @param makeExecutable boolean indicating whether the output file should be made executable when done copying
     * @return true indicates the file was successfully copied, false if an error occurs
     * @throws java.lang.NullPointerException if the inputu or output is null
     * @throws IOException                    if an I/O error occurs
     * @throws java.lang.ArithmeticException  if the byte count is too large
     */
    private static boolean copyFromJar(String fromName, File output, StrSubstitutor substitutor,
            boolean makeExecutable) throws IOException {
        boolean successful = true;
        InputStream is = null;

        try {
            LOGGER.log(Level.FINE, "Copying file {0} to {1}", new Object[] { fromName, output });
            is = GitHooks.class.getResourceAsStream(fromName);
            if (is == null) {
                LOGGER.log(Level.WARNING, "Unable to locate file {0} for copying.", fromName);
                throw new IOException("Unable to locate file " + fromName + " for copying");
            }
            final PrintWriter pw = new PrintWriter(new FileWriter(output));

            for (final String line : IOUtils.readLines(is, Charsets.UTF_8)) {
                if (substitutor != null) {
                    pw.println(substitutor.replace(line));
                } else {
                    pw.println(line);
                }
            }
            pw.close();
            if (makeExecutable) {
                output.setExecutable(true);
            }
        } catch (IOException e) {
            LOGGER.log(Level.WARNING, "Exception copying to file " + output + " - file may be incompletely copied.",
                    e);
            successful = false;
        } finally {
            IOUtils.closeQuietly(is);
        }
        return successful;
    }
}