Rewrite resolve in terms of RevWalk

We want to eventually get rid of the mapCommit, mapTree APIs on
Repository and force everyone into the faster parsers that exist
in RevWalk.  Rewriting resolve in terms of the faster parsers is
a good first step.

It actually simplifies the code a bit, as we no longer need to
keep track of an ObjectId and an Object (the parsed form), since
all RevObjects implicitly have their ObjectId readily available.

Change-Id: I4d234630195616e2c263e7e70038b55a1be4e7a3
Signed-off-by: Shawn O. Pearce <spearce@spearce.org>
This commit is contained in:
Shawn O. Pearce 2010-06-23 17:26:43 -07:00
parent 47c07e1a0d
commit b6ba9739d5
1 changed files with 83 additions and 119 deletions

View File

@ -67,6 +67,10 @@
import org.eclipse.jgit.errors.ConfigInvalidException; import org.eclipse.jgit.errors.ConfigInvalidException;
import org.eclipse.jgit.errors.IncorrectObjectTypeException; import org.eclipse.jgit.errors.IncorrectObjectTypeException;
import org.eclipse.jgit.errors.RevisionSyntaxException; import org.eclipse.jgit.errors.RevisionSyntaxException;
import org.eclipse.jgit.revwalk.RevBlob;
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.revwalk.RevObject;
import org.eclipse.jgit.revwalk.RevWalk;
import org.eclipse.jgit.util.FS; import org.eclipse.jgit.util.FS;
import org.eclipse.jgit.util.IO; import org.eclipse.jgit.util.IO;
import org.eclipse.jgit.util.RawParseUtils; import org.eclipse.jgit.util.RawParseUtils;
@ -745,36 +749,37 @@ public RefRename renameRef(final String fromRef, final String toRef) throws IOEx
* *
* Currently supported is combinations of these. * Currently supported is combinations of these.
* <ul> * <ul>
* <li>SHA-1 - a SHA-1</li> * <li>SHA-1 - a SHA-1</li>
* <li>refs/... - a ref name</li> * <li>refs/... - a ref name</li>
* <li>ref^n - nth parent reference</li> * <li>ref^n - nth parent reference</li>
* <li>ref~n - distance via parent reference</li> * <li>ref~n - distance via parent reference</li>
* <li>ref@{n} - nth version of ref</li> * <li>ref@{n} - nth version of ref</li>
* <li>ref^{tree} - tree references by ref</li> * <li>ref^{tree} - tree references by ref</li>
* <li>ref^{commit} - commit references by ref</li> * <li>ref^{commit} - commit references by ref</li>
* </ul> * </ul>
* *
* Not supported is * Not supported is:
* <ul> * <ul>
* <li>timestamps in reflogs, ref@{full or relative timestamp}</li> * <li>timestamps in reflogs, ref@{full or relative timestamp}</li>
* <li>abbreviated SHA-1's</li> * <li>abbreviated SHA-1's</li>
* </ul> * </ul>
* *
* @param revstr A git object references expression * @param revstr
* A git object references expression
* @return an ObjectId or null if revstr can't be resolved to any ObjectId * @return an ObjectId or null if revstr can't be resolved to any ObjectId
* @throws IOException on serious errors * @throws IOException
* on serious errors
*/ */
public ObjectId resolve(final String revstr) throws IOException { public ObjectId resolve(final String revstr) throws IOException {
char[] rev = revstr.toCharArray(); char[] rev = revstr.toCharArray();
Object ref = null; RevObject ref = null;
ObjectId refId = null; RevWalk rw = new RevWalk(this);
for (int i = 0; i < rev.length; ++i) { for (int i = 0; i < rev.length; ++i) {
switch (rev[i]) { switch (rev[i]) {
case '^': case '^':
if (refId == null) { if (ref == null) {
String refstr = new String(rev,0,i); ref = parseSimple(rw, new String(rev, 0, i));
refId = resolveSimple(refstr); if (ref == null)
if (refId == null)
return null; return null;
} }
if (i + 1 < rev.length) { if (i + 1 < rev.length) {
@ -790,19 +795,12 @@ public ObjectId resolve(final String revstr) throws IOException {
case '8': case '8':
case '9': case '9':
int j; int j;
ref = mapObject(refId, null); ref = rw.parseCommit(ref);
while (ref instanceof Tag) { for (j = i + 1; j < rev.length; ++j) {
Tag tag = (Tag)ref;
refId = tag.getObjId();
ref = mapObject(refId, null);
}
if (!(ref instanceof Commit))
throw new IncorrectObjectTypeException(refId, Constants.TYPE_COMMIT);
for (j=i+1; j<rev.length; ++j) {
if (!Character.isDigit(rev[j])) if (!Character.isDigit(rev[j]))
break; break;
} }
String parentnum = new String(rev, i+1, j-i-1); String parentnum = new String(rev, i + 1, j - i - 1);
int pnum; int pnum;
try { try {
pnum = Integer.parseInt(parentnum); pnum = Integer.parseInt(parentnum);
@ -812,123 +810,83 @@ public ObjectId resolve(final String revstr) throws IOException {
revstr); revstr);
} }
if (pnum != 0) { if (pnum != 0) {
final ObjectId parents[] = ((Commit) ref) RevCommit commit = (RevCommit) ref;
.getParentIds(); if (pnum > commit.getParentCount())
if (pnum > parents.length) ref = null;
refId = null;
else else
refId = parents[pnum - 1]; ref = commit.getParent(pnum - 1);
} }
i = j - 1; i = j - 1;
break; break;
case '{': case '{':
int k; int k;
String item = null; String item = null;
for (k=i+2; k<rev.length; ++k) { for (k = i + 2; k < rev.length; ++k) {
if (rev[k] == '}') { if (rev[k] == '}') {
item = new String(rev, i+2, k-i-2); item = new String(rev, i + 2, k - i - 2);
break; break;
} }
} }
i = k; i = k;
if (item != null) if (item != null)
if (item.equals("tree")) { if (item.equals("tree")) {
ref = mapObject(refId, null); ref = rw.parseTree(ref);
while (ref instanceof Tag) { } else if (item.equals("commit")) {
Tag t = (Tag)ref; ref = rw.parseCommit(ref);
refId = t.getObjId(); } else if (item.equals("blob")) {
ref = mapObject(refId, null); ref = rw.peel(ref);
} if (!(ref instanceof RevBlob))
if (ref instanceof Treeish) throw new IncorrectObjectTypeException(ref,
refId = ((Treeish)ref).getTreeId(); Constants.TYPE_BLOB);
else } else if (item.equals("")) {
throw new IncorrectObjectTypeException(refId, Constants.TYPE_TREE); ref = rw.peel(ref);
} } else
else if (item.equals("commit")) {
ref = mapObject(refId, null);
while (ref instanceof Tag) {
Tag t = (Tag)ref;
refId = t.getObjId();
ref = mapObject(refId, null);
}
if (!(ref instanceof Commit))
throw new IncorrectObjectTypeException(refId, Constants.TYPE_COMMIT);
}
else if (item.equals("blob")) {
ref = mapObject(refId, null);
while (ref instanceof Tag) {
Tag t = (Tag)ref;
refId = t.getObjId();
ref = mapObject(refId, null);
}
if (!(ref instanceof byte[]))
throw new IncorrectObjectTypeException(refId, Constants.TYPE_BLOB);
}
else if (item.equals("")) {
ref = mapObject(refId, null);
while (ref instanceof Tag) {
Tag t = (Tag)ref;
refId = t.getObjId();
ref = mapObject(refId, null);
}
}
else
throw new RevisionSyntaxException(revstr); throw new RevisionSyntaxException(revstr);
else else
throw new RevisionSyntaxException(revstr); throw new RevisionSyntaxException(revstr);
break; break;
default: default:
ref = mapObject(refId, null); ref = rw.parseAny(ref);
if (ref instanceof Commit) { if (ref instanceof RevCommit) {
final ObjectId parents[] = ((Commit) ref) RevCommit commit = ((RevCommit) ref);
.getParentIds(); if (commit.getParentCount() == 0)
if (parents.length == 0) ref = null;
refId = null;
else else
refId = parents[0]; ref = commit.getParent(0);
} else } else
throw new IncorrectObjectTypeException(refId, Constants.TYPE_COMMIT); throw new IncorrectObjectTypeException(ref,
Constants.TYPE_COMMIT);
} }
} else { } else {
ref = mapObject(refId, null); ref = rw.peel(ref);
while (ref instanceof Tag) { if (ref instanceof RevCommit) {
Tag tag = (Tag)ref; RevCommit commit = ((RevCommit) ref);
refId = tag.getObjId(); if (commit.getParentCount() == 0)
ref = mapObject(refId, null); ref = null;
}
if (ref instanceof Commit) {
final ObjectId parents[] = ((Commit) ref)
.getParentIds();
if (parents.length == 0)
refId = null;
else else
refId = parents[0]; ref = commit.getParent(0);
} else } else
throw new IncorrectObjectTypeException(refId, Constants.TYPE_COMMIT); throw new IncorrectObjectTypeException(ref,
Constants.TYPE_COMMIT);
} }
break; break;
case '~': case '~':
if (ref == null) { if (ref == null) {
String refstr = new String(rev,0,i); ref = parseSimple(rw, new String(rev, 0, i));
refId = resolveSimple(refstr); if (ref == null)
if (refId == null)
return null; return null;
ref = mapObject(refId, null);
} }
while (ref instanceof Tag) { ref = rw.peel(ref);
Tag tag = (Tag)ref; if (!(ref instanceof RevCommit))
refId = tag.getObjId(); throw new IncorrectObjectTypeException(ref,
ref = mapObject(refId, null); Constants.TYPE_COMMIT);
}
if (!(ref instanceof Commit))
throw new IncorrectObjectTypeException(refId, Constants.TYPE_COMMIT);
int l; int l;
for (l = i + 1; l < rev.length; ++l) { for (l = i + 1; l < rev.length; ++l) {
if (!Character.isDigit(rev[l])) if (!Character.isDigit(rev[l]))
break; break;
} }
String distnum = new String(rev, i+1, l-i-1); String distnum = new String(rev, i + 1, l - i - 1);
int dist; int dist;
try { try {
dist = Integer.parseInt(distnum); dist = Integer.parseInt(distnum);
@ -937,13 +895,14 @@ else if (item.equals("")) {
JGitText.get().invalidAncestryLength, revstr); JGitText.get().invalidAncestryLength, revstr);
} }
while (dist > 0) { while (dist > 0) {
final ObjectId[] parents = ((Commit) ref).getParentIds(); RevCommit commit = (RevCommit) ref;
if (parents.length == 0) { if (commit.getParentCount() == 0) {
refId = null; ref = null;
break; break;
} }
refId = parents[0]; commit = commit.getParent(0);
ref = mapCommit(refId); rw.parseHeaders(commit);
ref = commit;
--dist; --dist;
} }
i = l - 1; i = l - 1;
@ -951,30 +910,35 @@ else if (item.equals("")) {
case '@': case '@':
int m; int m;
String time = null; String time = null;
for (m=i+2; m<rev.length; ++m) { for (m = i + 2; m < rev.length; ++m) {
if (rev[m] == '}') { if (rev[m] == '}') {
time = new String(rev, i+2, m-i-2); time = new String(rev, i + 2, m - i - 2);
break; break;
} }
} }
if (time != null) if (time != null)
throw new RevisionSyntaxException(JGitText.get().reflogsNotYetSupportedByRevisionParser, revstr); throw new RevisionSyntaxException(
JGitText.get().reflogsNotYetSupportedByRevisionParser,
revstr);
i = m - 1; i = m - 1;
break; break;
default: default:
if (refId != null) if (ref != null)
throw new RevisionSyntaxException(revstr); throw new RevisionSyntaxException(revstr);
} }
} }
if (refId == null) return ref != null ? ref.copy() : resolveSimple(revstr);
refId = resolveSimple(revstr); }
return refId;
private RevObject parseSimple(RevWalk rw, String revstr) throws IOException {
ObjectId id = resolveSimple(revstr);
return id != null ? rw.parseAny(id) : null;
} }
private ObjectId resolveSimple(final String revstr) throws IOException { private ObjectId resolveSimple(final String revstr) throws IOException {
if (ObjectId.isId(revstr)) if (ObjectId.isId(revstr))
return ObjectId.fromString(revstr); return ObjectId.fromString(revstr);
final Ref r = refs.getRef(revstr); final Ref r = getRefDatabase().getRef(revstr);
return r != null ? r.getObjectId() : null; return r != null ? r.getObjectId() : null;
} }