mercurial/tags.py
changeset 21892 89cdebc31cda
parent 21832 4b93e19cd6e6
child 23139 e53f6b72a0e4
--- a/mercurial/tags.py	Fri Jun 20 00:42:35 2014 +0900
+++ b/mercurial/tags.py	Sat Jun 28 01:42:39 2014 +0200
@@ -84,20 +84,29 @@
 
     _updatetags(filetags, "local", alltags, tagtypes)
 
-def _readtags(ui, repo, lines, fn, recode=None):
+def _readtaghist(ui, repo, lines, fn, recode=None, calcnodelines=False):
     '''Read tag definitions from a file (or any source of lines).
-    Return a mapping from tag name to (node, hist): node is the node id
-    from the last line read for that name, and hist is the list of node
-    ids previously associated with it (in file order).  All node ids are
-    binary, not hex.'''
+    This function returns two sortdicts with similar information:
+    - the first dict, bingtaglist, contains the tag information as expected by
+      the _readtags function, i.e. a mapping from tag name to (node, hist):
+        - node is the node id from the last line read for that name,
+        - hist is the list of node ids previously associated with it (in file
+          order).  All node ids are binary, not hex.
+    - the second dict, hextaglines, is a mapping from tag name to a list of
+      [hexnode, line number] pairs, ordered from the oldest to the newest node.
+    When calcnodelines is False the hextaglines dict is not calculated (an
+    empty dict is returned). This is done to improve this function's
+    performance in cases where the line numbers are not needed.
+    '''
 
-    filetags = util.sortdict()  # map tag name to (node, hist)
+    bintaghist = util.sortdict()
+    hextaglines = util.sortdict()
     count = 0
 
     def warn(msg):
         ui.warn(_("%s, line %s: %s\n") % (fn, count, msg))
 
-    for line in lines:
+    for nline, line in enumerate(lines):
         count += 1
         if not line:
             continue
@@ -116,11 +125,28 @@
             continue
 
         # update filetags
-        hist = []
-        if name in filetags:
-            n, hist = filetags[name]
-            hist.append(n)
-        filetags[name] = (nodebin, hist)
+        if calcnodelines:
+            # map tag name to a list of line numbers
+            if name not in hextaglines:
+                hextaglines[name] = []
+            hextaglines[name].append([nodehex, nline])
+            continue
+        # map tag name to (node, hist)
+        if name not in bintaghist:
+            bintaghist[name] = []
+        bintaghist[name].append(nodebin)
+    return bintaghist, hextaglines
+
+def _readtags(ui, repo, lines, fn, recode=None, calcnodelines=False):
+    '''Read tag definitions from a file (or any source of lines).
+    Return a mapping from tag name to (node, hist): node is the node id
+    from the last line read for that name, and hist is the list of node
+    ids previously associated with it (in file order).  All node ids are
+    binary, not hex.'''
+    filetags, nodelines = _readtaghist(ui, repo, lines, fn, recode=recode,
+                                       calcnodelines=calcnodelines)
+    for tag, taghist in filetags.items():
+        filetags[tag] = (taghist[-1], taghist[:-1])
     return filetags
 
 def _updatetags(filetags, tagtype, alltags, tagtypes):