massive refactoring of extended Git

This commit is contained in:
Brian Long 2021-01-11 09:50:59 -05:00
parent a58e369ada
commit 3536943567

View File

@ -1,38 +1,35 @@
package com.inteligr8.git;
import java.io.IOException;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
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.CreateBranchCommand.SetupUpstreamMode;
import org.eclipse.jgit.api.ListBranchCommand.ListMode;
import org.eclipse.jgit.api.ResetCommand.ResetType;
import org.eclipse.jgit.api.errors.CheckoutConflictException;
import org.eclipse.jgit.api.errors.GitAPIException;
import org.eclipse.jgit.api.errors.InvalidRefNameException;
import org.eclipse.jgit.api.errors.InvalidRemoteException;
import org.eclipse.jgit.api.errors.RefAlreadyExistsException;
import org.eclipse.jgit.api.errors.RefNotFoundException;
import org.eclipse.jgit.api.errors.TransportException;
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.transport.RemoteConfig;
import org.eclipse.jgit.transport.URIish;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class ExtendedGit extends CachedGit {
private static final Pattern gitUrlPattern = Pattern.compile("(((ssh|http(s)?)://([^@]+@)?([^:/]+)(:[0-9]+)?/)|git@([^:]+):)([\\w\\.@\\:/\\-~]+)(\\.git)");
private final Logger logger = LoggerFactory.getLogger(ExtendedGit.class);
public ExtendedGit(Git git) {
@ -47,67 +44,87 @@ public class ExtendedGit extends CachedGit {
super(repo);
}
public String getRepositoryFullyQualifiedName() throws GitAPIException, URISyntaxException {
String gitUrl = this.getFirstRemoteUrl();
if (this.logger.isDebugEnabled())
this.logger.debug("Remote URL: " + gitUrl);
return getRepositoryFullyQualifiedName(gitUrl);
public Collection<RemoteConfig> findRemotesByHostname(String hostname) throws GitAPIException {
List<RemoteConfig> matchingRemotes = new LinkedList<>();
List<RemoteConfig> remotes = this.remoteList().call();
for (RemoteConfig remote : remotes) {
for (URIish uri : remote.getURIs()) {
GitUrl url = new GitUrl(uri);
if (hostname.equalsIgnoreCase(url.getHostname())) {
matchingRemotes.add(remote);
break;
}
}
}
return matchingRemotes;
}
public static String getRepositoryFullyQualifiedName(String gitUrl) throws URISyntaxException {
Matcher matcher = gitUrlPattern.matcher(gitUrl);
if (!matcher.find())
throw new URISyntaxException(gitUrl, "The Git URL does not match the expected regular expression: " + gitUrlPattern.toString());
return matcher.group(9);
public Collection<String> findRemoteNames(String branchName) throws IOException, GitAPIException {
List<String> remoteNames = new LinkedList<>();
List<RemoteConfig> remotes = this.remoteList().call();
for (RemoteConfig remote : remotes)
if (this.getRepository().exactRef(Constants.R_REMOTES + remote.getName() + "/" + branchName) != null)
remoteNames.add(remote.getName());
return remoteNames;
}
/**
* Creates a local branch, if one does not already exist.
* Checks out the repository, targeting the remote branch.
* Resets the local branch up to the remote branch.
*/
public Ref normalize(String localBranchName, String exactRemoteBranchName)
throws RefAlreadyExistsException, RefNotFoundException, InvalidRefNameException, CheckoutConflictException, GitAPIException, IOException {
public Collection<Ref> findRemoteRefsByName(String branchName) throws IOException, GitAPIException {
List<Ref> refs = new LinkedList<>();
List<RemoteConfig> remotes = this.remoteList().call();
for (RemoteConfig remote : remotes) {
Ref ref = this.getRepository().exactRef(Constants.R_REMOTES + remote.getName() + "/" + branchName);
if (ref != null)
refs.add(ref);
}
return refs;
}
public Ref resetAndCheckout(Ref ref) throws IOException, GitAPIException {
if (!ref.getName().startsWith(Constants.R_HEADS))
throw new IllegalArgumentException("The '" + ref + "' is not a local ref");
return this._resetAndCheckout(ref);
}
public Ref resetAndCheckout(String branchName) throws IOException, GitAPIException {
if (this.logger.isTraceEnabled())
this.logger.trace("normalize('" + localBranchName + "', '" + exactRemoteBranchName + "')");
this.logger.trace("resetOrCheckout('" + branchName + "')");
Ref localRef = this.getRepository().exactRef(Constants.R_HEADS + localBranchName);
if (localRef == null) {
if (this.logger.isDebugEnabled())
this.logger.debug("normalize('" + localBranchName + "', '" + exactRemoteBranchName + "'): local branch does not yet exist");
localRef = this.branchCreate()
.setUpstreamMode(SetupUpstreamMode.NOTRACK)
.setName(localBranchName)
.setStartPoint(exactRemoteBranchName)
.call();
if (this.logger.isDebugEnabled())
this.logger.debug("normalize('" + localBranchName + "', '" + exactRemoteBranchName + "'): created local branch: " + localRef.getName());
Ref localRef = this.getRepository().exactRef(Constants.R_HEADS + branchName);
if (localRef == null)
throw new IllegalArgumentException("The '" + branchName + "' branch must already exist");
return this._resetAndCheckout(localRef);
}
private Ref _resetAndCheckout(Ref ref) throws IOException, GitAPIException {
Ref localRef = ref;
if (!this.status().call().isClean()) {
if (this.logger.isTraceEnabled())
this.logger.trace("resetOrCheckout('" + ref + "'): repo is dirty");
localRef = this.reset().setMode(ResetType.HARD).call();
}
Ref checkoutRef = this.checkout()
.setName(localBranchName)
.setStartPoint(exactRemoteBranchName)
.call();
if (this.logger.isDebugEnabled())
this.logger.debug("normalize('" + localBranchName + "', '" + exactRemoteBranchName + "'): checked out");
if (!localRef.getObjectId().getName().equals(checkoutRef.getObjectId().getName())) {
this.logger.warn("A checkout did not move the local branch to the proper commit; performing reset: " + localRef.getName());
this.reset()
.setMode(ResetType.HARD)
.setRef(exactRemoteBranchName)
.call();
if (this.logger.isDebugEnabled())
this.logger.debug("normalize('" + localBranchName + "', '" + exactRemoteBranchName + "'): reset");
if (!this.getRepository().getFullBranch().equals(localRef.getName())) {
if (this.logger.isTraceEnabled())
this.logger.trace("resetOrCheckout('" + ref + "'): repo is on a different branch");
localRef = this.checkout().setName(localRef.getName()).call();
}
return checkoutRef;
return localRef;
}
/**
* This method retrieves all branches, but excludes remote branches that are tracked with a local branch.
* @return
*/
@Deprecated
public List<Ref> getAllUniqueBranches() throws GitAPIException {
return this.getAllUniqueBranches(null);
}
@ -116,6 +133,7 @@ public class ExtendedGit extends CachedGit {
* This method retrieves all branches, but excludes remote branches that are tracked with a local branch.
* @return
*/
@Deprecated
public List<Ref> getAllUniqueBranches(String containsCommitish) throws GitAPIException {
if (this.logger.isTraceEnabled())
this.logger.trace("getAllUniqueBranches('" + containsCommitish + "')");
@ -184,5 +202,18 @@ public class ExtendedGit extends CachedGit {
return trimmedBranches;
}
@Deprecated
private boolean allSameCommit(Collection<Ref> refs) {
if (refs.size() < 2)
return true;
Iterator<Ref> i = refs.iterator();
ObjectId commit = i.next().getObjectId();
while (i.hasNext())
if (!commit.equals(i.next().getObjectId()))
return false;
return true;
}
}