changeset 16376:d3908c911d5e

context: internalize lookup logic This allows us to avoid doing rev->node->rev lookups on silly instances like "0", which end up caching the whole nodemap.
author Matt Mackall <mpm@selenic.com>
date Sun, 08 Apr 2012 12:38:07 -0500
parents d7d64b89a65c
children f8ce254e514f
files mercurial/context.py
diffstat 1 files changed, 78 insertions(+), 6 deletions(-) [+]
line wrap: on
line diff
--- a/mercurial/context.py	Sun Apr 08 12:38:02 2012 -0500
+++ b/mercurial/context.py	Sun Apr 08 12:38:07 2012 -0500
@@ -5,7 +5,7 @@
 # This software may be used and distributed according to the terms of the
 # GNU General Public License version 2 or any later version.
 
-from node import nullid, nullrev, short, hex
+from node import nullid, nullrev, short, hex, bin
 from i18n import _
 import ancestor, mdiff, error, util, scmutil, subrepo, patch, encoding, phases
 import match as matchmod
@@ -21,12 +21,84 @@
         if changeid == '':
             changeid = '.'
         self._repo = repo
-        if isinstance(changeid, (long, int)):
+
+        if isinstance(changeid, int):
             self._rev = changeid
-            self._node = self._repo.changelog.node(changeid)
-        else:
-            self._node = self._repo.lookup(changeid)
-            self._rev = self._repo.changelog.rev(self._node)
+            self._node = repo.changelog.node(changeid)
+            return
+        if changeid == '.':
+            self._node = repo.dirstate.p1()
+            self._rev = repo.changelog.rev(self._node)
+            return
+        if changeid == 'null':
+            self._node = nullid
+            self._rev = nullrev
+            return
+        if changeid == 'tip':
+            self._rev = len(repo.changelog) - 1
+            self._node = repo.changelog.node(self._rev)
+            return
+        if len(changeid) == 20:
+            try:
+                self._node = changeid
+                self._rev = repo.changelog.rev(changeid)
+                return
+            except LookupError:
+                pass
+
+        try:
+            r = int(changeid)
+            if str(r) != changeid:
+                raise ValueError
+            l = len(repo.changelog)
+            if r < 0:
+                r += l
+            if r < 0 or r >= l:
+                raise ValueError
+            self._rev = r
+            self._node = repo.changelog.node(r)
+            return
+        except (ValueError, OverflowError):
+            pass
+
+        if len(changeid) == 40:
+            try:
+                self._node = bin(changeid)
+                self._rev = repo.changelog.rev(self._node)
+                return
+            except (TypeError, LookupError):
+                pass
+
+        if changeid in repo._bookmarks:
+            self._node = repo._bookmarks[changeid]
+            self._rev = repo.changelog.rev(self._node)
+            return
+        if changeid in repo._tagscache.tags:
+            self._node = repo._tagscache.tags[changeid]
+            self._rev = repo.changelog.rev(self._node)
+            return
+        if changeid in repo.branchtags():
+            self._node = repo.branchtags()[changeid]
+            self._rev = repo.changelog.rev(self._node)
+            return
+
+        self._node = repo.changelog._partialmatch(changeid)
+        if self._node is not None:
+            self._rev = repo.changelog.rev(self._node)
+            return
+
+        # lookup failed
+        # check if it might have come from damaged dirstate
+        if changeid in repo.dirstate.parents():
+            raise error.Abort(_("working directory has unknown parent '%s'!")
+                              % short(changeid))
+        try:
+            if len(changeid) == 20:
+                changeid = hex(changeid)
+        except TypeError:
+            pass
+        raise error.RepoLookupError(
+            _("unknown revision '%s'") % changeid)
 
     def __str__(self):
         return short(self.node())