/* * To change this template, choose Tools | Templates * and open the template in the editor. */ package br.uff.ic.oceano.core.tools.vcs; import br.uff.ic.oceano.core.tools.vcs.PathModel.PathChangeModel; import java.io.File; import java.io.IOException; import java.util.*; import java.util.Map.Entry; import org.eclipse.jgit.api.*; import org.eclipse.jgit.api.errors.*; import org.eclipse.jgit.diff.DiffEntry; import org.eclipse.jgit.diff.DiffEntry.ChangeType; import org.eclipse.jgit.diff.DiffFormatter; import org.eclipse.jgit.diff.RawTextComparator; import org.eclipse.jgit.errors.IncorrectObjectTypeException; import org.eclipse.jgit.errors.MissingObjectException; import org.eclipse.jgit.errors.UnmergedPathException; 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.storage.file.FileRepositoryBuilder; import org.eclipse.jgit.transport.CredentialsProvider; import org.eclipse.jgit.transport.UsernamePasswordCredentialsProvider; import org.eclipse.jgit.treewalk.TreeWalk; import org.eclipse.jgit.util.io.DisabledOutputStream; /** * * @author Gleiph, João Felipe */ public class GitCommands { private FileRepositoryBuilder builder; private Repository repository; private Git git; public GitCommands(String path) throws IOException { builder = new FileRepositoryBuilder(); repository = builder.setGitDir(new File(path + "/.git")).readEnvironment() // scan environment GIT_* variables .findGitDir() // scan up the file system tree .build(); git = new Git(repository); } public void create() throws IOException { repository.create(); } public void add(List<String> files) throws NoFilepatternException { AddCommand add = git.add(); for (String file : files) { add.addFilepattern(file); } add.call(); } public void commit(String message) throws NoHeadException, NoMessageException, UnmergedPathException, ConcurrentRefUpdateException, JGitInternalException, WrongRepositoryStateException { CommitCommand commit = git.commit(); RevCommit revision = commit.setMessage(message).call(); System.out.println(revision.getShortMessage()); } public void addingCommit(String message) throws NoFilepatternException, NoHeadException, NoMessageException, UnmergedPathException, ConcurrentRefUpdateException, JGitInternalException, WrongRepositoryStateException { add(Arrays.asList(".")); commit(message); } public void checkout(String developmentLine, boolean branch) throws JGitInternalException, InvalidRefNameException, RefAlreadyExistsException, RefNotFoundException { CheckoutCommand co = git.checkout(); co.setName(developmentLine); co.setCreateBranch(branch); co.call(); } public void checkoutRevision(String revision) throws JGitInternalException, InvalidRefNameException, RefAlreadyExistsException, RefNotFoundException { checkout(revision, false); } public void checkoutDevelopmentLine(String developmentLine) throws JGitInternalException, InvalidRefNameException, RefAlreadyExistsException, RefNotFoundException { checkout(developmentLine, false); } public void branch(String name) throws JGitInternalException, InvalidRefNameException, RefAlreadyExistsException, RefNotFoundException { checkout(name, true); } //Missing commands: // *Push // *Pull // *Clone public void pull(String username, String password) throws WrongRepositoryStateException, InvalidConfigurationException, DetachedHeadException, InvalidRemoteException, CanceledException, RefNotFoundException, NoHeadException { CredentialsProvider authentication = new UsernamePasswordCredentialsProvider(username, password); PullCommand pull = git.pull(); // pull.setCredentialsProvider(authentication); pull.call(); } /** * Returns a list of references in the repository matching "refs". If the * repository is null or empty, an empty list is returned. * * @param repository * @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 List<RefModel> getRefs(Repository repository, String refs, boolean fullName, int maxCount) { List<RefModel> list = new ArrayList<RefModel>(); if (maxCount == 0) { return list; } if (!hasCommits(repository)) { return list; } try { Map<String, Ref> map = repository.getRefDatabase().getRefs(refs); RevWalk rw = new RevWalk(repository); for (Entry<String, Ref> entry : map.entrySet()) { Ref ref = entry.getValue(); RevObject object = rw.parseAny(ref.getObjectId()); String name = entry.getKey(); if (fullName && !refs.equals("")) { 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<RefModel>(list.subList(0, maxCount)); } } catch (IOException e) { System.err.println("Repository {0} failed to retrieve {1}" + refs); } return list; } /** * Returns the list of local branches in the repository. If repository does * not exist or is empty, an empty list is returned. * * @param repository * @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 */ private List<RefModel> getLocalBranches(Repository repository, boolean fullName, int maxCount) { return getRefs(repository, Constants.R_HEADS, fullName, maxCount); } /** * 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 * @return the objectid of a branch * @throws Exception */ private 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<RefModel> 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; } private 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 list of files changed in a specified commit. If the * repository does not exist or is empty, an empty list is returned. * * @param repository * @param commit * if null, HEAD is assumed. * @return list of files changed in a commit */ public List<PathChangeModel> getFilesInCommit(RevCommit commit) { List<PathChangeModel> list = new ArrayList<PathChangeModel>(); if (!hasCommits(repository)) { return list; } RevWalk rw = new RevWalk(repository); try { if (commit == null) { ObjectId object = getDefaultBranch(repository); commit = rw.parseCommit(object); } if (commit.getParentCount() == 0) { TreeWalk tw = new TreeWalk(repository); tw.reset(); tw.setRecursive(true); tw.addTree(commit.getTree()); while (tw.next()) { list.add(new PathChangeModel(tw.getPathString(), tw.getPathString(), 0, tw .getRawMode(0), commit.getId().getName(), ChangeType.ADD)); } tw.release(); } else { RevCommit parent = rw.parseCommit(commit.getParent(0).getId()); DiffFormatter df = new DiffFormatter(DisabledOutputStream.INSTANCE); df.setRepository(repository); df.setDiffComparator(RawTextComparator.DEFAULT); df.setDetectRenames(true); List<DiffEntry> diffs = df.scan(parent.getTree(), commit.getTree()); for (DiffEntry diff : diffs) { if (diff.getChangeType().equals(ChangeType.DELETE)) { list.add(new PathChangeModel(diff.getOldPath(), diff.getOldPath(), 0, diff .getNewMode().getBits(), commit.getId().getName(), diff .getChangeType())); } else if (diff.getChangeType().equals(ChangeType.RENAME)) { list.add(new PathChangeModel(diff.getOldPath(), diff.getNewPath(), 0, diff .getNewMode().getBits(), commit.getId().getName(), diff .getChangeType())); } else { list.add(new PathChangeModel(diff.getNewPath(), diff.getNewPath(), 0, diff .getNewMode().getBits(), commit.getId().getName(), diff .getChangeType())); } } } } catch (Throwable t) { System.err.println("Repository failed to determine files in commit!"); } finally { rw.dispose(); } return list; } public Iterator<RevCommit> log() throws NoHeadException, MissingObjectException, IncorrectObjectTypeException, IOException { Iterable<RevCommit> log = git.log().call(); return log.iterator(); } }