# HG changeset patch # User Manuel Jacob # Date 1554394050 -7200 # Node ID 3a2df812e1c7a7fed0ff50c436f04433830d0f61 # Parent 4077d6222cf1fb1407e41fd407b4c7b48d902929 pull: add --remote-hidden option and pass it through peer creation This option will allow to pull changesets that are hidden on the remote. This is useful when looking into a changeset’s evolution history, resolving evolution instability or mirroring a repository. The option is best effort and will only affect the pull when it can. The option will be ignored when it cannot be honored. Support for each type of peer is yet to be implemented. They currently all warn about lack of support. The warning code will get removed as peers gain support for this option. The option is still experimental, so we will have freedom to update the UI or implementation before it graduates out of experimental. Based on a changeset by Pierre-Yves David, which added the option. diff -r 4077d6222cf1 -r 3a2df812e1c7 hgext/narrow/narrowrepo.py --- a/hgext/narrow/narrowrepo.py Sat Apr 13 01:17:56 2019 +0200 +++ b/hgext/narrow/narrowrepo.py Thu Apr 04 18:07:30 2019 +0200 @@ -19,8 +19,8 @@ dirstate = super(narrowrepository, self)._makedirstate() return narrowdirstate.wrapdirstate(self, dirstate) - def peer(self, path=None): - peer = super(narrowrepository, self).peer(path=path) + def peer(self, *args, **kwds): + peer = super(narrowrepository, self).peer(*args, **kwds) peer._caps.add(wireprototypes.NARROWCAP) peer._caps.add(wireprototypes.ELLIPSESCAP) return peer diff -r 4077d6222cf1 -r 3a2df812e1c7 mercurial/bundlerepo.py --- a/mercurial/bundlerepo.py Sat Apr 13 01:17:56 2019 +0200 +++ b/mercurial/bundlerepo.py Thu Apr 04 18:07:30 2019 +0200 @@ -484,8 +484,8 @@ def cancopy(self): return False - def peer(self, path=None): - return bundlepeer(self, path=path) + def peer(self, path=None, remotehidden=False): + return bundlepeer(self, path=path, remotehidden=remotehidden) def getcwd(self): return encoding.getcwd() # always outside the repo diff -r 4077d6222cf1 -r 3a2df812e1c7 mercurial/commands.py --- a/mercurial/commands.py Sat Apr 13 01:17:56 2019 +0200 +++ b/mercurial/commands.py Thu Apr 04 18:07:30 2019 +0200 @@ -5405,6 +5405,12 @@ _(b'a specific branch you would like to pull'), _(b'BRANCH'), ), + ( + b'', + b'remote-hidden', + False, + _(b"include changesets hidden on the remote (EXPERIMENTAL)"), + ), ] + remoteopts, _(b'[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]...'), @@ -5442,6 +5448,14 @@ Specifying bookmark as ``.`` is equivalent to specifying the active bookmark's name. + .. container:: verbose + + One can use the `--remote-hidden` flag to pull changesets + hidden on the remote. This flag is "best effort", and will only + work if the server supports the feature and is configured to + allow the user to access hidden changesets. This option is + experimental and backwards compatibility is not garanteed. + Returns 0 on success, 1 if an update had unresolved files. """ @@ -5456,12 +5470,16 @@ for path in urlutil.get_pull_paths(repo, ui, sources): ui.status(_(b'pulling from %s\n') % urlutil.hidepassword(path.loc)) ui.flush() - other = hg.peer(repo, opts, path) + other = hg.peer(repo, opts, path, remotehidden=opts[b'remote_hidden']) update_conflict = None try: branches = (path.branch, opts.get(b'branch', [])) revs, checkout = hg.addbranchrevs( - repo, other, branches, opts.get(b'rev') + repo, + other, + branches, + opts.get(b'rev'), + remotehidden=opts[b'remote_hidden'], ) pullopargs = {} diff -r 4077d6222cf1 -r 3a2df812e1c7 mercurial/hg.py --- a/mercurial/hg.py Sat Apr 13 01:17:56 2019 +0200 +++ b/mercurial/hg.py Thu Apr 04 18:07:30 2019 +0200 @@ -65,10 +65,10 @@ sharedbookmarks = b'bookmarks' -def addbranchrevs(lrepo, other, branches, revs): +def addbranchrevs(lrepo, other, branches, revs, remotehidden=False): if util.safehasattr(other, 'peer'): # a courtesy to callers using a localrepo for other - peer = other.peer() + peer = other.peer(remotehidden=remotehidden) else: peer = other hashbranch, branches = branches @@ -242,7 +242,15 @@ return repo.filtered(b'visible') -def peer(uiorrepo, opts, path, create=False, intents=None, createopts=None): +def peer( + uiorrepo, + opts, + path, + create=False, + intents=None, + createopts=None, + remotehidden=False, +): '''return a repository peer for the specified path''' ui = getattr(uiorrepo, 'ui', uiorrepo) rui = remoteui(uiorrepo, opts) @@ -260,6 +268,7 @@ create, intents=intents, createopts=createopts, + remotehidden=remotehidden, ) _setup_repo_or_peer(rui, peer) else: @@ -274,7 +283,7 @@ intents=intents, createopts=createopts, ) - peer = repo.peer(path=peer_path) + peer = repo.peer(path=peer_path, remotehidden=remotehidden) return peer diff -r 4077d6222cf1 -r 3a2df812e1c7 mercurial/httppeer.py --- a/mercurial/httppeer.py Sat Apr 13 01:17:56 2019 +0200 +++ b/mercurial/httppeer.py Thu Apr 04 18:07:30 2019 +0200 @@ -381,8 +381,17 @@ class httppeer(wireprotov1peer.wirepeer): - def __init__(self, ui, path, url, opener, requestbuilder, caps): - super().__init__(ui, path=path) + def __init__( + self, ui, path, url, opener, requestbuilder, caps, remotehidden=False + ): + super().__init__(ui, path=path, remotehidden=remotehidden) + if remotehidden: + msg = _( + b"ignoring `--remote-hidden` request\n" + b"(access to hidden changeset for http peers not " + b"supported yet)\n" + ) + ui.warn(msg) self._url = url self._caps = caps self.limitedarguments = caps is not None and b'httppostargs' not in caps @@ -592,7 +601,9 @@ return respurl, info -def _make_peer(ui, path, opener=None, requestbuilder=urlreq.request): +def _make_peer( + ui, path, opener=None, requestbuilder=urlreq.request, remotehidden=False +): """Construct an appropriate HTTP peer instance. ``opener`` is an ``url.opener`` that should be used to establish @@ -615,11 +626,19 @@ respurl, info = performhandshake(ui, url, opener, requestbuilder) return httppeer( - ui, path, respurl, opener, requestbuilder, info[b'v1capabilities'] + ui, + path, + respurl, + opener, + requestbuilder, + info[b'v1capabilities'], + remotehidden=remotehidden, ) -def make_peer(ui, path, create, intents=None, createopts=None): +def make_peer( + ui, path, create, intents=None, createopts=None, remotehidden=False +): if create: raise error.Abort(_(b'cannot create new http repository')) try: @@ -628,7 +647,7 @@ _(b'Python support for SSL and HTTPS is not installed') ) - inst = _make_peer(ui, path) + inst = _make_peer(ui, path, remotehidden=remotehidden) return inst except error.RepoError as httpexception: diff -r 4077d6222cf1 -r 3a2df812e1c7 mercurial/interfaces/repository.py --- a/mercurial/interfaces/repository.py Sat Apr 13 01:17:56 2019 +0200 +++ b/mercurial/interfaces/repository.py Thu Apr 04 18:07:30 2019 +0200 @@ -388,7 +388,7 @@ limitedarguments = False - def __init__(self, ui, path=None): + def __init__(self, ui, path=None, remotehidden=False): self.ui = ui self.path = path diff -r 4077d6222cf1 -r 3a2df812e1c7 mercurial/localrepo.py --- a/mercurial/localrepo.py Sat Apr 13 01:17:56 2019 +0200 +++ b/mercurial/localrepo.py Thu Apr 04 18:07:30 2019 +0200 @@ -307,8 +307,18 @@ class localpeer(repository.peer): '''peer for a local repo; reflects only the most recent API''' - def __init__(self, repo, caps=None, path=None): - super(localpeer, self).__init__(repo.ui, path=path) + def __init__(self, repo, caps=None, path=None, remotehidden=False): + super(localpeer, self).__init__( + repo.ui, path=path, remotehidden=remotehidden + ) + + if remotehidden: + msg = _( + b"ignoring `--remote-hidden` request\n" + b"(access to hidden changeset for %r not " + b"supported yet)\n" + ) % type(self) + self.ui.warn(msg) if caps is None: caps = moderncaps.copy() @@ -455,8 +465,10 @@ """peer extension which implements legacy methods too; used for tests with restricted capabilities""" - def __init__(self, repo, path=None): - super(locallegacypeer, self).__init__(repo, caps=legacycaps, path=path) + def __init__(self, repo, path=None, remotehidden=False): + super(locallegacypeer, self).__init__( + repo, caps=legacycaps, path=path, remotehidden=remotehidden + ) # Begin of baselegacywirecommands interface. @@ -1657,8 +1669,10 @@ parts.pop() return False - def peer(self, path=None): - return localpeer(self, path=path) # not cached to avoid reference cycle + def peer(self, path=None, remotehidden=False): + return localpeer( + self, path=path, remotehidden=remotehidden + ) # not cached to avoid reference cycle def unfiltered(self): """Return unfiltered version of the repository diff -r 4077d6222cf1 -r 3a2df812e1c7 mercurial/sshpeer.py --- a/mercurial/sshpeer.py Sat Apr 13 01:17:56 2019 +0200 +++ b/mercurial/sshpeer.py Thu Apr 04 18:07:30 2019 +0200 @@ -372,7 +372,16 @@ class sshv1peer(wireprotov1peer.wirepeer): def __init__( - self, ui, path, proc, stdin, stdout, stderr, caps, autoreadstderr=True + self, + ui, + path, + proc, + stdin, + stdout, + stderr, + caps, + autoreadstderr=True, + remotehidden=False, ): """Create a peer from an existing SSH connection. @@ -383,7 +392,14 @@ ``autoreadstderr`` denotes whether to automatically read from stderr and to forward its output. """ - super().__init__(ui, path=path) + super().__init__(ui, path=path, remotehidden=remotehidden) + if remotehidden: + msg = _( + b"ignoring `--remote-hidden` request\n" + b"(access to hidden changeset for ssh peers not supported " + b"yet)\n" + ) + ui.warn(msg) # self._subprocess is unused. Keeping a handle on the process # holds a reference and prevents it from being garbage collected. self._subprocess = proc @@ -568,7 +584,16 @@ self._readerr() -def _make_peer(ui, path, proc, stdin, stdout, stderr, autoreadstderr=True): +def _make_peer( + ui, + path, + proc, + stdin, + stdout, + stderr, + autoreadstderr=True, + remotehidden=False, +): """Make a peer instance from existing pipes. ``path`` and ``proc`` are stored on the eventual peer instance and may @@ -598,6 +623,7 @@ stderr, caps, autoreadstderr=autoreadstderr, + remotehidden=remotehidden, ) else: _cleanuppipes(ui, stdout, stdin, stderr, warn=None) @@ -606,7 +632,9 @@ ) -def make_peer(ui, path, create, intents=None, createopts=None): +def make_peer( + ui, path, create, intents=None, createopts=None, remotehidden=False +): """Create an SSH peer. The returned object conforms to the ``wireprotov1peer.wirepeer`` interface. @@ -658,7 +686,9 @@ ui, sshcmd, args, remotecmd, remotepath, sshenv ) - peer = _make_peer(ui, path, proc, stdin, stdout, stderr) + peer = _make_peer( + ui, path, proc, stdin, stdout, stderr, remotehidden=remotehidden + ) # Finally, if supported by the server, notify it about our own # capabilities. diff -r 4077d6222cf1 -r 3a2df812e1c7 mercurial/statichttprepo.py --- a/mercurial/statichttprepo.py Sat Apr 13 01:17:56 2019 +0200 +++ b/mercurial/statichttprepo.py Thu Apr 04 18:07:30 2019 +0200 @@ -237,8 +237,8 @@ def local(self): return False - def peer(self, path=None): - return statichttppeer(self, path=path) + def peer(self, path=None, remotehidden=False): + return statichttppeer(self, path=path, remotehidden=remotehidden) def wlock(self, wait=True): raise error.LockUnavailable( @@ -260,8 +260,12 @@ pass # statichttprepository are read only -def make_peer(ui, path, create, intents=None, createopts=None): +def make_peer( + ui, path, create, intents=None, createopts=None, remotehidden=False +): if create: raise error.Abort(_(b'cannot create new static-http repository')) url = path.loc[7:] - return statichttprepository(ui, url).peer(path=path) + return statichttprepository(ui, url).peer( + path=path, remotehidden=remotehidden + ) diff -r 4077d6222cf1 -r 3a2df812e1c7 mercurial/unionrepo.py --- a/mercurial/unionrepo.py Sat Apr 13 01:17:56 2019 +0200 +++ b/mercurial/unionrepo.py Thu Apr 04 18:07:30 2019 +0200 @@ -270,8 +270,8 @@ def cancopy(self): return False - def peer(self, path=None): - return unionpeer(self, path=None) + def peer(self, path=None, remotehidden=False): + return unionpeer(self, path=None, remotehidden=remotehidden) def getcwd(self): return encoding.getcwd() # always outside the repo diff -r 4077d6222cf1 -r 3a2df812e1c7 tests/notcapable --- a/tests/notcapable Sat Apr 13 01:17:56 2019 +0200 +++ b/tests/notcapable Thu Apr 04 18:07:30 2019 +0200 @@ -15,10 +15,10 @@ if name in b'$CAP'.split(b' '): return False return orig(self, name, *args, **kwargs) -def wrappeer(orig, self, path=None): +def wrappeer(orig, self, *args, **kwargs): # Since we're disabling some newer features, we need to make sure local # repos add in the legacy features again. - return localrepo.locallegacypeer(self, path=path) + return localrepo.locallegacypeer(self, *args, **kwargs) EOF echo '[extensions]' >> $HGRCPATH diff -r 4077d6222cf1 -r 3a2df812e1c7 tests/test-completion.t --- a/tests/test-completion.t Sat Apr 13 01:17:56 2019 +0200 +++ b/tests/test-completion.t Thu Apr 04 18:07:30 2019 +0200 @@ -366,7 +366,7 @@ parents: rev, style, template paths: template phase: public, draft, secret, force, rev - pull: update, force, confirm, rev, bookmark, branch, ssh, remotecmd, insecure + pull: update, force, confirm, rev, bookmark, branch, remote-hidden, ssh, remotecmd, insecure purge: abort-on-err, all, ignored, dirs, files, print, print0, confirm, include, exclude push: force, rev, bookmark, all-bookmarks, branch, new-branch, pushvars, publish, ssh, remotecmd, insecure recover: verify