nz.co.fortytwo.signalk.handler.GitHandler.java Source code

Java tutorial

Introduction

Here is the source code for nz.co.fortytwo.signalk.handler.GitHandler.java

Source

/*
 * 
 * Copyright (C) 2012-2014 R T Huitema. All Rights Reserved.
 * Web: www.42.co.nz
 * Email: robert@42.co.nz
 * Author: R T Huitema
 * 
 * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
 * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 * http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package nz.co.fortytwo.signalk.handler;

import static nz.co.fortytwo.signalk.util.ConfigConstants.STATIC_DIR;

import java.io.File;
import java.io.IOException;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import nz.co.fortytwo.signalk.util.SignalKConstants;
import nz.co.fortytwo.signalk.util.Util;

import org.apache.commons.io.FileUtils;
import org.apache.log4j.Logger;
import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.storage.file.FileRepositoryBuilder;
import org.eclipse.jgit.transport.FetchResult;

/*
 * Processes REST requests for Signal K installs from Github
 * 
 * 
 * @author robert
 */
public class GitHandler {

    private static final String SLASH = "/";
    private static Logger logger = Logger.getLogger(GitHandler.class);
    private File staticDir = null;

    private static String github = "https://github.com/SignalK/";

    public GitHandler() {
        super();
        staticDir = new File(Util.getConfigProperty(STATIC_DIR));
    }

    /**
     * Process a signalk install
     * 
     * @param request
     * @param response
     * @param signalkModel
     * @return
     * @throws IOException
     */
    public Object processInstall(HttpServletRequest request, HttpServletResponse response) throws IOException {
        // use Restlet API to create the response
        String path = request.getPathInfo();
        // String path = exchange.getIn().getHeader(Exchange.HTTP_URI, String.class);
        if (logger.isDebugEnabled())
            logger.debug("We are processing the path = " + path);

        // check valid request.
        if (path.length() < SignalKConstants.SIGNALK_INSTALL.length()
                || !path.startsWith(SignalKConstants.SIGNALK_INSTALL)) {
            response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
            return null;
        }
        path = path.substring(SignalKConstants.SIGNALK_INSTALL.length());
        if (path.startsWith(SLASH))
            path = path.substring(1);
        if (logger.isDebugEnabled())
            logger.debug("We are processing the extension:" + path);
        // now we should have a valid github project name
        try {
            String fileName = install(path);
            response.setStatus(HttpServletResponse.SC_OK);
            response.sendRedirect("/logs.html");
            return fileName;
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
            response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
            return e.getMessage();
        }

    }

    /**
     * Process a signalk install
     * 
     * @param request
     * @param response
     * @param signalkModel
     * @return
     * @throws IOException
     */
    public Object processUpgrade(HttpServletRequest request, HttpServletResponse response) throws IOException {
        // use Restlet API to create the response
        String path = request.getPathInfo();
        // String path = exchange.getIn().getHeader(Exchange.HTTP_URI, String.class);
        if (logger.isDebugEnabled())
            logger.debug("We are processing the path = " + path);

        // check valid request.
        if (path.length() < SignalKConstants.SIGNALK_UPGRADE.length()
                || !path.startsWith(SignalKConstants.SIGNALK_UPGRADE)) {
            response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
            return null;
        }
        path = path.substring(SignalKConstants.SIGNALK_UPGRADE.length());
        if (path.startsWith(SLASH))
            path = path.substring(1);
        if (logger.isDebugEnabled())
            logger.debug("We are processing the extension:" + path);
        // now we should have a valid github project name
        try {
            String fileName = upgrade(path);
            response.setStatus(HttpServletResponse.SC_OK);
            response.sendRedirect("/logs.html");
            return fileName;
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
            response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
            return e.getMessage();
        }

    }

