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.IncorrectObjectTypeException;
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.IO;
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.
* <ul>
* <li>SHA-1 - a SHA-1</li>
* <li>refs/... - a ref name</li>
* <li>ref^n - nth parent reference</li>
* <li>ref~n - distance via parent reference</li>
* <li>ref@{n} - nth version of ref</li>
* <li>ref^{tree} - tree references by ref</li>
* <li>ref^{commit} - commit references by ref</li>
* <li>SHA-1 - a SHA-1</li>
* <li>refs/... - a ref name</li>
* <li>ref^n - nth parent reference</li>
* <li>ref~n - distance via parent reference</li>
* <li>ref@{n} - nth version of ref</li>
* <li>ref^{tree} - tree references by ref</li>
* <li>ref^{commit} - commit references by ref</li>
* </ul>
*
* Not supported is
* Not supported is:
* <ul>
* <li>timestamps in reflogs, ref@{full or relative timestamp}</li>
* <li>abbreviated SHA-1's</li>
* </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
* @throws IOException on serious errors
* @throws IOException
* on serious errors
*/
public ObjectId resolve(final String revstr) throws IOException {
char[] rev = revstr.toCharArray();
Object ref = null;
ObjectId refId = null;
RevObject ref = null;
RevWalk rw = new RevWalk(this);
for (int i = 0; i < rev.length; ++i) {
switch (rev[i]) {
case '^':
if (refId == null) {
String refstr = new String(rev,0,i);
refId = resolveSimple(refstr);
if (refId == null)
if (ref == null) {
ref = parseSimple(rw, new String(rev, 0, i));
if (ref == null)
return null;
}
if (i + 1 < rev.length) {
@ -790,19 +795,12 @@ public ObjectId resolve(final String revstr) throws IOException {
case '8':
case '9':
int j;
ref = mapObject(refId, null);
while (ref instanceof Tag) {
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) {
ref = rw.parseCommit(ref);
for (j = i + 1; j < rev.length; ++j) {
if (!Character.isDigit(rev[j]))
break;
}
String parentnum = new String(rev, i+1, j-i-1);
String parentnum = new String(rev, i + 1, j - i - 1);
int pnum;
try {
pnum = Integer.parseInt(parentnum);
@ -812,123 +810,83 @@ public ObjectId resolve(final String revstr) throws IOException {
revstr);
}
if (pnum != 0) {
final ObjectId parents[] = ((Commit) ref)
.getParentIds();
if (pnum > parents.length)
refId = null;
RevCommit commit = (RevCommit) ref;
if (pnum > commit.getParentCount())
ref = null;
else
refId = parents[pnum - 1];
ref = commit.getParent(pnum - 1);
}
i = j - 1;
break;
case '{':
int k;
String item = null;
for (k=i+2; k<rev.length; ++k) {
for (k = i + 2; k < rev.length; ++k) {
if (rev[k] == '}') {
item = new String(rev, i+2, k-i-2);
item = new String(rev, i + 2, k - i - 2);
break;
}
}
i = k;
if (item != null)
if (item.equals("tree")) {
ref = mapObject(refId, null);
while (ref instanceof Tag) {
Tag t = (Tag)ref;
refId = t.getObjId();
ref = mapObject(refId, null);
}
if (ref instanceof Treeish)
refId = ((Treeish)ref).getTreeId();
else
throw new IncorrectObjectTypeException(refId, Constants.TYPE_TREE);
}
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
ref = rw.parseTree(ref);
} else if (item.equals("commit")) {
ref = rw.parseCommit(ref);
} else if (item.equals("blob")) {
ref = rw.peel(ref);
if (!(ref instanceof RevBlob))
throw new IncorrectObjectTypeException(ref,
Constants.TYPE_BLOB);
} else if (item.equals("")) {
ref = rw.peel(ref);
} else
throw new RevisionSyntaxException(revstr);
else
throw new RevisionSyntaxException(revstr);
break;
default:
ref = mapObject(refId, null);
if (ref instanceof Commit) {
final ObjectId parents[] = ((Commit) ref)
.getParentIds();
if (parents.length == 0)
refId = null;
ref = rw.parseAny(ref);
if (ref instanceof RevCommit) {
RevCommit commit = ((RevCommit) ref);
if (commit.getParentCount() == 0)
ref = null;
else
refId = parents[0];
ref = commit.getParent(0);
} else
throw new IncorrectObjectTypeException(refId, Constants.TYPE_COMMIT);
throw new IncorrectObjectTypeException(ref,
Constants.TYPE_COMMIT);
}
} else {
ref = mapObject(refId, null);
while (ref instanceof Tag) {
Tag tag = (Tag)ref;
refId = tag.getObjId();
ref = mapObject(refId, null);
}
if (ref instanceof Commit) {
final ObjectId parents[] = ((Commit) ref)
.getParentIds();
if (parents.length == 0)
refId = null;
ref = rw.peel(ref);
if (ref instanceof RevCommit) {
RevCommit commit = ((RevCommit) ref);
if (commit.getParentCount() == 0)
ref = null;
else
refId = parents[0];
ref = commit.getParent(0);
} else
throw new IncorrectObjectTypeException(refId, Constants.TYPE_COMMIT);
throw new IncorrectObjectTypeException(ref,
Constants.TYPE_COMMIT);
}
break;
case '~':
if (ref == null) {
String refstr = new String(rev,0,i);
refId = resolveSimple(refstr);
if (refId == null)
ref = parseSimple(rw, new String(rev, 0, i));
if (ref == null)
return null;
ref = mapObject(refId, null);
}
while (ref instanceof Tag) {
Tag tag = (Tag)ref;
refId = tag.getObjId();
ref = mapObject(refId, null);
}
if (!(ref instanceof Commit))
throw new IncorrectObjectTypeException(refId, Constants.TYPE_COMMIT);
ref = rw.peel(ref);
if (!(ref instanceof RevCommit))
throw new IncorrectObjectTypeException(ref,
Constants.TYPE_COMMIT);
int l;
for (l = i + 1; l < rev.length; ++l) {
if (!Character.isDigit(rev[l]))
break;
}
String distnum = new String(rev, i+1, l-i-1);
String distnum = new String(rev, i + 1, l - i - 1);
int dist;
try {
dist = Integer.parseInt(distnum);
@ -937,13 +895,14 @@ else if (item.equals("")) {
JGitText.get().invalidAncestryLength, revstr);
}
while (dist > 0) {
final ObjectId[] parents = ((Commit) ref).getParentIds();
if (parents.length == 0) {
refId = null;
RevCommit commit = (RevCommit) ref;
if (commit.getParentCount() == 0) {
ref = null;
break;
}
refId = parents[0];
ref = mapCommit(refId);
commit = commit.getParent(0);
rw.parseHeaders(commit);
ref = commit;
--dist;
}
i = l - 1;
@ -951,30 +910,35 @@ else if (item.equals("")) {
case '@':
int m;
String time = null;
for (m=i+2; m<rev.length; ++m) {
for (m = i + 2; m < rev.length; ++m) {
if (rev[m] == '}') {
time = new String(rev, i+2, m-i-2);
time = new String(rev, i + 2, m - i - 2);
break;
}
}
if (time != null)
throw new RevisionSyntaxException(JGitText.get().reflogsNotYetSupportedByRevisionParser, revstr);
throw new RevisionSyntaxException(
JGitText.get().reflogsNotYetSupportedByRevisionParser,
revstr);
i = m - 1;
break;
default:
if (refId != null)
if (ref != null)
throw new RevisionSyntaxException(revstr);
}
}
if (refId == null)
refId = resolveSimple(revstr);
return refId;
return ref != null ? ref.copy() : resolveSimple(revstr);
}
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 {
if (ObjectId.isId(revstr))
return ObjectId.fromString(revstr);
final Ref r = refs.getRef(revstr);
final Ref r = getRefDatabase().getRef(revstr);
return r != null ? r.getObjectId() : null;
}