org.obiba.git.command.DiffCommand.java Source code

Java tutorial

Introduction

Here is the source code for org.obiba.git.command.DiffCommand.java

Source

/*
 * Copyright (c) 2013 OBiBa. All rights reserved.
 *
 * This program and the accompanying materials
 * are made available under the terms of the GNU Public License v3.0.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package org.obiba.git.command;

import java.io.File;
import java.io.IOException;

import javax.annotation.Nullable;
import javax.validation.constraints.NotNull;

import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.diff.DiffEntry;
import org.eclipse.jgit.diff.DiffFormatter;
import org.eclipse.jgit.diff.RawTextComparator;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.ObjectReader;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.revwalk.RevWalk;
import org.eclipse.jgit.treewalk.AbstractTreeIterator;
import org.eclipse.jgit.treewalk.CanonicalTreeParser;
import org.eclipse.jgit.treewalk.EmptyTreeIterator;
import org.eclipse.jgit.treewalk.filter.PathFilter;
import org.obiba.git.GitException;

import com.google.common.base.Strings;

/**
 * Opal GIT command used to extract the diff between two commits. By default, the diff is between the given commit and
 * its parent. By providing a valid 'nthCommit' value, the command will extract the appropriate diff from the repo.
 */
public class DiffCommand extends AbstractGitCommand<Iterable<DiffEntry>> {

    private String path;

    private final String commitId;

    private String previousCommitId;

    private int nthCommit = 1;

    protected DiffCommand(@NotNull File repositoryPath, @Nullable File workPath, String commitId) {
        super(repositoryPath, workPath);
        this.commitId = commitId;
    }

    @Override
    public Iterable<DiffEntry> execute(Git git) {

        Repository repository = git.getRepository();
        ObjectReader reader = repository.newObjectReader();
        try {
            DiffCurrentPreviousTreeParsersFactory parsersFactory = new DiffCurrentPreviousTreeParsersFactory(
                    repository, reader);
            return compareDiffTrees(repository, parsersFactory);
        } catch (IOException e) {
            throw new GitException(e);
        } finally {
            reader.release();
        }
    }

    private Iterable<DiffEntry> compareDiffTrees(Repository repository,
            DiffCurrentPreviousTreeParsersFactory parsersFactory) throws IOException {

        DiffFormatter diffFormatter = new DiffFormatter(null);
        diffFormatter.setRepository(repository);
        diffFormatter.setDiffComparator(RawTextComparator.DEFAULT);
        diffFormatter.setDetectRenames(true);
        if (!Strings.isNullOrEmpty(path)) {
            diffFormatter.setPathFilter(PathFilter.create(path));
        }
        return diffFormatter.scan(parsersFactory.getPreviousCommitParser(),
                parsersFactory.getCurrentCommitParser());
    }

    private class DiffCurrentPreviousTreeParsersFactory {

        private final Repository repository;

        private final ObjectReader reader;

        private CanonicalTreeParser currentCommitParser;

        private AbstractTreeIterator previousCommitParser;

        private DiffCurrentPreviousTreeParsersFactory(Repository repository, ObjectReader reader)
                throws IOException {
            this.repository = repository;
            this.reader = reader;
            init();
        }

        private void init() throws IOException {
            RevCommit currentCommit = getCommitById(commitId);
            if (currentCommit == null) {
                throw new GitException(String.format("There are no commit with id '%s'", commitId));
            }

            currentCommitParser = new CanonicalTreeParser();
            currentCommitParser.reset(reader, currentCommit.getTree());

            RevCommit previousCommit = Strings.isNullOrEmpty(previousCommitId) //
                    ? getCommitById(commitId + "~" + nthCommit) //
                    : getCommitById(previousCommitId);

            if (previousCommit == null) {
                // currentCommit is the first commit in the tree
                previousCommitParser = new EmptyTreeIterator();
            } else {
                CanonicalTreeParser parser = new CanonicalTreeParser();
                parser.reset(reader, previousCommit.getTree());
                previousCommitParser = parser;
            }
        }

        public CanonicalTreeParser getCurrentCommitParser() {
            return currentCommitParser;
        }

        public AbstractTreeIterator getPreviousCommitParser() {
            return previousCommitParser;
        }

        @Nullable
        private RevCommit getCommitById(String id) throws IOException {
            ObjectId objectId = repository.resolve(id);
            return objectId == null ? null : new RevWalk(repository).parseCommit(objectId);
        }
    }

    @SuppressWarnings("ParameterHidesMemberVariable")
    public static class Builder {

        private final DiffCommand command;

        public Builder(@NotNull File repositoryPath, String commitId) {
            this(repositoryPath, null, commitId);
        }

        public Builder(@NotNull File repositoryPath, @Nullable File workPath, String commitId) {
            command = new DiffCommand(repositoryPath, workPath, commitId);
        }

        public Builder path(String path) {
            command.path = path;
            return this;
        }

        public Builder previousCommitId(String previousCommitId) {
            command.previousCommitId = previousCommitId;
            return this;
        }

        public Builder nthCommit(int nthCommit) {
            command.nthCommit = nthCommit;
            return this;
        }

        public DiffCommand build() {
            return command;
        }
    }

}