    protected String install(String path) throws Exception {
        //staticDir.mkdirs();
        Git result = null;
        try {
            File installLogDir = new File(staticDir, "logs");
            installLogDir.mkdirs();
            //make log name
            String logFile = "output.log";
            File output = new File(installLogDir, logFile);
            File destDir = new File(staticDir, SLASH + path);
            destDir.mkdirs();
            String gitPath = github + path + ".git";
            logger.debug("Cloning from " + gitPath + " to " + destDir.getAbsolutePath());
            FileUtils.writeStringToFile(output,
                    "Updating from " + gitPath + " to " + destDir.getAbsolutePath() + "\n", false);
            try {
                result = Git.cloneRepository().setURI(gitPath).setDirectory(destDir).call();
                result.fetch().setRemote(gitPath);
                logger.debug("Cloned " + gitPath + " repository: " + result.getRepository().getDirectory());
                FileUtils.writeStringToFile(output,
                        "Cloned " + gitPath + " repository: " + result.getRepository().getDirectory(), true);
            } catch (Exception e) {
                FileUtils.writeStringToFile(output, e.getMessage(), true);
                FileUtils.writeStringToFile(output, e.getStackTrace().toString(), true);
                logger.debug("Error updating " + gitPath + " repository: " + e.getMessage(), e);
            }
            try {
                //now run npm install
                runNpmInstall(output, destDir);
            } catch (Exception e) {
                FileUtils.writeStringToFile(output, e.getMessage(), true);
                FileUtils.writeStringToFile(output, e.getStackTrace().toString(), true);
                logger.debug("Error updating " + gitPath + " repository: " + e.getMessage(), e);
            }
            return logFile;

        } finally {
            if (result != null)
                result.close();
        }

    }

    private void runNpmInstall(final File output, File destDir) throws Exception {
        FileUtils.writeStringToFile(output, "\nBeginning npm install", true);
        ProcessBuilder pb = new ProcessBuilder("npm", "install");
        Map<String, String> env = System.getenv();
        if (env.containsKey("PATH")) {
            pb.environment().put("PATH", env.get("PATH"));
        }
        if (env.containsKey("Path")) {
            pb.environment().put("Path", env.get("Path"));
        }
        if (env.containsKey("path")) {
            pb.environment().put("path", env.get("path"));
        }
        pb.directory(destDir);
        pb.redirectErrorStream(true);
        pb.redirectOutput(output);
        final Process p = pb.start();
        Thread t = new Thread() {

            @Override
            public void run() {
                try {
                    p.waitFor();
                    FileUtils.writeStringToFile(output, "\nDONE: Npm ended sucessfully", true);
                } catch (Exception e) {
                    try {
                        logger.error(e);
                        FileUtils.writeStringToFile(output, "\nNpm ended badly:" + e.getMessage(), true);
                        FileUtils.writeStringToFile(output, "\n" + e.getStackTrace(), true);
                    } catch (IOException e1) {
                        logger.error(e1);
                    }
                }
            }

        };
        t.start();
    }

    protected String upgrade(String path) throws Exception {
        //staticDir.mkdirs();
        Repository repository = null;
        try {
            String logFile = "output.log";
            File installLogDir = new File(staticDir, "logs");
            installLogDir.mkdirs();
            //
            File destDir = new File(staticDir, SLASH + path);
            destDir.mkdirs();
            File output = new File(installLogDir, logFile);
            String gitPath = github + path + ".git";
            logger.debug("Cloning from " + gitPath + " to " + destDir.getAbsolutePath());
            FileUtils.writeStringToFile(output,
                    "Updating from " + gitPath + " to " + destDir.getAbsolutePath() + "\n", false);
            try {
                FileRepositoryBuilder builder = new FileRepositoryBuilder();
                repository = builder.setGitDir(destDir).readEnvironment() // scan environment GIT_* variables
                        .findGitDir() // scan up the file system tree
                        .build();

                FetchResult result = new Git(repository).fetch().setRemote(gitPath).setCheckFetchedObjects(true)
                        .call();
                FileUtils.writeStringToFile(output, result.getMessages(), true);
                logger.debug("Updated " + gitPath + " repository: " + result.getMessages());

                //now run npm install
                runNpmInstall(output, destDir);
            } catch (Exception e) {
                FileUtils.writeStringToFile(output, e.getMessage(), true);
                FileUtils.writeStringToFile(output, e.getStackTrace().toString(), true);
                logger.debug("Error updating " + gitPath + " repository: " + e.getMessage(), e);
            }
            return logFile;

        } finally {
            if (repository != null)
                repository.close();
        }

    }

}