firefoxtree: support pulling firefoxtree labels from local peers (
bug 1275663); r=smacleod
Today I learned that "local" peer repository instances in Mercurial
have a separate code path from remote peer repos (namely httppeer
and sshpeer) for retrieving capabilities and calling wire proto
commands.
localrepo.py has a "moderncaps" module level variable holding a set
of capabilities. This is used by localpeer.__init__ to set the
capabilities for localpeer instances. Fortunately,
localrepository._restrictcapabilities is called during
localpeer.__init__, giving us a hook point to adjust the capabilities
set. If you look at the default implementation of that function, it
adds a capability, so the "restrict" part of its name isn't very
accurate.
We implement our own _restrictcapabilities function that supplements
the capabilities set if the repo is a Firefox repo.
But that's not all. Calling commands on localpeers is different because
there is no generic "call" API on localpeer instances. Instead,
methods call functions directly. So, when calling the "firefoxtrees"
wire protocol command, we detect local peers and make a direct
function call.
I wonder how many other extensions in version-control-tools won't work
with localpeer instances because we haven't implemented this pattern
before...
MozReview-Commit-ID: FpCOLCzyuq1
--- a/hgext/firefoxtree/__init__.py
+++ b/hgext/firefoxtree/__init__.py
@@ -324,17 +324,23 @@ def wrappedpullobsolete(orig, pullop):
repo = pullop.repo
remote = pullop.remote
if not isfirefoxrepo(repo):
return res
if remote.capable('firefoxtrees'):
bmstore = bookmarks.bmstore(repo)
- lines = remote._call('firefoxtrees').splitlines()
+ # remote.local() returns a localrepository or None. If local,
+ # just pass it into the wire protocol command/function to simulate
+ # the remote command call.
+ if remote.local():
+ lines = firefoxtrees(remote.local(), None).splitlines()
+ else:
+ lines = remote._call('firefoxtrees').splitlines()
oldtags = {}
for tag, node, tree, uri in get_firefoxtrees(repo):
oldtags[tag] = node
newtags = {}
for line in lines:
tag, node = line.split()
newtags[tag] = node
@@ -561,16 +567,26 @@ def extsetup(ui):
templatekw.dockeywords.update(keywords)
def reposetup(ui, repo):
if not repo.local():
return
class firefoxtreesrepo(repo.__class__):
+ # Wrap _restrictcapabilities so capabilities are exposed to local peers.
+ def _restrictcapabilities(self, caps):
+ caps = super(firefoxtreesrepo, self)._restrictcapabilities(caps)
+
+ if (isfirefoxrepo(self) and
+ self.ui.configbool('firefoxtree', 'servetags', False)):
+ caps.add('firefoxtrees')
+
+ return caps
+
@util.propertycache
def firefoxtrees(self):
trees = {}
try:
with open(self._firefoxtreespath, 'rb') as fh:
data = fh.read()
except IOError as e:
--- a/hgext/firefoxtree/tests/test-pull-tags-wireproto.t
+++ b/hgext/firefoxtree/tests/test-pull-tags-wireproto.t
@@ -91,16 +91,39 @@ Doing an incremental pull will print com
updated firefox tree tag inbound (+2 commits)
(run 'hg update' to get a working copy)
$ cat .hg/firefoxtrees
central 994ec05999daf04fb3c01a8cb0dea1458a7d4d3d
fx-team a4521c3750458afd82406ac87977b3fdc2fdc62a
inbound 388ff24b5456e83175491ae321bceb89aad2259f (no-eol)
+Local filesystem pull should retrieve tree tags
+
+ $ cd ..
+ $ hg init localpull
+ $ cd localpull
+ $ touch .hg/IS_FIREFOX_REPO
+ $ hg pull ../root/unified
+ pulling from ../root/unified
+ requesting all changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 8 changesets with 8 changes to 2 files (+1 heads)
+ updated firefox tree tag central
+ updated firefox tree tag fx-team
+ updated firefox tree tag inbound
+ (run 'hg heads' to see heads, 'hg merge' to merge)
+
+ $ cat .hg/firefoxtrees
+ central 994ec05999daf04fb3c01a8cb0dea1458a7d4d3d
+ fx-team a4521c3750458afd82406ac87977b3fdc2fdc62a
+ inbound 388ff24b5456e83175491ae321bceb89aad2259f (no-eol)
+
Serve firefoxtree tags from bookmarks
$ cd $TESTTMP/root/unified
$ cat > .hg/hgrc << EOF
> [firefoxtree]
> servetags = true
> servetagsfrombookmarks = true
> EOF