io.macgyver.plugin.git.GitResourceProvider.java Source code

Java tutorial

Introduction

Here is the source code for io.macgyver.plugin.git.GitResourceProvider.java

Source

/**
 * 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 io.macgyver.plugin.git;

import io.macgyver.core.resource.Resource;
import io.macgyver.core.resource.ResourceMatcher;
import io.macgyver.core.resource.ResourceProvider;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.List;
import java.util.concurrent.TimeUnit;

import org.eclipse.jgit.api.CloneCommand;
import org.eclipse.jgit.api.FetchCommand;
import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.api.errors.GitAPIException;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.revwalk.RevTree;
import org.eclipse.jgit.revwalk.RevWalk;
import org.eclipse.jgit.transport.UsernamePasswordCredentialsProvider;
import org.eclipse.jgit.treewalk.TreeWalk;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.common.base.Optional;
import com.google.common.base.Preconditions;
import com.google.common.base.Strings;
import com.google.common.collect.Lists;
import com.google.common.io.Files;

public class GitResourceProvider extends ResourceProvider {

    Logger logger = LoggerFactory.getLogger(GitResourceProvider.class);

    Optional<GitRepository> gitRepository = Optional.absent();

    long lastRefreshTime = 0;

    long fetchIntervalMillis = TimeUnit.SECONDS.toMillis(300);

    Git git;
    Repository repo;

    String ref = "refs/heads/master";

    protected GitResourceProvider() {

    }

    public GitResourceProvider(String url, String username, String password) {
        GitRepository gitRepository = new GitRepository();
        gitRepository.setUrl(url);
        gitRepository.setUsername(username);
        gitRepository.setPassword(password);
        this.gitRepository = Optional.of(gitRepository);
    }

    public GitResourceProvider(String url) {
        this(url, null, null);
    }

    public GitResourceProvider(GitRepository r) {
        gitRepository = Optional.of(r);
    }

    public GitRepository getGitRepository() {

        return gitRepository.get();

    }

    public String getGitRef() {
        return ref;
    }

    public ObjectId resolveRef(String ref) throws IOException {
        Preconditions.checkNotNull(ref);
        ensureLocalClone();
        return repo.resolve(ref);
    }

    public void setGitRef(String ref) {
        this.ref = ref;

    }

    public synchronized void ensureLocalClone() throws IOException {
        GitRepository gitRepository = getGitRepository();
        try {
            if (git != null) {
                return;
            }
            File dir = Files.createTempDir();

            logger.info("cloning {} into {}", gitRepository.getUrl(), dir);

            CloneCommand cc = Git.cloneRepository().setURI(gitRepository.getUrl()).setBare(true).setDirectory(dir)
                    .setCloneAllBranches(true);

            if ((!Strings.isNullOrEmpty(gitRepository.getUsername()))
                    || (!Strings.isNullOrEmpty(gitRepository.getPassword()))) {
                cc = cc.setCredentialsProvider(
                        new UsernamePasswordCredentialsProvider(Strings.nullToEmpty(gitRepository.getUsername()),
                                Strings.nullToEmpty(gitRepository.getPassword())));
            }
            git = cc.call();
            repo = git.getRepository();

        } catch (GitAPIException e) {
            throw new IOException(e);
        }

    }

    public synchronized void fetch() throws IOException {
        long t0 = System.currentTimeMillis();
        GitRepository gitRepository = getGitRepository();

        try {

            ensureLocalClone();
            FetchCommand fc = git.fetch();

            if ((!Strings.isNullOrEmpty(gitRepository.getUsername()))
                    || (!Strings.isNullOrEmpty(gitRepository.getPassword()))) {
                fc = fc.setCredentialsProvider(
                        new UsernamePasswordCredentialsProvider(Strings.nullToEmpty(gitRepository.getUsername()),
                                Strings.nullToEmpty(gitRepository.getPassword())));
            }
            fc.call();
        } catch (GitAPIException e) {
            throw new IOException(e);
        } finally {
            long t1 = System.currentTimeMillis();
            logger.info("fetch took {} ms", t1 - t0);
        }

    }

    @Override
    public Iterable<Resource> findResources(ResourceMatcher matcher) throws IOException {
        Preconditions.checkNotNull(matcher);
        refreshIfNecessary();
        ObjectId headCommit = repo.resolve(getGitRef());

        if (headCommit == null) {
            throw new IOException("ref not found: " + getGitRef());
        }
        TreeWalk tw = null;
        RevWalk rw = new RevWalk(repo);
        try {
            RevCommit rc = rw.parseCommit(headCommit);

            RevTree tree = rc.getTree();

            tw = new TreeWalk(repo);
            tw.addTree(tree);
            tw.setRecursive(true);
            List<Resource> list = Lists.newArrayList();
            while (tw.next()) {

                GitResourceImpl gri = new GitResourceImpl(this, tw.getObjectId(0), tw.getPathString());
                if (matcher.matches(gri)) {
                    list.add(gri);
                }

            }
            return list;
        } finally {
            if (tw != null) {
                tw.release();
            }
            if (rw != null) {
                rw.release();
            }
        }

    }

    @Override
    public Resource getResourceByPath(String path) throws IOException {

        refreshIfNecessary();
        TreeWalk tw = null;
        RevWalk rw = null;
        try {
            ObjectId headCommit = repo.resolve(getGitRef());
            rw = new RevWalk(repo);

            tw = TreeWalk.forPath(repo, path, rw.parseCommit(headCommit).getTree());
            if (tw == null) {
                throw new FileNotFoundException(
                        path + " not found in ref " + getGitRef() + " (" + headCommit.getName() + ")");
            }
            ObjectId id = tw.getObjectId(0);
            GitResourceImpl gri = new GitResourceImpl(this, id, path);
            return gri;
        } finally {
            if (tw != null) {
                tw.release();
            }
            if (rw != null) {
                rw.release();
            }
        }
    }

    public void close() {
        if (repo != null) {
            repo.close();
        }
        if (git != null) {
            git.close();
        }
    }

    public synchronized void refreshIfNecessary() throws IOException {
        ensureLocalClone();

        long timeSinceRefresh = System.currentTimeMillis() - lastRefreshTime;

        if (timeSinceRefresh > getFetchIntervalMillis()) {
            logger.debug("fetching updates from git repo");
            lastRefreshTime = System.currentTimeMillis();
            fetch();
        }

    }

    public long getFetchIntervalMillis() {
        return fetchIntervalMillis;
    }

    @Override
    public synchronized void refresh() throws IOException {
        ensureLocalClone();
        fetch();
    }

    public void setFetchIntervalSecs(int secs) {
        fetchIntervalMillis = TimeUnit.SECONDS.toMillis(secs);
    }
}