io.fabric8.project.support.GitUtils.java Source code

Java tutorial

Introduction

Here is the source code for io.fabric8.project.support.GitUtils.java

Source

/**
 * Copyright 2005-2015 Red Hat, Inc.
 * <p>
 * Red Hat licenses this file to you 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
 * <p>
 * http://www.apache.org/licenses/LICENSE-2.0
 * <p>
 * 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 io.fabric8.project.support;

import com.jcraft.jsch.JSch;
import com.jcraft.jsch.JSchException;
import com.jcraft.jsch.Session;
import com.jcraft.jsch.UserInfo;
import io.fabric8.utils.Files;
import io.fabric8.utils.IOHelpers;
import io.fabric8.utils.Strings;
import io.fabric8.utils.ssl.TrustEverythingSSLTrustManager;
import org.eclipse.jgit.api.CommitCommand;
import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.api.GitCommand;
import org.eclipse.jgit.api.PushCommand;
import org.eclipse.jgit.api.TransportCommand;
import org.eclipse.jgit.api.TransportConfigCallback;
import org.eclipse.jgit.api.errors.GitAPIException;
import org.eclipse.jgit.lib.PersonIdent;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.lib.StoredConfig;
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.storage.file.FileRepositoryBuilder;
import org.eclipse.jgit.transport.CredentialsProvider;
import org.eclipse.jgit.transport.CredentialsProviderUserInfo;
import org.eclipse.jgit.transport.JschConfigSessionFactory;
import org.eclipse.jgit.transport.OpenSshConfig;
import org.eclipse.jgit.transport.PushResult;
import org.eclipse.jgit.transport.RemoteRefUpdate;
import org.eclipse.jgit.transport.SshSessionFactory;
import org.eclipse.jgit.transport.SshTransport;
import org.eclipse.jgit.transport.Transport;
import org.eclipse.jgit.util.FS;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.TrustManager;
import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;

/**
 */
public class GitUtils {
    private static final transient Logger LOG = LoggerFactory.getLogger(GitUtils.class);

    public static File getRootGitDirectory(Git git) {
        return git.getRepository().getDirectory().getParentFile();
    }

    public static String toString(Collection<RemoteRefUpdate> updates) {
        StringBuilder builder = new StringBuilder();
        for (RemoteRefUpdate update : updates) {
            if (builder.length() > 0) {
                builder.append(" ");
            }
            builder.append(update.getMessage() + " " + update.getRemoteName() + " " + update.getNewObjectId());
        }
        return builder.toString();
    }

