major refactoring
This commit is contained in:
parent
0d6d1290b7
commit
ef829b45f2
42
src/main/java/me/brianlong/git/CompositeIterator.java
Normal file
42
src/main/java/me/brianlong/git/CompositeIterator.java
Normal file
@ -0,0 +1,42 @@
|
||||
package me.brianlong.git;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.NoSuchElementException;
|
||||
|
||||
public class CompositeIterator<E> implements Iterator<E> {
|
||||
|
||||
private final List<Iterator<E>> iterators = new LinkedList<Iterator<E>>();
|
||||
private final Iterator<Iterator<E>> iteratorIterators;
|
||||
private Iterator<E> iterator;
|
||||
|
||||
public CompositeIterator(@SuppressWarnings("unchecked") Collection<E>... cs) {
|
||||
for (Collection<E> c : cs)
|
||||
if (c != null && !c.isEmpty())
|
||||
this.iterators.add(c.iterator());
|
||||
this.iteratorIterators = this.iterators.iterator();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
if (this.iterator == null) {
|
||||
if (!this.iteratorIterators.hasNext())
|
||||
return false;
|
||||
this.iterator = this.iteratorIterators.next();
|
||||
}
|
||||
|
||||
while (!this.iterator.hasNext() && this.iteratorIterators.hasNext())
|
||||
this.iterator = this.iteratorIterators.next();
|
||||
return this.iterator.hasNext();
|
||||
}
|
||||
|
||||
@Override
|
||||
public E next() {
|
||||
if (!this.hasNext())
|
||||
throw new NoSuchElementException();
|
||||
return this.iterator.next();
|
||||
}
|
||||
|
||||
}
|
@ -12,7 +12,7 @@ import org.eclipse.jgit.api.errors.TransportException;
|
||||
import org.eclipse.jgit.lib.Repository;
|
||||
import org.eclipse.jgit.transport.CredentialsProvider;
|
||||
|
||||
public class CredentialedGit extends CachedGit {
|
||||
public class CredentialedGit extends ExtendedGit {
|
||||
|
||||
private CredentialsProvider credProvider;
|
||||
|
||||
|
127
src/main/java/me/brianlong/git/ExtendedGit.java
Normal file
127
src/main/java/me/brianlong/git/ExtendedGit.java
Normal file
@ -0,0 +1,127 @@
|
||||
package me.brianlong.git;
|
||||
|
||||
import java.net.URISyntaxException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.eclipse.jgit.api.CloneCommand;
|
||||
import org.eclipse.jgit.api.Git;
|
||||
import org.eclipse.jgit.api.ListBranchCommand;
|
||||
import org.eclipse.jgit.api.ListBranchCommand.ListMode;
|
||||
import org.eclipse.jgit.api.errors.GitAPIException;
|
||||
import org.eclipse.jgit.api.errors.InvalidRemoteException;
|
||||
import org.eclipse.jgit.api.errors.TransportException;
|
||||
import org.eclipse.jgit.lib.Constants;
|
||||
import org.eclipse.jgit.lib.Ref;
|
||||
import org.eclipse.jgit.lib.Repository;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public class ExtendedGit extends CachedGit {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(ExtendedGit.class);
|
||||
private final Pattern gitUrlPattern = Pattern.compile("(((ssh|http(s)?)://([^@]+@)?([^:/]+)(:[0-9]+)?/)|git@([^:]+):)([\\w\\.@\\:/\\-~]+)(\\.git)");
|
||||
|
||||
public ExtendedGit(Git git) {
|
||||
super(git.getRepository());
|
||||
}
|
||||
|
||||
public ExtendedGit(CloneCommand clone) throws TransportException, InvalidRemoteException, GitAPIException {
|
||||
super(clone.call().getRepository());
|
||||
}
|
||||
|
||||
public ExtendedGit(Repository repo) {
|
||||
super(repo);
|
||||
}
|
||||
|
||||
public String getFirstRemoteUrl() throws GitAPIException {
|
||||
return this.remoteList().call().iterator().next().getURIs().iterator().next().toString();
|
||||
}
|
||||
|
||||
public String getRepositoryFullyQualifiedName() throws GitAPIException, URISyntaxException {
|
||||
String gitUrl = this.getFirstRemoteUrl();
|
||||
if (this.logger.isDebugEnabled())
|
||||
this.logger.debug("Remote URL: " + gitUrl);
|
||||
|
||||
Matcher matcher = this.gitUrlPattern.matcher(gitUrl);
|
||||
if (!matcher.find())
|
||||
throw new URISyntaxException(gitUrl, "The Git URL does not match the expected regular expression: " + this.gitUrlPattern.toString());
|
||||
return matcher.group(9);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method retrieves all branches, but excludes remote branches that are tracked with a local branch.
|
||||
* @return
|
||||
*/
|
||||
public List<Ref> getAllUniqueBranches() throws GitAPIException {
|
||||
return this.getAllUniqueBranches(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method retrieves all branches, but excludes remote branches that are tracked with a local branch.
|
||||
* @return
|
||||
*/
|
||||
public List<Ref> getAllUniqueBranches(String containsCommitish) throws GitAPIException {
|
||||
ListBranchCommand command = this.branchList().setListMode(ListMode.ALL);
|
||||
if (containsCommitish != null)
|
||||
command.setContains(containsCommitish);
|
||||
List<Ref> branches = command.call();
|
||||
|
||||
Set<String> abbrevBranchNames = new HashSet<String>(branches.size());
|
||||
List<Ref> trimmedBranches = new ArrayList<Ref>(branches.size());
|
||||
|
||||
// sort them by local, then remote; keep order the same otherwise
|
||||
Collections.sort(branches, new Comparator<Ref>() {
|
||||
@Override
|
||||
public int compare(Ref o1, Ref o2) {
|
||||
if (o1 == null) return -1;
|
||||
else if (o2 == null) return 1;
|
||||
else {
|
||||
boolean o1local = o1.getName().startsWith(Constants.R_HEADS);
|
||||
boolean o2local = o2.getName().startsWith(Constants.R_HEADS);
|
||||
if (o1local && o2local) return 0;
|
||||
else if (o1local) return -1;
|
||||
else if (o2local) return 1;
|
||||
else return 0;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
for (Ref branch : branches) {
|
||||
String fqBranchName = branch.getName();
|
||||
|
||||
String abbrevBranchName = null;
|
||||
if (fqBranchName.startsWith(Constants.R_REMOTES)) {
|
||||
if (this.logger.isDebugEnabled())
|
||||
this.logger.debug("Ref is a remote branch: " + fqBranchName);
|
||||
abbrevBranchName = this.getRepository().shortenRemoteBranchName(fqBranchName);
|
||||
} else if (fqBranchName.startsWith(Constants.R_HEADS)) {
|
||||
if (this.logger.isDebugEnabled())
|
||||
this.logger.debug("Ref is a local branch: " + fqBranchName);
|
||||
abbrevBranchName = Repository.shortenRefName(fqBranchName);
|
||||
} else {
|
||||
if (this.logger.isDebugEnabled())
|
||||
this.logger.debug("Ref is not a local or remote branch: " + fqBranchName);
|
||||
}
|
||||
|
||||
if (abbrevBranchName != null) {
|
||||
if (abbrevBranchNames.contains(abbrevBranchName)) {
|
||||
if (this.logger.isDebugEnabled())
|
||||
this.logger.debug("Branch already found; ignoring ...");
|
||||
} else {
|
||||
abbrevBranchNames.add(abbrevBranchName);
|
||||
trimmedBranches.add(branch);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return trimmedBranches;
|
||||
}
|
||||
|
||||
}
|
@ -48,19 +48,19 @@ public class LocalRepositoryCache {
|
||||
this.clear();
|
||||
}
|
||||
|
||||
public synchronized Git acquire(String url) throws GitAPIException, InvalidRemoteException, RefNotFoundException {
|
||||
public synchronized ExtendedGit acquire(String url) throws GitAPIException, InvalidRemoteException, RefNotFoundException {
|
||||
return this.acquire(url, null, null);
|
||||
}
|
||||
|
||||
public synchronized Git acquire(String url, GitCredentials creds) throws GitAPIException, InvalidRemoteException, RefNotFoundException {
|
||||
public synchronized ExtendedGit acquire(String url, GitCredentials creds) throws GitAPIException, InvalidRemoteException, RefNotFoundException {
|
||||
return this.acquire(url, creds, null);
|
||||
}
|
||||
|
||||
public synchronized Git acquire(String url, String branch) throws GitAPIException, InvalidRemoteException, RefNotFoundException {
|
||||
public synchronized ExtendedGit acquire(String url, String branch) throws GitAPIException, InvalidRemoteException, RefNotFoundException {
|
||||
return this.acquire(url, null, branch);
|
||||
}
|
||||
|
||||
public synchronized Git acquire(String url, GitCredentials creds, String branch) throws GitAPIException, InvalidRemoteException, RefNotFoundException {
|
||||
public synchronized ExtendedGit acquire(String url, GitCredentials creds, String branch) throws GitAPIException, InvalidRemoteException, RefNotFoundException {
|
||||
if (this.logger.isTraceEnabled())
|
||||
this.logger.trace("acquire('" + url + "', " + creds + ", '" + branch + "')");
|
||||
|
||||
@ -78,7 +78,7 @@ public class LocalRepositoryCache {
|
||||
|
||||
if (this.logger.isDebugEnabled())
|
||||
this.logger.debug("cloning Git repository: " + url);
|
||||
Git git = creds != null ? new CredentialedGit(clone, creds) : new CachedGit(clone);
|
||||
ExtendedGit git = creds != null ? new CredentialedGit(clone, creds) : new ExtendedGit(clone);
|
||||
if (this.logger.isInfoEnabled())
|
||||
this.logger.info("Cloned Git Repository");
|
||||
return git;
|
||||
|
236
src/main/java/me/brianlong/git/UniquePriorityFifoQueue.java
Normal file
236
src/main/java/me/brianlong/git/UniquePriorityFifoQueue.java
Normal file
@ -0,0 +1,236 @@
|
||||
package me.brianlong.git;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Comparator;
|
||||
import java.util.Iterator;
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.Queue;
|
||||
import java.util.TreeSet;
|
||||
|
||||
public class UniquePriorityFifoQueue<T> implements Queue<T> {
|
||||
|
||||
private final Counter counter = new SimpleCounter();
|
||||
private final Counter fakeCounter = new FakeCounter();
|
||||
private final TreeSet<PriorityFifoElement<T>> elements;
|
||||
|
||||
public UniquePriorityFifoQueue() {
|
||||
this.elements = new TreeSet<PriorityFifoElement<T>>();
|
||||
}
|
||||
|
||||
public UniquePriorityFifoQueue(Collection<? extends T> c) {
|
||||
this.elements = new TreeSet<PriorityFifoElement<T>>();
|
||||
for (T element : c)
|
||||
this.elements.add(new PriorityFifoElement<T>(element, this.counter));
|
||||
}
|
||||
|
||||
public UniquePriorityFifoQueue(final Comparator<? super T> comparator) {
|
||||
this.elements = new TreeSet<PriorityFifoElement<T>>(new Comparator<PriorityFifoElement<T>>() {
|
||||
@Override
|
||||
public int compare(PriorityFifoElement<T> o1, PriorityFifoElement<T> o2) {
|
||||
int compare = comparator.compare(o1.element, o2.element);
|
||||
if (compare != 0) return compare;
|
||||
return o1.compareTo(o2);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean add(T e) {
|
||||
return this.elements.add(new PriorityFifoElement<T>(e, this.counter));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean addAll(Collection<? extends T> c) {
|
||||
if (c != null) for (T e : c)
|
||||
this.elements.add(new PriorityFifoElement<T>(e, this.counter));
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
this.elements.clear();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public boolean contains(Object o) {
|
||||
return this.elements.contains(new PriorityFifoElement<T>((T)o, this.fakeCounter));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsAll(Collection<?> c) {
|
||||
if (c != null) for (Object o : c)
|
||||
if (!this.contains(o))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public T element() {
|
||||
return this.elements.iterator().next().element;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return this.elements.isEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<T> iterator() {
|
||||
final Iterator<PriorityFifoElement<T>> i = this.elements.iterator();
|
||||
return new Iterator<T>() {
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
return i.hasNext();
|
||||
}
|
||||
|
||||
@Override
|
||||
public T next() {
|
||||
return i.next().element;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove() {
|
||||
i.remove();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean offer(T e) {
|
||||
return this.elements.add(new PriorityFifoElement<T>(e, this.counter));
|
||||
}
|
||||
|
||||
@Override
|
||||
public T peek() {
|
||||
Iterator<T> i = this.iterator();
|
||||
return i.hasNext() ? i.next() : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public T poll() {
|
||||
PriorityFifoElement<T> element = this.elements.pollFirst();
|
||||
return element == null ? null : element.element;
|
||||
}
|
||||
|
||||
@Override
|
||||
public T remove() {
|
||||
PriorityFifoElement<T> element = this.elements.pollFirst();
|
||||
if (element == null)
|
||||
throw new NoSuchElementException();
|
||||
return element.element;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public boolean remove(Object o) {
|
||||
return this.elements.remove(new PriorityFifoElement<T>((T)o, this.fakeCounter));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean removeAll(Collection<?> c) {
|
||||
if (c != null) for (Object o : c)
|
||||
this.remove(o);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean retainAll(Collection<?> c) {
|
||||
Iterator<PriorityFifoElement<T>> i = this.elements.iterator();
|
||||
while (i.hasNext()) {
|
||||
T e = i.next().element;
|
||||
if (!c.contains(e))
|
||||
i.remove();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return this.elements.size();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public Object[] toArray() {
|
||||
Object[] objs = this.elements.toArray();
|
||||
Object[] ts = new Object[objs.length];
|
||||
for (int i = 0; i < objs.length; i++)
|
||||
ts[i] = ((PriorityFifoElement<T>)objs[i]).element;
|
||||
return ts;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public <U extends Object> U[] toArray(U[] a) {
|
||||
if (a.length < this.elements.size())
|
||||
a = Arrays.copyOf(a, this.elements.size());
|
||||
|
||||
int i = 0;
|
||||
for (PriorityFifoElement<T> element : this.elements)
|
||||
a[i] = (U)element.element;
|
||||
return a;
|
||||
}
|
||||
|
||||
|
||||
|
||||
private class PriorityFifoElement<E> implements Comparable<PriorityFifoElement<E>> {
|
||||
|
||||
private final E element;
|
||||
private final int fifoId;
|
||||
|
||||
public PriorityFifoElement(E element, Counter counter) {
|
||||
this.element = element;
|
||||
this.fifoId = counter.next();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(PriorityFifoElement<E> o) {
|
||||
if (o == null) return 1;
|
||||
else return this.fifoId - o.fifoId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return this.element.hashCode();
|
||||
}
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj instanceof PriorityFifoElement) {
|
||||
return this.element.equals(((PriorityFifoElement)obj).element);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private interface Counter {
|
||||
|
||||
int next();
|
||||
|
||||
}
|
||||
|
||||
public class FakeCounter implements Counter {
|
||||
|
||||
public int next() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public class SimpleCounter implements Counter {
|
||||
|
||||
private int count = 0;
|
||||
|
||||
public synchronized int next() {
|
||||
this.count++;
|
||||
return this.count;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user