package org.eclipse.buckminster.git.internal; import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.Map.Entry; import org.eclipse.buckminster.core.ctype.IComponentType; import org.eclipse.buckminster.core.resolver.NodeQuery; import org.eclipse.buckminster.core.rmap.model.Provider; import org.eclipse.buckminster.core.version.AbstractSCCSVersionFinder; import org.eclipse.buckminster.core.version.VersionMatch; import org.eclipse.buckminster.runtime.BuckminsterException; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.jgit.lib.Constants; 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.RevTag; import org.eclipse.jgit.revwalk.RevWalk; import org.eclipse.jgit.treewalk.TreeWalk; public class VersionFinder extends AbstractSCCSVersionFinder { private static String getBranchName(String name) { final boolean remote = name.startsWith(Constants.R_REMOTES); if (remote) { // cut off remote name final int slash = name.indexOf('/', Constants.R_REMOTES.length()); if (slash > -1) { return name.substring(slash + 1); } } return Repository.shortenRefName(name); } private RepositoryAccess repoAccess; public VersionFinder(Provider provider, IComponentType ctype, NodeQuery query) throws CoreException { super(provider, ctype, query); @SuppressWarnings("unchecked") Map<String, String> props = (Map<String, String>) provider.getProperties(query.getProperties()); repoAccess = new RepositoryAccess(getProvider().getURI(props), props); } @Override protected boolean checkComponentExistence(VersionMatch versionMatch, IProgressMonitor monitor) throws CoreException { synchronized (repoAccess.getRepositoryPath()) { TreeWalk walk = repoAccess.getTreeWalk(versionMatch, null, monitor); try { return walk.next(); } catch (Exception e) { throw BuckminsterException.wrap(e); } finally { walk.close(); } } } @Override public synchronized void close() { if (repoAccess != null) { repoAccess.close(); repoAccess = null; } } @Override protected List<RevisionEntry> getBranchesOrTags(boolean branches, IProgressMonitor monitor) throws CoreException { try { Repository repo = repoAccess.getRepository(); synchronized (repoAccess.getRepositoryPath()) { RevWalk revWalk = new RevWalk(repo); try { ArrayList<RevisionEntry> branchesOrTags = new ArrayList<RevisionEntry>(); String component = repoAccess.getComponent(); if (branches) { for (Ref ref : repo.getAllRefs().values()) { String name = ref.getName(); int lastSlash = name.lastIndexOf('/'); if (lastSlash < 0) continue; RevObject obj = revWalk.parseAny(ref.getObjectId()); if (!(obj instanceof RevCommit)) continue; // Last part of name is the branch String branch = getBranchName(name); if (Constants.MASTER.equals(branch)) continue; RevCommit c = (RevCommit) obj; if (!(component == null || TreeWalk.forPath(repo, component, c.getTree()) != null)) continue; // repoAccess.inspectRef(ref); // TODO: RevisionEntry should hold abbreviated // object id // instead of long revision branchesOrTags.add(new RevisionEntry(branch, c.getAuthorIdent().getWhen(), 0L)); } } else { final Map<String, Ref> tags = repo.getTags(); for (Entry<String, Ref> entry : tags.entrySet()) { RevObject obj = revWalk.parseAny(entry.getValue().getObjectId()); if (obj instanceof RevTag) { RevTag tag = (RevTag) obj; if (component != null) { // Check that the component exists in the // associated // Commit do { obj = ((RevTag) obj).getObject(); } while (obj instanceof RevTag); if (!(obj instanceof RevCommit && ((RevCommit) obj).getTree() != null && TreeWalk.forPath(repo, component, ((RevCommit) obj).getTree()) != null)) continue; } branchesOrTags.add(new RevisionEntry(tag.getTagName(), tag.getTaggerIdent().getWhen(), 0L)); } else if (obj instanceof RevCommit) { RevCommit c = (RevCommit) obj; String tag = entry.getKey(); branchesOrTags.add(new RevisionEntry(tag, c.getAuthorIdent().getWhen(), 0L)); } } } return branchesOrTags; } finally { revWalk.close(); } } } catch (IOException e) { throw BuckminsterException.wrap(e); } } @Override protected RevisionEntry getTrunk(IProgressMonitor monitor) throws CoreException { // In git, this means get the current HEAD Repository repo = repoAccess.getRepository(null, monitor); RevWalk revWalk = new RevWalk(repo); try { String component = repoAccess.getComponent(); Ref head = repo.getRef(Constants.HEAD); if (head == null) return null; RevCommit c = revWalk.parseCommit(head.getObjectId()); if (component != null && TreeWalk.forPath(repo, component, c.getTree()) == null) return null; // TODO: RevisionEntry should hold abbreviated object id instead // of long revision return new RevisionEntry(component, c.getAuthorIdent().getWhen(), 0L); } catch (Exception e) { throw BuckminsterException.wrap(e); } finally { revWalk.close(); } } }