All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.github.juliangamble.util.JGitUtils Maven / Gradle / Ivy

The newest version!
package com.github.juliangamble.util;

import org.apache.commons.lang3.StringUtils;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.revwalk.RevObject;
import org.eclipse.jgit.revwalk.RevWalk;
import org.eclipse.jgit.revwalk.filter.CommitTimeRevFilter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.io.IOException;
import java.text.MessageFormat;
import java.util.*;


/**
 * Collection of static methods for retrieving information from a repository.
 *
 * @author James Moger
 *
 */
public class JGitUtils {

    static final Logger LOGGER = LoggerFactory.getLogger(JGitUtils.class);

    /**
     * Returns a list of commits since the minimum date starting from the
     * specified object id.
     *
     * @param repository The Git repository to scan
     * @param objectId
     *            if unspecified, HEAD is assumed.
     * @param minimumDate The date to scan back through the git log
     * @return list of commits
     */
    public static List getRevLog(Repository repository, String objectId, Date minimumDate) {
        List list = new ArrayList();
        if (!hasCommits(repository)) {
            return list;
        }
        try {
            // resolve branch
            ObjectId branchObject;
            if (StringUtils.isEmpty(objectId)) {
                branchObject = getDefaultBranch(repository);
            } else {
                branchObject = repository.resolve(objectId);
            }

            RevWalk rw = new RevWalk(repository);
            rw.markStart(rw.parseCommit(branchObject));
            rw.setRevFilter(CommitTimeRevFilter.after(minimumDate));
            Iterable revlog = rw;
            for (RevCommit rev : revlog) {
                list.add(rev);
            }
            rw.dispose();
        } catch (Throwable t) {
            error(t, repository, "{0} failed to get {1} revlog for minimum date {2}", objectId,
                    minimumDate);
        }
        return list;
    }

    /**
     * Determine if a repository has any commits. This is determined by checking
     * the for loose and packed objects.
     *
     * @param repository The Git repository to scan
     * @return true if the repository has commits
     */
    public static boolean hasCommits(Repository repository) {
        if (repository != null && repository.getDirectory().exists()) {
            return (new File(repository.getDirectory(), "objects").list().length > 2)
                    || (new File(repository.getDirectory(), "objects/pack").list().length > 0);
        }
        return false;
    }

    /**
     * Returns the default branch to use for a repository. Normally returns
     * whatever branch HEAD points to, but if HEAD points to nothing it returns
     * the most recently updated branch.
     *
     * @param repository The Git repository to scan
     * @return the objectid of a branch
     * @throws Exception If there is a file issue
     */
    public static ObjectId getDefaultBranch(Repository repository) throws Exception {
        ObjectId object = repository.resolve(Constants.HEAD);
        if (object == null) {
            // no HEAD
            // perhaps non-standard repository, try local branches
            List branchModels = getLocalBranches(repository, true, -1);
            if (branchModels.size() > 0) {
                // use most recently updated branch
                RefModel branch = null;
                Date lastDate = new Date(0);
                for (RefModel branchModel : branchModels) {
                    if (branchModel.getDate().after(lastDate)) {
                        branch = branchModel;
                        lastDate = branch.getDate();
                    }
                }
                object = branch.getReferencedObjectId();
            }
        }
        return object;
    }

    /**
     * Returns the list of local branches in the repository. If repository does
     * not exist or is empty, an empty list is returned.
     *
     * @param repository The Git repository to scan
     * @param fullName
     *            if true, /refs/heads/yadayadayada is returned. If false,
     *            yadayadayada is returned.
     * @param maxCount
     *            if < 0, all local branches are returned
     * @return list of local branches
     */
    public static List getLocalBranches(Repository repository, boolean fullName,
                                                  int maxCount) {
        return getRefs(repository, Constants.R_HEADS, fullName, maxCount);
    }

    /**
     * Retrieves a Java Date from a Git commit.
     *
     * @param commit The commit to examine
     * @return date of the commit or Date(0) if the commit is null
     */
    public static Date getAuthorDate(RevCommit commit) {
        if (commit == null) {
            return new Date(0);
        }
        return commit.getAuthorIdent().getWhen();
    }

    /**
     * Returns a list of references in the repository matching "refs". If the
     * repository is null or empty, an empty list is returned.
     *
     * @param repository The Git repository to scan
     * @param refs
     *            if unspecified, all refs are returned
     * @param fullName
     *            if true, /refs/something/yadayadayada is returned. If false,
     *            yadayadayada is returned.
     * @param maxCount
     *            if < 0, all references are returned
     * @return list of references
     */
    private static List getRefs(Repository repository, String refs, boolean fullName,
                                          int maxCount) {
        List list = new ArrayList();
        if (maxCount == 0) {
            return list;
        }
        if (!hasCommits(repository)) {
            return list;
        }
        try {
            Map map = repository.getRefDatabase().getRefs(refs);
            RevWalk rw = new RevWalk(repository);
            for (Map.Entry entry : map.entrySet()) {
                Ref ref = entry.getValue();
                RevObject object = rw.parseAny(ref.getObjectId());
                String name = entry.getKey();
                if (fullName && !StringUtils.isEmpty(refs)) {
                    name = refs + name;
                }
                list.add(new RefModel(name, ref, object));
            }
            rw.dispose();
            Collections.sort(list);
            Collections.reverse(list);
            if (maxCount > 0 && list.size() > maxCount) {
                list = new ArrayList(list.subList(0, maxCount));
            }
        } catch (IOException e) {
            error(e, repository, "{0} failed to retrieve {1}", refs);
        }
        return list;
    }

    /**
     * Log an error message and exception.
     *
     * @param t The error reference
     * @param repository
     *            if repository is not null it MUST be the {0} parameter in the
     *            pattern.
     * @param pattern
     * @param objects
     */
    private static void error(Throwable t, Repository repository, String pattern, Object... objects) {
        List parameters = new ArrayList();
        if (objects != null && objects.length > 0) {
            for (Object o : objects) {
                parameters.add(o);
            }
        }
        if (repository != null) {
            parameters.add(0, repository.getDirectory().getAbsolutePath());
        }
        LOGGER.error(MessageFormat.format(pattern, parameters.toArray()), t);
    }

}