org.commonjava.gitwrap.GitRepository.java Source code

Java tutorial

Introduction

Here is the source code for org.commonjava.gitwrap.GitRepository.java

Source

/*
 * Copyright (c) 2010 Red Hat, Inc.
 * 
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published
 * by the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * 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 General Public License for more details.
 * 
 * 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.commonjava.gitwrap;

import org.apache.log4j.Logger;
import org.eclipse.jgit.api.AddCommand;
import org.eclipse.jgit.api.errors.ConcurrentRefUpdateException;
import org.eclipse.jgit.api.errors.JGitInternalException;
import org.eclipse.jgit.api.errors.NoFilepatternException;
import org.eclipse.jgit.api.errors.NoHeadException;
import org.eclipse.jgit.api.errors.NoMessageException;
import org.eclipse.jgit.api.errors.WrongRepositoryStateException;
import org.eclipse.jgit.errors.UnmergedPathException;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.GitIndex;
import org.eclipse.jgit.lib.PersonIdent;
import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.lib.RefUpdate;
import org.eclipse.jgit.lib.RefUpdate.Result;
import org.eclipse.jgit.lib.Tree;
import org.eclipse.jgit.lib.WorkDirCheckout;
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.revwalk.RevTree;
import org.eclipse.jgit.revwalk.RevWalk;
import org.eclipse.jgit.storage.file.FileRepository;
import org.eclipse.jgit.transport.FetchResult;
import org.eclipse.jgit.treewalk.FileTreeIterator;

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

@SuppressWarnings("deprecation")
public class GitRepository extends BareGitRepository {

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

    public GitRepository(final File workDir) throws IOException {
        this(workDir, true);
    }

    public GitRepository(final File workDir, final boolean create) throws IOException {
        super(new File(workDir, Constants.DOT_GIT), create, workDir);
    }

    public static GitRepository cloneWithWorkdir(final String remoteUrl, final String remoteName,
            final File targetDir, final boolean bare) throws GitWrapException {
        return cloneWithWorkdir(remoteUrl, remoteName, null, targetDir, bare);
    }

    public static GitRepository cloneWithWorkdir(final String remoteUrl, final String remoteName,
            final String branch, final File targetDir, final boolean bare) throws GitWrapException {
        File workDir = targetDir;
        if (workDir.getName().equals(".git")) {
            workDir = workDir.getParentFile();
        }

        GitRepository repo;
        try {
            repo = new GitRepository(workDir, true);
        } catch (final IOException e) {
            throw new GitWrapException("Cannot initialize new Git repository in: %s. Reason: %s", e, targetDir,
                    e.getMessage());
        }

        repo.doClone(remoteUrl, remoteName, branch);

        return repo;
    }

    public GitRepository commitChanges(final String message, final String... filePatterns) throws GitWrapException {
        final AddCommand add = getGit().add();
        add.setWorkingTreeIterator(new FileTreeIterator(getRepository()));
        for (final String pattern : filePatterns) {
            add.addFilepattern(pattern);
        }

        try {
            add.call();
        } catch (final NoFilepatternException e) {
            throw new GitWrapException("Failed to add file patterns: %s", e, e.getMessage());
        }

        try {
            getGit().commit().setMessage(message).setAuthor(new PersonIdent(getRepository())).call();
        } catch (final NoHeadException e) {
            throw new GitWrapException("Commit failed: no repository HEAD. Nested error: %s", e, e.getMessage());
        } catch (final NoMessageException e) {
            throw new GitWrapException("Commit failed: no message provided. Nested error: %s", e, e.getMessage());
        } catch (final UnmergedPathException e) {
            throw new GitWrapException("Commit failed: you have unmerged paths. Nested error: %s", e,
                    e.getMessage());
        } catch (final ConcurrentRefUpdateException e) {
            throw new GitWrapException("Commit failed: %s", e, e.getMessage());
        } catch (final JGitInternalException e) {
            throw new GitWrapException("Commit failed: %s", e, e.getMessage());
        } catch (final WrongRepositoryStateException e) {
            throw new GitWrapException("Commit failed: %s", e, e.getMessage());
        }

        return this;
    }

    @Override
    public GitRepository createBranch(final String source, final String name) throws GitWrapException {
        super.createBranch(source, name);

        checkoutBranch(name);

        return this;
    }

    public GitRepository checkoutBranch(final String name) throws GitWrapException {
        final String refName;
        if (name == null) {
            refName = Constants.HEAD;
        } else if (name.startsWith(Constants.R_HEADS) || name.startsWith(Constants.R_TAGS)) {
            refName = name;
        } else {
            refName = Constants.R_HEADS + name;
        }

        if (hasBranch(refName)) {
            if (LOGGER.isDebugEnabled()) {
                LOGGER.debug("Checking out: " + refName);
            }

            final FileRepository repository = getRepository();
            final boolean detach = !refName.startsWith(Constants.R_HEADS);

            try {
                final RevWalk walk = new RevWalk(repository);
                final RevCommit newCommit = walk.parseCommit(repository.resolve(refName));
                final RevCommit oldCommit = walk.parseCommit(repository.resolve(Constants.HEAD));
                final GitIndex index = repository.getIndex();
                final RevTree newTree = newCommit.getTree();
                final RevTree oldTree = oldCommit.getTree();

                if (LOGGER.isDebugEnabled()) {
                    LOGGER.debug("Checking out: " + newCommit + " (resolved from: " + refName + ")");
                }

                final WorkDirCheckout checkout = new WorkDirCheckout(repository, repository.getWorkTree(),
                        repository.mapTree(oldTree), index, repository.mapTree(newTree));

                checkout.checkout();

                if (LOGGER.isDebugEnabled()) {
                    LOGGER.debug("Writing index...");
                }

                index.write();

                final RefUpdate u = repository.updateRef(Constants.HEAD, detach);
                Result result;
                if (detach) {
                    u.setNewObjectId(newCommit.getId());
                    u.setRefLogMessage("Switching to detached branch: " + refName, false);

                    if (LOGGER.isDebugEnabled()) {
                        LOGGER.debug("Updating head ref to point to: " + newCommit.getId());
                    }

                    result = u.forceUpdate();
                } else {
                    u.setRefLogMessage("Switching to linked branch: " + refName, false);

                    if (LOGGER.isDebugEnabled()) {
                        LOGGER.debug("Linking head ref to: " + refName);
                    }

                    result = u.link(refName);
                }

                switch (result) {
                case NEW:
                case FORCED:
                case NO_CHANGE:
                case FAST_FORWARD:
                    break;
                default:
                    throw new GitWrapException("Error checking out branch: %s. Result: %s", refName,
                            u.getResult().name());
                }
            } catch (final IOException e) {
                throw new GitWrapException("Failed to checkout branch: %s.\nReason: %s", e, refName,
                        e.getMessage());
            }
        } else {
            throw new GitWrapException(
                    "Cannot checkout non-existent branch: %s. Perhaps you meant to call createBranch(..)?",
                    refName);
        }

        return this;
    }

    @Override
    protected void postClone(final String remoteUrl, final String branchRef) throws GitWrapException {
        super.postClone(remoteUrl, branchRef);

        final FetchResult fetchResult = getLatestFetchResult();

        try {
            final Ref remoteHead = fetchResult.getAdvertisedRef(branchRef);
            if (remoteHead != null && remoteHead.getObjectId() != null) {
                final FileRepository repo = getRepository();

                final RevWalk walk = new RevWalk(repo);
                final RevCommit commit = walk.parseCommit(remoteHead.getObjectId());
                final GitIndex index = new GitIndex(repo);
                final Tree tree = repo.mapTree(commit.getTree());

                new WorkDirCheckout(repo, repo.getWorkTree(), index, tree).checkout();
                index.write();
            }
        } catch (final IOException e) {
            throw new GitWrapException("Failed to checkout: %s after cloning from: %s.\nReason: %s", e, branchRef,
                    remoteUrl, e.getMessage());
        } finally {
        }
    }

}