de.blizzy.documentr.repository.ProjectRepositoryManager.java Source code

Java tutorial

Introduction

Here is the source code for de.blizzy.documentr.repository.ProjectRepositoryManager.java

Source

/*
documentr - Edit, maintain, and present software documentation on the web.
Copyright (C) 2012-2013 Maik Schreiber
    
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 de.blizzy.documentr.repository;

import java.io.File;
import java.io.IOException;
import java.util.Collections;
import java.util.List;

import org.apache.commons.io.FileUtils;
import org.eclipse.jgit.api.CreateBranchCommand;
import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.api.errors.GitAPIException;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.PersonIdent;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.lib.RepositoryBuilder;
import org.eclipse.jgit.lib.StoredConfig;
import org.eclipse.jgit.transport.RefSpec;
import org.gitective.core.RepositoryUtils;
import org.springframework.util.Assert;

import com.google.common.base.Function;
import com.google.common.collect.Lists;
import com.google.common.eventbus.EventBus;
import com.google.common.io.Closeables;

import de.blizzy.documentr.DocumentrConstants;
import de.blizzy.documentr.access.User;

class ProjectRepositoryManager {
    private static final String CENTRAL_REPO_NAME = "_central"; //$NON-NLS-1$

    private String projectName;
    private File reposDir;
    private LockManager lockManager;
    private EventBus eventBus;
    private File centralRepoDir;

    ProjectRepositoryManager(String projectName, File reposDir, LockManager lockManager, EventBus eventBus) {
        this.projectName = projectName;
        this.reposDir = reposDir;
        this.lockManager = lockManager;
        this.eventBus = eventBus;
        centralRepoDir = new File(reposDir, CENTRAL_REPO_NAME);
    }

    ILockedRepository createCentralRepository(User user) throws IOException, GitAPIException {
        return createCentralRepository(true, user);
    }

    ILockedRepository createCentralRepository(boolean bare, User user) throws IOException, GitAPIException {
        if (centralRepoDir.isDirectory()) {
            throw new IllegalStateException("repository already exists: " + centralRepoDir.getAbsolutePath()); //$NON-NLS-1$
        }

        ILock lock = lockManager.lockAll();
        try {
            Repository repo = null;
            File gitDir = new File(centralRepoDir, ".git"); //$NON-NLS-1$
            try {
                RepositoryBuilder builder = new RepositoryBuilder().setGitDir(gitDir);
                if (bare) {
                    builder.setBare();
                }
                repo = builder.build();
                repo.create();
            } finally {
                RepositoryUtil.closeQuietly(repo);
            }

            File tempGitDir = new File(new File(reposDir, CENTRAL_REPO_NAME + "_temp"), ".git"); //$NON-NLS-1$ //$NON-NLS-2$
            Repository tempRepo = null;
            try {
                tempRepo = Git.cloneRepository().setURI(gitDir.toURI().toString()).setDirectory(tempGitDir).call()
                        .getRepository();
                Git git = Git.wrap(tempRepo);
                PersonIdent ident = new PersonIdent(user.getLoginName(), user.getEmail());
                git.commit().setAuthor(ident).setCommitter(ident).setMessage("init").call(); //$NON-NLS-1$
                git.push().call();
            } finally {
                RepositoryUtil.closeQuietly(tempRepo);
            }
            FileUtils.forceDelete(tempGitDir.getParentFile());
        } finally {
            lockManager.unlock(lock);
        }

        return getCentralRepository(bare);
    }

    ILockedRepository getCentralRepository() throws IOException {
        return getCentralRepository(true);
    }

    ILockedRepository getCentralRepository(boolean bare) throws IOException {
        if (!centralRepoDir.isDirectory()) {
            throw RepositoryNotFoundException.forCentralRepository(projectName);
        }

        LockedRepository lockedRepo = LockedRepository.lockProjectCentral(projectName, lockManager);
        Repository repo = getCentralRepositoryInternal(bare);
        lockedRepo.setRepository(repo);
        return lockedRepo;
    }

    private Repository getCentralRepositoryInternal(boolean bare) throws IOException {
        RepositoryBuilder builder = new RepositoryBuilder().findGitDir(centralRepoDir);
        if (bare) {
            builder.setBare();
        }
        return builder.build();
    }

    ILockedRepository createBranchRepository(String branchName, String startingBranch)
            throws IOException, GitAPIException {
        Assert.hasLength(branchName);
        if (startingBranch != null) {
            Assert.hasLength(startingBranch);
        }

        File repoDir = new File(reposDir, branchName);
        if (repoDir.isDirectory()) {
            throw new IllegalStateException("repository already exists: " + repoDir.getAbsolutePath()); //$NON-NLS-1$
        }

        List<String> branches = listBranches();
        if (branches.contains(branchName)) {
            throw new IllegalArgumentException("branch already exists: " + branchName); //$NON-NLS-1$
        }

        if ((startingBranch == null) && !branches.isEmpty()) {
            throw new IllegalArgumentException("must specify a starting branch"); //$NON-NLS-1$
        }

        ILock lock = lockManager.lockAll();
        try {
            Repository centralRepo = null;
            File centralRepoGitDir;
            try {
                centralRepo = getCentralRepositoryInternal(true);
                centralRepoGitDir = centralRepo.getDirectory();
            } finally {
                RepositoryUtil.closeQuietly(centralRepo);
                centralRepo = null;
            }

            Repository repo = null;
            try {
                repo = Git.cloneRepository().setURI(centralRepoGitDir.toURI().toString()).setDirectory(repoDir)
                        .call().getRepository();

                try {
                    centralRepo = getCentralRepositoryInternal(true);
                    if (!RepositoryUtils.getBranches(centralRepo).contains(branchName)) {
                        CreateBranchCommand createBranchCommand = Git.wrap(centralRepo).branchCreate();
                        if (startingBranch != null) {
                            createBranchCommand.setStartPoint(startingBranch);
                        }
                        createBranchCommand.setName(branchName).call();
                    }
                } finally {
                    RepositoryUtil.closeQuietly(centralRepo);
                }

                Git git = Git.wrap(repo);
                RefSpec refSpec = new RefSpec("refs/heads/" + branchName + ":refs/remotes/origin/" + branchName); //$NON-NLS-1$ //$NON-NLS-2$
                git.fetch().setRemote("origin").setRefSpecs(refSpec).call(); //$NON-NLS-1$
                git.branchCreate().setName(branchName).setStartPoint("origin/" + branchName).call(); //$NON-NLS-1$
                git.checkout().setName(branchName).call();
            } finally {
                RepositoryUtil.closeQuietly(repo);
            }
        } finally {
            lockManager.unlock(lock);
        }

        return getBranchRepository(branchName);
    }

    ILockedRepository getBranchRepository(String branchName) throws IOException, GitAPIException {
        Assert.hasLength(branchName);

        File repoDir = new File(reposDir, branchName);
        if (!repoDir.isDirectory()) {
            throw new RepositoryNotFoundException(projectName, branchName);
        }

        LockedRepository lockedRepo = LockedRepository.lockProjectBranch(projectName, branchName, lockManager);
        Repository repo = new RepositoryBuilder().findGitDir(repoDir).build();
        Git.wrap(repo).pull().call();
        lockedRepo.setRepository(repo);
        return lockedRepo;
    }

    public List<String> listBranches() throws IOException {
        ILockedRepository repo = null;
        try {
            repo = getCentralRepository();
            List<String> result = Lists.newArrayList(RepositoryUtils.getBranches(repo.r()));
            final int prefixLen = "refs/heads/".length(); //$NON-NLS-1$
            Function<String, String> function = new Function<String, String>() {
                @Override
                public String apply(String branch) {
                    return branch.substring(prefixLen);
                }
            };
            result = Lists.newArrayList(Lists.transform(result, function));
            result.remove(Constants.MASTER);
            Collections.sort(result);
            return result;
        } finally {
            Closeables.closeQuietly(repo);
        }
    }

    public void importSampleContents() throws IOException, GitAPIException {
        // TODO: synchronization is not quite correct here, but should be okay in this edge case
        if (listBranches().isEmpty()) {
            ILock lock = lockManager.lockAll();
            List<String> branches;
            try {
                File gitDir = new File(centralRepoDir, ".git"); //$NON-NLS-1$
                FileUtils.forceDelete(gitDir);

                Git.cloneRepository().setURI(DocumentrConstants.SAMPLE_REPO_URL).setDirectory(gitDir).setBare(true)
                        .call();

                Repository centralRepo = null;
                File centralRepoGitDir;
                try {
                    centralRepo = getCentralRepositoryInternal(true);
                    centralRepoGitDir = centralRepo.getDirectory();
                    StoredConfig config = centralRepo.getConfig();
                    config.unsetSection("remote", "origin"); //$NON-NLS-1$ //$NON-NLS-2$
                    config.unsetSection("branch", "master"); //$NON-NLS-1$ //$NON-NLS-2$
                    config.save();
                } finally {
                    RepositoryUtil.closeQuietly(centralRepo);
                }

                branches = listBranches();
                for (String branchName : branches) {
                    File repoDir = new File(reposDir, branchName);
                    Repository repo = null;
                    try {
                        repo = Git.cloneRepository().setURI(centralRepoGitDir.toURI().toString())
                                .setDirectory(repoDir).call().getRepository();

                        Git git = Git.wrap(repo);
                        RefSpec refSpec = new RefSpec(
                                "refs/heads/" + branchName + ":refs/remotes/origin/" + branchName); //$NON-NLS-1$ //$NON-NLS-2$
                        git.fetch().setRemote("origin").setRefSpecs(refSpec).call(); //$NON-NLS-1$
                        git.branchCreate().setName(branchName).setStartPoint("origin/" + branchName).call(); //$NON-NLS-1$
                        git.checkout().setName(branchName).call();
                    } finally {
                        RepositoryUtil.closeQuietly(repo);
                    }
                }
            } finally {
                lockManager.unlock(lock);
            }

            for (String branch : branches) {
                eventBus.post(new BranchCreatedEvent(projectName, branch));
            }
        }
    }
}