    public static void disableSslCertificateChecks() {
        LOG.info("Trusting all SSL certificates");

        try {
            SSLContext context = SSLContext.getInstance("TLS");
            context.init(null, new TrustManager[] { new TrustEverythingSSLTrustManager() },
                    new java.security.SecureRandom());
            HttpsURLConnection.setDefaultSSLSocketFactory(context.getSocketFactory());
            // bypass host name check, too.
            HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() {
                public boolean verify(String s, SSLSession sslSession) {
                    return true;
                }
            });
        } catch (NoSuchAlgorithmException e) {
            LOG.warn("Failed to bypass certificate check", e);
        } catch (KeyManagementException e) {
            LOG.warn("Failed to bypass certificate check", e);
        }
    }

    /**
     * Returns the remote git URL for the given branch
     */
    public static String getRemoteURL(Git git, String branch) {
        Repository repository = git.getRepository();
        return getRemoteURL(repository, branch);
    }

    /**
     * Returns the remote repository for the current branch in the given repository
     */
    public static String getRemoteURL(Repository repository) throws IOException {
        if (repository != null) {
            return getRemoteURL(repository, "origin");
        }
        return null;
    }

    public static String getRemoteURL(Repository repository, String remoteName) {
        if (repository != null) {
            StoredConfig config = repository.getConfig();
            if (config != null) {
                return config.getString("remote", remoteName, "url");
            }
        }
        return null;
    }

    public static void configureBranch(Git git, String branch, String origin, String remoteRepository) {
        // lets update the merge config
        if (!Strings.isNullOrBlank(branch)) {
            StoredConfig config = git.getRepository().getConfig();
            config.setString("branch", branch, "remote", origin);
            config.setString("branch", branch, "merge", "refs/heads/" + branch);

            config.setString("remote", origin, "url", remoteRepository);
            config.setString("remote", origin, "fetch", "+refs/heads/*:refs/remotes/" + origin + "/*");
            try {
                config.save();
            } catch (IOException e) {
                LOG.error("Failed to save the git configuration to " + git.getRepository().getDirectory()
                        + " with branch " + branch + " on " + origin + " remote repo: " + remoteRepository
                        + " due: " + e.getMessage() + ". This exception is ignored.", e);
            }
        }
    }

    public static void addFiles(Git git, File... files) throws GitAPIException, IOException {
        File rootDir = getRootGitDirectory(git);
        for (File file : files) {
            String relativePath = getFilePattern(rootDir, file);
            git.add().addFilepattern(relativePath).call();
        }
    }

    public static String getFilePattern(File rootDir, File file) throws IOException {
        String relativePath = Files.getRelativePath(rootDir, file);
        if (relativePath.startsWith(File.separator)) {
            relativePath = relativePath.substring(1);
        }
        return relativePath.replace(File.separatorChar, '/');
    }

    public static RevCommit doCommitAndPush(Git git, String message, UserDetails userDetails, PersonIdent author,
            String branch, String origin, boolean pushOnCommit) throws GitAPIException {
        CommitCommand commit = git.commit().setAll(true).setMessage(message);
        if (author != null) {
            commit = commit.setAuthor(author);
        }

        RevCommit answer = commit.call();
        if (LOG.isDebugEnabled()) {
            LOG.debug("Committed " + answer.getId() + " " + answer.getFullMessage());
        }

        if (pushOnCommit) {
            PushCommand push = git.push();
            configureCommand(push, userDetails);
            Iterable<PushResult> results = push.setRemote(origin).call();
            for (PushResult result : results) {
                if (LOG.isDebugEnabled()) {
                    LOG.debug("Pushed " + result.getMessages() + " " + result.getURI() + " branch: " + branch
                            + " updates: " + toString(result.getRemoteUpdates()));
                }
            }
        }
        return answer;
    }

    public static void doAddCommitAndPushFiles(Git git, UserDetails userDetails, PersonIdent personIdent,
            String branch, String origin, String message, boolean pushOnCommit) throws GitAPIException {
        git.add().addFilepattern(".").call();
        doCommitAndPush(git, message, userDetails, personIdent, branch, origin, pushOnCommit);
    }

    /**
     * Retrieves a Java Date from a Git commit.
     *
     * @param commit the commit
     * @return date of the commit or Date(0) if the commit is null
     */
    public static Date getCommitDate(RevCommit commit) {
        if (commit == null) {
            return new Date(0);
        }
        return new Date(commit.getCommitTime() * 1000L);
    }

    /**
     * Configures the transport of the command to deal with things like SSH
     */
    public static <C extends GitCommand> void configureCommand(TransportCommand<C, ?> command,
            UserDetails userDetails) {
        configureCommand(command, userDetails.createCredentialsProvider(), userDetails.getSshPrivateKey(),
                userDetails.getSshPublicKey());
        command.setCredentialsProvider(userDetails.createCredentialsProvider());
    }

    /**
     * Configures the transport of the command to deal with things like SSH
     */
    public static <C extends GitCommand> void configureCommand(TransportCommand<C, ?> command,
            CredentialsProvider credentialsProvider, final File sshPrivateKey, final File sshPublicKey) {
        LOG.info("Using " + credentialsProvider);
        if (sshPrivateKey != null) {
            final CredentialsProvider provider = credentialsProvider;
            command.setTransportConfigCallback(new TransportConfigCallback() {
                @Override
                public void configure(Transport transport) {
                    if (transport instanceof SshTransport) {
                        SshTransport sshTransport = (SshTransport) transport;
                        SshSessionFactory sshSessionFactory = new JschConfigSessionFactory() {
                            @Override
                            protected void configure(OpenSshConfig.Host host, Session session) {
                                session.setConfig("StrictHostKeyChecking", "no");
                                UserInfo userInfo = new CredentialsProviderUserInfo(session, provider);
                                session.setUserInfo(userInfo);
                            }

                            @Override
                            protected JSch createDefaultJSch(FS fs) throws JSchException {
                                JSch jsch = super.createDefaultJSch(fs);
                                jsch.removeAllIdentity();
                                String absolutePath = sshPrivateKey.getAbsolutePath();
                                if (LOG.isDebugEnabled()) {
                                    LOG.debug("Adding identity privateKey: " + sshPrivateKey + " publicKey: "
                                            + sshPublicKey);
                                }
                                if (sshPublicKey != null) {
                                    jsch.addIdentity(absolutePath, sshPublicKey.getAbsolutePath(), null);
                                } else {
                                    jsch.addIdentity(absolutePath);
                                }
                                return jsch;
                            }
                        };
                        sshTransport.setSshSessionFactory(sshSessionFactory);
                    }
                }
            });
        }
    }

    /**
     * Git tends to ignore empty directories so lets add a dummy file to empty folders to keep them in git
     */
    public static void addDummyFileToEmptyFolders(File dir) {
        if (dir != null && dir.isDirectory()) {
            File[] children = dir.listFiles();
            if (children == null || children.length == 0) {
                File dummyFile = new File(dir, ".gitkeep");
                try {
                    IOHelpers.writeFully(dummyFile,
                            "This file is only here to avoid git removing empty folders\nOnce there are files in this folder feel free to delete this file!");
                } catch (IOException e) {
                    LOG.warn("Failed to write file " + dummyFile + ". " + e, e);
                }
            } else {
                for (File child : children) {
                    if (child.isDirectory()) {
                        addDummyFileToEmptyFolders(child);
                    }
                }
            }
        }
    }

    /**
     * Returns the git repository for the current folder or null if none can be found
     */
    public static Repository findRepository(File baseDir) throws IOException {
        File gitFolder = io.fabric8.utils.GitHelpers.findGitFolder(baseDir);
        if (gitFolder == null) {
            // No git repository found
            return null;
        }
        FileRepositoryBuilder builder = new FileRepositoryBuilder();
        Repository repository = builder.readEnvironment().setGitDir(gitFolder).build();
        return repository;
    }

    /**
     * Returns the ~/.gitconfig file parsed
     */
    public static Map<String, Properties> parseGitConfig() throws IOException {
        String homeDir = System.getProperty("user.home", ".");
        File file = new File(homeDir, ".gitconfig");
        if (file.exists() && file.isFile()) {
            return IniFileUtils.parseIniFile(file);
        } else {
            return new HashMap<>();
        }
    }

    public static String getGitHostName(String gitUrl) {
        try {
            URI uri = new URI(gitUrl);
            return uri.getHost();
        } catch (URISyntaxException e) {
            // ignore
        }
        String[] split = gitUrl.split(":");
        if (split.length > 1) {
            String prefix = split[0];
            int idx = prefix.indexOf('@');
            if (idx >= 0) {
                return prefix.substring(idx + 1);
            } else {
                return prefix;
            }
        }
        return null;
    }

    public static String getGitProtocol(String gitUrl) {
        try {
            URI uri = new URI(gitUrl);
            return uri.getScheme();
        } catch (URISyntaxException e) {
            // ignore
        }
        String[] split = gitUrl.split(":");
        if (split.length > 1) {
            String prefix = split[0];
            int idx = prefix.indexOf('@');
            if (idx >= 0) {
                return "ssh";
            }
        }
        return null;
    }
}