Skip to content
Snippets Groups Projects
Commit 7fa4df3e authored by Georg Seibt's avatar Georg Seibt :nerd:
Browse files

implement getting and verifying of commits and branches using 'git rev-parse --verify'

parent 6a89c494
No related branches found
No related tags found
No related merge requests found
...@@ -22,9 +22,8 @@ import java.util.logging.Level; ...@@ -22,9 +22,8 @@ import java.util.logging.Level;
import java.util.logging.Logger; import java.util.logging.Logger;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import org.apache.commons.io.FileUtils;
import de.uni_passau.fim.seibt.gitwrapper.process.ProcessExecutor.ExecRes; import de.uni_passau.fim.seibt.gitwrapper.process.ProcessExecutor.ExecRes;
import org.apache.commons.io.FileUtils;
/** /**
* A git {@link Repository}. * A git {@link Repository}.
...@@ -53,6 +52,10 @@ public class Repository { ...@@ -53,6 +52,10 @@ public class Repository {
private static final String CONFLICT_MIDDLE = "======="; private static final String CONFLICT_MIDDLE = "=======";
private static final String CONFLICT_END = ">>>>>>>"; private static final String CONFLICT_END = ">>>>>>>";
// The prefixes of the full symbolic names of (remote) branches.
private static final String FULL_SYMBOLIC_BRANCH = "refs/heads/";
private static final String FULL_SYMBOLIC_REMOTE_BRANCH = "refs/remotes/";
private GitWrapper git; private GitWrapper git;
private String url; private String url;
...@@ -234,43 +237,11 @@ public class Repository { ...@@ -234,43 +237,11 @@ public class Repository {
return Optional.of(commits.get(id)); return Optional.of(commits.get(id));
} }
if (!isCommit(id)) { return verify(false, id, TYPE_COMMIT).map(sha1 -> commits.computeIfAbsent(sha1, fullID -> new Commit(this, fullID)));
return Optional.empty();
}
return toHash(id).map(sha1 -> commits.computeIfAbsent(sha1, fullID -> new Commit(this, fullID)));
} }
/** /**
* Determines whether the given object ID designates a commit. * Optionally returns a {@link Branch} for the given name. If the given name does not designate a branch that
*
* @param id
* the ID to check
* @return true if the ID designates a commit
*/
private boolean isCommit(String id) {
Optional<ExecRes> catFile = git.exec(dir, "cat-file", "-t", id);
Function<ExecRes, Boolean> toBoolean = res -> {
if (git.failed(res)) {
LOG.warning(() -> String.format("Failed to determine whether %s is a valid commit id.", id));
return null;
}
boolean isCommit = res.getStdOutTrimmed().startsWith(TYPE_COMMIT);
if (isCommit) {
LOG.finer(() -> String.format("%s is a commit.", id));
}
return isCommit;
};
return catFile.map(toBoolean).orElse(false);
}
/**
* Optionally returns a {@link Branch} for the given name. If the given name does not designated a branch that
* exists in this {@link Repository}, an empty {@link Optional} will be returned. * exists in this {@link Repository}, an empty {@link Optional} will be returned.
* *
* @param name * @param name
...@@ -282,39 +253,27 @@ public class Repository { ...@@ -282,39 +253,27 @@ public class Repository {
return Optional.of(branches.get(name)); return Optional.of(branches.get(name));
} }
if (!isBranch(name)) { Function<String, Branch> toBranch = fullName -> {
return Optional.empty(); if (fullName.isEmpty()) {
} LOG.warning(() -> String.format("The name '%s' does not designate a branch in %s.", name, this));
return Optional.of(branches.computeIfAbsent(name, theName -> new Branch(this, theName)));
}
/**
* Determines whether the given name designates a branch.
*
* @param name
* the branch name to check
* @return true if the ID designates a commit
*/
private boolean isBranch(String name) {
Optional<ExecRes> catFile = git.exec(dir, "branch", "--list", "--no-color", "--column=plain");
Function<ExecRes, Boolean> toBoolean = res -> {
if (git.failed(res)) {
LOG.warning(() -> String.format("Failed to determine whether %s is a valid branch id.", name));
return null; return null;
} }
boolean isBranch = res.stdOut.contains(name); String branchName;
if (isBranch) { if (fullName.startsWith(FULL_SYMBOLIC_BRANCH)) {
LOG.finer(() -> String.format("%s is a branch.", name)); branchName = fullName.substring(FULL_SYMBOLIC_BRANCH.length());
} else if (fullName.startsWith(FULL_SYMBOLIC_REMOTE_BRANCH)) {
branchName = fullName.substring(FULL_SYMBOLIC_REMOTE_BRANCH.length());
} else {
LOG.warning(() -> String.format("The name '%s' designates neither a local nor a remote branch in %s.", fullName, this));
return null;
} }
return isBranch; return branches.computeIfAbsent(branchName, newBranchName -> new Branch(this, newBranchName));
}; };
return catFile.map(toBoolean).orElse(false); return verify(true, name, null).map(toBranch);
} }
/** /**
...@@ -322,20 +281,50 @@ public class Repository { ...@@ -322,20 +281,50 @@ public class Repository {
* *
* @param id * @param id
* the <code>id</code> to transform * the <code>id</code> to transform
* @return the full SHA1 hash or an empty {@link Optional} if an exception occurs * @return the full SHA1 hash or an empty {@link Optional} if an exception occurs or {@code id} can not be converted
* to its associated git hash
*/ */
Optional<String> toHash(String id) { Optional<String> toHash(String id) {
Optional<ExecRes> revParse = git.exec(dir, "rev-parse", id); return verify(false, id, null);
}
/**
* Verifies that the given git-thing exists and can be resolved to a raw SHA1 hash. If type is not {@link null},
* git will be asked to verify that the thing is also of the given type. If {@code fullSymbolicName} is set, the
* returned {@code String} will be (if present) the full symbolic name of the reference. If {@code arg} does
* not designate a reference but does exist in the repository, an empty {@code String} will be returned. This
* is the case (for example) for an existing commit in the repository.
*
* @param fullSymbolicName
* whether to return the full symbolic name of {@code arg} if possible
* @param arg
* the thing to check
* @param type
* the type of the thing, ignored if {@code null}
* @return optionally the full SHA1 hash (or full symbolic name) or an empty {@link Optional} if the thing can not
* be found or turned into a full hash
*/
private Optional<String> verify(boolean fullSymbolicName, String arg, String type) {
String argument = type != null ? String.format("%s^{%s}", arg, type) : arg;
Optional<ExecRes> revParse;
if (fullSymbolicName) {
revParse = git.exec(dir, "rev-parse", "--symbolic-full-name", "--verify", argument);
} else {
revParse = git.exec(dir, "rev-parse", "--verify", argument);
}
Function<ExecRes, String> toHash = res -> { Function<ExecRes, String> toHash = res -> {
if (git.failed(res)) { if (git.failed(res)) {
LOG.warning(() -> String.format("Failed to resolve %s to its unique SHA1 hash.", id)); LOG.warning(() -> String.format("Failed to resolve '%s' to its unique SHA1 hash.", arg));
return null; return null;
} }
LOG.finer(() -> String.format("Resolved %s to %s.", id, res.getStdOutTrimmed())); String hash = res.getStdOutTrimmed();
LOG.finer(() -> String.format("Verified that %s exists and resolved it to %s.", arg, hash));
return res.getStdOutTrimmed(); return hash;
}; };
return revParse.map(toHash); return revParse.map(toHash);
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment