mercurial/wireprotov2server.py
changeset 40923 3ed77780f4a6
parent 40649 f83cea7f54d7
child 40924 08cfa77d7288
--- a/mercurial/wireprotov2server.py	Mon Dec 10 17:26:12 2018 +0000
+++ b/mercurial/wireprotov2server.py	Mon Dec 10 18:04:12 2018 +0000
@@ -984,9 +984,7 @@
 
     return fl
 
-def emitfilerevisions(repo, path, revisions, fields):
-    clnode = repo.changelog.node
-
+def emitfilerevisions(repo, path, revisions, linknodes, fields):
     for revision in revisions:
         d = {
             b'node': revision.node,
@@ -996,13 +994,7 @@
             d[b'parents'] = [revision.p1node, revision.p2node]
 
         if b'linknode' in fields:
-            # TODO by creating the filectx against a specific file revision
-            # instead of changeset, linkrev() is always used. This is wrong for
-            # cases where linkrev() may refer to a hidden changeset. We need an
-            # API for performing linkrev adjustment that takes this into
-            # account.
-            fctx = repo.filectx(path, fileid=revision.node)
-            d[b'linknode'] = clnode(fctx.introrev())
+            d[b'linknode'] = linknodes[revision.node]
 
         followingmeta = []
         followingdata = []
@@ -1086,6 +1078,9 @@
     except FileAccessError as e:
         raise error.WireprotoCommandError(e.msg, e.args)
 
+    clnode = repo.changelog.node
+    linknodes = {}
+
     # Validate requested nodes.
     for node in nodes:
         try:
@@ -1094,6 +1089,14 @@
             raise error.WireprotoCommandError('unknown file node: %s',
                                               (hex(node),))
 
+        # TODO by creating the filectx against a specific file revision
+        # instead of changeset, linkrev() is always used. This is wrong for
+        # cases where linkrev() may refer to a hidden changeset. But since this
+        # API doesn't know anything about changesets, we're not sure how to
+        # disambiguate the linknode. Perhaps we should delete this API?
+        fctx = repo.filectx(path, fileid=node)
+        linknodes[node] = clnode(fctx.introrev())
+
     revisions = store.emitrevisions(nodes,
                                     revisiondata=b'revision' in fields,
                                     assumehaveparentrevisions=haveparents)
@@ -1102,7 +1105,7 @@
         b'totalitems': len(nodes),
     }
 
-    for o in emitfilerevisions(repo, path, revisions, fields):
+    for o in emitfilerevisions(repo, path, revisions, linknodes, fields):
         yield o
 
 def filesdatacapabilities(repo, proto):
@@ -1154,12 +1157,14 @@
     # changeset.
 
     cl = repo.changelog
+    clnode = cl.node
     outgoing = resolvenodes(repo, revisions)
     filematcher = makefilematcher(repo, pathfilter)
 
     # Figure out what needs to be emitted.
     changedpaths = set()
-    fnodes = collections.defaultdict(set)
+    # path -> {fnode: linknode}
+    fnodes = collections.defaultdict(dict)
 
     for node in outgoing:
         ctx = repo[node]
@@ -1182,7 +1187,7 @@
                 linkrev = store.linkrev(rev)
 
                 if linkrev in outgoingclrevs:
-                    fnodes[path].add(store.node(rev))
+                    fnodes[path].setdefault(store.node(rev), clnode(linkrev))
 
     # If ancestors aren't known, we walk the manifests and send all
     # encountered file revisions.
@@ -1192,7 +1197,7 @@
 
             for path, fnode in mctx.read().items():
                 if filematcher(path):
-                    fnodes[path].add(fnode)
+                    fnodes[path].setdefault(fnode, node)
 
     yield {
         b'totalpaths': len(fnodes),
@@ -1210,11 +1215,11 @@
             b'totalitems': len(filenodes),
         }
 
-        revisions = store.emitrevisions(filenodes,
+        revisions = store.emitrevisions(filenodes.keys(),
                                         revisiondata=b'revision' in fields,
                                         assumehaveparentrevisions=haveparents)
 
-        for o in emitfilerevisions(repo, path, revisions, fields):
+        for o in emitfilerevisions(repo, path, revisions, filenodes, fields):
             yield o
 
 @wireprotocommand(