Re: [PATCH 7 of 7] hgweb: convert _siblings to a factory function of mappinggenerator
On Sat, 14 Apr 2018 21:49:17 +0900 Yuya Nishiharawrote: > # HG changeset patch > # User Yuya Nishihara > # Date 1522594234 -32400 > # Sun Apr 01 23:50:34 2018 +0900 > # Node ID fe959b32685068231cad8ef26387c7c16fe0961a > # Parent 8e479b1d96bf94e81f76c78605c16b2864b219a5 > hgweb: convert _siblings to a factory function of mappinggenerator Queued, thanks! ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
D3380: wireprotov2: establish a type for representing command response
indygreg created this revision. Herald added a subscriber: mercurial-devel. Herald added a reviewer: hg-reviewers. REVISION SUMMARY It will be desirable to have a higher-level type for representing command responses. This will allow us to do nicer things. For now, the instance encapsulates existing logic. It is still a bit primitive. But we're slowly making things better. Version 1 protocols have a wrapping layer that decodes the raw string data into a data structure and that data structure is sent to the future. Version 2 doesn't yet have this layer and the future is receiving the raw wire response. Hence why debugcommands needed to be taught about the response type. REPOSITORY rHG Mercurial REVISION DETAIL https://phab.mercurial-scm.org/D3380 AFFECTED FILES mercurial/debugcommands.py mercurial/wireprotov2peer.py CHANGE DETAILS diff --git a/mercurial/wireprotov2peer.py b/mercurial/wireprotov2peer.py --- a/mercurial/wireprotov2peer.py +++ b/mercurial/wireprotov2peer.py @@ -17,6 +17,26 @@ wireprotoframing, ) +class commandresponse(object): +"""Represents the response to a command request.""" + +def __init__(self, requestid, command): +self.requestid = requestid +self.command = command + +self.cbor = False +self.b = util.bytesio() + +def cborobjects(self): +"""Obtain decoded CBOR objects from this response.""" +size = self.b.tell() +self.b.seek(0) + +decoder = cbor.CBORDecoder(self.b) + +while self.b.tell() < size: +yield decoder.decode() + class clienthandler(object): """Object to handle higher-level client activities. @@ -48,10 +68,7 @@ rid = request.requestid self._requests[rid] = request self._futures[rid] = f -self._responses[rid] = { -'cbor': False, -'b': util.bytesio(), -} +self._responses[rid] = commandresponse(rid, command) return iter(()) @@ -104,28 +121,13 @@ response = self._responses[frame.requestid] if action == 'responsedata': -response['b'].write(meta['data']) +response.b.write(meta['data']) if meta['cbor']: -response['cbor'] = True +response.cbor = True if meta['eos']: -if meta['cbor']: -# If CBOR, decode every object. -b = response['b'] - -size = b.tell() -b.seek(0) - -decoder = cbor.CBORDecoder(b) - -result = [] -while b.tell() < size: -result.append(decoder.decode()) -else: -result = [response['b'].getvalue()] - -self._futures[frame.requestid].set_result(result) +self._futures[frame.requestid].set_result(response) del self._requests[frame.requestid] del self._futures[frame.requestid] diff --git a/mercurial/debugcommands.py b/mercurial/debugcommands.py --- a/mercurial/debugcommands.py +++ b/mercurial/debugcommands.py @@ -83,6 +83,7 @@ vfs as vfsmod, wireprotoframing, wireprotoserver, +wireprotov2peer, ) from .utils import ( dateutil, @@ -3012,7 +3013,16 @@ with peer.commandexecutor() as e: res = e.callcommand(command, args).result() -ui.status(_('response: %s\n') % stringutil.pprint(res)) +if isinstance(res, wireprotov2peer.commandresponse): +if res.cbor: +val = list(res.cborobjects()) +else: +val = [res.b.getvalue()] + +ui.status(_('response: %s\n') % stringutil.pprint(val)) + +else: +ui.status(_('response: %s\n') % stringutil.pprint(res)) elif action == 'batchbegin': if batchedcommands is not None: To: indygreg, #hg-reviewers Cc: mercurial-devel ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
D3387: wireprotov2: remove support for sending bytes response
indygreg created this revision. Herald added a subscriber: mercurial-devel. Herald added a reviewer: hg-reviewers. REVISION SUMMARY We recently declared that all responses must be CBOR. So remove support for sending a type that isn't CBOR data. REPOSITORY rHG Mercurial REVISION DETAIL https://phab.mercurial-scm.org/D3387 AFFECTED FILES mercurial/wireprotov2server.py CHANGE DETAILS diff --git a/mercurial/wireprotov2server.py b/mercurial/wireprotov2server.py --- a/mercurial/wireprotov2server.py +++ b/mercurial/wireprotov2server.py @@ -301,11 +301,7 @@ res.status = b'200 OK' res.headers[b'Content-Type'] = FRAMINGTYPE -if isinstance(rsp, wireprototypes.bytesresponse): -action, meta = reactor.oncommandresponseready(outstream, - command['requestid'], - rsp.data) -elif isinstance(rsp, wireprototypes.cborresponse): +if isinstance(rsp, wireprototypes.cborresponse): encoded = cbor.dumps(rsp.value, canonical=True) action, meta = reactor.oncommandresponseready(outstream, command['requestid'], To: indygreg, #hg-reviewers Cc: mercurial-devel ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
D3382: wireprotov2: define response data as CBOR
indygreg created this revision. Herald added a subscriber: mercurial-devel. Herald added a reviewer: hg-reviewers. REVISION SUMMARY Previously, response data was defined as a stream of bytes. We had the option to declare it as CBOR using a frame flag. We've converged all wire protocol commands exposed on version 2 to CBOR. I think consistency is important. The overhead to encoding things with CBOR is minimal. Even a very large bytestring can be efficiently encoded using an indefinite length bytestring. Now, there are limitations with consumers not being able to efficiently stream large CBOR values. But these feel like solvable problems. This commit removes the "is CBOR" frame flag from command response frames and defines the frame as always consisting of a stream of CBOR values. The framing protocol media type has been bumped to reflect this BC change. REPOSITORY rHG Mercurial REVISION DETAIL https://phab.mercurial-scm.org/D3382 AFFECTED FILES mercurial/debugcommands.py mercurial/help/internals/wireprotocol.txt mercurial/wireprotoframing.py mercurial/wireprotov2peer.py mercurial/wireprotov2server.py tests/test-http-api-httpv2.t tests/test-http-protocol.t tests/test-wireproto-command-branchmap.t tests/test-wireproto-command-capabilities.t tests/test-wireproto-command-heads.t tests/test-wireproto-command-known.t tests/test-wireproto-command-listkeys.t tests/test-wireproto-command-lookup.t tests/test-wireproto-command-pushkey.t tests/wireprotohelpers.sh CHANGE DETAILS diff --git a/tests/wireprotohelpers.sh b/tests/wireprotohelpers.sh --- a/tests/wireprotohelpers.sh +++ b/tests/wireprotohelpers.sh @@ -1,5 +1,5 @@ HTTPV2=exp-http-v2-0001 -MEDIATYPE=application/mercurial-exp-framing-0003 +MEDIATYPE=application/mercurial-exp-framing-0004 sendhttpraw() { hg --verbose debugwireproto --peer raw http://$LOCALIP:$HGPORT/ @@ -26,16 +26,16 @@ @wireproto.wireprotocommand('customreadonly', permission='pull', transportpolicy=wireproto.POLICY_V2_ONLY) def customreadonlyv2(repo, proto): -return wireprototypes.bytesresponse(b'customreadonly bytes response') +return wireprototypes.cborresponse(b'customreadonly bytes response') @wireproto.wireprotocommand('customreadwrite', permission='push') def customreadwrite(repo, proto): return wireprototypes.bytesresponse(b'customreadwrite bytes response') @wireproto.wireprotocommand('customreadwrite', permission='push', transportpolicy=wireproto.POLICY_V2_ONLY) def customreadwritev2(repo, proto): -return wireprototypes.bytesresponse(b'customreadwrite bytes response') +return wireprototypes.cborresponse(b'customreadwrite bytes response') EOF cat >> $HGRCPATH << EOF diff --git a/tests/test-wireproto-command-pushkey.t b/tests/test-wireproto-command-pushkey.t --- a/tests/test-wireproto-command-pushkey.t +++ b/tests/test-wireproto-command-pushkey.t @@ -32,8 +32,8 @@ sending pushkey command s> *\r\n (glob) s> Accept-Encoding: identity\r\n - s> accept: application/mercurial-exp-framing-0003\r\n - s> content-type: application/mercurial-exp-framing-0003\r\n + s> accept: application/mercurial-exp-framing-0004\r\n + s> content-type: application/mercurial-exp-framing-0004\r\n s> content-length: 105\r\n s> host: $LOCALIP:$HGPORT\r\n (glob) s> user-agent: Mercurial debugwireproto\r\n @@ -43,14 +43,14 @@ s> HTTP/1.1 200 OK\r\n s> Server: testing stub value\r\n s> Date: $HTTP_DATE$\r\n - s> Content-Type: application/mercurial-exp-framing-0003\r\n + s> Content-Type: application/mercurial-exp-framing-0004\r\n s> Transfer-Encoding: chunked\r\n s> \r\n s> 9\r\n - s> *\x00\x01\x00\x02\x01F (glob) + s> \x01\x00\x00\x01\x00\x02\x01B s> \xf5 s> \r\n - received frame(size=*; request=1; stream=2; streamflags=stream-begin; type=bytes-response; flags=eos|cbor) (glob) + received frame(size=1; request=1; stream=2; streamflags=stream-begin; type=bytes-response; flags=eos) s> 0\r\n s> \r\n response: True @@ -63,8 +63,8 @@ sending listkeys command s> POST /api/exp-http-v2-0001/ro/listkeys HTTP/1.1\r\n s> Accept-Encoding: identity\r\n - s> accept: application/mercurial-exp-framing-0003\r\n - s> content-type: application/mercurial-exp-framing-0003\r\n + s> accept: application/mercurial-exp-framing-0004\r\n + s> content-type: application/mercurial-exp-framing-0004\r\n s> content-length: 49\r\n s> host: $LOCALIP:$HGPORT\r\n (glob) s> user-agent: Mercurial debugwireproto\r\n @@ -74,14 +74,14 @@ s> HTTP/1.1 200 OK\r\n s> Server: testing stub value\r\n s> Date: $HTTP_DATE$\r\n - s> Content-Type: application/mercurial-exp-framing-0003\r\n + s> Content-Type: application/mercurial-exp-framing-0004\r\n s>
D3303: cborutil: implement support for streaming encoding, bytestring decoding
indygreg updated this revision to Diff 8301. REPOSITORY rHG Mercurial CHANGES SINCE LAST UPDATE https://phab.mercurial-scm.org/D3303?vs=8152=8301 REVISION DETAIL https://phab.mercurial-scm.org/D3303 AFFECTED FILES contrib/import-checker.py mercurial/utils/cborutil.py tests/test-cbor.py CHANGE DETAILS diff --git a/tests/test-cbor.py b/tests/test-cbor.py new file mode 100644 --- /dev/null +++ b/tests/test-cbor.py @@ -0,0 +1,211 @@ +from __future__ import absolute_import + +import io +import unittest + +from mercurial.thirdparty import ( +cbor, +) +from mercurial.utils import ( +cborutil, +) + +def loadit(it): +return cbor.loads(b''.join(it)) + +class BytestringTests(unittest.TestCase): +def testsimple(self): +self.assertEqual( +list(cborutil.streamencode(b'foobar')), +[b'\x46', b'foobar']) + +self.assertEqual( +loadit(cborutil.streamencode(b'foobar')), +b'foobar') + +def testlong(self): +source = b'x' * 1048576 + +self.assertEqual(loadit(cborutil.streamencode(source)), source) + +def testfromiter(self): +# This is the example from RFC 7049 Section 2.2.2. +source = [b'\xaa\xbb\xcc\xdd', b'\xee\xff\x99'] + +self.assertEqual( +list(cborutil.streamencodebytestringfromiter(source)), +[ +b'\x5f', +b'\x44', +b'\xaa\xbb\xcc\xdd', +b'\x43', +b'\xee\xff\x99', +b'\xff', +]) + +self.assertEqual( +loadit(cborutil.streamencodebytestringfromiter(source)), +b''.join(source)) + +def testfromiterlarge(self): +source = [b'a' * 16, b'b' * 128, b'c' * 1024, b'd' * 1048576] + +self.assertEqual( +loadit(cborutil.streamencodebytestringfromiter(source)), +b''.join(source)) + +def testindefinite(self): +source = b'\x00\x01\x02\x03' + b'\xff' * 16384 + +it = cborutil.streamencodeindefinitebytestring(source, chunksize=2) + +self.assertEqual(next(it), b'\x5f') +self.assertEqual(next(it), b'\x42') +self.assertEqual(next(it), b'\x00\x01') +self.assertEqual(next(it), b'\x42') +self.assertEqual(next(it), b'\x02\x03') +self.assertEqual(next(it), b'\x42') +self.assertEqual(next(it), b'\xff\xff') + +dest = b''.join(cborutil.streamencodeindefinitebytestring( +source, chunksize=42)) +self.assertEqual(cbor.loads(dest), b''.join(source)) + +def testreadtoiter(self): +source = io.BytesIO(b'\x5f\x44\xaa\xbb\xcc\xdd\x43\xee\xff\x99\xff') + +it = cborutil.readindefinitebytestringtoiter(source) +self.assertEqual(next(it), b'\xaa\xbb\xcc\xdd') +self.assertEqual(next(it), b'\xee\xff\x99') + +with self.assertRaises(StopIteration): +next(it) + +class IntTests(unittest.TestCase): +def testsmall(self): +self.assertEqual(list(cborutil.streamencode(0)), [b'\x00']) +self.assertEqual(list(cborutil.streamencode(1)), [b'\x01']) +self.assertEqual(list(cborutil.streamencode(2)), [b'\x02']) +self.assertEqual(list(cborutil.streamencode(3)), [b'\x03']) +self.assertEqual(list(cborutil.streamencode(4)), [b'\x04']) + +def testnegativesmall(self): +self.assertEqual(list(cborutil.streamencode(-1)), [b'\x20']) +self.assertEqual(list(cborutil.streamencode(-2)), [b'\x21']) +self.assertEqual(list(cborutil.streamencode(-3)), [b'\x22']) +self.assertEqual(list(cborutil.streamencode(-4)), [b'\x23']) +self.assertEqual(list(cborutil.streamencode(-5)), [b'\x24']) + +def testrange(self): +for i in range(-7, 7, 10): +self.assertEqual( +b''.join(cborutil.streamencode(i)), +cbor.dumps(i)) + +class ArrayTests(unittest.TestCase): +def testempty(self): +self.assertEqual(list(cborutil.streamencode([])), [b'\x80']) +self.assertEqual(loadit(cborutil.streamencode([])), []) + +def testbasic(self): +source = [b'foo', b'bar', 1, -10] + +self.assertEqual(list(cborutil.streamencode(source)), [ +b'\x84', b'\x43', b'foo', b'\x43', b'bar', b'\x01', b'\x29']) + +def testemptyfromiter(self): +self.assertEqual(b''.join(cborutil.streamencodearrayfromiter([])), + b'\x9f\xff') + +def testfromiter1(self): +source = [b'foo'] + +self.assertEqual(list(cborutil.streamencodearrayfromiter(source)), [ +b'\x9f', +b'\x43', b'foo', +b'\xff', +]) + + +dest = b''.join(cborutil.streamencodearrayfromiter(source)) +self.assertEqual(cbor.loads(dest), source) + +def testtuple(self): +source = (b'foo', None, 42) + +self.assertEqual(cbor.loads(b''.join(cborutil.streamencode(source))), +
D3377: hg: pass command intents to repo/peer creation (API)
indygreg created this revision. Herald added a subscriber: mercurial-devel. Herald added a reviewer: hg-reviewers. REVISION SUMMARY The previous commit introduced a mechanism to declare command intents. This commit changes the repository and peer instantiation mechanism so the intents are passed down to each repository and peer type so they can do with them whatever they please. Currently, nobody does anything with any intent. REPOSITORY rHG Mercurial REVISION DETAIL https://phab.mercurial-scm.org/D3377 AFFECTED FILES hgext/schemes.py mercurial/bundlerepo.py mercurial/dispatch.py mercurial/hg.py mercurial/httppeer.py mercurial/localrepo.py mercurial/sshpeer.py mercurial/statichttprepo.py mercurial/unionrepo.py CHANGE DETAILS diff --git a/mercurial/unionrepo.py b/mercurial/unionrepo.py --- a/mercurial/unionrepo.py +++ b/mercurial/unionrepo.py @@ -231,7 +231,7 @@ def getcwd(self): return pycompat.getcwd() # always outside the repo -def instance(ui, path, create): +def instance(ui, path, create, intents=None): if create: raise error.Abort(_('cannot create new union repository')) parentpath = ui.config("bundle", "mainreporoot") diff --git a/mercurial/statichttprepo.py b/mercurial/statichttprepo.py --- a/mercurial/statichttprepo.py +++ b/mercurial/statichttprepo.py @@ -215,7 +215,7 @@ def _writecaches(self): pass # statichttprepository are read only -def instance(ui, path, create): +def instance(ui, path, create, intents=None): if create: raise error.Abort(_('cannot create new static-http repository')) return statichttprepository(ui, path[7:]) diff --git a/mercurial/sshpeer.py b/mercurial/sshpeer.py --- a/mercurial/sshpeer.py +++ b/mercurial/sshpeer.py @@ -587,7 +587,7 @@ raise error.RepoError(_('unknown version of SSH protocol: %s') % protoname) -def instance(ui, path, create): +def instance(ui, path, create, intents=None): """Create an SSH peer. The returned object conforms to the ``wireprotov1peer.wirepeer`` interface. diff --git a/mercurial/localrepo.py b/mercurial/localrepo.py --- a/mercurial/localrepo.py +++ b/mercurial/localrepo.py @@ -413,7 +413,7 @@ 'bisect.state', } -def __init__(self, baseui, path, create=False): +def __init__(self, baseui, path, create=False, intents=None): self.requirements = set() self.filtername = None # wvfs: rooted at the repository root, used to access the working copy @@ -2332,8 +2332,9 @@ assert name.startswith('journal') return os.path.join(base, name.replace('journal', 'undo', 1)) -def instance(ui, path, create): -return localrepository(ui, util.urllocalpath(path), create) +def instance(ui, path, create, intents=None): +return localrepository(ui, util.urllocalpath(path), create, + intents=intents) def islocal(path): return True diff --git a/mercurial/httppeer.py b/mercurial/httppeer.py --- a/mercurial/httppeer.py +++ b/mercurial/httppeer.py @@ -990,7 +990,7 @@ return httppeer(ui, path, respurl, opener, requestbuilder, info['v1capabilities']) -def instance(ui, path, create): +def instance(ui, path, create, intents=None): if create: raise error.Abort(_('cannot create new http repository')) try: diff --git a/mercurial/hg.py b/mercurial/hg.py --- a/mercurial/hg.py +++ b/mercurial/hg.py @@ -157,9 +157,10 @@ # a list of (ui, repo) functions called for wire peer initialization wirepeersetupfuncs = [] -def _peerorrepo(ui, path, create=False, presetupfuncs=None): +def _peerorrepo(ui, path, create=False, presetupfuncs=None, +intents=None): """return a repository object for the specified path""" -obj = _peerlookup(path).instance(ui, path, create) +obj = _peerlookup(path).instance(ui, path, create, intents=intents) ui = getattr(obj, "ui", ui) for f in presetupfuncs or []: f(ui, obj) @@ -172,19 +173,20 @@ f(ui, obj) return obj -def repository(ui, path='', create=False, presetupfuncs=None): +def repository(ui, path='', create=False, presetupfuncs=None, intents=None): """return a repository object for the specified path""" -peer = _peerorrepo(ui, path, create, presetupfuncs=presetupfuncs) +peer = _peerorrepo(ui, path, create, presetupfuncs=presetupfuncs, + intents=intents) repo = peer.local() if not repo: raise error.Abort(_("repository '%s' is not local") % (path or peer.url())) return repo.filtered('visible') -def peer(uiorrepo, opts, path, create=False): +def peer(uiorrepo, opts, path, create=False, intents=None): '''return a repository peer for the specified path''' rui = remoteui(uiorrepo, opts) -return _peerorrepo(rui, path, create).peer() +return _peerorrepo(rui, path, create,
D3384: wireprotov2: change frame type and name for command response
indygreg created this revision. Herald added a subscriber: mercurial-devel. Herald added a reviewer: hg-reviewers. REVISION SUMMARY There was hole at frame type value 3. And the frame is better named as a command response. REPOSITORY rHG Mercurial REVISION DETAIL https://phab.mercurial-scm.org/D3384 AFFECTED FILES mercurial/help/internals/wireprotocol.txt mercurial/wireprotoframing.py mercurial/wireprotov2server.py tests/test-http-api-httpv2.t tests/test-http-protocol.t tests/test-wireproto-clientreactor.py tests/test-wireproto-command-branchmap.t tests/test-wireproto-command-capabilities.t tests/test-wireproto-command-heads.t tests/test-wireproto-command-known.t tests/test-wireproto-command-listkeys.t tests/test-wireproto-command-lookup.t tests/test-wireproto-command-pushkey.t tests/test-wireproto-serverreactor.py CHANGE DETAILS diff --git a/tests/test-wireproto-serverreactor.py b/tests/test-wireproto-serverreactor.py --- a/tests/test-wireproto-serverreactor.py +++ b/tests/test-wireproto-serverreactor.py @@ -211,19 +211,19 @@ results.append(self._sendsingleframe( reactor, ffs(b'1 1 stream-begin command-request new ' b"cbor:{b'name': b'command'}"))) -result = reactor.onbytesresponseready(outstream, 1, b'response1') +result = reactor.oncommandresponseready(outstream, 1, b'response1') self.assertaction(result, b'sendframes') list(result[1][b'framegen']) results.append(self._sendsingleframe( reactor, ffs(b'1 1 stream-begin command-request new ' b"cbor:{b'name': b'command'}"))) -result = reactor.onbytesresponseready(outstream, 1, b'response2') +result = reactor.oncommandresponseready(outstream, 1, b'response2') self.assertaction(result, b'sendframes') list(result[1][b'framegen']) results.append(self._sendsingleframe( reactor, ffs(b'1 1 stream-begin command-request new ' b"cbor:{b'name': b'command'}"))) -result = reactor.onbytesresponseready(outstream, 1, b'response3') +result = reactor.oncommandresponseready(outstream, 1, b'response3') self.assertaction(result, b'sendframes') list(result[1][b'framegen']) @@ -347,10 +347,10 @@ list(sendcommandframes(reactor, instream, 1, b'mycommand', {})) outstream = reactor.makeoutputstream() -result = reactor.onbytesresponseready(outstream, 1, b'response') +result = reactor.oncommandresponseready(outstream, 1, b'response') self.assertaction(result, b'sendframes') self.assertframesequal(result[1][b'framegen'], [ -b'1 2 stream-begin bytes-response eos response', +b'1 2 stream-begin command-response eos response', ]) def testmultiframeresponse(self): @@ -363,11 +363,11 @@ list(sendcommandframes(reactor, instream, 1, b'mycommand', {})) outstream = reactor.makeoutputstream() -result = reactor.onbytesresponseready(outstream, 1, first + second) +result = reactor.oncommandresponseready(outstream, 1, first + second) self.assertaction(result, b'sendframes') self.assertframesequal(result[1][b'framegen'], [ -b'1 2 stream-begin bytes-response continuation %s' % first, -b'1 2 0 bytes-response eos %s' % second, +b'1 2 stream-begin command-response continuation %s' % first, +b'1 2 0 command-response eos %s' % second, ]) def testapplicationerror(self): @@ -392,12 +392,12 @@ self.assertaction(results[0], b'runcommand') outstream = reactor.makeoutputstream() -result = reactor.onbytesresponseready(outstream, 1, b'response') +result = reactor.oncommandresponseready(outstream, 1, b'response') self.assertaction(result, b'noop') result = reactor.oninputeof() self.assertaction(result, b'sendframes') self.assertframesequal(result[1][b'framegen'], [ -b'1 2 stream-begin bytes-response eos response', +b'1 2 stream-begin command-response eos response', ]) def testmultiplecommanddeferresponse(self): @@ -407,15 +407,15 @@ list(sendcommandframes(reactor, instream, 3, b'command2', {})) outstream = reactor.makeoutputstream() -result = reactor.onbytesresponseready(outstream, 1, b'response1') +result = reactor.oncommandresponseready(outstream, 1, b'response1') self.assertaction(result, b'noop') -result = reactor.onbytesresponseready(outstream, 3, b'response2') +result = reactor.oncommandresponseready(outstream, 3, b'response2') self.assertaction(result, b'noop') result = reactor.oninputeof() self.assertaction(result, b'sendframes') self.assertframesequal(result[1][b'framegen'], [ -b'1 2 stream-begin
D3383: wireprotov2: change frame type value for command data
indygreg created this revision. Herald added a subscriber: mercurial-devel. Herald added a reviewer: hg-reviewers. REVISION SUMMARY When we dropped the dedicated command argument frame type, this left a hole in our frame type numbering. Let's start plugging that hole. The command data frame is now type value 2 instead of 3. There was limited test fallout because a) we do a good job of using the constants to refer to frame types b) not many tests are sending command data frames. Bumping the media type will be performed in a later commit, once all type value adjustment has been performed. REPOSITORY rHG Mercurial REVISION DETAIL https://phab.mercurial-scm.org/D3383 AFFECTED FILES mercurial/help/internals/wireprotocol.txt mercurial/wireprotoframing.py tests/test-wireproto-serverreactor.py CHANGE DETAILS diff --git a/tests/test-wireproto-serverreactor.py b/tests/test-wireproto-serverreactor.py --- a/tests/test-wireproto-serverreactor.py +++ b/tests/test-wireproto-serverreactor.py @@ -185,7 +185,7 @@ ffs(b'1 1 stream-begin command-data 0 ignored')) self.assertaction(result, b'error') self.assertEqual(result[1], { -b'message': b'expected command request frame; got 3', +b'message': b'expected command request frame; got 2', }) def testunexpectedcommanddatareceiving(self): diff --git a/mercurial/wireprotoframing.py b/mercurial/wireprotoframing.py --- a/mercurial/wireprotoframing.py +++ b/mercurial/wireprotoframing.py @@ -42,7 +42,7 @@ } FRAME_TYPE_COMMAND_REQUEST = 0x01 -FRAME_TYPE_COMMAND_DATA = 0x03 +FRAME_TYPE_COMMAND_DATA = 0x02 FRAME_TYPE_BYTES_RESPONSE = 0x04 FRAME_TYPE_ERROR_RESPONSE = 0x05 FRAME_TYPE_TEXT_OUTPUT = 0x06 diff --git a/mercurial/help/internals/wireprotocol.txt b/mercurial/help/internals/wireprotocol.txt --- a/mercurial/help/internals/wireprotocol.txt +++ b/mercurial/help/internals/wireprotocol.txt @@ -638,10 +638,10 @@ ``0x01`` or ``0x02`` MUST be set to indicate this frame's role in a series of command request frames. -If command data frames are to be sent, ``0x10`` MUST be set on ALL +If command data frames are to be sent, ``0x08`` MUST be set on ALL command request frames. -Command Data (``0x03``) +Command Data (``0x02``) --- This frame contains raw data for a command. To: indygreg, #hg-reviewers Cc: mercurial-devel ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
D3379: wireprotov2: move response handling out of httppeer
indygreg created this revision. Herald added a subscriber: mercurial-devel. Herald added a reviewer: hg-reviewers. REVISION SUMMARY And fix some bugs while we're here. The code for processing response data from the unified framing protocol is mostly peer agnostic. The peer-specific bits are the configuration of the client reactor and how I/O is performed. I initially implemented things in httppeer for expediency. This commit establishes a module for holding the peer API level code for the framing based protocol. Inside this module we have a class to help coordinate higher-level activities, such as managing response object. The client handler bits could be rolled into clientreactor. However, I want clientreactor to be sans I/O and I want it to only be concerned with protocol-level details, not higher-level concepts like how protocol events are converted into peer API concepts. I want clientreactor to receive a frame and then tell the caller what should probably be done about it. If we start putting things like future resolution into clientreactor, we'll constrain how the protocol can be used (e.g. by requiring futures). The new code is loosely based on what was in httppeer before. I changed things a bit around response handling. We now buffer the entire response "body" and then handle it as one atomic unit. This fixed a bug around decoding CBOR data that spanned multiple frames. I also fixed an off-by-one bug where we failed to read a single byte CBOR value at the end of the stream. That's why tests have changed. The new state of httppeer is much cleaner. It is largely agnostic about framing protocol implementation details. That's how it should be: the framing protocol is designed to be largely transport agnostic. We want peers merely putting bytes on the wire and telling the framing protocol where to read response data from. There's still a bit of work to be done here, especially for representing responses. But at least we're a step closer to having a higher-level peer interface that can be plugged into the SSH peer someday. I initially added this class to wireprotoframing. However, we'll eventually need version 2 specific functions to convert CBOR responses into data structures expected by the code calling commands. This needs to live somewhere. Since that code would be shared across peers, we need a common module. We have wireprotov1peer for the equivalent version 1 code. So I decided to establish wireprotov2peer. REPOSITORY rHG Mercurial REVISION DETAIL https://phab.mercurial-scm.org/D3379 AFFECTED FILES mercurial/httppeer.py mercurial/wireprotov2peer.py tests/test-wireproto-command-known.t tests/test-wireproto-command-pushkey.t CHANGE DETAILS diff --git a/tests/test-wireproto-command-pushkey.t b/tests/test-wireproto-command-pushkey.t --- a/tests/test-wireproto-command-pushkey.t +++ b/tests/test-wireproto-command-pushkey.t @@ -53,7 +53,7 @@ received frame(size=*; request=1; stream=2; streamflags=stream-begin; type=bytes-response; flags=eos|cbor) (glob) s> 0\r\n s> \r\n - response: [] + response: [True] $ sendhttpv2peer << EOF > command listkeys diff --git a/tests/test-wireproto-command-known.t b/tests/test-wireproto-command-known.t --- a/tests/test-wireproto-command-known.t +++ b/tests/test-wireproto-command-known.t @@ -50,7 +50,7 @@ received frame(size=1; request=1; stream=2; streamflags=stream-begin; type=bytes-response; flags=eos|cbor) s> 0\r\n s> \r\n - response: [] + response: [b''] Single known node works diff --git a/mercurial/wireprotov2peer.py b/mercurial/wireprotov2peer.py new file mode 100644 --- /dev/null +++ b/mercurial/wireprotov2peer.py @@ -0,0 +1,135 @@ +# wireprotov2peer.py - client side code for wire protocol version 2 +# +# Copyright 2018 Gregory Szorc+# +# This software may be used and distributed according to the terms of the +# GNU General Public License version 2 or any later version. + +from __future__ import absolute_import + +from .i18n import _ +from .thirdparty import ( +cbor, +) +from . import ( +error, +util, +wireprotoframing, +) + +class clienthandler(object): +"""Object to handle higher-level client activities. + +The ``clientreactor`` is used to hold low-level state about the frame-based +protocol, such as which requests and streams are active. This type is used +for higher-level operations, such as reading frames from a socket, exposing +and managing a higher-level primitive for representing command responses, +etc. This class is what peers should probably use to bridge wire activity +with the higher-level peer API. +""" + +def __init__(self, ui, clientreactor): +self._ui = ui +self._reactor = clientreactor +self._requests = {} +self._futures = {} +self._responses = {} + +def
D3386: wireprotov2: change behavior of error frame
indygreg created this revision. Herald added a subscriber: mercurial-devel. Herald added a reviewer: hg-reviewers. REVISION SUMMARY Now that we have a leading CBOR map in command response frames to indicate overall command result status, we don't need to use the error response frame to represent command errors. Instead, we can reserve it for protocol and server level errors. And for the special case of a command error that occurred after command response frames were emitted. The code for error handling still needs a ton of work. But we're slowly going in the right direction... REPOSITORY rHG Mercurial REVISION DETAIL https://phab.mercurial-scm.org/D3386 AFFECTED FILES mercurial/help/internals/wireprotocol.txt mercurial/wireprotoframing.py mercurial/wireprotov2server.py tests/test-wireproto-serverreactor.py CHANGE DETAILS diff --git a/tests/test-wireproto-serverreactor.py b/tests/test-wireproto-serverreactor.py --- a/tests/test-wireproto-serverreactor.py +++ b/tests/test-wireproto-serverreactor.py @@ -373,16 +373,18 @@ b'1 2 0 command-response eos %s' % second, ]) -def testapplicationerror(self): +def testservererror(self): reactor = makereactor() instream = framing.stream(1) list(sendcommandframes(reactor, instream, 1, b'mycommand', {})) outstream = reactor.makeoutputstream() -result = reactor.onapplicationerror(outstream, 1, b'some message') +result = reactor.onservererror(outstream, 1, b'some message') self.assertaction(result, b'sendframes') self.assertframesequal(result[1][b'framegen'], [ -b'1 2 stream-begin error-response application some message', +b"1 2 stream-begin error-response 0 " +b"cbor:{b'type': b'server', " +b"b'message': [{b'msg': b'some message'}]}", ]) def test1commanddeferresponse(self): diff --git a/mercurial/wireprotov2server.py b/mercurial/wireprotov2server.py --- a/mercurial/wireprotov2server.py +++ b/mercurial/wireprotov2server.py @@ -311,7 +311,7 @@ command['requestid'], encoded) else: -action, meta = reactor.onapplicationerror( +action, meta = reactor.onservererror( _('unhandled response type from wire proto command')) if action == 'sendframes': diff --git a/mercurial/wireprotoframing.py b/mercurial/wireprotoframing.py --- a/mercurial/wireprotoframing.py +++ b/mercurial/wireprotoframing.py @@ -87,20 +87,12 @@ b'eos': FLAG_COMMAND_RESPONSE_EOS, } -FLAG_ERROR_RESPONSE_PROTOCOL = 0x01 -FLAG_ERROR_RESPONSE_APPLICATION = 0x02 - -FLAGS_ERROR_RESPONSE = { -b'protocol': FLAG_ERROR_RESPONSE_PROTOCOL, -b'application': FLAG_ERROR_RESPONSE_APPLICATION, -} - # Maps frame types to their available flags. FRAME_TYPE_FLAGS = { FRAME_TYPE_COMMAND_REQUEST: FLAGS_COMMAND_REQUEST, FRAME_TYPE_COMMAND_DATA: FLAGS_COMMAND_DATA, FRAME_TYPE_COMMAND_RESPONSE: FLAGS_COMMAND_RESPONSE, -FRAME_TYPE_ERROR_RESPONSE: FLAGS_ERROR_RESPONSE, +FRAME_TYPE_ERROR_RESPONSE: {}, FRAME_TYPE_TEXT_OUTPUT: {}, FRAME_TYPE_PROGRESS: {}, FRAME_TYPE_STREAM_SETTINGS: {}, @@ -394,20 +386,19 @@ if done: break -def createerrorframe(stream, requestid, msg, protocol=False, application=False): +def createerrorframe(stream, requestid, msg, errtype): # TODO properly handle frame size limits. assert len(msg) <= DEFAULT_MAX_FRAME_SIZE -flags = 0 -if protocol: -flags |= FLAG_ERROR_RESPONSE_PROTOCOL -if application: -flags |= FLAG_ERROR_RESPONSE_APPLICATION +payload = cbor.dumps({ +b'type': errtype, +b'message': [{b'msg': msg}], +}, canonical=True) yield stream.makeframe(requestid=requestid, typeid=FRAME_TYPE_ERROR_RESPONSE, - flags=flags, - payload=msg) + flags=0, + payload=payload) def createtextoutputframe(stream, requestid, atoms, maxframesize=DEFAULT_MAX_FRAME_SIZE): @@ -664,12 +655,12 @@ 'framegen': makegen(), } -def onapplicationerror(self, stream, requestid, msg): +def onservererror(self, stream, requestid, msg): ensureserverstream(stream) return 'sendframes', { 'framegen': createerrorframe(stream, requestid, msg, - application=True), + errtype='server'), } def makeoutputstream(self): @@ -1051,6 +1042,7 @@ handlers = { FRAME_TYPE_COMMAND_RESPONSE: self._oncommandresponseframe, +FRAME_TYPE_ERROR_RESPONSE: self._onerrorresponseframe, } meth =
D3378: debugcommands: ability to suppress logging of handshake
indygreg created this revision. Herald added a subscriber: mercurial-devel. Herald added a reviewer: hg-reviewers. REVISION SUMMARY The tests for calling wire protocol commands were getting quite verbose because they included the results of the capabilities request. Furthermore, it was annoying to have to update several tests every time the capabilities response changed. The only tests that really care about the low-level details of the capabilities requests are those testing the protocol handshake. And those are mostly not instantiating peer instances or are contained to limited files. This commit adds an option to `hg debugwireproto` to suppress logging of the handshake. The shell helper function to perform HTTP tests has been updated to use this by default. Lots of excessive test output has gone away. REPOSITORY rHG Mercurial REVISION DETAIL https://phab.mercurial-scm.org/D3378 AFFECTED FILES mercurial/debugcommands.py tests/test-completion.t tests/test-http-api-httpv2.t tests/test-wireproto-command-branchmap.t tests/test-wireproto-command-capabilities.t tests/test-wireproto-command-heads.t tests/test-wireproto-command-known.t tests/test-wireproto-command-listkeys.t tests/test-wireproto-command-lookup.t tests/test-wireproto-command-pushkey.t tests/wireprotohelpers.sh CHANGE DETAILS diff --git a/tests/wireprotohelpers.sh b/tests/wireprotohelpers.sh --- a/tests/wireprotohelpers.sh +++ b/tests/wireprotohelpers.sh @@ -6,6 +6,10 @@ } sendhttpv2peer() { + hg --verbose debugwireproto --nologhandshake --peer http2 http://$LOCALIP:$HGPORT/ +} + +sendhttpv2peerhandshake() { hg --verbose debugwireproto --peer http2 http://$LOCALIP:$HGPORT/ } diff --git a/tests/test-wireproto-command-pushkey.t b/tests/test-wireproto-command-pushkey.t --- a/tests/test-wireproto-command-pushkey.t +++ b/tests/test-wireproto-command-pushkey.t @@ -29,23 +29,6 @@ > new 426bada5c67598ca65036d57d9e4b64b0c1ce7a0 > EOF creating http peer for wire protocol version 2 - s> *\r\n (glob) - s> Accept-Encoding: identity\r\n - s> vary: X-HgProto-1,X-HgUpgrade-1\r\n - s> x-hgproto-1: cbor\r\n - s> x-hgupgrade-1: exp-http-v2-0001\r\n - s> accept: application/mercurial-0.1\r\n - s> host: $LOCALIP:$HGPORT\r\n (glob) - s> user-agent: Mercurial debugwireproto\r\n - s> \r\n - s> makefile('rb', None) - s> HTTP/1.1 200 OK\r\n - s> Server: testing stub value\r\n - s> Date: $HTTP_DATE$\r\n - s> Content-Type: application/mercurial-cbor\r\n - s> Content-Length: *\r\n (glob) - s> \r\n - s> \xa3Dapis\xa1Pexp-http-v2-0001\xa4Hcommands\xa7Eheads\xa2Dargs\xa1Jpubliconly\xf4Kpermissions\x81DpullEknown\xa2Dargs\xa1Enodes\x81HdeadbeefKpermissions\x81DpullFlookup\xa2Dargs\xa1CkeyCfooKpermissions\x81DpullGpushkey\xa2Dargs\xa4CkeyCkeyCnewCnewColdColdInamespaceBnsKpermissions\x81DpushHlistkeys\xa2Dargs\xa1InamespaceBnsKpermissions\x81DpullIbranchmap\xa2Dargs\xa0Kpermissions\x81DpullLcapabilities\xa2Dargs\xa0Kpermissions\x81DpullKcompression\x82\xa1DnameDzstd\xa1DnameDzlibNrawrepoformats\x82LgeneraldeltaHrevlogv1Qframingmediatypes\x81X/mercurial-exp-framing-0003GapibaseDapi/Nv1capabilitiesY\x01\xcabatch branchmap $USUAL_BUNDLE2_CAPS_SERVER$ changegroupsubset compression=$BUNDLE2_COMPRESSIONS$ getbundle httpheader=1024 httpmediatype=0.1rx,0.1tx,0.2tx known lookup pushkey streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash sending pushkey command s> *\r\n (glob) s> Accept-Encoding: identity\r\n @@ -77,23 +60,6 @@ > namespace bookmarks > EOF creating http peer for wire protocol version 2 - s> GET /?cmd=capabilities HTTP/1.1\r\n - s> Accept-Encoding: identity\r\n - s> vary: X-HgProto-1,X-HgUpgrade-1\r\n - s> x-hgproto-1: cbor\r\n - s> x-hgupgrade-1: exp-http-v2-0001\r\n - s> accept: application/mercurial-0.1\r\n - s> host: $LOCALIP:$HGPORT\r\n (glob) - s> user-agent: Mercurial debugwireproto\r\n - s> \r\n - s> makefile('rb', None) - s> HTTP/1.1 200 OK\r\n - s> Server: testing stub value\r\n - s> Date: $HTTP_DATE$\r\n - s> Content-Type: application/mercurial-cbor\r\n - s> Content-Length: *\r\n (glob) - s> \r\n - s> \xa3Dapis\xa1Pexp-http-v2-0001\xa4Hcommands\xa7Eheads\xa2Dargs\xa1Jpubliconly\xf4Kpermissions\x81DpullEknown\xa2Dargs\xa1Enodes\x81HdeadbeefKpermissions\x81DpullFlookup\xa2Dargs\xa1CkeyCfooKpermissions\x81DpullGpushkey\xa2Dargs\xa4CkeyCkeyCnewCnewColdColdInamespaceBnsKpermissions\x81DpushHlistkeys\xa2Dargs\xa1InamespaceBnsKpermissions\x81DpullIbranchmap\xa2Dargs\xa0Kpermissions\x81DpullLcapabilities\xa2Dargs\xa0Kpermissions\x81DpullKcompression\x82\xa1DnameDzstd\xa1DnameDzlibNrawrepoformats\x82LgeneraldeltaHrevlogv1Qframingmediatypes\x81X/mercurial-exp-framing-0003GapibaseDapi/Nv1capabilitiesY\x01\xcabatch branchmap $USUAL_BUNDLE2_CAPS_SERVER$ changegroupsubset
D3388: wireprotov2: add support for more response types
indygreg created this revision. Herald added a subscriber: mercurial-devel. Herald added a reviewer: hg-reviewers. REVISION SUMMARY This adds types to represent error and generator responses from server commands. REPOSITORY rHG Mercurial REVISION DETAIL https://phab.mercurial-scm.org/D3388 AFFECTED FILES mercurial/wireprotoframing.py mercurial/wireprototypes.py mercurial/wireprotov2server.py CHANGE DETAILS diff --git a/mercurial/wireprotov2server.py b/mercurial/wireprotov2server.py --- a/mercurial/wireprotov2server.py +++ b/mercurial/wireprotov2server.py @@ -306,6 +306,15 @@ action, meta = reactor.oncommandresponseready(outstream, command['requestid'], encoded) +elif isinstance(rsp, wireprototypes.v2streamingresponse): +action, meta = reactor.oncommandresponsereadygen(outstream, + command['requestid'], + rsp.gen) +elif isinstance(rsp, wireprototypes.v2errorresponse): +action, meta = reactor.oncommanderror(outstream, + command['requestid'], + rsp.message, + rsp.args) else: action, meta = reactor.onservererror( _('unhandled response type from wire proto command')) diff --git a/mercurial/wireprototypes.py b/mercurial/wireprototypes.py --- a/mercurial/wireprototypes.py +++ b/mercurial/wireprototypes.py @@ -106,6 +106,23 @@ def __init__(self, v): self.value = v +class v2errorresponse(object): +"""Represents a command error for version 2 transports.""" +def __init__(self, message, args=None): +self.message = message +self.args = args + +class v2streamingresponse(object): +"""A response whose data is supplied by a generator. + +The generator can either consist of data structures to CBOR +encode or a stream of already-encoded bytes. +""" +def __init__(self, gen, compressible=True, iscbor=False): +self.gen = gen +self.compressible = compressible +self.iscbor = iscbor + # list of nodes encoding / decoding def decodelist(l, sep=' '): if l: diff --git a/mercurial/wireprotoframing.py b/mercurial/wireprotoframing.py --- a/mercurial/wireprotoframing.py +++ b/mercurial/wireprotoframing.py @@ -386,6 +386,56 @@ if done: break +def createbytesresponseframesfromgen(stream, requestid, gen, + maxframesize=DEFAULT_MAX_FRAME_SIZE): +overall = cbor.dumps({b'status': b'ok'}, canonical=True) + +yield stream.makeframe(requestid=requestid, + typeid=FRAME_TYPE_COMMAND_RESPONSE, + flags=FLAG_COMMAND_RESPONSE_CONTINUATION, + payload=overall) + +cb = util.chunkbuffer(gen) + +flags = 0 + +while True: +chunk = cb.read(maxframesize) +if not chunk: +break + +yield stream.makeframe(requestid=requestid, + typeid=FRAME_TYPE_COMMAND_RESPONSE, + flags=flags, + payload=chunk) + +flags |= FLAG_COMMAND_RESPONSE_CONTINUATION + +flags ^= FLAG_COMMAND_RESPONSE_CONTINUATION +flags |= FLAG_COMMAND_RESPONSE_EOS +yield stream.makeframe(requestid=requestid, + typeid=FRAME_TYPE_COMMAND_RESPONSE, + flags=flags, + payload=b'') + +def createcommanderrorresponse(stream, requestid, message, args=None): +m = { +b'status': b'error', +b'error': { +b'message': message, +} +} + +if args: +m[b'error'][b'args'] = args + +overall = cbor.dumps(m, canonical=True) + +yield stream.makeframe(requestid=requestid, + typeid=FRAME_TYPE_COMMAND_RESPONSE, + flags=FLAG_COMMAND_RESPONSE_EOS, + payload=overall) + def createerrorframe(stream, requestid, msg, errtype): # TODO properly handle frame size limits. assert len(msg) <= DEFAULT_MAX_FRAME_SIZE @@ -634,6 +684,19 @@ 'framegen': result, } +def oncommandresponsereadygen(self, stream, requestid, gen): +"""Signal that a bytes response is ready, with data as a generator.""" +ensureserverstream(stream) + +def sendframes(): +for frame in createbytesresponseframesfromgen(stream, requestid, + gen): +yield frame + +self._activecommands.remove(requestid) + +return self._handlesendframes(sendframes()) + def oninputeof(self):
D3372: keepalive: add ** overlooked in 83250442dc81
This revision was automatically updated to reflect the committed changes. Closed by commit rHG2177b499db6b: keepalive: add ** overlooked in 83250442dc81 (authored by durin42, committed by ). REPOSITORY rHG Mercurial CHANGES SINCE LAST UPDATE https://phab.mercurial-scm.org/D3372?vs=8276=8287 REVISION DETAIL https://phab.mercurial-scm.org/D3372 AFFECTED FILES mercurial/keepalive.py CHANGE DETAILS diff --git a/mercurial/keepalive.py b/mercurial/keepalive.py --- a/mercurial/keepalive.py +++ b/mercurial/keepalive.py @@ -326,16 +326,16 @@ data = urllibcompat.getdata(req) h.putrequest( req.get_method(), urllibcompat.getselector(req), -skipheaders) +**skipheaders) if r'content-type' not in headers: h.putheader(r'Content-type', r'application/x-www-form-urlencoded') if r'content-length' not in headers: h.putheader(r'Content-length', r'%d' % len(data)) else: h.putrequest( req.get_method(), urllibcompat.getselector(req), -skipheaders) +**skipheaders) except socket.error as err: raise urlerr.urlerror(err) for k, v in headers.items(): To: durin42, #hg-reviewers Cc: mercurial-devel ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
Re: [PATCH 1 of 5 V2] test-lfs: add tests to force server error path coverage
On Sat, 14 Apr 2018 14:47:33 -0400, Matt Harbison wrote: > # HG changeset patch > # User Matt Harbison> # Date 1523119701 14400 > # Sat Apr 07 12:48:21 2018 -0400 > # Node ID a83bc37bcf3da077f78bf3377b88b61d328bd4ce > # Parent 9d509015742603624ef0df5497f0f205d8768ebf > test-lfs: add tests to force server error path coverage Queued, thanks. ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
Re: [PATCH 1 of 2] templates: add whyunstable template keyword
On Sat, 14 Apr 2018 20:50:19 +0800, Anton Shestakov wrote: > On Sat, 14 Apr 2018 21:03:23 +0900 > Yuya Nishiharawrote: > > > +def formatnode(ctx): > > > +return ' %s (%s)' % (scmutil.formatchangeid(ctx), > > > ctx.phasestr()) > > > > Nit: leading ' ' isn't nice when you join() the list. > > I was trying to avoid something like '{if(divergentnodes, " ")}', but > maybe it wouldn't be too bad. I'll come back to this tomorrow. '{separate(' ', blah, blah, ...)}' could be used instead of if(). ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
Re: [PATCH] test-check-commit: don't run hg per commit
> On Apr 14, 2018, at 4:49 AM, Yuya Nishiharawrote: > > # HG changeset patch > # User Yuya Nishihara > # Date 1523694452 -32400 > # Sat Apr 14 17:27:32 2018 +0900 > # Node ID 34cde18a454484a1cf6e716a3325ca9282277d59 > # Parent e743b8524d608684b5a947337c37b686cfc0ae5b > test-check-commit: don't run hg per commit Queued with enthusiasm, many thanks. (This has been on my hit list for a while, and I never got around to it.) > > We aren't stress testing CPU. > > $ time ./run-tests.py -l test-check-commit.t --timeout 600 > (orig) 162.59s user 17.98s system 101% cpu 2:58.55 total > (new) 5.85s user 0.99s system 98% cpu 6.939 total > > diff --git a/tests/test-check-commit.t b/tests/test-check-commit.t > --- a/tests/test-check-commit.t > +++ b/tests/test-check-commit.t > @@ -8,15 +8,16 @@ Go back in the hg repo > > $ cd $TESTDIR/.. > > - $ for node in `testrepohg log --rev 'not public() and ::. and not desc("# > no-check-commit")' --template '{node|short}\n'`; do > - >testrepohg export --git $node \ > - >| contrib/check-commit > ${TESTTMP}/check-commit.out > + $ mkdir "$TESTTMP/p" > + $ testrepohg export --git -o "$TESTTMP/p/%n-%h" \ > + > -r 'not public() and ::. and not desc("# no-check-commit")' > + $ for f in `ls "$TESTTMP/p"`; do > + >contrib/check-commit < "$TESTTMP/p/$f" > "$TESTTMP/check-commit.out" >> if [ $? -ne 0 ]; then > + >node="${f##*-}" >> echo "Revision $node does not comply with rules" >> echo '--' >> cat ${TESTTMP}/check-commit.out >> echo >> fi >> done > - > - > ___ > Mercurial-devel mailing list > Mercurial-devel@mercurial-scm.org > https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
Re: [PATCH] test-check-commit: don't run hg per commit
On Sat, 14 Apr 2018 04:49:38 -0400, Yuya Nishiharawrote: # HG changeset patch # User Yuya Nishihara # Date 1523694452 -32400 # Sat Apr 14 17:27:32 2018 +0900 # Node ID 34cde18a454484a1cf6e716a3325ca9282277d59 # Parent e743b8524d608684b5a947337c37b686cfc0ae5b test-check-commit: don't run hg per commit We aren't stress testing CPU. $ time ./run-tests.py -l test-check-commit.t --timeout 600 (orig) 162.59s user 17.98s system 101% cpu 2:58.55 total (new) 5.85s user 0.99s system 98% cpu 6.939 total +1 On my idle Windows laptop: real17m40.978s user0m0.045s sys 0m0.062s to: real0m59.448s user0m0.030s sys 0m0.062s ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
[PATCH 4 of 5 V2] lfs: gracefully handle aborts on the server when corrupt blobs are detected
# HG changeset patch # User Matt Harbison# Date 1519585633 18000 # Sun Feb 25 14:07:13 2018 -0500 # Node ID 6645ae6f5e2a248f23ec05df1ff6f48f3377cc47 # Parent 414fdd730760f960aaa9b9e8cfb7853b543c8fca lfs: gracefully handle aborts on the server when corrupt blobs are detected The aborts weren't killing the server, but this seems cleaner. I'm not sure if it matters to handle the remaining IOError in the test like this, for consistency. The error code still feels wrong (especially if the client is trying to download a corrupt blob) but I don't see anything better in the RFCs, and this is already used elsewhere because the Batch API spec specifically mentioned this as a "Validation Error". diff --git a/hgext/lfs/blobstore.py b/hgext/lfs/blobstore.py --- a/hgext/lfs/blobstore.py +++ b/hgext/lfs/blobstore.py @@ -152,7 +152,8 @@ class local(object): realoid = sha256.hexdigest() if realoid != oid: -raise error.Abort(_('corrupt remote lfs object: %s') % oid) +raise LfsCorruptionError(_('corrupt remote lfs object: %s') + % oid) self._linktousercache(oid) @@ -526,8 +527,8 @@ def _deduplicate(pointers): def _verify(oid, content): realoid = hashlib.sha256(content).hexdigest() if realoid != oid: -raise error.Abort(_('detected corrupt lfs object: %s') % oid, - hint=_('run hg verify')) +raise LfsCorruptionError(_('detected corrupt lfs object: %s') % oid, + hint=_('run hg verify')) def remote(repo, remote=None): """remotestore factory. return a store in _storemap depending on config @@ -573,3 +574,8 @@ def remote(repo, remote=None): class LfsRemoteError(error.RevlogError): pass + +class LfsCorruptionError(error.Abort): +"""Raised when a corrupt blob is detected, aborting an operation + +It exists to allow specialized handling on the server side.""" diff --git a/hgext/lfs/wireprotolfsserver.py b/hgext/lfs/wireprotolfsserver.py --- a/hgext/lfs/wireprotolfsserver.py +++ b/hgext/lfs/wireprotolfsserver.py @@ -20,6 +20,8 @@ from mercurial import ( pycompat, ) +from . import blobstore + HTTP_OK = hgwebcommon.HTTP_OK HTTP_CREATED = hgwebcommon.HTTP_CREATED HTTP_BAD_REQUEST = hgwebcommon.HTTP_BAD_REQUEST @@ -276,13 +278,15 @@ def _processbasictransfer(repo, req, res # Content-Length, but what happens if a client sends less than it # says it will? -# TODO: download() will abort if the checksum fails. It should raise -# something checksum specific that can be caught here, and turned -# into an http code. -localstore.download(oid, req.bodyfh) +statusmessage = hgwebcommon.statusmessage +try: +localstore.download(oid, req.bodyfh) +res.status = statusmessage(HTTP_OK if existed else HTTP_CREATED) +except blobstore.LfsCorruptionError: +_logexception(req) -statusmessage = hgwebcommon.statusmessage -res.status = statusmessage(HTTP_OK if existed else HTTP_CREATED) +# XXX: Is this the right code? +res.status = statusmessage(422, b'corrupt blob') # There's no payload here, but this is the header that lfs-test-server # sends back. This eliminates some gratuitous test output conditionals. @@ -296,9 +300,18 @@ def _processbasictransfer(repo, req, res res.status = hgwebcommon.statusmessage(HTTP_OK) res.headers[b'Content-Type'] = b'application/octet-stream' -# TODO: figure out how to send back the file in chunks, instead of -# reading the whole thing. -res.setbodybytes(localstore.read(oid)) +try: +# TODO: figure out how to send back the file in chunks, instead of +# reading the whole thing. (Also figure out how to send back +# an error status if an IOError occurs after a partial write +# in that case. Here, everything is read before starting.) +res.setbodybytes(localstore.read(oid)) +except blobstore.LfsCorruptionError: +_logexception(req) + +# XXX: Is this the right code? +res.status = hgwebcommon.statusmessage(422, b'corrupt blob') +res.setbodybytes(b'') return True else: diff --git a/tests/test-lfs-serve-access.t b/tests/test-lfs-serve-access.t --- a/tests/test-lfs-serve-access.t +++ b/tests/test-lfs-serve-access.t @@ -236,7 +236,7 @@ Test a bad checksum sent by the client i $ hg -R client push http://localhost:$HGPORT1 pushing to http://localhost:$HGPORT1/ searching for changes - abort: HTTP error: HTTP Error 500: Internal Server Error (oid=b5bb9d8014a0f9b1d61e21e796d78dccdf1352f23cd32812f4850b878ae4944c, action=upload)! + abort: HTTP error: HTTP Error 422: corrupt
[PATCH 3 of 5 V2] lfs: fix the inferred remote store path when using a --prefix
# HG changeset patch # User Matt Harbison# Date 1523643390 14400 # Fri Apr 13 14:16:30 2018 -0400 # Node ID 414fdd730760f960aaa9b9e8cfb7853b543c8fca # Parent f5420feae687abf2e16e8444c385bdac9eedfeab lfs: fix the inferred remote store path when using a --prefix This wasn't appending the '.git/info/lfs' path in this case. diff --git a/hgext/lfs/blobstore.py b/hgext/lfs/blobstore.py --- a/hgext/lfs/blobstore.py +++ b/hgext/lfs/blobstore.py @@ -561,7 +561,7 @@ def remote(repo, remote=None): if defaulturl.scheme in (b'http', b'https'): if defaulturl.path and defaulturl.path[:-1] != b'/': defaulturl.path += b'/' -defaulturl.path = defaulturl.path or b'' + b'.git/info/lfs' +defaulturl.path = (defaulturl.path or b'') + b'.git/info/lfs' url = util.url(bytes(defaulturl)) repo.ui.note(_('lfs: assuming remote store: %s\n') % url) diff --git a/tests/test-lfs-serve-access.t b/tests/test-lfs-serve-access.t --- a/tests/test-lfs-serve-access.t +++ b/tests/test-lfs-serve-access.t @@ -73,8 +73,7 @@ Blob URIs are correct when --prefix is u >-A $TESTTMP/access.log -E $TESTTMP/errors.log $ cat hg.pid >> $DAEMON_PIDS - $ hg --config lfs.url=http://localhost:$HGPORT/subdir/mount/point/.git/info/lfs \ - >clone --debug http://localhost:$HGPORT/subdir/mount/point cloned2 + $ hg clone --debug http://localhost:$HGPORT/subdir/mount/point cloned2 using http://localhost:$HGPORT/subdir/mount/point sending capabilities command query 1; heads @@ -104,6 +103,7 @@ Blob URIs are correct when --prefix is u resolving manifests branchmerge: False, force: False, partial: False ancestor: , local: +, remote: 525251863cad + lfs: assuming remote store: http://localhost:$HGPORT/subdir/mount/point/.git/info/lfs Status: 200 Content-Length: 371 Content-Type: application/vnd.git-lfs+json ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
[PATCH 1 of 5 V2] test-lfs: add tests to force server error path coverage
# HG changeset patch # User Matt Harbison# Date 1523119701 14400 # Sat Apr 07 12:48:21 2018 -0400 # Node ID a83bc37bcf3da077f78bf3377b88b61d328bd4ce # Parent 9d509015742603624ef0df5497f0f205d8768ebf test-lfs: add tests to force server error path coverage The tests are somewhat fragile in that the extension that forces the errors is counting how many times some of the functions are being called, so it depends heavily on the content of the repo. Maybe we can do something clever like load an extension on the client, and have it send over instructions in the HTTP header how to fail. (I'm trying to avoid killing and restarting the server, because Windows seems to have issues with doing that a lot.) But I'd rather fix issues than polish tests before the freeze. diff --git a/tests/test-lfs-serve-access.t b/tests/test-lfs-serve-access.t --- a/tests/test-lfs-serve-access.t +++ b/tests/test-lfs-serve-access.t @@ -4,7 +4,6 @@ > [extensions] > lfs= > [lfs] - > url=http://localhost:$HGPORT/.git/info/lfs > track=all() > [web] > push_ssl = False @@ -149,3 +148,187 @@ Blob URIs are correct when --prefix is u $LOCALIP - - [$LOGDATE$] "GET /subdir/mount/point?cmd=getbundle HTTP/1.1" 200 - x-hgarg-1:bookmarks=1=HG20%2Cbundle2%3DHG20%250Abookmarks%250Achangegroup%253D01%252C02%252C03%250Adigests%253Dmd5%252Csha1%252Csha512%250Aerror%253Dabort%252Cunsupportedcontent%252Cpushraced%252Cpushkey%250Ahgtagsfnodes%250Alistkeys%250Aphases%253Dheads%250Apushkey%250Aremote-changegroup%253Dhttp%252Chttps%250Arev-branch-cache%250Astream%253Dv2=1==525251863cad618e55d483555f3d00a2ca99597e=bookmarks=1 x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull (glob) $LOCALIP - - [$LOGDATE$] "POST /subdir/mount/point/.git/info/lfs/objects/batch HTTP/1.1" 200 - (glob) $LOCALIP - - [$LOGDATE$] "GET /subdir/mount/point/.hg/lfs/objects/f03217a32529a28a42d03b1244fe09b6e0f9fd06d7b966d4d50567be2abe6c0e HTTP/1.1" 200 - (glob) + + $ cat >> $TESTTMP/lfsstoreerror.py < import errno + > from hgext.lfs import blobstore + > + > _numverifies = 0 + > _readerr = True + > + > def reposetup(ui, repo): + > # Nothing to do with a remote repo + > if not repo.local(): + > return + > + > store = repo.svfs.lfslocalblobstore + > class badstore(store.__class__): + > def download(self, oid, src): + > '''Called in the server to handle reading from the client in a + > PUT request.''' + > origread = src.read + > def _badread(nbytes): + > # Simulate bad data/checksum failure from the client + > return b'0' * len(origread(nbytes)) + > src.read = _badread + > super(badstore, self).download(oid, src) + > + > def _read(self, vfs, oid, verify): + > '''Called in the server to read data for a GET request, and then + > calls self._verify() on it before returning.''' + > global _readerr + > # One time simulation of a read error + > if _readerr: + > _readerr = False + > raise IOError(errno.EIO, '%s: I/O error' % oid) + > # Simulate corrupt content on client download + > blobstore._verify(oid, 'dummy content') + > + > def verify(self, oid): + > '''Called in the server to populate the Batch API response, + > letting the client re-upload if the file is corrupt.''' + > # Fail verify in Batch API for one clone command and one push + > # command with an IOError. Then let it through to access other + > # functions. Checksum failure is tested elsewhere. + > global _numverifies + > _numverifies += 1 + > if _numverifies <= 2: + > raise IOError(errno.EIO, '%s: I/O error' % oid) + > return super(badstore, self).verify(oid) + > + > store.__class__ = badstore + > EOF + + $ rm -rf `hg config lfs.usercache` + $ rm -f $TESTTMP/access.log $TESTTMP/errors.log + $ hg --config "lfs.usercache=$TESTTMP/servercache" \ + >--config extensions.lfsstoreerror=$TESTTMP/lfsstoreerror.py \ + >-R server serve -d \ + >-p $HGPORT1 --pid-file=hg.pid -A $TESTTMP/access.log -E $TESTTMP/errors.log + $ cat hg.pid >> $DAEMON_PIDS + +Test an I/O error in localstore.verify() (Batch API) with GET + + $ hg clone http://localhost:$HGPORT1 httpclone2 + requesting all changes + adding changesets + adding manifests + adding file changes + added 1 changesets with 1 changes to 1 files + new changesets 525251863cad + updating to branch default + abort: LFS server error for "lfs.bin": Internal server error! + [255] + +Test an I/O error in localstore.verify() (Batch API) with PUT + + $ echo foo > client/lfs.bin + $ hg -R client ci -m 'mod lfs' + $
[PATCH 5 of 5 V2] lfs: update the HTTP status codes in error cases
# HG changeset patch # User Matt Harbison# Date 1523651553 14400 # Fri Apr 13 16:32:33 2018 -0400 # Node ID 075edc6d6add061ac13578bc3301c581de347412 # Parent 6645ae6f5e2a248f23ec05df1ff6f48f3377cc47 lfs: update the HTTP status codes in error cases I'm not bothering with validating PUT requests (for now), because the spec doesn't explicitly call out a Content-Type (though the example transcript does use the sensible 'application/octet-stream'). diff --git a/hgext/lfs/wireprotolfsserver.py b/hgext/lfs/wireprotolfsserver.py --- a/hgext/lfs/wireprotolfsserver.py +++ b/hgext/lfs/wireprotolfsserver.py @@ -26,6 +26,9 @@ HTTP_OK = hgwebcommon.HTTP_OK HTTP_CREATED = hgwebcommon.HTTP_CREATED HTTP_BAD_REQUEST = hgwebcommon.HTTP_BAD_REQUEST HTTP_NOT_FOUND = hgwebcommon.HTTP_NOT_FOUND +HTTP_METHOD_NOT_ALLOWED = hgwebcommon.HTTP_METHOD_NOT_ALLOWED +HTTP_NOT_ACCEPTABLE = hgwebcommon.HTTP_NOT_ACCEPTABLE +HTTP_UNSUPPORTED_MEDIA_TYPE = hgwebcommon.HTTP_UNSUPPORTED_MEDIA_TYPE def handlewsgirequest(orig, rctx, req, res, checkperm): """Wrap wireprotoserver.handlewsgirequest() to possibly process an LFS @@ -105,12 +108,16 @@ def _processbatchrequest(repo, req, res) # "operation": "upload" # } -if (req.method != b'POST' -or req.headers[b'Content-Type'] != b'application/vnd.git-lfs+json' -or req.headers[b'Accept'] != b'application/vnd.git-lfs+json'): -# TODO: figure out what the proper handling for a bad request to the -# Batch API is. -_sethttperror(res, HTTP_BAD_REQUEST, b'Invalid Batch API request') +if req.method != b'POST': +_sethttperror(res, HTTP_METHOD_NOT_ALLOWED) +return True + +if req.headers[b'Content-Type'] != b'application/vnd.git-lfs+json': +_sethttperror(res, HTTP_UNSUPPORTED_MEDIA_TYPE) +return True + +if req.headers[b'Accept'] != b'application/vnd.git-lfs+json': +_sethttperror(res, HTTP_NOT_ACCEPTABLE) return True # XXX: specify an encoding? @@ -315,6 +322,6 @@ def _processbasictransfer(repo, req, res return True else: -_sethttperror(res, HTTP_BAD_REQUEST, +_sethttperror(res, HTTP_METHOD_NOT_ALLOWED, message=b'Unsupported LFS transfer method: %s' % method) return True diff --git a/mercurial/hgweb/common.py b/mercurial/hgweb/common.py --- a/mercurial/hgweb/common.py +++ b/mercurial/hgweb/common.py @@ -30,6 +30,8 @@ HTTP_UNAUTHORIZED = 401 HTTP_FORBIDDEN = 403 HTTP_NOT_FOUND = 404 HTTP_METHOD_NOT_ALLOWED = 405 +HTTP_NOT_ACCEPTABLE = 406 +HTTP_UNSUPPORTED_MEDIA_TYPE = 415 HTTP_SERVER_ERROR = 500 ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
[PATCH 2 of 5 V2] lfs: log information about Internal Server Errors reported in the Batch API
# HG changeset patch # User Matt Harbison# Date 1523637594 14400 # Fri Apr 13 12:39:54 2018 -0400 # Node ID f5420feae687abf2e16e8444c385bdac9eedfeab # Parent a83bc37bcf3da077f78bf3377b88b61d328bd4ce lfs: log information about Internal Server Errors reported in the Batch API Reporting a 500 and then not leaving any traces on the server seems like a receipe for frustration. There's similar log writing in hgweb.server.do_POST(). That doesn't write directly to the wsgi.errors object, so it doesn't seem worth trying to refactor. It does seem like earlier stack frames are missing for some reason. diff --git a/hgext/lfs/wireprotolfsserver.py b/hgext/lfs/wireprotolfsserver.py --- a/hgext/lfs/wireprotolfsserver.py +++ b/hgext/lfs/wireprotolfsserver.py @@ -10,6 +10,7 @@ from __future__ import absolute_import import datetime import errno import json +import traceback from mercurial.hgweb import ( common as hgwebcommon, @@ -63,6 +64,19 @@ def _sethttperror(res, code, message=Non res.headers[b'Content-Type'] = b'text/plain; charset=utf-8' res.setbodybytes(b'') +def _logexception(req): +"""Write information about the current exception to wsgi.errors.""" +tb = pycompat.sysbytes(traceback.format_exc()) +errorlog = req.rawenv[r'wsgi.errors'] + +uri = b'' +if req.apppath: +uri += req.apppath +uri += b'/' + req.dispatchpath + +errorlog.write(b"Exception happened while processing request '%s':\n%s" % + (uri, tb)) + def _processbatchrequest(repo, req, res): """Handle a request for the Batch API, which is the gateway to granting file access. @@ -179,6 +193,8 @@ def _batchresponseobjects(req, objects, verifies = store.verify(oid) except IOError as inst: if inst.errno != errno.ENOENT: +_logexception(req) + rsp['error'] = { 'code': 500, 'message': inst.strerror or 'Internal Server Server' diff --git a/tests/test-lfs-serve-access.t b/tests/test-lfs-serve-access.t --- a/tests/test-lfs-serve-access.t +++ b/tests/test-lfs-serve-access.t @@ -289,6 +289,18 @@ Test a checksum failure during the proce $LOCALIP - - [$LOGDATE$] "GET /.hg/lfs/objects/276f73cfd75f9fb519810df5f5d96d6594ca2521abd86cbcd92122f7d51a1f3d HTTP/1.1" 500 - (glob) $ grep -v ' File "' $TESTTMP/errors.log + $LOCALIP - - [$ERRDATE$] HG error: Exception happened while processing request '/.git/info/lfs/objects/batch': (glob) + $LOCALIP - - [$ERRDATE$] HG error: Traceback (most recent call last): (glob) + $LOCALIP - - [$ERRDATE$] HG error: verifies = store.verify(oid) (glob) + $LOCALIP - - [$ERRDATE$] HG error: raise IOError(errno.EIO, '%s: I/O error' % oid) (glob) + $LOCALIP - - [$ERRDATE$] HG error: IOError: [Errno 5] f03217a32529a28a42d03b1244fe09b6e0f9fd06d7b966d4d50567be2abe6c0e: I/O error (glob) + $LOCALIP - - [$ERRDATE$] HG error: (glob) + $LOCALIP - - [$ERRDATE$] HG error: Exception happened while processing request '/.git/info/lfs/objects/batch': (glob) + $LOCALIP - - [$ERRDATE$] HG error: Traceback (most recent call last): (glob) + $LOCALIP - - [$ERRDATE$] HG error: verifies = store.verify(oid) (glob) + $LOCALIP - - [$ERRDATE$] HG error: raise IOError(errno.EIO, '%s: I/O error' % oid) (glob) + $LOCALIP - - [$ERRDATE$] HG error: IOError: [Errno 5] b5bb9d8014a0f9b1d61e21e796d78dccdf1352f23cd32812f4850b878ae4944c: I/O error (glob) + $LOCALIP - - [$ERRDATE$] HG error: (glob) $LOCALIP - - [$ERRDATE$] Exception happened during processing request '/.hg/lfs/objects/b5bb9d8014a0f9b1d61e21e796d78dccdf1352f23cd32812f4850b878ae4944c': (glob) Traceback (most recent call last): self.do_write() ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
Re: [PATCH 1 of 5] test-lfs: add tests to force server error path coverage
On Sat, 14 Apr 2018 03:28:49 -0400, Yuya Nishiharawrote: On Fri, 13 Apr 2018 18:04:33 -0400, Matt Harbison wrote: # HG changeset patch # User Matt Harbison # Date 1523119701 14400 # Sat Apr 07 12:48:21 2018 -0400 # Node ID 1d394ac0efd4aa4f61f428fbac140fe57398f0b8 # Parent bfdd20d22a86edc318493b4da84a1d7ff4ef98f2 test-lfs: add tests to force server error path coverage The test failed on my machine. Can you take a look? It crossed paths with 330ada7e8ea5. Will resend. ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
Re: [PATCH] dispatch: add a whitelist map of commands to implicitly loaded extensions
On Sat, 14 Apr 2018 03:09:01 -0400, Yuya Nishiharawrote: On Fri, 13 Apr 2018 23:30:43 -0400, Matt Harbison wrote: On Fri, 13 Apr 2018 15:10:45 -0400, Gregory Szorc wrote: > What we may want instead is to key things off .hg/requires or a > to-be-invented supplemental requirements-like file that declares soft > features. localrepository.__init__ could then load trusted extensions at > repo open time if a requirements/capability was present/requested. i.e. > if > you talk to an LFS server, write a semaphore somewhere into .hg/ and have > something in core look for that and automatically load lfs if present. > This would get you the "automatically enable LFS when talking to LFS > servers" > benefits. Sounds promising. One of the things the lfs extension is doing is writing '[extensions]\nlfs=' to the repo's local hgrc file in a commit hook (it should probably be handling transactions too). So it would be nice if this was baked into the core somehow (largefiles could use exactly the same handling, and I'm assuming narrow will be similar). It's also manually adding to the requires file, since that doesn't seem to be updated in exchange. Assuming the semaphore is persistent, it could be beneficial to load extensions indicated by it around the normal load time (e.g., largefiles wraps the clone command and adds extra switches). I'm not sure if this addresses Yuya's concern about long lived processes though. If the extensions to be loaded are bound to a repo, yes, that should be fine. A well-designed extension should check the repo requirements. What doesn't work in command server is to load extensions per-command basis. While "bound to a repo" makes it sound like the extension would be isolated and could unload if the repo is GC'd, what I don't get is what that phrase means for all of the module functions that are wrapped. ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
D2880: bundle: add the possibility to bundle bookmarks (issue5792)
martinvonz added inline comments. INLINE COMMENTS > lothiraldan wrote in test-bundle-bookmarks.t:37-63 > I have added such test and indeed this case is not handled right now. I'm not > aware of how Mercurial handle this case when exchanging bookmarks, I will > need to take a look at the code to find out. > > What is the correct behavior here? Change the existing bookmark or the > bookmark from the bundle? I think it should be the same thing as pulling from another repo. Try putting the same changes in another repo and pulling from it without giving the path a name (nothing in [paths] config). I haven't checked what suffix will be used on the divergent bookmark, but it probably makes sense to use the same here (perhaps it's just going to be "https://phab.mercurial-scm.org/D1@1; as I guessed before). REPOSITORY rHG Mercurial REVISION DETAIL https://phab.mercurial-scm.org/D2880 To: lothiraldan, #hg-reviewers, indygreg Cc: martinvonz, indygreg, pulkit, mercurial-devel ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
[PATCH 3 of 3] makefile: add Ubuntu Bionic docker targets (.deb and ppa)
# HG changeset patch # User Antonio Muci # Date 1523713197 -7200 # Sat Apr 14 15:39:57 2018 +0200 # Node ID b29e5ecc90eef3af76eaaa4c21b992da66b8e444 # Parent b5874ec21df592d83c3f97aa12ea33dfdb03e839 makefile: add Ubuntu Bionic docker targets (.deb and ppa) Bionic Beaver is an LTS release, supported until 2023-04. diff --git a/Makefile b/Makefile --- a/Makefile +++ b/Makefile @@ -239,6 +239,12 @@ docker-ubuntu-artful: contrib/docker/ubu docker-ubuntu-artful-ppa: contrib/docker/ubuntu-artful contrib/dockerdeb ubuntu artful --source-only +docker-ubuntu-bionic: contrib/docker/ubuntu-bionic + contrib/dockerdeb ubuntu bionic + +docker-ubuntu-bionic-ppa: contrib/docker/ubuntu-bionic + contrib/dockerdeb ubuntu bionic --source-only + fedora20: mkdir -p packages/fedora20 contrib/buildrpm @@ -308,6 +314,7 @@ linux-wheels-i686: docker-ubuntu-trusty docker-ubuntu-trusty-ppa \ docker-ubuntu-xenial docker-ubuntu-xenial-ppa \ docker-ubuntu-artful docker-ubuntu-artful-ppa \ + docker-ubuntu-bionic docker-ubuntu-bionic-ppa \ fedora20 docker-fedora20 \ fedora21 docker-fedora21 \ centos5 docker-centos5 \ ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
[PATCH 2 of 3] makefile: reformat .PHONY targets
# HG changeset patch # User Antonio Muci # Date 1523723037 -7200 # Sat Apr 14 18:23:57 2018 +0200 # Node ID b5874ec21df592d83c3f97aa12ea33dfdb03e839 # Parent 3c8463e542db60db1ad234ec80f39e290ed17658 makefile: reformat .PHONY targets the list of make targets is likely to evolve over time. This reformatting streamlines future patches. diff --git a/Makefile b/Makefile --- a/Makefile +++ b/Makefile @@ -302,10 +302,15 @@ linux-wheels-i686: .PHONY: help all local build doc cleanbutpackages clean install install-bin \ install-doc install-home install-home-bin install-home-doc \ dist dist-notests check tests check-code format-c update-pot \ - osx deb ppa docker-debian-jessie docker-debian-stretch \ + osx deb ppa \ + docker-debian-jessie \ + docker-debian-stretch \ docker-ubuntu-trusty docker-ubuntu-trusty-ppa \ docker-ubuntu-xenial docker-ubuntu-xenial-ppa \ docker-ubuntu-artful docker-ubuntu-artful-ppa \ - fedora20 docker-fedora20 fedora21 docker-fedora21 \ - centos5 docker-centos5 centos6 docker-centos6 centos7 docker-centos7 \ + fedora20 docker-fedora20 \ + fedora21 docker-fedora21 \ + centos5 docker-centos5 \ + centos6 docker-centos6 \ + centos7 docker-centos7 \ linux-wheels ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
[PATCH 1 of 3] makefile: mkdir is not needed on templatized docker builds
# HG changeset patch # User Antonio Muci # Date 1523714275 -7200 # Sat Apr 14 15:57:55 2018 +0200 # Node ID 3c8463e542db60db1ad234ec80f39e290ed17658 # Parent 1541e1a8e87de9bd6b869ed498ad8e9b93c59d4d makefile: mkdir is not needed on templatized docker builds this imitates e63dfbbdbd07 and is a small addition to 231690dba9b4 and 5c1283713293 diff --git a/Makefile b/Makefile --- a/Makefile +++ b/Makefile @@ -213,11 +213,9 @@ contrib/docker/debian-%: contrib/docker/ sed "s/__CODENAME__/$*/" $< > $@ docker-debian-jessie: contrib/docker/debian-jessie - mkdir -p packages/debian-jessie contrib/dockerdeb debian jessie docker-debian-stretch: contrib/docker/debian-stretch - mkdir -p packages/debian-stretch contrib/dockerdeb debian stretch contrib/docker/ubuntu-%: contrib/docker/ubuntu.template ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
D3371: scmutil: make shortesthexnodeidprefix() take a full binary nodeid
martinvonz updated this revision to Diff 8286. REPOSITORY rHG Mercurial CHANGES SINCE LAST UPDATE https://phab.mercurial-scm.org/D3371?vs=8256=8286 REVISION DETAIL https://phab.mercurial-scm.org/D3371 AFFECTED FILES hgext/show.py mercurial/scmutil.py mercurial/templatefuncs.py tests/test-command-template.t CHANGE DETAILS diff --git a/tests/test-command-template.t b/tests/test-command-template.t --- a/tests/test-command-template.t +++ b/tests/test-command-template.t @@ -3900,6 +3900,21 @@ $ hg log -r 'wdir()' -T '{node|shortest}\n' + $ hg log --template '{shortest("f")}\n' -l1 + f + + $ hg log --template '{shortest("0123456789012345678901234567890123456789")}\n' -l1 + 0123456789012345678901234567890123456789 + + $ hg log --template '{shortest("01234567890123456789012345678901234567890123456789")}\n' -l1 + 01234567890123456789012345678901234567890123456789 + + $ hg log --template '{shortest("not a hex string")}\n' -l1 + not a hex string + + $ hg log --template '{shortest("not a hex string, but it'\''s 40 bytes long")}\n' -l1 + not a hex string, but it's 40 bytes long + $ cd .. Test shortest(node) with the repo having short hash collision: diff --git a/mercurial/templatefuncs.py b/mercurial/templatefuncs.py --- a/mercurial/templatefuncs.py +++ b/mercurial/templatefuncs.py @@ -26,6 +26,9 @@ templateutil, util, ) +from .node import ( +bin, +) from .utils import ( dateutil, stringutil, @@ -579,15 +582,29 @@ # i18n: "shortest" is a keyword raise error.ParseError(_("shortest() expects one or two arguments")) -node = evalstring(context, mapping, args[0]) +hexnode = evalstring(context, mapping, args[0]) minlength = 4 if len(args) > 1: minlength = evalinteger(context, mapping, args[1], # i18n: "shortest" is a keyword _("shortest() expects an integer minlength")) repo = context.resource(mapping, 'ctx')._repo +if len(hexnode) > 40: +return hexnode +elif len(hexnode) == 40: +try: +node = bin(hexnode) +except TypeError: +return hexnode +else: +try: +node = scmutil.resolvehexnodeidprefix(repo, hexnode) +except (error.LookupError, error.WdirUnsupported): +return hexnode +if not node: +return hexnode return scmutil.shortesthexnodeidprefix(repo, node, minlength) @templatefunc('strip(text[, chars])') diff --git a/mercurial/scmutil.py b/mercurial/scmutil.py --- a/mercurial/scmutil.py +++ b/mercurial/scmutil.py @@ -443,12 +443,12 @@ repo.changelog.rev(node) # make sure node isn't filtered return node -def shortesthexnodeidprefix(repo, hexnode, minlength=1): +def shortesthexnodeidprefix(repo, node, minlength=1): """Find the shortest unambiguous prefix that matches hexnode.""" # _partialmatch() of filtered changelog could take O(len(repo)) time, # which would be unacceptably slow. so we look for hash collision in # unfiltered space, which means some hashes may be slightly longer. -return repo.unfiltered().changelog.shortest(hexnode, minlength) +return repo.unfiltered().changelog.shortest(hex(node), minlength) def isrevsymbol(repo, symbol): """Checks if a symbol exists in the repo. diff --git a/hgext/show.py b/hgext/show.py --- a/hgext/show.py +++ b/hgext/show.py @@ -29,7 +29,6 @@ from mercurial.i18n import _ from mercurial.node import ( -hex, nullrev, ) from mercurial import ( @@ -448,8 +447,8 @@ if not revs: return minlen cl = repo.changelog -return max(len(scmutil.shortesthexnodeidprefix(repo, hex(cl.node(r)), - minlen)) for r in revs) +return max(len(scmutil.shortesthexnodeidprefix(repo, cl.node(r), minlen)) + for r in revs) # Adjust the docstring of the show command so it shows all registered views. # This is a bit hacky because it runs at the end of module load. When moved To: martinvonz, #hg-reviewers Cc: mercurial-devel ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
D3309: scmutil: rename resolvepartialhexnodeid() to resolvehexnodeidprefix()
martinvonz updated this revision to Diff 8283. REPOSITORY rHG Mercurial CHANGES SINCE LAST UPDATE https://phab.mercurial-scm.org/D3309?vs=8260=8283 REVISION DETAIL https://phab.mercurial-scm.org/D3309 AFFECTED FILES hgext/eol.py hgext/histedit.py mercurial/context.py mercurial/scmutil.py CHANGE DETAILS diff --git a/mercurial/scmutil.py b/mercurial/scmutil.py --- a/mercurial/scmutil.py +++ b/mercurial/scmutil.py @@ -434,8 +434,8 @@ hexfunc = short return '%d:%s' % (rev, hexfunc(node)) -def resolvepartialhexnodeid(repo, prefix): -# Uses unfiltered repo because it's faster when then prefix is ambiguous/ +def resolvehexnodeidprefix(repo, prefix): +# Uses unfiltered repo because it's faster when prefix is ambiguous/ # This matches the "shortest" template function. node = repo.unfiltered().changelog._partialmatch(prefix) if node is None: diff --git a/mercurial/context.py b/mercurial/context.py --- a/mercurial/context.py +++ b/mercurial/context.py @@ -392,7 +392,7 @@ # * If you know that "x" is a branch or in some other namespace, #use the appropriate mechanism for that namespace # * If you know that "x" is a hex nodeid prefix, use -#repo[scmutil.resolvepartialhexnodeid(repo, x)] +#repo[scmutil.resolvehexnodeidprefix(repo, x)] # * If "x" is a string that can be any of the above, but you don't want #to allow general revsets (perhaps because "x" may come from a remote #user and the revset may be too costly), use scmutil.revsymbol(repo, x) @@ -476,7 +476,7 @@ except KeyError: pass -self._node = scmutil.resolvepartialhexnodeid(repo, changeid) +self._node = scmutil.resolvehexnodeidprefix(repo, changeid) if self._node is not None: self._rev = repo.changelog.rev(self._node) changectxdeprecwarn(repo) diff --git a/hgext/histedit.py b/hgext/histedit.py --- a/hgext/histedit.py +++ b/hgext/histedit.py @@ -443,7 +443,7 @@ """ Verifies semantic correctness of the rule""" repo = self.repo ha = node.hex(self.node) -self.node = scmutil.resolvepartialhexnodeid(repo, ha) +self.node = scmutil.resolvehexnodeidprefix(repo, ha) if self.node is None: raise error.ParseError(_('unknown changeset %s listed') % ha[:12]) self._verifynodeconstraints(prev, expected, seen) diff --git a/hgext/eol.py b/hgext/eol.py --- a/hgext/eol.py +++ b/hgext/eol.py @@ -300,7 +300,7 @@ hook = checkheadshook def preupdate(ui, repo, hooktype, parent1, parent2): -p1node = scmutil.resolvepartialhexnodeid(repo, parent1) +p1node = scmutil.resolvehexnodeidprefix(repo, parent1) repo.loadeol([p1node]) return False To: martinvonz, durin42, #hg-reviewers Cc: mercurial-devel ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
D3310: scmutil: use resolvehexnodeidprefix() from revsymbol()
martinvonz updated this revision to Diff 8284. REPOSITORY rHG Mercurial CHANGES SINCE LAST UPDATE https://phab.mercurial-scm.org/D3310?vs=8261=8284 REVISION DETAIL https://phab.mercurial-scm.org/D3310 AFFECTED FILES mercurial/scmutil.py CHANGE DETAILS diff --git a/mercurial/scmutil.py b/mercurial/scmutil.py --- a/mercurial/scmutil.py +++ b/mercurial/scmutil.py @@ -503,7 +503,7 @@ except KeyError: pass -node = repo.unfiltered().changelog._partialmatch(symbol) +node = resolvehexnodeidprefix(repo, symbol) if node is not None: rev = repo.changelog.rev(node) return repo[rev] To: martinvonz, #hg-reviewers Cc: mercurial-devel ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
D3370: scmutil: introduce shortesthexnodeidprefix()
martinvonz updated this revision to Diff 8285. REPOSITORY rHG Mercurial CHANGES SINCE LAST UPDATE https://phab.mercurial-scm.org/D3370?vs=8262=8285 REVISION DETAIL https://phab.mercurial-scm.org/D3370 AFFECTED FILES hgext/show.py mercurial/scmutil.py mercurial/templatefuncs.py CHANGE DETAILS diff --git a/mercurial/templatefuncs.py b/mercurial/templatefuncs.py --- a/mercurial/templatefuncs.py +++ b/mercurial/templatefuncs.py @@ -590,8 +590,8 @@ # _partialmatch() of filtered changelog could take O(len(repo)) time, # which would be unacceptably slow. so we look for hash collision in # unfiltered space, which means some hashes may be slightly longer. -cl = context.resource(mapping, 'ctx')._repo.unfiltered().changelog -return cl.shortest(node, minlength) +repo = context.resource(mapping, 'ctx')._repo +return scmutil.shortesthexnodeidprefix(repo.unfiltered(), node, minlength) @templatefunc('strip(text[, chars])') def strip(context, mapping, args): diff --git a/mercurial/scmutil.py b/mercurial/scmutil.py --- a/mercurial/scmutil.py +++ b/mercurial/scmutil.py @@ -443,6 +443,10 @@ repo.changelog.rev(node) # make sure node isn't filtered return node +def shortesthexnodeidprefix(repo, hexnode, minlength=1): +"""Find the shortest unambiguous prefix that matches hexnode.""" +return repo.changelog.shortest(hexnode, minlength) + def isrevsymbol(repo, symbol): """Checks if a symbol exists in the repo. diff --git a/hgext/show.py b/hgext/show.py --- a/hgext/show.py +++ b/hgext/show.py @@ -45,6 +45,7 @@ registrar, revset, revsetlang, +scmutil, ) # Note for extension authors: ONLY specify testedwith = 'ships-with-hg-core' for @@ -447,8 +448,10 @@ if not revs: return minlen # don't use filtered repo because it's slow. see templater.shortest(). -cl = repo.unfiltered().changelog -return max(len(cl.shortest(hex(cl.node(r)), minlen)) for r in revs) +cl = repo.changelog +return max(len(scmutil.shortesthexnodeidprefix(repo.unfiltered(), + hex(cl.node(r)), + minlen)) for r in revs) # Adjust the docstring of the show command so it shows all registered views. # This is a bit hacky because it runs at the end of module load. When moved To: martinvonz, #hg-reviewers Cc: mercurial-devel ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
D3308: scmutil: document that isrevsymbol() raises on ambiguous node prefix
martinvonz updated this revision to Diff 8282. REPOSITORY rHG Mercurial CHANGES SINCE LAST UPDATE https://phab.mercurial-scm.org/D3308?vs=8259=8282 REVISION DETAIL https://phab.mercurial-scm.org/D3308 AFFECTED FILES mercurial/scmutil.py CHANGE DETAILS diff --git a/mercurial/scmutil.py b/mercurial/scmutil.py --- a/mercurial/scmutil.py +++ b/mercurial/scmutil.py @@ -444,6 +444,11 @@ return node def isrevsymbol(repo, symbol): +"""Checks if a symbol exists in the repo. + + See revsymbol() for details. Raises error.LookupError if the symbol is an + ambiguous nodeid prefix. +""" try: revsymbol(repo, symbol) return True To: martinvonz, #hg-reviewers Cc: mercurial-devel ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
D3311: revset: use resolvehexnodeidprefix() in id() predicate (BC)
martinvonz added a comment. In https://phab.mercurial-scm.org/D3311#53712, @yuja wrote: > I have vague memory that it was intentional. Since `rev()` and `id()` never > error out on unknown identifier, it doesn't make sense to reject only > ambiguous nodeid. I'm fine with dropping this patch. The rest of the stack doesn't depend on it anyway. REPOSITORY rHG Mercurial REVISION DETAIL https://phab.mercurial-scm.org/D3311 To: martinvonz, #hg-reviewers, yuja Cc: yuja, mercurial-devel ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
D3375: cleanup: polyfill assertRaisesRegex so we can avoid assertRaisesRegexp
durin42 updated this revision to Diff 8281. REPOSITORY rHG Mercurial CHANGES SINCE LAST UPDATE https://phab.mercurial-scm.org/D3375?vs=8280=8281 REVISION DETAIL https://phab.mercurial-scm.org/D3375 AFFECTED FILES tests/test-simplekeyvaluefile.py tests/test-wireproto-clientreactor.py tests/test-wireproto-framing.py tests/test-wsgirequest.py CHANGE DETAILS diff --git a/tests/test-wsgirequest.py b/tests/test-wsgirequest.py --- a/tests/test-wsgirequest.py +++ b/tests/test-wsgirequest.py @@ -196,21 +196,27 @@ self.assertEqual(r.dispatchparts, [b'pathinfo']) self.assertEqual(r.dispatchpath, b'pathinfo') +if not getattr(unittest.TestCase, 'assertRaisesRegex', False): +# Python 3.7 deprecates the regex*p* version, but 2.7 lacks +# the regex version. +assertRaisesRegex = (# camelcase-required +unittest.TestCase.assertRaisesRegexp) + def testreponame(self): """repository path components get stripped from URL.""" -with self.assertRaisesRegexp(error.ProgrammingError, +with self.assertRaisesRegex(error.ProgrammingError, b'reponame requires PATH_INFO'): parse(DEFAULT_ENV, reponame=b'repo') -with self.assertRaisesRegexp(error.ProgrammingError, +with self.assertRaisesRegex(error.ProgrammingError, b'PATH_INFO does not begin with repo ' b'name'): parse(DEFAULT_ENV, reponame=b'repo', extra={ r'PATH_INFO': r'/pathinfo', }) -with self.assertRaisesRegexp(error.ProgrammingError, +with self.assertRaisesRegex(error.ProgrammingError, b'reponame prefix of PATH_INFO'): parse(DEFAULT_ENV, reponame=b'repo', extra={ r'PATH_INFO': r'/repoextra/path', diff --git a/tests/test-wireproto-framing.py b/tests/test-wireproto-framing.py --- a/tests/test-wireproto-framing.py +++ b/tests/test-wireproto-framing.py @@ -103,19 +103,25 @@ ffs(b'1 1 0 command-data eos %s' % data.getvalue()), ]) +if not getattr(unittest.TestCase, 'assertRaisesRegex', False): +# Python 3.7 deprecates the regex*p* version, but 2.7 lacks +# the regex version. +assertRaisesRegex = (# camelcase-required +unittest.TestCase.assertRaisesRegexp) + def testtextoutputformattingstringtype(self): """Formatting string must be bytes.""" -with self.assertRaisesRegexp(ValueError, 'must use bytes formatting '): +with self.assertRaisesRegex(ValueError, 'must use bytes formatting '): list(framing.createtextoutputframe(None, 1, [ (b'foo'.decode('ascii'), [], [])])) def testtextoutputargumentbytes(self): -with self.assertRaisesRegexp(ValueError, 'must use bytes for argument'): +with self.assertRaisesRegex(ValueError, 'must use bytes for argument'): list(framing.createtextoutputframe(None, 1, [ (b'foo', [b'foo'.decode('ascii')], [])])) def testtextoutputlabelbytes(self): -with self.assertRaisesRegexp(ValueError, 'must use bytes for labels'): +with self.assertRaisesRegex(ValueError, 'must use bytes for labels'): list(framing.createtextoutputframe(None, 1, [ (b'foo', [], [b'foo'.decode('ascii')])])) diff --git a/tests/test-wireproto-clientreactor.py b/tests/test-wireproto-clientreactor.py --- a/tests/test-wireproto-clientreactor.py +++ b/tests/test-wireproto-clientreactor.py @@ -24,6 +24,13 @@ class SingleSendTests(unittest.TestCase): """A reactor that can only send once rejects subsequent sends.""" + +if not getattr(unittest.TestCase, 'assertRaisesRegex', False): +# Python 3.7 deprecates the regex*p* version, but 2.7 lacks +# the regex version. +assertRaisesRegex = (# camelcase-required +unittest.TestCase.assertRaisesRegexp) + def testbasic(self): reactor = framing.clientreactor(hasmultiplesend=False, buffersends=True) @@ -39,11 +46,11 @@ self.assertEqual(request.state, b'sent') -with self.assertRaisesRegexp(error.ProgrammingError, +with self.assertRaisesRegex(error.ProgrammingError, 'cannot issue new commands'): reactor.callcommand(b'foo', {}) -with self.assertRaisesRegexp(error.ProgrammingError, +with self.assertRaisesRegex(error.ProgrammingError, 'cannot issue new commands'): reactor.callcommand(b'foo', {}) @@ -77,6 +84,12 @@ self.assertEqual(request.state, b'sent') class BadFrameRecvTests(unittest.TestCase): +if not getattr(unittest.TestCase, 'assertRaisesRegex', False): +# Python 3.7 deprecates the regex*p* version, but 2.7 lacks +# the
D3375: cleanup: polyfill assertRaisesRegex so we can avoid assertRaisesRegexp
durin42 created this revision. Herald added a subscriber: mercurial-devel. Herald added a reviewer: hg-reviewers. REVISION SUMMARY The latter is deprecated on Python 3.7 and causes our tests to fail due to the warning. REPOSITORY rHG Mercurial REVISION DETAIL https://phab.mercurial-scm.org/D3375 AFFECTED FILES tests/test-simplekeyvaluefile.py tests/test-wireproto-clientreactor.py tests/test-wireproto-framing.py tests/test-wsgirequest.py CHANGE DETAILS diff --git a/tests/test-wsgirequest.py b/tests/test-wsgirequest.py --- a/tests/test-wsgirequest.py +++ b/tests/test-wsgirequest.py @@ -196,21 +196,26 @@ self.assertEqual(r.dispatchparts, [b'pathinfo']) self.assertEqual(r.dispatchpath, b'pathinfo') +if not getattr(unittest.TestCase, 'assertRaisesRegex', False): +# Python 3.7 deprecates the regex*p* version, but 2.7 lacks +# the regex version. +assertRaisesRegex = unittest.TestCase.assertRaisesRegexp + def testreponame(self): """repository path components get stripped from URL.""" -with self.assertRaisesRegexp(error.ProgrammingError, +with self.assertRaisesRegex(error.ProgrammingError, b'reponame requires PATH_INFO'): parse(DEFAULT_ENV, reponame=b'repo') -with self.assertRaisesRegexp(error.ProgrammingError, +with self.assertRaisesRegex(error.ProgrammingError, b'PATH_INFO does not begin with repo ' b'name'): parse(DEFAULT_ENV, reponame=b'repo', extra={ r'PATH_INFO': r'/pathinfo', }) -with self.assertRaisesRegexp(error.ProgrammingError, +with self.assertRaisesRegex(error.ProgrammingError, b'reponame prefix of PATH_INFO'): parse(DEFAULT_ENV, reponame=b'repo', extra={ r'PATH_INFO': r'/repoextra/path', diff --git a/tests/test-wireproto-framing.py b/tests/test-wireproto-framing.py --- a/tests/test-wireproto-framing.py +++ b/tests/test-wireproto-framing.py @@ -103,19 +103,24 @@ ffs(b'1 1 0 command-data eos %s' % data.getvalue()), ]) +if not getattr(unittest.TestCase, 'assertRaisesRegex', False): +# Python 3.7 deprecates the regex*p* version, but 2.7 lacks +# the regex version. +assertRaisesRegex = unittest.TestCase.assertRaisesRegexp + def testtextoutputformattingstringtype(self): """Formatting string must be bytes.""" -with self.assertRaisesRegexp(ValueError, 'must use bytes formatting '): +with self.assertRaisesRegex(ValueError, 'must use bytes formatting '): list(framing.createtextoutputframe(None, 1, [ (b'foo'.decode('ascii'), [], [])])) def testtextoutputargumentbytes(self): -with self.assertRaisesRegexp(ValueError, 'must use bytes for argument'): +with self.assertRaisesRegex(ValueError, 'must use bytes for argument'): list(framing.createtextoutputframe(None, 1, [ (b'foo', [b'foo'.decode('ascii')], [])])) def testtextoutputlabelbytes(self): -with self.assertRaisesRegexp(ValueError, 'must use bytes for labels'): +with self.assertRaisesRegex(ValueError, 'must use bytes for labels'): list(framing.createtextoutputframe(None, 1, [ (b'foo', [], [b'foo'.decode('ascii')])])) diff --git a/tests/test-wireproto-clientreactor.py b/tests/test-wireproto-clientreactor.py --- a/tests/test-wireproto-clientreactor.py +++ b/tests/test-wireproto-clientreactor.py @@ -24,6 +24,12 @@ class SingleSendTests(unittest.TestCase): """A reactor that can only send once rejects subsequent sends.""" + +if not getattr(unittest.TestCase, 'assertRaisesRegex', False): +# Python 3.7 deprecates the regex*p* version, but 2.7 lacks +# the regex version. +assertRaisesRegex = unittest.TestCase.assertRaisesRegexp + def testbasic(self): reactor = framing.clientreactor(hasmultiplesend=False, buffersends=True) @@ -39,11 +45,11 @@ self.assertEqual(request.state, b'sent') -with self.assertRaisesRegexp(error.ProgrammingError, +with self.assertRaisesRegex(error.ProgrammingError, 'cannot issue new commands'): reactor.callcommand(b'foo', {}) -with self.assertRaisesRegexp(error.ProgrammingError, +with self.assertRaisesRegex(error.ProgrammingError, 'cannot issue new commands'): reactor.callcommand(b'foo', {}) @@ -77,6 +83,11 @@ self.assertEqual(request.state, b'sent') class BadFrameRecvTests(unittest.TestCase): +if not getattr(unittest.TestCase, 'assertRaisesRegex', False): +# Python 3.7 deprecates the regex*p* version, but 2.7 lacks +# the regex
D3303: cborutil: implement support for streaming encoding, bytestring decoding
indygreg added a comment. In https://phab.mercurial-scm.org/D3303#53422, @yuja wrote: > If it's just for date tuple, I have a patch to get rid of floating-point timestamps > as our timestamps should be effectively ints. I believe that's the only place we use floats. Or at least the only place I saw it in test failures. REPOSITORY rHG Mercurial REVISION DETAIL https://phab.mercurial-scm.org/D3303 To: indygreg, #hg-reviewers Cc: yuja, mercurial-devel ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
D3373: tests: port test-hg-parseurl.py to unittest
durin42 created this revision. Herald added a subscriber: mercurial-devel. Herald added a reviewer: hg-reviewers. REPOSITORY rHG Mercurial REVISION DETAIL https://phab.mercurial-scm.org/D3373 AFFECTED FILES tests/test-hg-parseurl.py tests/test-hg-parseurl.py.out CHANGE DETAILS diff --git a/tests/test-hg-parseurl.py.out b/tests/test-hg-parseurl.py.out deleted file mode 100644 --- a/tests/test-hg-parseurl.py.out +++ /dev/null @@ -1,8 +0,0 @@ -http://example.com/no/anchor, branches: (None, []) -http://example.com/an/anchor, branches: ('foo', []) -http://example.com/no/anchor/branches, branches: (None, ['foo']) -http://example.com/an/anchor/branches, branches: ('bar', ['foo']) -http://example.com/an/anchor/branches-None, branches: ('foo', []) -http://example.com/, branches: (None, []) -http://example.com/, branches: (None, []) -http://example.com/, branches: ('foo', []) diff --git a/tests/test-hg-parseurl.py b/tests/test-hg-parseurl.py --- a/tests/test-hg-parseurl.py +++ b/tests/test-hg-parseurl.py @@ -1,17 +1,34 @@ from __future__ import absolute_import, print_function +import unittest + from mercurial import ( hg, ) -def testparse(url, branch=[]): -print('%s, branches: %r' % hg.parseurl(url, branch)) +class ParseRequestTests(unittest.TestCase): +def testparse(self): -testparse('http://example.com/no/anchor') -testparse('http://example.com/an/anchor#foo') -testparse('http://example.com/no/anchor/branches', branch=['foo']) -testparse('http://example.com/an/anchor/branches#bar', branch=['foo']) -testparse('http://example.com/an/anchor/branches-None#foo', branch=None) -testparse('http://example.com/') -testparse('http://example.com') -testparse('http://example.com#foo') +self.assertEqual(hg.parseurl('http://example.com/no/anchor'), + ('http://example.com/no/anchor', (None, []))) +self.assertEqual(hg.parseurl('http://example.com/an/anchor#foo'), + ('http://example.com/an/anchor', ('foo', []))) +self.assertEqual( +hg.parseurl('http://example.com/no/anchor/branches', ['foo']), +('http://example.com/no/anchor/branches', (None, ['foo']))) +self.assertEqual( +hg.parseurl('http://example.com/an/anchor/branches#bar', ['foo']), +('http://example.com/an/anchor/branches', ('bar', ['foo']))) +self.assertEqual(hg.parseurl( +'http://example.com/an/anchor/branches-None#foo', None), +('http://example.com/an/anchor/branches-None', ('foo', []))) +self.assertEqual(hg.parseurl('http://example.com/'), + ('http://example.com/', (None, []))) +self.assertEqual(hg.parseurl('http://example.com'), + ('http://example.com/', (None, []))) +self.assertEqual(hg.parseurl('http://example.com#foo'), + ('http://example.com/', ('foo', []))) + +if __name__ == '__main__': +import silenttestrunner +silenttestrunner.main(__name__) To: durin42, #hg-reviewers Cc: mercurial-devel ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
D3374: tests: add b prefixes to test-hg-parseurl.py
durin42 created this revision. Herald added a subscriber: mercurial-devel. Herald added a reviewer: hg-reviewers. REVISION SUMMARY Now passes on Python 3. REPOSITORY rHG Mercurial REVISION DETAIL https://phab.mercurial-scm.org/D3374 AFFECTED FILES tests/test-hg-parseurl.py CHANGE DETAILS diff --git a/tests/test-hg-parseurl.py b/tests/test-hg-parseurl.py --- a/tests/test-hg-parseurl.py +++ b/tests/test-hg-parseurl.py @@ -9,25 +9,25 @@ class ParseRequestTests(unittest.TestCase): def testparse(self): -self.assertEqual(hg.parseurl('http://example.com/no/anchor'), - ('http://example.com/no/anchor', (None, []))) -self.assertEqual(hg.parseurl('http://example.com/an/anchor#foo'), - ('http://example.com/an/anchor', ('foo', []))) +self.assertEqual(hg.parseurl(b'http://example.com/no/anchor'), + (b'http://example.com/no/anchor', (None, []))) +self.assertEqual(hg.parseurl(b'http://example.com/an/anchor#foo'), + (b'http://example.com/an/anchor', (b'foo', []))) self.assertEqual( -hg.parseurl('http://example.com/no/anchor/branches', ['foo']), -('http://example.com/no/anchor/branches', (None, ['foo']))) +hg.parseurl(b'http://example.com/no/anchor/branches', [b'foo']), +(b'http://example.com/no/anchor/branches', (None, [b'foo']))) self.assertEqual( -hg.parseurl('http://example.com/an/anchor/branches#bar', ['foo']), -('http://example.com/an/anchor/branches', ('bar', ['foo']))) +hg.parseurl(b'http://example.com/an/anchor/branches#bar', [b'foo']), +(b'http://example.com/an/anchor/branches', (b'bar', [b'foo']))) self.assertEqual(hg.parseurl( -'http://example.com/an/anchor/branches-None#foo', None), -('http://example.com/an/anchor/branches-None', ('foo', []))) -self.assertEqual(hg.parseurl('http://example.com/'), - ('http://example.com/', (None, []))) -self.assertEqual(hg.parseurl('http://example.com'), - ('http://example.com/', (None, []))) -self.assertEqual(hg.parseurl('http://example.com#foo'), - ('http://example.com/', ('foo', []))) +b'http://example.com/an/anchor/branches-None#foo', None), +(b'http://example.com/an/anchor/branches-None', (b'foo', []))) +self.assertEqual(hg.parseurl(b'http://example.com/'), + (b'http://example.com/', (None, []))) +self.assertEqual(hg.parseurl(b'http://example.com'), + (b'http://example.com/', (None, []))) +self.assertEqual(hg.parseurl(b'http://example.com#foo'), + (b'http://example.com/', (b'foo', []))) if __name__ == '__main__': import silenttestrunner To: durin42, #hg-reviewers Cc: mercurial-devel ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
D3367: hgwebdir: un-bytes the env dict before re-parsing env
durin42 updated this revision to Diff 8277. Herald added a reviewer: pulkit. REPOSITORY rHG Mercurial CHANGES SINCE LAST UPDATE https://phab.mercurial-scm.org/D3367?vs=8275=8277 REVISION DETAIL https://phab.mercurial-scm.org/D3367 AFFECTED FILES contrib/python3-whitelist mercurial/hgweb/hgwebdir_mod.py CHANGE DETAILS diff --git a/mercurial/hgweb/hgwebdir_mod.py b/mercurial/hgweb/hgwebdir_mod.py --- a/mercurial/hgweb/hgwebdir_mod.py +++ b/mercurial/hgweb/hgwebdir_mod.py @@ -422,8 +422,12 @@ if real: # Re-parse the WSGI environment to take into account our # repository path component. +uenv = req.rawenv +if pycompat.ispy3: +uenv = {k.decode('latin1'): v for k, v in +uenv.iteritems()} req = requestmod.parserequestfromenv( -req.rawenv, reponame=virtualrepo, +uenv, reponame=virtualrepo, altbaseurl=self.ui.config('web', 'baseurl')) try: # ensure caller gets private copy of ui diff --git a/contrib/python3-whitelist b/contrib/python3-whitelist --- a/contrib/python3-whitelist +++ b/contrib/python3-whitelist @@ -153,6 +153,7 @@ test-glog-topological.t test-gpg.t test-graft.t +test-hg-parseurl.py test-hghave.t test-hgignore.t test-hgk.t To: durin42, #hg-reviewers, yuja, pulkit Cc: yuja, mercurial-devel ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
D3372: keepalive: add ** overlooked in 83250442dc81
durin42 created this revision. Herald added a subscriber: mercurial-devel. Herald added a reviewer: hg-reviewers. REVISION SUMMARY Caught by Yuya in https://phab.mercurial-scm.org/D3326. REPOSITORY rHG Mercurial REVISION DETAIL https://phab.mercurial-scm.org/D3372 AFFECTED FILES mercurial/keepalive.py CHANGE DETAILS diff --git a/mercurial/keepalive.py b/mercurial/keepalive.py --- a/mercurial/keepalive.py +++ b/mercurial/keepalive.py @@ -326,16 +326,16 @@ data = urllibcompat.getdata(req) h.putrequest( req.get_method(), urllibcompat.getselector(req), -skipheaders) +**skipheaders) if r'content-type' not in headers: h.putheader(r'Content-type', r'application/x-www-form-urlencoded') if r'content-length' not in headers: h.putheader(r'Content-length', r'%d' % len(data)) else: h.putrequest( req.get_method(), urllibcompat.getselector(req), -skipheaders) +**skipheaders) except socket.error as err: raise urlerr.urlerror(err) for k, v in headers.items(): To: durin42, #hg-reviewers Cc: mercurial-devel ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
D3367: hgwebdir: un-bytes the env dict before re-parsing env
durin42 updated this revision to Diff 8275. REPOSITORY rHG Mercurial CHANGES SINCE LAST UPDATE https://phab.mercurial-scm.org/D3367?vs=8244=8275 REVISION DETAIL https://phab.mercurial-scm.org/D3367 AFFECTED FILES mercurial/hgweb/hgwebdir_mod.py CHANGE DETAILS diff --git a/mercurial/hgweb/hgwebdir_mod.py b/mercurial/hgweb/hgwebdir_mod.py --- a/mercurial/hgweb/hgwebdir_mod.py +++ b/mercurial/hgweb/hgwebdir_mod.py @@ -422,8 +422,12 @@ if real: # Re-parse the WSGI environment to take into account our # repository path component. +uenv = req..rawenv +if pycompat.ispy3: +uenv = {k.decode('latin1'): v for k, v in +uenv.iteritems()} req = requestmod.parserequestfromenv( -req.rawenv, reponame=virtualrepo, +uenv, reponame=virtualrepo, altbaseurl=self.ui.config('web', 'baseurl')) try: # ensure caller gets private copy of ui To: durin42, #hg-reviewers, yuja Cc: yuja, mercurial-devel ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
D3364: largefiles: opts appears to already be bytes in this instance
durin42 updated this revision to Diff 8274. REPOSITORY rHG Mercurial CHANGES SINCE LAST UPDATE https://phab.mercurial-scm.org/D3364?vs=8241=8274 REVISION DETAIL https://phab.mercurial-scm.org/D3364 AFFECTED FILES contrib/python3-whitelist hgext/largefiles/overrides.py CHANGE DETAILS diff --git a/hgext/largefiles/overrides.py b/hgext/largefiles/overrides.py --- a/hgext/largefiles/overrides.py +++ b/hgext/largefiles/overrides.py @@ -897,7 +897,7 @@ # Caching is implicitly limited to 'rev' option, since the dest repo was # truncated at that point. The user may expect a download count with # this option, so attempt whether or not this is a largefile repo. -if opts.get(r'all_largefiles'): +if opts.get('all_largefiles'): success, missing = lfcommands.downloadlfiles(ui, repo, None) if missing != 0: diff --git a/contrib/python3-whitelist b/contrib/python3-whitelist --- a/contrib/python3-whitelist +++ b/contrib/python3-whitelist @@ -210,6 +210,7 @@ test-largefiles-misc.t test-largefiles-small-disk.t test-largefiles-update.t +test-largefiles.t test-lfs-largefiles.t test-linerange.py test-locate.t To: durin42, pulkit, #hg-reviewers Cc: mercurial-devel ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
D3350: tests: fix up a couple of minor bytes inconsistencies in run-tests.py
durin42 updated this revision to Diff 8269. REPOSITORY rHG Mercurial CHANGES SINCE LAST UPDATE https://phab.mercurial-scm.org/D3350?vs=8227=8269 REVISION DETAIL https://phab.mercurial-scm.org/D3350 AFFECTED FILES contrib/python3-whitelist tests/run-tests.py CHANGE DETAILS diff --git a/tests/run-tests.py b/tests/run-tests.py --- a/tests/run-tests.py +++ b/tests/run-tests.py @@ -2215,10 +2215,11 @@ 'Failed to identify failure point for %s' % test) continue dat = m.groupdict() -verb = 'broken' if dat['goodbad'] == 'bad' else 'fixed' +verb = 'broken' if dat['goodbad'] == b'bad' else 'fixed' self.stream.writeln( '%s %s by %s (%s)' % ( -test, verb, dat['node'], dat['summary'])) +test, verb, dat['node'].decode('ascii'), +dat['summary'].decode('utf8', 'ignore'))) def printtimes(self, times): # iolock held by run diff --git a/contrib/python3-whitelist b/contrib/python3-whitelist --- a/contrib/python3-whitelist +++ b/contrib/python3-whitelist @@ -392,6 +392,7 @@ test-revset-outgoing.t test-rollback.t test-run-tests.py +test-run-tests.t test-schemes.t test-serve.t test-setdiscovery.t To: durin42, pulkit, #hg-reviewers Cc: mercurial-devel ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
D3351: py3: fix test-shelve.t on Python 3
durin42 updated this revision to Diff 8270. REPOSITORY rHG Mercurial CHANGES SINCE LAST UPDATE https://phab.mercurial-scm.org/D3351?vs=8228=8270 REVISION DETAIL https://phab.mercurial-scm.org/D3351 AFFECTED FILES contrib/python3-whitelist tests/test-shelve.t CHANGE DETAILS diff --git a/tests/test-shelve.t b/tests/test-shelve.t --- a/tests/test-shelve.t +++ b/tests/test-shelve.t @@ -1273,7 +1273,7 @@ $ rm .hg/unshelverebasestate $ hg unshelve --abort unshelve of 'default' aborted - abort: $ENOENT$ + abort: $ENOENT$* (glob) [255] Can the user leave the current state? $ hg up -C . diff --git a/contrib/python3-whitelist b/contrib/python3-whitelist --- a/contrib/python3-whitelist +++ b/contrib/python3-whitelist @@ -397,6 +397,7 @@ test-serve.t test-setdiscovery.t test-share.t +test-shelve.t test-show-stack.t test-show-work.t test-show.t To: durin42, pulkit, #hg-reviewers Cc: mercurial-devel ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
D3358: stringutil: teach pprint how to format None
durin42 updated this revision to Diff 8272. REPOSITORY rHG Mercurial CHANGES SINCE LAST UPDATE https://phab.mercurial-scm.org/D3358?vs=8235=8272 REVISION DETAIL https://phab.mercurial-scm.org/D3358 AFFECTED FILES mercurial/utils/stringutil.py CHANGE DETAILS diff --git a/mercurial/utils/stringutil.py b/mercurial/utils/stringutil.py --- a/mercurial/utils/stringutil.py +++ b/mercurial/utils/stringutil.py @@ -42,6 +42,8 @@ return '%d' % o elif isinstance(o, float): return '%f' % o +elif o is None: +return b'None' else: raise error.ProgrammingError('do not know how to format %r' % o) To: durin42, #hg-reviewers Cc: mercurial-devel ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
D3356: wsgicgi: un-do some prior porting work that is now wrong
durin42 updated this revision to Diff 8271. REPOSITORY rHG Mercurial CHANGES SINCE LAST UPDATE https://phab.mercurial-scm.org/D3356?vs=8233=8271 REVISION DETAIL https://phab.mercurial-scm.org/D3356 AFFECTED FILES contrib/python3-whitelist mercurial/hgweb/wsgicgi.py CHANGE DETAILS diff --git a/mercurial/hgweb/wsgicgi.py b/mercurial/hgweb/wsgicgi.py --- a/mercurial/hgweb/wsgicgi.py +++ b/mercurial/hgweb/wsgicgi.py @@ -10,8 +10,10 @@ from __future__ import absolute_import +import os + from .. import ( -encoding, +pycompat, ) from ..utils import ( @@ -26,7 +28,7 @@ procutil.setbinary(procutil.stdin) procutil.setbinary(procutil.stdout) -environ = dict(encoding.environ.iteritems()) +environ = dict(os.environ.iteritems()) # re-exports environ.setdefault(r'PATH_INFO', '') if environ.get(r'SERVER_SOFTWARE', r'').startswith(r'Microsoft-IIS'): # IIS includes script_name in PATH_INFO @@ -61,9 +63,10 @@ elif not headers_sent: # Before the first output, send the stored headers status, response_headers = headers_sent[:] = headers_set -out.write('Status: %s\r\n' % status) -for header in response_headers: -out.write('%s: %s\r\n' % header) +out.write('Status: %s\r\n' % pycompat.bytesurl(status)) +for hk, hv in response_headers: +out.write('%s: %s\r\n' % (pycompat.bytesurl(hk), + pycompat.bytesurl(hv))) out.write('\r\n') out.write(data) diff --git a/contrib/python3-whitelist b/contrib/python3-whitelist --- a/contrib/python3-whitelist +++ b/contrib/python3-whitelist @@ -45,6 +45,7 @@ test-check-pylint.t test-check-shbang.t test-children.t +test-clone-cgi.t test-clone-pull-corruption.t test-clone-r.t test-clone-update-order.t To: durin42, pulkit, #hg-reviewers Cc: mercurial-devel ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
D3348: py3: another three passing
durin42 updated this revision to Diff 8268. REPOSITORY rHG Mercurial CHANGES SINCE LAST UPDATE https://phab.mercurial-scm.org/D3348?vs=8225=8268 REVISION DETAIL https://phab.mercurial-scm.org/D3348 AFFECTED FILES contrib/python3-whitelist CHANGE DETAILS diff --git a/contrib/python3-whitelist b/contrib/python3-whitelist --- a/contrib/python3-whitelist +++ b/contrib/python3-whitelist @@ -140,6 +140,7 @@ test-exchange-obsmarkers-case-D4.t test-execute-bit.t test-export.t +test-extdata.t test-extdiff.t test-extra-filelog-entry.t test-filebranch.t @@ -175,6 +176,7 @@ test-http-branchmap.t test-http-bundle1.t test-http-clone-r.t +test-http.t test-identify.t test-import-unknown.t test-import.t @@ -432,6 +434,7 @@ test-update-names.t test-update-reverse.t test-upgrade-repo.t +test-url-download.t test-url-rev.t test-username-newline.t test-verify.t To: durin42, pulkit, #hg-reviewers Cc: mercurial-devel ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
Re: [PATCH 3 of 3 V4] revset: skip legacy lookup for revspec wrapped in 'revset(…)'
On Sat, 14 Apr 2018 15:07:06 +0200, Boris Feld wrote: > # HG changeset patch > # User Boris Feld> # Date 1523369212 -7200 > # Tue Apr 10 16:06:52 2018 +0200 > # Node ID e345b7103fef40be16f792cda46aa899d0ef8dd1 > # Parent 304b6671aa1be37fc410edb38f2f2f3040ce6708 > # EXP-Topic noname > # Available At https://bitbucket.org/octobus/mercurial-devel/ > # hg pull https://bitbucket.org/octobus/mercurial-devel/ -r > e345b7103fef > revset: skip legacy lookup for revspec wrapped in 'revset(…)' > def matchany(ui, specs, repo=None, localalias=None): > """Create a matcher that will include any revisions matching one of the > given specs > @@ -2196,7 +2199,13 @@ def matchany(ui, specs, repo=None, local > lookup = lookupfn(repo) > parsedspecs = [] > for s in specs: > -parsedspecs.append(revsetlang.parse(s, lookup)) > +lookupthis = lookup > +stripped = s.strip() > +if (stripped.startswith(prefixrevset) > +and stripped.endswith(postfixrevset)): > +s = s[len(prefixrevset):-len(postfixrevset)] ^ This would confuse the error reporting. Instead maybe we can handle this hack in revsetlang.py. 1) nullify lookup function at revsetlang.parse(), _parsewith(), or tokenize() 2) and, rewrite (func 'revset' x[2]) to x[2] by _analyze() (2) would be something like elif op == 'func': f = getsymbol(x[1]) if f == 'revset': return _analyze(x[2]) "hg debugrevspec -v" will show how the parsed tree will be rewritten. ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
[PATCH 1 of 3 V4] revset: add more test to show current behaviors with label looking like revset
# HG changeset patch # User Boris Feld# Date 1519922236 18000 # Thu Mar 01 11:37:16 2018 -0500 # Node ID 5c1a0d784a26d4e8659dcec80503c8764432a303 # Parent e45545f7895e66d55379a7db48b13831eff6cf2a # EXP-Topic noname # Available At https://bitbucket.org/octobus/mercurial-devel/ # hg pull https://bitbucket.org/octobus/mercurial-devel/ -r 5c1a0d784a26 revset: add more test to show current behaviors with label looking like revset There are very few constraints on what character can be put into tags and other labels. We add more tests showing some of extreme cases that user can currently use. diff --git a/tests/test-legacy-lookup.t b/tests/test-legacy-lookup.t new file mode 100644 --- /dev/null +++ b/tests/test-legacy-lookup.t @@ -0,0 +1,259 @@ + + $ cat >> $HGRCPATH << EOF + > [ui] + > logtemplate="{rev}:{node|short} {desc} [{tags}]\n" + > EOF + + $ hg init legacy-lookup + $ cd legacy-lookup + $ echo a > a + $ hg add a + $ hg commit -m 'first' + $ echo aa > a + $ hg commit -m 'second' + $ hg log -G + @ 1:43114e71eddd second [tip] + | + o 0:a87874c6ec31 first [] + + +Create a tag that looks like a revset + + $ hg tag 'rev(0)' + $ hg log -G + @ 2:fb616635b18f Added tag rev(0) for changeset 43114e71eddd [tip] + | + o 1:43114e71eddd second [rev(0)] + | + o 0:a87874c6ec31 first [] + + +See how various things are resolved +--- + +Revision numbers + + $ hg log -r '0' + 0:a87874c6ec31 first [] + $ hg log -r '1' + 1:43114e71eddd second [rev(0)] + +"rev(x)" form (the one conflicting with the tags) +(resolved as a label) + + $ hg log -r 'rev(0)' + 1:43114e71eddd second [rev(0)] + $ hg log -r 'rev(1)' + 1:43114e71eddd second [rev(0)] + +same within a simple revspec +(still resolved as the label) + + $ hg log -r ':rev(0)' + 0:a87874c6ec31 first [] + 1:43114e71eddd second [rev(0)] + $ hg log -r 'rev(0):' + 1:43114e71eddd second [rev(0)] + 2:fb616635b18f Added tag rev(0) for changeset 43114e71eddd [tip] + +within a more advances revset +(still resolved as the label) + + $ hg log -r 'rev(0) and branch(default)' + 0:a87874c6ec31 first [] + +some of the above with quote to force its resolution as a label + + $ hg log -r ':"rev(0)"' + 0:a87874c6ec31 first [] + 1:43114e71eddd second [rev(0)] + $ hg log -r '"rev(0)":' + 1:43114e71eddd second [rev(0)] + 2:fb616635b18f Added tag rev(0) for changeset 43114e71eddd [tip] + $ hg log -r '"rev(0)" and branch(default)' + 1:43114e71eddd second [rev(0)] + +confusing bits within parents + + $ hg log -r '(rev(0))' + 0:a87874c6ec31 first [] + $ hg log -r '( rev(0))' + 0:a87874c6ec31 first [] + $ hg log -r '("rev(0)")' + 1:43114e71eddd second [rev(0)] + +Test label with quote in them. + + $ hg tag '"foo"' + + $ hg log -r '"foo"' + 2:fb616635b18f Added tag rev(0) for changeset 43114e71eddd ["foo"] + $ hg log -r '("foo")' + abort: unknown revision 'foo'! + [255] + $ hg log -r '("\"foo\"")' + 2:fb616635b18f Added tag rev(0) for changeset 43114e71eddd ["foo"] + +Test label with dash in them. + + $ hg tag 'foo-bar' + + $ hg log -r 'foo-bar' + 3:a50aae922707 Added tag "foo" for changeset fb616635b18f [foo-bar] + $ hg log -r '(foo-bar)' + 3:a50aae922707 Added tag "foo" for changeset fb616635b18f [foo-bar] + $ hg log -r '"foo-bar"' + 3:a50aae922707 Added tag "foo" for changeset fb616635b18f [foo-bar] + $ hg log -r '("foo-bar")' + 3:a50aae922707 Added tag "foo" for changeset fb616635b18f [foo-bar] + +Test label with + in them. + + $ hg tag 'foo+bar' + + $ hg log -r 'foo+bar' + 4:bbf52b87b370 Added tag foo-bar for changeset a50aae922707 [foo+bar] + $ hg log -r '(foo+bar)' + abort: unknown revision 'foo'! + [255] + $ hg log -r '"foo+bar"' + 4:bbf52b87b370 Added tag foo-bar for changeset a50aae922707 [foo+bar] + $ hg log -r '("foo+bar")' + 4:bbf52b87b370 Added tag foo-bar for changeset a50aae922707 [foo+bar] + +Test tag with numeric version number. + + $ hg tag '1.2' + + $ hg log -r '1.2' + 5:ff42fde8edbb Added tag foo+bar for changeset bbf52b87b370 [1.2] + $ hg log -r '(1.2)' + 5:ff42fde8edbb Added tag foo+bar for changeset bbf52b87b370 [1.2] + $ hg log -r '"1.2"' + 5:ff42fde8edbb Added tag foo+bar for changeset bbf52b87b370 [1.2] + $ hg log -r '("1.2")' + 5:ff42fde8edbb Added tag foo+bar for changeset bbf52b87b370 [1.2] + $ hg log -r '::"1.2"' + 0:a87874c6ec31 first [] + 1:43114e71eddd second [rev(0)] + 2:fb616635b18f Added tag rev(0) for changeset 43114e71eddd ["foo"] + 3:a50aae922707 Added tag "foo" for changeset fb616635b18f [foo-bar] + 4:bbf52b87b370 Added tag foo-bar for changeset a50aae922707 [foo+bar] + 5:ff42fde8edbb Added tag foo+bar for changeset bbf52b87b370 [1.2] + $ hg log -r '::1.2' + 0:a87874c6ec31 first [] + 1:43114e71eddd second [rev(0)] + 2:fb616635b18f Added tag rev(0) for changeset 43114e71eddd ["foo"] + 3:a50aae922707 Added tag "foo" for changeset fb616635b18f [foo-bar] + 4:bbf52b87b370 Added tag
[PATCH 3 of 3 V4] revset: skip legacy lookup for revspec wrapped in 'revset(…)'
# HG changeset patch # User Boris Feld# Date 1523369212 -7200 # Tue Apr 10 16:06:52 2018 +0200 # Node ID e345b7103fef40be16f792cda46aa899d0ef8dd1 # Parent 304b6671aa1be37fc410edb38f2f2f3040ce6708 # EXP-Topic noname # Available At https://bitbucket.org/octobus/mercurial-devel/ # hg pull https://bitbucket.org/octobus/mercurial-devel/ -r e345b7103fef revset: skip legacy lookup for revspec wrapped in 'revset(…)' Currently, multiple labels can take forms that can be confused with revset (eg: "rev(0)" is a valid tag). Since we look up for tags before evaluating revset, this means a tag can shadow a valid revset at any time. We now enforce the strict revset parsing when wrapped with 'revset(…)'. For now, This only work on a whole revspec. This might change in the future if we improve the implementation. The feature is undocumented for now, keeping it in the experimental namespace. In case a better approach to achieve the same goal is found. The syntax looks like a revset but is not implemented as such for now. Since the goal is to avoid some preprocessing that happens before revset parsing, we cannot simply implement it as a revset predicate. There was other approaches discussed over the mailing-list but they were less convincing. Having a configuration flag to disable legacy lookup have been considered but discarded. There are too many common uses of ambiguous identifier (eg: '+', '-' or '..') to have the legacy lookup mechanism turned off. In addition, the approach can control the parsing of each revset, making it more flexible. For example, a revset used as the value of an existing configuration option (eg: pushrev) could enforce its resolution as a revset (by using the prefix) while user inputs would still use the legacy lookup. In addition of offering a way to unambiguously input a revset, this prefix allow skipping the name lookup providing a significant speedup in some case. diff --git a/mercurial/revset.py b/mercurial/revset.py --- a/mercurial/revset.py +++ b/mercurial/revset.py @@ -2177,6 +2177,9 @@ def match(ui, spec, repo=None): """Create a matcher for a single revision spec""" return matchany(ui, [spec], repo=repo) +prefixrevset = 'revset(' +postfixrevset = ')' + def matchany(ui, specs, repo=None, localalias=None): """Create a matcher that will include any revisions matching one of the given specs @@ -2196,7 +2199,13 @@ def matchany(ui, specs, repo=None, local lookup = lookupfn(repo) parsedspecs = [] for s in specs: -parsedspecs.append(revsetlang.parse(s, lookup)) +lookupthis = lookup +stripped = s.strip() +if (stripped.startswith(prefixrevset) +and stripped.endswith(postfixrevset)): +s = s[len(prefixrevset):-len(postfixrevset)] +lookupthis = None +parsedspecs.append(revsetlang.parse(s, lookupthis)) if len(parsedspecs) == 1: tree = parsedspecs[0] else: diff --git a/tests/test-legacy-lookup.t b/tests/test-legacy-lookup.t --- a/tests/test-legacy-lookup.t +++ b/tests/test-legacy-lookup.t @@ -62,6 +62,12 @@ within a more advances revset $ hg log -r 'rev(0) and branch(default)' 0:a87874c6ec31 first [] +with explicit revset resolution +(still resolved as the label) + + $ hg log -r 'revset(rev(0))' + 0:a87874c6ec31 first [] + some of the above with quote to force its resolution as a label $ hg log -r ':"rev(0)"' @@ -91,8 +97,13 @@ Test label with quote in them. $ hg log -r '("foo")' abort: unknown revision 'foo'! [255] + $ hg log -r 'revset("foo")' + abort: unknown revision 'foo'! + [255] $ hg log -r '("\"foo\"")' 2:fb616635b18f Added tag rev(0) for changeset 43114e71eddd ["foo"] + $ hg log -r 'revset("\"foo\"")' + 2:fb616635b18f Added tag rev(0) for changeset 43114e71eddd ["foo"] Test label with dash in them. @@ -116,6 +127,9 @@ Test label with + in them. $ hg log -r '(foo+bar)' abort: unknown revision 'foo'! [255] + $ hg log -r 'revset(foo+bar)' + abort: unknown revision 'foo'! + [255] $ hg log -r '"foo+bar"' 4:bbf52b87b370 Added tag foo-bar for changeset a50aae922707 [foo+bar] $ hg log -r '("foo+bar")' @@ -129,6 +143,8 @@ Test tag with numeric version number. 5:ff42fde8edbb Added tag foo+bar for changeset bbf52b87b370 [1.2] $ hg log -r '(1.2)' 5:ff42fde8edbb Added tag foo+bar for changeset bbf52b87b370 [1.2] + $ hg log -r 'revset(1.2)' + 5:ff42fde8edbb Added tag foo+bar for changeset bbf52b87b370 [1.2] $ hg log -r '"1.2"' 5:ff42fde8edbb Added tag foo+bar for changeset bbf52b87b370 [1.2] $ hg log -r '("1.2")' @@ -157,6 +173,9 @@ Test tag with parenthesis (but not a val $ hg log -r '(release_4.1(candidate1))' hg: parse error: unknown identifier: release_4.1 [255] + $ hg log -r 'revset(release_4.1(candidate1))' + hg: parse error: unknown identifier: release_4.1 + [255] $ hg log -r '"release_4.1(candidate1)"'
[PATCH 2 of 3 V4] revset: use and explicit loop to resolve each spec
# HG changeset patch # User Boris Feld# Date 1523367822 -7200 # Tue Apr 10 15:43:42 2018 +0200 # Node ID 304b6671aa1be37fc410edb38f2f2f3040ce6708 # Parent 5c1a0d784a26d4e8659dcec80503c8764432a303 # EXP-Topic noname # Available At https://bitbucket.org/octobus/mercurial-devel/ # hg pull https://bitbucket.org/octobus/mercurial-devel/ -r 304b6671aa1b revset: use and explicit loop to resolve each spec This is useful to clarify the next changeset. diff --git a/mercurial/revset.py b/mercurial/revset.py --- a/mercurial/revset.py +++ b/mercurial/revset.py @@ -2190,14 +2190,17 @@ def matchany(ui, specs, repo=None, local return mfunc if not all(specs): raise error.ParseError(_("empty query")) + lookup = None if repo: lookup = lookupfn(repo) -if len(specs) == 1: -tree = revsetlang.parse(specs[0], lookup) +parsedspecs = [] +for s in specs: +parsedspecs.append(revsetlang.parse(s, lookup)) +if len(parsedspecs) == 1: +tree = parsedspecs[0] else: -tree = ('or', -('list',) + tuple(revsetlang.parse(s, lookup) for s in specs)) +tree = ('or', ('list',) + tuple(parsedspecs)) aliases = [] warn = None ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
Re: [PATCH] templates: make divergentnodes in whyunstable keyword be a hybrid list
On Sat, 14 Apr 2018 20:39:21 +0800, Anton Shestakov wrote: > # HG changeset patch > # User Anton Shestakov> # Date 1523709254 -28800 > # Sat Apr 14 20:34:14 2018 +0800 > # Node ID c7fc8a7ca7f5ca13e7e54a2690872f4252a41796 > # Parent 987c05eac1801d0b919c874280d03f9e8cccb411 > templates: make divergentnodes in whyunstable keyword be a hybrid list Queued, thanks. ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
Re: [PATCH 1 of 2] templates: add whyunstable template keyword
On Sat, 14 Apr 2018 21:03:23 +0900 Yuya Nishiharawrote: > On Sat, 14 Apr 2018 19:43:15 +0800, Anton Shestakov wrote: > > # HG changeset patch > > # User Anton Shestakov > > # Date 1522054812 -28800 > > # Mon Mar 26 17:00:12 2018 +0800 > > # Node ID 987c05eac1801d0b919c874280d03f9e8cccb411 > > # Parent 8bacc09814ba5500d15fb40c472e84cb95ae2f99 > > templates: add whyunstable template keyword > > Queued, thanks. > > > +@templatekeyword('whyunstable', requires={'repo', 'ctx'}) > > +def showwhyunstable(context, mapping): > > +"""List of dicts explaining all instabilities of a changeset. > > +(EXPERIMENTAL) > > +""" > > +repo = context.resource(mapping, 'repo') > > +ctx = context.resource(mapping, 'ctx') > > + > > +def formatnode(ctx): > > +return ' %s (%s)' % (scmutil.formatchangeid(ctx), ctx.phasestr()) > > Nit: leading ' ' isn't nice when you join() the list. I was trying to avoid something like '{if(divergentnodes, " ")}', but maybe it wouldn't be too bad. I'll come back to this tomorrow. ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
[PATCH 4 of 7] hgweb: make revnav.gen() simply build a list of mappings by one pass
# HG changeset patch # User Yuya Nishihara# Date 1522593269 -32400 # Sun Apr 01 23:34:29 2018 +0900 # Node ID ec55e9ef2255378a190bdda6f060dca23659cc9d # Parent b7742898a29d79f01beb36c1cedd58acfdab05ab hgweb: make revnav.gen() simply build a list of mappings by one pass There was actually no lazy stuff. diff --git a/mercurial/hgweb/webutil.py b/mercurial/hgweb/webutil.py --- a/mercurial/hgweb/webutil.py +++ b/mercurial/hgweb/webutil.py @@ -127,8 +127,7 @@ class revnav(object): The return is: - a single element tuple - containing a dictionary with a `before` and `after` key -- values are generator functions taking arbitrary number of kwargs -- yield items are dictionaries with `label` and `node` keys +- values are dictionaries with `label` and `node` keys """ if not self: # empty repo @@ -143,22 +142,21 @@ class revnav(object): targets.sort() first = self._first() -navbefore = [("(%i)" % first, self.hex(first))] +navbefore = [{'label': '(%i)' % first, 'node': self.hex(first)}] navafter = [] for rev in targets: if rev not in self._revlog: continue if pos < rev < limit: -navafter.append(("+%d" % abs(rev - pos), self.hex(rev))) +navafter.append({'label': '+%d' % abs(rev - pos), + 'node': self.hex(rev)}) if 0 < rev < pos: -navbefore.append(("-%d" % abs(rev - pos), self.hex(rev))) - +navbefore.append({'label': '-%d' % abs(rev - pos), + 'node': self.hex(rev)}) -navafter.append(("tip", "tip")) +navafter.append({'label': 'tip', 'node': 'tip'}) -data = lambda i: {"label": i[0], "node": i[1]} -return ({'before': lambda **map: (data(i) for i in navbefore), - 'after': lambda **map: (data(i) for i in navafter)},) +return ({'before': navbefore, 'after': navafter},) class filerevnav(revnav): ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
[PATCH 3 of 7] hgweb: lift {sessionvars} to a wrapped type
# HG changeset patch # User Yuya Nishihara# Date 1522591957 -32400 # Sun Apr 01 23:12:37 2018 +0900 # Node ID b7742898a29d79f01beb36c1cedd58acfdab05ab # Parent 8bee5eca0b75333eee2c555663ae535005505991 hgweb: lift {sessionvars} to a wrapped type Since a sessionvars object is updated in-place, we can't simply wrap it by mappinglist. diff --git a/mercurial/hgweb/webutil.py b/mercurial/hgweb/webutil.py --- a/mercurial/hgweb/webutil.py +++ b/mercurial/hgweb/webutil.py @@ -651,7 +651,7 @@ def diffstat(tmpl, ctx, statgen, parity) 'parity': next(parity), }) -class sessionvars(object): +class sessionvars(templateutil.wrapped): def __init__(self, vars, start='?'): self._start = start self._vars = vars @@ -665,7 +665,7 @@ class sessionvars(object): def __copy__(self): return sessionvars(copy.copy(self._vars), self._start) -def __iter__(self): +def itermaps(self, context): separator = self._start for key, value in sorted(self._vars.iteritems()): yield {'name': key, @@ -674,6 +674,16 @@ class sessionvars(object): } separator = '&' +def join(self, context, mapping, sep): +# could be '{separator}{name}={value|urlescape}' +raise error.ParseError(_('not displayable without template')) + +def show(self, context, mapping): +return self.join(context, '') + +def tovalue(self, context, mapping): +return self._vars + class wsgiui(uimod.ui): # default termwidth breaks under mod_wsgi def termwidth(self): ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
[PATCH 2 of 7] hgweb: make sessionvars class less dense
# HG changeset patch # User Yuya Nishihara# Date 1522591438 -32400 # Sun Apr 01 23:03:58 2018 +0900 # Node ID 8bee5eca0b75333eee2c555663ae535005505991 # Parent 7b406ab5b3e9c3da9527a3001ba62e29506bd73a hgweb: make sessionvars class less dense diff --git a/mercurial/hgweb/webutil.py b/mercurial/hgweb/webutil.py --- a/mercurial/hgweb/webutil.py +++ b/mercurial/hgweb/webutil.py @@ -655,12 +655,16 @@ class sessionvars(object): def __init__(self, vars, start='?'): self._start = start self._vars = vars + def __getitem__(self, key): return self._vars[key] + def __setitem__(self, key, value): self._vars[key] = value + def __copy__(self): return sessionvars(copy.copy(self._vars), self._start) + def __iter__(self): separator = self._start for key, value in sorted(self._vars.iteritems()): ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
[PATCH 6 of 7] hgweb: extract a generator function of _siblings class
# HG changeset patch # User Yuya Nishihara# Date 1522594063 -32400 # Sun Apr 01 23:47:43 2018 +0900 # Node ID 8e479b1d96bf94e81f76c78605c16b2864b219a5 # Parent affefa7df3fe2dd06be7cab086c16626010bc8b4 hgweb: extract a generator function of _siblings class _siblings will be converted to a plain function. diff --git a/mercurial/hgweb/webutil.py b/mercurial/hgweb/webutil.py --- a/mercurial/hgweb/webutil.py +++ b/mercurial/hgweb/webutil.py @@ -181,6 +181,22 @@ class filerevnav(revnav): def hex(self, rev): return hex(self._changelog.node(self._revlog.linkrev(rev))) +# TODO: maybe this can be a wrapper class for changectx/filectx list, which +# yields {'ctx': ctx} +def _ctxsgen(ctxs): +for s in ctxs: +d = { +'node': s.hex(), +'rev': s.rev(), +'user': s.user(), +'date': s.date(), +'description': s.description(), +'branch': s.branch(), +} +if util.safehasattr(s, 'path'): +d['file'] = s.path() +yield d + class _siblings(object): def __init__(self, siblings=None, hiderev=None): if siblings is None: @@ -190,18 +206,7 @@ class _siblings(object): self.siblings = [] def __iter__(self): -for s in self.siblings: -d = { -'node': s.hex(), -'rev': s.rev(), -'user': s.user(), -'date': s.date(), -'description': s.description(), -'branch': s.branch(), -} -if util.safehasattr(s, 'path'): -d['file'] = s.path() -yield d +return _ctxsgen(self.siblings) def __len__(self): return len(self.siblings) ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
[PATCH 1 of 7] hgweb: prefix private variables of sessionvars with '_'
# HG changeset patch # User Yuya Nishihara# Date 1522591382 -32400 # Sun Apr 01 23:03:02 2018 +0900 # Node ID 7b406ab5b3e9c3da9527a3001ba62e29506bd73a # Parent 34cde18a454484a1cf6e716a3325ca9282277d59 hgweb: prefix private variables of sessionvars with '_' diff --git a/mercurial/hgweb/webutil.py b/mercurial/hgweb/webutil.py --- a/mercurial/hgweb/webutil.py +++ b/mercurial/hgweb/webutil.py @@ -653,17 +653,17 @@ def diffstat(tmpl, ctx, statgen, parity) class sessionvars(object): def __init__(self, vars, start='?'): -self.start = start -self.vars = vars +self._start = start +self._vars = vars def __getitem__(self, key): -return self.vars[key] +return self._vars[key] def __setitem__(self, key, value): -self.vars[key] = value +self._vars[key] = value def __copy__(self): -return sessionvars(copy.copy(self.vars), self.start) +return sessionvars(copy.copy(self._vars), self._start) def __iter__(self): -separator = self.start -for key, value in sorted(self.vars.iteritems()): +separator = self._start +for key, value in sorted(self._vars.iteritems()): yield {'name': key, 'value': pycompat.bytestr(value), 'separator': separator, ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
[PATCH 5 of 7] hgweb: wrap {changenav} and {nav} with mappinglist
# HG changeset patch # User Yuya Nishihara# Date 1522593608 -32400 # Sun Apr 01 23:40:08 2018 +0900 # Node ID affefa7df3fe2dd06be7cab086c16626010bc8b4 # Parent ec55e9ef2255378a190bdda6f060dca23659cc9d hgweb: wrap {changenav} and {nav} with mappinglist diff --git a/mercurial/hgweb/webcommands.py b/mercurial/hgweb/webcommands.py --- a/mercurial/hgweb/webcommands.py +++ b/mercurial/hgweb/webcommands.py @@ -1084,7 +1084,7 @@ def filelog(web): linerange = webutil.formatlinerange(*lrange) # deactivate numeric nav links when linerange is specified as this # would required a dedicated "revnav" class -nav = [] +nav = templateutil.mappinglist([]) if descend: it = dagop.blockdescendants(fctx, *lrange) else: diff --git a/mercurial/hgweb/webutil.py b/mercurial/hgweb/webutil.py --- a/mercurial/hgweb/webutil.py +++ b/mercurial/hgweb/webutil.py @@ -125,13 +125,16 @@ class revnav(object): :limit: how far shall we link The return is: -- a single element tuple +- a single element mappinglist - containing a dictionary with a `before` and `after` key - values are dictionaries with `label` and `node` keys """ if not self: # empty repo -return ({'before': (), 'after': ()},) +return templateutil.mappinglist([ +{'before': templateutil.mappinglist([]), + 'after': templateutil.mappinglist([])}, +]) targets = [] for f in _navseq(1, pagelen): @@ -156,7 +159,11 @@ class revnav(object): navafter.append({'label': 'tip', 'node': 'tip'}) -return ({'before': navbefore, 'after': navafter},) +# TODO: maybe this can be a scalar object supporting tomap() +return templateutil.mappinglist([ +{'before': templateutil.mappinglist(navbefore), + 'after': templateutil.mappinglist(navafter)}, +]) class filerevnav(revnav): ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
Re: [PATCH 2 of 2] templates: make divergentnodes in whyunstable keyword be a mappinglist too (RFC)
On Sat, 14 Apr 2018 21:09:46 +0900 Yuya Nishiharawrote: > On Sat, 14 Apr 2018 19:43:16 +0800, Anton Shestakov wrote: > > # HG changeset patch > > # User Anton Shestakov > > # Date 1523705764 -28800 > > # Sat Apr 14 19:36:04 2018 +0800 > > # Node ID 6287c68bde7bcdc1dc260da9983ecc7fffc9ee20 > > # Parent 987c05eac1801d0b919c874280d03f9e8cccb411 > > templates: make divergentnodes in whyunstable keyword be a mappinglist too > > (RFC) > > > I'd like this to work, but it doesn't: "{divergentnodes}" show a178212c3433 > > as > > the divergent node, and not 70d5a63ca112 (so the whole test case fails). > > > for entry in entries: > > if entry.get('divergentnodes'): > > -dnodes = entry['divergentnodes'] > > -entry['divergentnodes'] = ''.join(formatnode(dnode) > > - for dnode in dnodes) > > +dnodes = [{ctx: dnode} for dnode in entry['divergentnodes']] > ^^^ > 'ctx': Ah. Yep, that was it. ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
[PATCH] templates: make divergentnodes in whyunstable keyword be a hybrid list
# HG changeset patch # User Anton Shestakov# Date 1523709254 -28800 # Sat Apr 14 20:34:14 2018 +0800 # Node ID c7fc8a7ca7f5ca13e7e54a2690872f4252a41796 # Parent 987c05eac1801d0b919c874280d03f9e8cccb411 templates: make divergentnodes in whyunstable keyword be a hybrid list diff --git a/mercurial/templatekw.py b/mercurial/templatekw.py --- a/mercurial/templatekw.py +++ b/mercurial/templatekw.py @@ -809,8 +809,11 @@ def showwhyunstable(context, mapping): for entry in entries: if entry.get('divergentnodes'): dnodes = entry['divergentnodes'] -entry['divergentnodes'] = ''.join(formatnode(dnode) - for dnode in dnodes) +dnhybrid = _hybrid(None, [dnode.hex() for dnode in dnodes], + lambda x: {'ctx': repo[x]}, + lambda x: formatnode(repo[x])) +entry['divergentnodes'] = dnhybrid + tmpl = '{instability}:{divergentnodes} {reason} {node|short}' return templateutil.mappinglist(entries, tmpl=tmpl, sep='\n') diff --git a/tests/test-obsolete-divergent.t b/tests/test-obsolete-divergent.t --- a/tests/test-obsolete-divergent.t +++ b/tests/test-obsolete-divergent.t @@ -725,6 +725,8 @@ Use scmutil.cleanupnodes API to create d content-divergent: 4:70d5a63ca112 (draft) predecessor a178212c3433 $ hg log -r 1a2a9b5b0030 --hidden -T '{whyunstable%"{instability}:{divergentnodes} {reason} {node}\n"}' content-divergent: 4:70d5a63ca112 (draft) predecessor a178212c3433c4e77b573f6011e29affb8aefa33 + $ hg log -r 1a2a9b5b0030 --hidden -T '{whyunstable%"{instability}:{divergentnodes % " {node} ({phase})"} {reason} {node}\n"}' + content-divergent: 70d5a63ca112acb3764bc1d7320ca90ea688d671 (draft) predecessor a178212c3433c4e77b573f6011e29affb8aefa33 #if serve ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
D3365: commands: drop spurious r'' on dry_run in forget
This revision was automatically updated to reflect the committed changes. Closed by commit rHG5fc502e149f1: commands: drop spurious r on dry_run in forget (authored by durin42, committed by ). REPOSITORY rHG Mercurial CHANGES SINCE LAST UPDATE https://phab.mercurial-scm.org/D3365?vs=8242=8267 REVISION DETAIL https://phab.mercurial-scm.org/D3365 AFFECTED FILES mercurial/commands.py CHANGE DETAILS diff --git a/mercurial/commands.py b/mercurial/commands.py --- a/mercurial/commands.py +++ b/mercurial/commands.py @@ -2090,7 +2090,7 @@ raise error.Abort(_('no files specified')) m = scmutil.match(repo[None], pats, opts) -dryrun = opts.get(r'dry_run') +dryrun = opts.get('dry_run') rejected = cmdutil.forget(ui, repo, m, prefix="", explicitonly=False, dryrun=dryrun)[0] return rejected and 1 or 0 To: durin42, #hg-reviewers Cc: mercurial-devel ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
D3366: tests: port inline extension in test-http-bundle1.t to py3
This revision was automatically updated to reflect the committed changes. Closed by commit rHGe481d54f516d: tests: port inline extension in test-http-bundle1.t to py3 (authored by durin42, committed by ). REPOSITORY rHG Mercurial CHANGES SINCE LAST UPDATE https://phab.mercurial-scm.org/D3366?vs=8243=8266 REVISION DETAIL https://phab.mercurial-scm.org/D3366 AFFECTED FILES tests/test-http-bundle1.t CHANGE DETAILS diff --git a/tests/test-http-bundle1.t b/tests/test-http-bundle1.t --- a/tests/test-http-bundle1.t +++ b/tests/test-http-bundle1.t @@ -179,13 +179,13 @@ > import base64 > from mercurial.hgweb import common > def perform_authentication(hgweb, req, op): - > auth = req.headers.get('Authorization') + > auth = req.headers.get(b'Authorization') > if not auth: - > raise common.ErrorResponse(common.HTTP_UNAUTHORIZED, 'who', - > [('WWW-Authenticate', 'Basic Realm="mercurial"')]) + > raise common.ErrorResponse(common.HTTP_UNAUTHORIZED, b'who', + > [(b'WWW-Authenticate', b'Basic Realm="mercurial"')]) > if base64.b64decode(auth.split()[1]).split(b':', 1) != [b'user', > b'pass']: - > raise common.ErrorResponse(common.HTTP_FORBIDDEN, 'no') + > raise common.ErrorResponse(common.HTTP_FORBIDDEN, b'no') > def extsetup(): > common.permhooks.insert(0, perform_authentication) > EOT To: durin42, #hg-reviewers Cc: mercurial-devel ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
D3368: stringutil: ast.literal_eval needs a unicode on py3
This revision was automatically updated to reflect the committed changes. Closed by commit rHG3942bd8db8b2: stringutil: ast.literal_eval needs a unicode on py3 (authored by durin42, committed by ). REPOSITORY rHG Mercurial CHANGES SINCE LAST UPDATE https://phab.mercurial-scm.org/D3368?vs=8245=8264 REVISION DETAIL https://phab.mercurial-scm.org/D3368 AFFECTED FILES contrib/python3-whitelist mercurial/utils/stringutil.py CHANGE DETAILS diff --git a/mercurial/utils/stringutil.py b/mercurial/utils/stringutil.py --- a/mercurial/utils/stringutil.py +++ b/mercurial/utils/stringutil.py @@ -510,4 +510,6 @@ def evalpythonliteral(s): """Evaluate a string containing a Python literal expression""" # We could backport our tokenizer hack to rewrite '' to u'' if we want +if pycompat.ispy3: +return ast.literal_eval(s.decode('latin1')) return ast.literal_eval(s) diff --git a/contrib/python3-whitelist b/contrib/python3-whitelist --- a/contrib/python3-whitelist +++ b/contrib/python3-whitelist @@ -437,4 +437,5 @@ test-verify.t test-websub.t test-win32text.t +test-wireproto-framing.py test-xdg.t To: durin42, pulkit, #hg-reviewers Cc: mercurial-devel ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
Re: [PATCH 1 of 2] templates: add whyunstable template keyword
On Sat, 14 Apr 2018 19:43:15 +0800, Anton Shestakov wrote: > # HG changeset patch > # User Anton Shestakov> # Date 1522054812 -28800 > # Mon Mar 26 17:00:12 2018 +0800 > # Node ID 987c05eac1801d0b919c874280d03f9e8cccb411 > # Parent 8bacc09814ba5500d15fb40c472e84cb95ae2f99 > templates: add whyunstable template keyword Queued, thanks. > +@templatekeyword('whyunstable', requires={'repo', 'ctx'}) > +def showwhyunstable(context, mapping): > +"""List of dicts explaining all instabilities of a changeset. > +(EXPERIMENTAL) > +""" > +repo = context.resource(mapping, 'repo') > +ctx = context.resource(mapping, 'ctx') > + > +def formatnode(ctx): > +return ' %s (%s)' % (scmutil.formatchangeid(ctx), ctx.phasestr()) Nit: leading ' ' isn't nice when you join() the list. > +for entry in entries: > +if entry.get('divergentnodes'): > +dnodes = entry['divergentnodes'] > +entry['divergentnodes'] = ''.join(formatnode(dnode) > + for dnode in dnodes) Perhaps this can be a hybrid list. Can you send a follow up? _hybrid(None, [c.hex() for c in dnodes], lambda x: {'ctx': repo[x]}, lambda x: formatnode(repo[c])) (We don't have a wrapper for a list of ctx objects yet.) ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
Re: [PATCH 1 of 2] templates: add whyunstable template keyword
On Mon, 26 Mar 2018 22:13:18 +0900 Yuya Nishiharawrote: > On Mon, 26 Mar 2018 19:55:20 +0800, Anton Shestakov wrote: > > # HG changeset patch > > # User Anton Shestakov > > # Date 1522054812 -28800 > > # Mon Mar 26 17:00:12 2018 +0800 > > # Node ID 123d9e4d706909c8912f11acee292735c0fb283c > > # Parent 6f570c501e3ebc3d9b59920f50ed7523d93cb847 > > templates: add whyunstable template keyword I went and revived this series. Let's see if I can squeeze some patches in before the freeze. > > +def makemap(entry): > > +item = {'ctx': repo[entry['node']], 'revcache': {}} >^^ > > 'revcache' is no longer needed. > > Perhaps, obsutil.whyunstable() can put 'ctx' instead of 'node'? At least in content-divergent cases, common predecessor can be absent from local repo. I don't think there's any "surrogate" ctx (i.e. created from hash alone) that would work here yet. > > +item.update(entry) > > +if item.get('divergentnodes'): > > +dnhybrid = _hybrid(None, item['divergentnodes'], > > + lambda x: {'ctx': x, 'revcache': {}}, > > + formatnode) > > Perhaps showrevslist() can be used. Each hybrid value has to be a printable > object such as int. Tried it, but it feels like I'm jumping through hoops for no good reason: doing ctx.rev() and then repo[rev] right after that just to get ctx back. Maybe I'm doing something wrong, but I have an idea (not sure how crazy it is): I'd like to have divergentnodes be a mappinglist with tmpl that works from inside the entries (also mappinglist). It doesn't work yet, but I've sent an RFC to get feedback on it. > > +item['divergentnodes'] = dnhybrid > > +return item > > + > > +entries = obsutil.whyunstable(repo, ctx) > > +return _hybrid(None, entries, makemap, formatentry) > > It isn't correct to wrap a list of template mappings by _hybrid. Instead, > makemap() has to build a mapping dict from a printable value. > > Can you hold off this series for 2-3 weeks? I have long series which will > add a wrapper for a list of template mappings. Basically it will allow us > to write the default string representation as template: > > return mappinglist(entries, tmpl='{instability}: {divergentnodes % ...') ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
D3367: hgwebdir: un-bytes the env dict before re-parsing env
yuja requested changes to this revision. yuja added inline comments. This revision now requires changes to proceed. INLINE COMMENTS > hgwebdir_mod.py:425 > # repository path component. > +uenv = {k.decode('latin1'): v for k, v in > +req.rawenv.iteritems()} Maybe needs `if ispy3` ? REPOSITORY rHG Mercurial REVISION DETAIL https://phab.mercurial-scm.org/D3367 To: durin42, #hg-reviewers, yuja Cc: yuja, mercurial-devel ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
[PATCH 2 of 2] templates: make divergentnodes in whyunstable keyword be a mappinglist too (RFC)
# HG changeset patch # User Anton Shestakov# Date 1523705764 -28800 # Sat Apr 14 19:36:04 2018 +0800 # Node ID 6287c68bde7bcdc1dc260da9983ecc7fffc9ee20 # Parent 987c05eac1801d0b919c874280d03f9e8cccb411 templates: make divergentnodes in whyunstable keyword be a mappinglist too (RFC) I'd like this to work, but it doesn't: "{divergentnodes}" show a178212c3433 as the divergent node, and not 70d5a63ca112 (so the whole test case fails). diff --git a/mercurial/templatekw.py b/mercurial/templatekw.py --- a/mercurial/templatekw.py +++ b/mercurial/templatekw.py @@ -800,20 +800,17 @@ def showwhyunstable(context, mapping): """ repo = context.resource(mapping, 'repo') ctx = context.resource(mapping, 'ctx') - -def formatnode(ctx): -return ' %s (%s)' % (scmutil.formatchangeid(ctx), ctx.phasestr()) - entries = obsutil.whyunstable(repo, ctx) +mappinglist = templateutil.mappinglist for entry in entries: if entry.get('divergentnodes'): -dnodes = entry['divergentnodes'] -entry['divergentnodes'] = ''.join(formatnode(dnode) - for dnode in dnodes) +dnodes = [{ctx: dnode} for dnode in entry['divergentnodes']] +tmpl = ' {rev}:{node|short} ({phase})' +entry['divergentnodes'] = mappinglist(dnodes, tmpl=tmpl) tmpl = '{instability}:{divergentnodes} {reason} {node|short}' -return templateutil.mappinglist(entries, tmpl=tmpl, sep='\n') +return mappinglist(entries, tmpl=tmpl, sep='\n') def loadkeyword(ui, extname, registrarobj): """Load template keyword from specified registrarobj diff --git a/tests/test-obsolete-divergent.t b/tests/test-obsolete-divergent.t --- a/tests/test-obsolete-divergent.t +++ b/tests/test-obsolete-divergent.t @@ -725,6 +725,8 @@ Use scmutil.cleanupnodes API to create d content-divergent: 4:70d5a63ca112 (draft) predecessor a178212c3433 $ hg log -r 1a2a9b5b0030 --hidden -T '{whyunstable%"{instability}:{divergentnodes} {reason} {node}\n"}' content-divergent: 4:70d5a63ca112 (draft) predecessor a178212c3433c4e77b573f6011e29affb8aefa33 + $ hg log -r 1a2a9b5b0030 --hidden -T '{whyunstable%"{instability}:{divergentnodes % " {node} ({phase})"} {reason} {node}\n"}' + content-divergent: 70d5a63ca112acb3764bc1d7320ca90ea688d671 (draft) predecessor a178212c3433c4e77b573f6011e29affb8aefa33 #if serve ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
[PATCH 1 of 2] templates: add whyunstable template keyword
# HG changeset patch # User Anton Shestakov# Date 1522054812 -28800 # Mon Mar 26 17:00:12 2018 +0800 # Node ID 987c05eac1801d0b919c874280d03f9e8cccb411 # Parent 8bacc09814ba5500d15fb40c472e84cb95ae2f99 templates: add whyunstable template keyword diff --git a/mercurial/templatekw.py b/mercurial/templatekw.py --- a/mercurial/templatekw.py +++ b/mercurial/templatekw.py @@ -793,6 +793,28 @@ def showverbosity(context, mapping): return 'verbose' return '' +@templatekeyword('whyunstable', requires={'repo', 'ctx'}) +def showwhyunstable(context, mapping): +"""List of dicts explaining all instabilities of a changeset. +(EXPERIMENTAL) +""" +repo = context.resource(mapping, 'repo') +ctx = context.resource(mapping, 'ctx') + +def formatnode(ctx): +return ' %s (%s)' % (scmutil.formatchangeid(ctx), ctx.phasestr()) + +entries = obsutil.whyunstable(repo, ctx) + +for entry in entries: +if entry.get('divergentnodes'): +dnodes = entry['divergentnodes'] +entry['divergentnodes'] = ''.join(formatnode(dnode) + for dnode in dnodes) + +tmpl = '{instability}:{divergentnodes} {reason} {node|short}' +return templateutil.mappinglist(entries, tmpl=tmpl, sep='\n') + def loadkeyword(ui, extname, registrarobj): """Load template keyword from specified registrarobj """ diff --git a/tests/test-obsolete-divergent.t b/tests/test-obsolete-divergent.t --- a/tests/test-obsolete-divergent.t +++ b/tests/test-obsolete-divergent.t @@ -721,6 +721,11 @@ Use scmutil.cleanupnodes API to create d $ hg debugwhyunstable 1a2a9b5b0030 content-divergent: 70d5a63ca112acb3764bc1d7320ca90ea688d671 (draft) predecessor a178212c3433c4e77b573f6011e29affb8aefa33 + $ hg log -r 1a2a9b5b0030 --hidden -T '{whyunstable}\n' + content-divergent: 4:70d5a63ca112 (draft) predecessor a178212c3433 + $ hg log -r 1a2a9b5b0030 --hidden -T '{whyunstable%"{instability}:{divergentnodes} {reason} {node}\n"}' + content-divergent: 4:70d5a63ca112 (draft) predecessor a178212c3433c4e77b573f6011e29affb8aefa33 + #if serve $ hg serve -n test -p $HGPORT -d --pid-file=hg.pid -A access.log -E errors.log diff --git a/tests/test-obsolete.t b/tests/test-obsolete.t --- a/tests/test-obsolete.t +++ b/tests/test-obsolete.t @@ -1044,6 +1044,15 @@ test debugwhyunstable output orphan: obsolete parent 3de5eca88c00aa039da7399a220f4a5221faa585 phase-divergent: immutable predecessor 245bde4270cd1072a27757984f9cda8ba26f08ca +test whyunstable template keyword + + $ hg log -r 50c51b361e60 -T '{whyunstable}\n' + orphan: obsolete parent 3de5eca88c00 + phase-divergent: immutable predecessor 245bde4270cd + $ hg log -r 50c51b361e60 -T '{whyunstable%"{instability}: {reason} {node}\n"}' + orphan: obsolete parent 3de5eca88c00aa039da7399a220f4a5221faa585 + phase-divergent: immutable predecessor 245bde4270cd1072a27757984f9cda8ba26f08ca + #if serve $ hg serve -n test -p $HGPORT -d --pid-file=hg.pid -A access.log -E errors.log ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
D2880: bundle: add the possibility to bundle bookmarks (issue5792)
lothiraldan added inline comments. INLINE COMMENTS > martinvonz wrote in test-bundle-bookmarks.t:37-63 > Can we have a similar test case where we create divergence? Create a fork in > the graph in the debugdrawdag call above. Let's say you have commit F that > branches off of B, then do something like this: > > $ hg bundle --all bundle > $ hg strip --no-backup C > $ hg bookmarks -f -r F D1 > $ hg unbundle -q bundle > $ hg log -G -T '{desc} {bookmarks}\n' > o E > | > o D D1 D2 > | > o C > | > | o F D1@1 > |/ > o B > | > o A A1 > > I don't know if "@1" is the appropriate divergence marker, but I can't think > of a better one. I haven't even looked at your code to try to guess what it > would be in practice (if it would work at all). I have added such test and indeed this case is not handled right now. I'm not aware of how Mercurial handle this case when exchanging bookmarks, I will need to take a look at the code to find out. What is the correct behavior here? Change the existing bookmark or the bookmark from the bundle? REPOSITORY rHG Mercurial REVISION DETAIL https://phab.mercurial-scm.org/D2880 To: lothiraldan, #hg-reviewers, indygreg Cc: martinvonz, indygreg, pulkit, mercurial-devel ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
D2880: bundle: add the possibility to bundle bookmarks (issue5792)
lothiraldan updated this revision to Diff 8263. REPOSITORY rHG Mercurial CHANGES SINCE LAST UPDATE https://phab.mercurial-scm.org/D2880?vs=7077=8263 REVISION DETAIL https://phab.mercurial-scm.org/D2880 AFFECTED FILES mercurial/bundle2.py mercurial/commands.py mercurial/configitems.py mercurial/debugcommands.py tests/test-bundle-bookmarks.t CHANGE DETAILS diff --git a/tests/test-bundle-bookmarks.t b/tests/test-bundle-bookmarks.t new file mode 100644 --- /dev/null +++ b/tests/test-bundle-bookmarks.t @@ -0,0 +1,116 @@ + $ cat >> $HGRCPATH < [experimental] + > bundle-bookmarks=yes + > [extensions] + > strip= + > drawdag=$TESTDIR/drawdag.py + > EOF + +Set up repo with linear history + $ hg init linear + $ cd linear + $ hg debugdrawdag <<'EOF' + > E + > | + > D + > | + > C + > | + > B + > | + > A + > EOF + $ hg bookmarks -r A "A1" + $ hg bookmarks -r D "D1" + $ hg bookmarks -r D "D2" + $ hg log -G -T '{desc} {bookmarks}\n' + o E + | + o D D1 D2 + | + o C + | + o B + | + o A A1 + +Bookmarks are restored when unbundling + $ hg bundle --all bundle + 5 changesets found + $ hg debugbundle bundle + Stream params: {Compression: BZ} + changegroup -- {nbchanges: 5, version: 02} + 426bada5c67598ca65036d57d9e4b64b0c1ce7a0 + 112478962961147124edd43549aedd1a335e44bf + 26805aba1e600a82e93661149f2313866a221a7b + f585351a92f85104bff7c284233c338b10eb1df7 + 9bc730a19041f9ec7cb33c626e811aa233efb18c + bookmarks -- {} + A1: Bk\xad\xa5\xc6u\x98\xcae\x03mW\xd9\xe4\xb6K\x0c\x1c\xe7\xa0 (esc) + D1: \xf5\x855\x1a\x92\xf8Q\x04\xbf\xf7\xc2\x84#<3\x8b\x10\xeb\x1d\xf7 (esc) + D2: \xf5\x855\x1a\x92\xf8Q\x04\xbf\xf7\xc2\x84#<3\x8b\x10\xeb\x1d\xf7 (esc) + $ hg strip --no-backup C + $ hg unbundle -q bundle + $ hg log -G -T '{desc} {bookmarks}\n' + o E + | + o D D1 D2 + | + o C + | + o B + | + o A A1 + +Bookmarks doesn't conflict with local bookmarks + + $ hg bookmarks -d A1 + $ hg bookmarks -r A "A2" + $ hg unbundle -q bundle + $ hg log -G -T '{desc} {bookmarks}\n' + o E + | + o D D1 D2 + | + o C + | + o B + | + o A A1 A2 + +Test bookmarks divergence + + $ hg bundle --all bundle + 5 changesets found + $ hg strip --no-backup C + +Create soem divergence + $ hg up B + 2 files updated, 0 files merged, 0 files removed, 0 files unresolved + $ touch F + $ hg add F + $ hg commit -m "F" + $ hg bookmarks -f -r "desc(F)" D1 + + $ hg log -G -T '{desc} {bookmarks}\n' + @ F D1 + | + o B D2 + | + o A A1 A2 + + + $ hg unbundle -q bundle + $ hg log -G -T '{desc} {bookmarks}\n' + o E + | + o D D1 D2 + | + o C + | + | @ F + |/ + o B + | + o A A1 A2 + diff --git a/mercurial/debugcommands.py b/mercurial/debugcommands.py --- a/mercurial/debugcommands.py +++ b/mercurial/debugcommands.py @@ -33,6 +33,7 @@ short, ) from . import ( +bookmarks, bundle2, changegroup, cmdutil, @@ -326,6 +327,14 @@ ui.write(indent_string) ui.write('%s %s\n' % (hex(head), phases.phasenames[phase])) +def _debugbookmarks(ui, data, indent=0): +"""display version and markers contained in 'data'""" +indent_string = ' ' * indent +bm = bookmarks.binarydecode(data) +for bookmark in sorted(bm): +ui.write(indent_string) +ui.write('%s: %s\n' % (bookmark[0], bookmark[1])) + def _quasirepr(thing): if isinstance(thing, (dict, util.sortdict, collections.OrderedDict)): return '{%s}' % ( @@ -353,6 +362,9 @@ if part.type == 'phase-heads': if not ui.quiet: _debugphaseheads(ui, part, indent=4) +if part.type == 'bookmarks': +if not ui.quiet: +_debugbookmarks(ui, part, indent=4) @command('debugbundle', [('a', 'all', None, _('show all details')), diff --git a/mercurial/configitems.py b/mercurial/configitems.py --- a/mercurial/configitems.py +++ b/mercurial/configitems.py @@ -419,6 +419,9 @@ coreconfigitem('experimental', 'archivemetatemplate', default=dynamicdefault, ) +coreconfigitem('experimental', 'bundle-bookmarks', +default=False, +) coreconfigitem('experimental', 'bundle-phases', default=False, ) diff --git a/mercurial/commands.py b/mercurial/commands.py --- a/mercurial/commands.py +++ b/mercurial/commands.py @@ -1267,6 +1267,8 @@ contentopts['obsolescence'] = True if repo.ui.configbool('experimental', 'bundle-phases'): contentopts['phases'] = True +if repo.ui.configbool('experimental', 'bundle-bookmarks'): +contentopts['bookmarks'] = True bundle2.writenewbundle(ui, repo, 'bundle', fname, bversion, outgoing, contentopts, compression=bcompression, compopts=compopts) @@ -5406,7 +5408,7 @@ """ fnames = (fname1,) + fnames -with repo.lock(): +with repo.wlock(), repo.lock(): for fname in fnames:
[PATCH] test-check-commit: don't run hg per commit
# HG changeset patch # User Yuya Nishihara# Date 1523694452 -32400 # Sat Apr 14 17:27:32 2018 +0900 # Node ID 34cde18a454484a1cf6e716a3325ca9282277d59 # Parent e743b8524d608684b5a947337c37b686cfc0ae5b test-check-commit: don't run hg per commit We aren't stress testing CPU. $ time ./run-tests.py -l test-check-commit.t --timeout 600 (orig) 162.59s user 17.98s system 101% cpu 2:58.55 total (new) 5.85s user 0.99s system 98% cpu 6.939 total diff --git a/tests/test-check-commit.t b/tests/test-check-commit.t --- a/tests/test-check-commit.t +++ b/tests/test-check-commit.t @@ -8,15 +8,16 @@ Go back in the hg repo $ cd $TESTDIR/.. - $ for node in `testrepohg log --rev 'not public() and ::. and not desc("# no-check-commit")' --template '{node|short}\n'`; do - >testrepohg export --git $node \ - >| contrib/check-commit > ${TESTTMP}/check-commit.out + $ mkdir "$TESTTMP/p" + $ testrepohg export --git -o "$TESTTMP/p/%n-%h" \ + > -r 'not public() and ::. and not desc("# no-check-commit")' + $ for f in `ls "$TESTTMP/p"`; do + >contrib/check-commit < "$TESTTMP/p/$f" > "$TESTTMP/check-commit.out" >if [ $? -ne 0 ]; then + >node="${f##*-}" >echo "Revision $node does not comply with rules" >echo '--' >cat ${TESTTMP}/check-commit.out >echo > fi > done - - ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
D3370: scmutil: introduce shortesthexnodeidprefix()
This revision was automatically updated to reflect the committed changes. Closed by commit rHGe743b8524d60: scmutil: introduce shortesthexnodeidprefix() (authored by martinvonz, committed by ). REPOSITORY rHG Mercurial CHANGES SINCE LAST UPDATE https://phab.mercurial-scm.org/D3370?vs=8254=8262 REVISION DETAIL https://phab.mercurial-scm.org/D3370 AFFECTED FILES hgext/show.py mercurial/scmutil.py mercurial/templatefuncs.py CHANGE DETAILS diff --git a/mercurial/templatefuncs.py b/mercurial/templatefuncs.py --- a/mercurial/templatefuncs.py +++ b/mercurial/templatefuncs.py @@ -590,8 +590,8 @@ # _partialmatch() of filtered changelog could take O(len(repo)) time, # which would be unacceptably slow. so we look for hash collision in # unfiltered space, which means some hashes may be slightly longer. -cl = context.resource(mapping, 'ctx')._repo.unfiltered().changelog -return cl.shortest(node, minlength) +repo = context.resource(mapping, 'ctx')._repo +return scmutil.shortesthexnodeidprefix(repo.unfiltered(), node, minlength) @templatefunc('strip(text[, chars])') def strip(context, mapping, args): diff --git a/mercurial/scmutil.py b/mercurial/scmutil.py --- a/mercurial/scmutil.py +++ b/mercurial/scmutil.py @@ -443,6 +443,10 @@ repo.changelog.rev(node) # make sure node isn't filtered return node +def shortesthexnodeidprefix(repo, hexnode, minlength=1): +"""Find the shortest unambiguous prefix that matches hexnode.""" +return repo.changelog.shortest(hexnode, minlength) + def isrevsymbol(repo, symbol): """Checks if a symbol exists in the repo. diff --git a/hgext/show.py b/hgext/show.py --- a/hgext/show.py +++ b/hgext/show.py @@ -45,6 +45,7 @@ registrar, revset, revsetlang, +scmutil, ) # Note for extension authors: ONLY specify testedwith = 'ships-with-hg-core' for @@ -447,8 +448,10 @@ if not revs: return minlen # don't use filtered repo because it's slow. see templater.shortest(). -cl = repo.unfiltered().changelog -return max(len(cl.shortest(hex(cl.node(r)), minlen)) for r in revs) +cl = repo.changelog +return max(len(scmutil.shortesthexnodeidprefix(repo.unfiltered(), + hex(cl.node(r)), + minlen)) for r in revs) # Adjust the docstring of the show command so it shows all registered views. # This is a bit hacky because it runs at the end of module load. When moved To: martinvonz, #hg-reviewers Cc: mercurial-devel ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
D3307: context: set stack level for deprecation warning
This revision was automatically updated to reflect the committed changes. Closed by commit rHG1764527af92e: context: set stack level for deprecation warning (authored by martinvonz, committed by ). REPOSITORY rHG Mercurial CHANGES SINCE LAST UPDATE https://phab.mercurial-scm.org/D3307?vs=8113=8258 REVISION DETAIL https://phab.mercurial-scm.org/D3307 AFFECTED FILES mercurial/context.py CHANGE DETAILS diff --git a/mercurial/context.py b/mercurial/context.py --- a/mercurial/context.py +++ b/mercurial/context.py @@ -399,7 +399,7 @@ # * If "x" can be a mix of the above, you'll have to figure it out #yourself repo.ui.deprecwarn("changectx.__init__ is getting more limited, see source " - "for details", "4.6") + "for details", "4.6", stacklevel=4) class changectx(basectx): """A changecontext object makes access to data related to a particular To: martinvonz, #hg-reviewers Cc: mercurial-devel ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
D3309: scmutil: rename resolvepartialhexnodeid() to resolvehexnodeidprefix()
This revision was automatically updated to reflect the committed changes. Closed by commit rHG5f8f013e7d52: scmutil: rename resolvepartialhexnodeid() to resolvehexnodeidprefix() (authored by martinvonz, committed by ). REPOSITORY rHG Mercurial CHANGES SINCE LAST UPDATE https://phab.mercurial-scm.org/D3309?vs=8252=8260 REVISION DETAIL https://phab.mercurial-scm.org/D3309 AFFECTED FILES hgext/eol.py hgext/histedit.py mercurial/context.py mercurial/scmutil.py CHANGE DETAILS diff --git a/mercurial/scmutil.py b/mercurial/scmutil.py --- a/mercurial/scmutil.py +++ b/mercurial/scmutil.py @@ -434,8 +434,8 @@ hexfunc = short return '%d:%s' % (rev, hexfunc(node)) -def resolvepartialhexnodeid(repo, prefix): -# Uses unfiltered repo because it's faster when then prefix is ambiguous/ +def resolvehexnodeidprefix(repo, prefix): +# Uses unfiltered repo because it's faster when prefix is ambiguous/ # This matches the "shortest" template function. node = repo.unfiltered().changelog._partialmatch(prefix) if node is None: diff --git a/mercurial/context.py b/mercurial/context.py --- a/mercurial/context.py +++ b/mercurial/context.py @@ -392,7 +392,7 @@ # * If you know that "x" is a branch or in some other namespace, #use the appropriate mechanism for that namespace # * If you know that "x" is a hex nodeid prefix, use -#repo[scmutil.resolvepartialhexnodeid(repo, x)] +#repo[scmutil.resolvehexnodeidprefix(repo, x)] # * If "x" is a string that can be any of the above, but you don't want #to allow general revsets (perhaps because "x" may come from a remote #user and the revset may be too costly), use scmutil.revsymbol(repo, x) @@ -476,7 +476,7 @@ except KeyError: pass -self._node = scmutil.resolvepartialhexnodeid(repo, changeid) +self._node = scmutil.resolvehexnodeidprefix(repo, changeid) if self._node is not None: self._rev = repo.changelog.rev(self._node) changectxdeprecwarn(repo) diff --git a/hgext/histedit.py b/hgext/histedit.py --- a/hgext/histedit.py +++ b/hgext/histedit.py @@ -443,7 +443,7 @@ """ Verifies semantic correctness of the rule""" repo = self.repo ha = node.hex(self.node) -self.node = scmutil.resolvepartialhexnodeid(repo, ha) +self.node = scmutil.resolvehexnodeidprefix(repo, ha) if self.node is None: raise error.ParseError(_('unknown changeset %s listed') % ha[:12]) self._verifynodeconstraints(prev, expected, seen) diff --git a/hgext/eol.py b/hgext/eol.py --- a/hgext/eol.py +++ b/hgext/eol.py @@ -300,7 +300,7 @@ hook = checkheadshook def preupdate(ui, repo, hooktype, parent1, parent2): -p1node = scmutil.resolvepartialhexnodeid(repo, parent1) +p1node = scmutil.resolvehexnodeidprefix(repo, parent1) repo.loadeol([p1node]) return False To: martinvonz, durin42, #hg-reviewers Cc: mercurial-devel ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
D3310: scmutil: use resolvehexnodeidprefix() from revsymbol()
This revision was automatically updated to reflect the committed changes. Closed by commit rHGab828755e1ea: scmutil: use resolvehexnodeidprefix() from revsymbol() (authored by martinvonz, committed by ). REPOSITORY rHG Mercurial CHANGES SINCE LAST UPDATE https://phab.mercurial-scm.org/D3310?vs=8253=8261 REVISION DETAIL https://phab.mercurial-scm.org/D3310 AFFECTED FILES mercurial/scmutil.py CHANGE DETAILS diff --git a/mercurial/scmutil.py b/mercurial/scmutil.py --- a/mercurial/scmutil.py +++ b/mercurial/scmutil.py @@ -503,7 +503,7 @@ except KeyError: pass -node = repo.unfiltered().changelog._partialmatch(symbol) +node = resolvehexnodeidprefix(repo, symbol) if node is not None: rev = repo.changelog.rev(node) return repo[rev] To: martinvonz, #hg-reviewers Cc: mercurial-devel ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
D3308: scmutil: document that isrevsymbol() raises on ambiguous node prefix
This revision was automatically updated to reflect the committed changes. Closed by commit rHG41ac707322ba: scmutil: document that isrevsymbol() raises on ambiguous node prefix (authored by martinvonz, committed by ). CHANGED PRIOR TO COMMIT https://phab.mercurial-scm.org/D3308?vs=8251=8259#toc REPOSITORY rHG Mercurial CHANGES SINCE LAST UPDATE https://phab.mercurial-scm.org/D3308?vs=8251=8259 REVISION DETAIL https://phab.mercurial-scm.org/D3308 AFFECTED FILES mercurial/scmutil.py CHANGE DETAILS diff --git a/mercurial/scmutil.py b/mercurial/scmutil.py --- a/mercurial/scmutil.py +++ b/mercurial/scmutil.py @@ -444,6 +444,11 @@ return node def isrevsymbol(repo, symbol): +"""Checks if a symbol exists in the repo. + +See revsymbol() for details. Raises error.LookupError if the symbol is an +ambiguous nodeid prefix. +""" try: revsymbol(repo, symbol) return True To: martinvonz, #hg-reviewers Cc: mercurial-devel ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
D3331: util: set correct stack level on deprecation warnings
This revision was automatically updated to reflect the committed changes. Closed by commit rHG5b8a260769a2: util: set correct stack level on deprecation warnings (authored by martinvonz, committed by ). REPOSITORY rHG Mercurial CHANGES SINCE LAST UPDATE https://phab.mercurial-scm.org/D3331?vs=8151=8257 REVISION DETAIL https://phab.mercurial-scm.org/D3331 AFFECTED FILES mercurial/util.py CHANGE DETAILS diff --git a/mercurial/util.py b/mercurial/util.py --- a/mercurial/util.py +++ b/mercurial/util.py @@ -3781,7 +3781,7 @@ fn = pycompat.sysbytes(func.__name__) mn = modname or pycompat.sysbytes(func.__module__)[len('mercurial.'):] msg = "'util.%s' is deprecated, use '%s.%s'" % (fn, mn, fn) -nouideprecwarn(msg, version) +nouideprecwarn(msg, version, stacklevel=2) return func(*args, **kwargs) wrapped.__name__ = func.__name__ return wrapped To: martinvonz, #hg-reviewers Cc: mercurial-devel ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
D3311: revset: use resolvehexnodeidprefix() in id() predicate (BC)
yuja requested changes to this revision. yuja added a comment. This revision now requires changes to proceed. I have vague memory that it was intentional. Since `rev()` and `id()` never error out on unknown identifier, it doesn't make sense to reject only ambiguous nodeid. REPOSITORY rHG Mercurial REVISION DETAIL https://phab.mercurial-scm.org/D3311 To: martinvonz, #hg-reviewers, yuja Cc: yuja, mercurial-devel ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
Re: [PATCH 3 of 5] lfs: fix the inferred remote store path when using a --prefix
On Fri, 13 Apr 2018 18:04:35 -0400, Matt Harbison wrote: > # HG changeset patch > # User Matt Harbison> # Date 1523643390 14400 > # Fri Apr 13 14:16:30 2018 -0400 > # Node ID a4c12789ef4bac6e736681ef8a08ccbe71fb5c41 > # Parent 54c1ab20ed7fbf415d087e6e94ca273d172046e8 > lfs: fix the inferred remote store path when using a --prefix The series looks good to me, except for the test failure. ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
Re: [PATCH 2 of 5] lfs: log information about Internal Server Errors reported in the Batch API
On Fri, 13 Apr 2018 18:04:34 -0400, Matt Harbison wrote: > # HG changeset patch > # User Matt Harbison> # Date 1523637594 14400 > # Fri Apr 13 12:39:54 2018 -0400 > # Node ID 54c1ab20ed7fbf415d087e6e94ca273d172046e8 > # Parent 1d394ac0efd4aa4f61f428fbac140fe57398f0b8 > lfs: log information about Internal Server Errors reported in the Batch API > +def _logexception(req): > +"""Write information about the current exception to wsgi.errors.""" > +tb = traceback.format_exc() > +# We need a native-string newline to poke in the log > +# message, because we won't get a newline when using an > +# r-string. This is the easy way out. > +newline = chr(10) > +errorlog = req.rawenv[r'wsgi.errors'] > + > +uri = '' > +if req.apppath: > +uri += req.apppath > +uri += b'/' + req.dispatchpath > + > +errorlog.write(r"Exception happened while processing request " > + r"'%s':%s%s" % (uri.decode('latin-1'), newline, tb)) errorlog is a binary stream as far as I can tell from our codebase. We'll instead have to convert tb to bytes by pycompat.sysbytes(). ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
Re: [PATCH 1 of 5] test-lfs: add tests to force server error path coverage
On Fri, 13 Apr 2018 18:04:33 -0400, Matt Harbison wrote: > # HG changeset patch > # User Matt Harbison> # Date 1523119701 14400 > # Sat Apr 07 12:48:21 2018 -0400 > # Node ID 1d394ac0efd4aa4f61f428fbac140fe57398f0b8 > # Parent bfdd20d22a86edc318493b4da84a1d7ff4ef98f2 > test-lfs: add tests to force server error path coverage The test failed on my machine. Can you take a look? --- /home/yuya/work/hghacks/mercurial-review/tests/test-lfs-serve-access.t +++ /home/yuya/work/hghacks/mercurial-review/tests/test-lfs-serve-access.t.err @@ -270,14 +270,12 @@ $LOCALIP - - [$LOGDATE$] "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=phases x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull (glob) $LOCALIP - - [$LOGDATE$] "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=bookmarks x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull (glob) $LOCALIP - - [$LOGDATE$] "GET /?cmd=branchmap HTTP/1.1" 200 - x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull (glob) - $LOCALIP - - [$LOGDATE$] "GET /?cmd=branchmap HTTP/1.1" 200 - x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull (glob) $LOCALIP - - [$LOGDATE$] "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=bookmarks x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull (glob) $LOCALIP - - [$LOGDATE$] "POST /.git/info/lfs/objects/batch HTTP/1.1" 200 - (glob) $LOCALIP - - [$LOGDATE$] "GET /?cmd=capabilities HTTP/1.1" 200 - (glob) $LOCALIP - - [$LOGDATE$] "GET /?cmd=batch HTTP/1.1" 200 - x-hgarg-1:cmds=heads+%3Bknown+nodes%3D392c05922088bacf8e68a6939b480017afbf245d x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull (glob) $LOCALIP - - [$LOGDATE$] "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=phases x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull (glob) $LOCALIP - - [$LOGDATE$] "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=bookmarks x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull (glob) - $LOCALIP - - [$LOGDATE$] "GET /?cmd=branchmap HTTP/1.1" 200 - x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull (glob) $LOCALIP - - [$LOGDATE$] "GET /?cmd=branchmap HTTP/1.1" 200 - x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull (glob) $LOCALIP - - [$LOGDATE$] "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=bookmarks x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull (glob) $LOCALIP - - [$LOGDATE$] "POST /.git/info/lfs/objects/batch HTTP/1.1" 200 - (glob) ERROR: test-lfs-serve-access.t output changed ! Failed test-lfs-serve-access.t: output changed # Ran 1 tests, 0 skipped, 1 failed. python hash seed: 3873177365 ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
D3308: scmutil: document that isrevsymbol() raises on ambiguous node prefix
martinvonz updated this revision to Diff 8251. REPOSITORY rHG Mercurial CHANGES SINCE LAST UPDATE https://phab.mercurial-scm.org/D3308?vs=8114=8251 REVISION DETAIL https://phab.mercurial-scm.org/D3308 AFFECTED FILES mercurial/scmutil.py CHANGE DETAILS diff --git a/mercurial/scmutil.py b/mercurial/scmutil.py --- a/mercurial/scmutil.py +++ b/mercurial/scmutil.py @@ -444,6 +444,11 @@ return node def isrevsymbol(repo, symbol): +"""Checks if a symbol exists in the repo. + + See revsymbol() for details. Raises error.LookupError if the symbol is an + ambiguous nodeid prefix. +""" try: revsymbol(repo, symbol) return True To: martinvonz, #hg-reviewers Cc: mercurial-devel ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
D3370: scmutil: introduce shortesthexnodeidprefix()
martinvonz updated this revision to Diff 8254. REPOSITORY rHG Mercurial CHANGES SINCE LAST UPDATE https://phab.mercurial-scm.org/D3370?vs=8249=8254 REVISION DETAIL https://phab.mercurial-scm.org/D3370 AFFECTED FILES hgext/show.py mercurial/scmutil.py mercurial/templatefuncs.py CHANGE DETAILS diff --git a/mercurial/templatefuncs.py b/mercurial/templatefuncs.py --- a/mercurial/templatefuncs.py +++ b/mercurial/templatefuncs.py @@ -590,8 +590,8 @@ # _partialmatch() of filtered changelog could take O(len(repo)) time, # which would be unacceptably slow. so we look for hash collision in # unfiltered space, which means some hashes may be slightly longer. -cl = context.resource(mapping, 'ctx')._repo.unfiltered().changelog -return cl.shortest(node, minlength) +repo = context.resource(mapping, 'ctx')._repo +return scmutil.shortesthexnodeidprefix(repo.unfiltered(), node, minlength) @templatefunc('strip(text[, chars])') def strip(context, mapping, args): diff --git a/mercurial/scmutil.py b/mercurial/scmutil.py --- a/mercurial/scmutil.py +++ b/mercurial/scmutil.py @@ -443,6 +443,10 @@ repo.changelog.rev(node) # make sure node isn't filtered return node +def shortesthexnodeidprefix(repo, hexnode, minlength=1): +"""Find the shortest unambiguous prefix that matches hexnode.""" +return repo.changelog.shortest(hexnode, minlength) + def isrevsymbol(repo, symbol): """Checks if a symbol exists in the repo. diff --git a/hgext/show.py b/hgext/show.py --- a/hgext/show.py +++ b/hgext/show.py @@ -45,6 +45,7 @@ registrar, revset, revsetlang, +scmutil, ) # Note for extension authors: ONLY specify testedwith = 'ships-with-hg-core' for @@ -447,8 +448,10 @@ if not revs: return minlen # don't use filtered repo because it's slow. see templater.shortest(). -cl = repo.unfiltered().changelog -return max(len(cl.shortest(hex(cl.node(r)), minlen)) for r in revs) +cl = repo.changelog +return max(len(scmutil.shortesthexnodeidprefix(repo.unfiltered(), + hex(cl.node(r)), + minlen)) for r in revs) # Adjust the docstring of the show command so it shows all registered views. # This is a bit hacky because it runs at the end of module load. When moved To: martinvonz, #hg-reviewers Cc: mercurial-devel ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
D3310: scmutil: use resolvehexnodeidprefix() from revsymbol()
martinvonz updated this revision to Diff 8253. REPOSITORY rHG Mercurial CHANGES SINCE LAST UPDATE https://phab.mercurial-scm.org/D3310?vs=8116=8253 REVISION DETAIL https://phab.mercurial-scm.org/D3310 AFFECTED FILES mercurial/scmutil.py CHANGE DETAILS diff --git a/mercurial/scmutil.py b/mercurial/scmutil.py --- a/mercurial/scmutil.py +++ b/mercurial/scmutil.py @@ -503,7 +503,7 @@ except KeyError: pass -node = repo.unfiltered().changelog._partialmatch(symbol) +node = resolvehexnodeidprefix(repo, symbol) if node is not None: rev = repo.changelog.rev(node) return repo[rev] To: martinvonz, #hg-reviewers Cc: mercurial-devel ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
D3309: scmutil: rename resolvepartialhexnodeid() to resolvehexnodeidprefix()
martinvonz updated this revision to Diff 8252. REPOSITORY rHG Mercurial CHANGES SINCE LAST UPDATE https://phab.mercurial-scm.org/D3309?vs=8247=8252 REVISION DETAIL https://phab.mercurial-scm.org/D3309 AFFECTED FILES hgext/eol.py hgext/histedit.py mercurial/context.py mercurial/scmutil.py CHANGE DETAILS diff --git a/mercurial/scmutil.py b/mercurial/scmutil.py --- a/mercurial/scmutil.py +++ b/mercurial/scmutil.py @@ -434,8 +434,8 @@ hexfunc = short return '%d:%s' % (rev, hexfunc(node)) -def resolvepartialhexnodeid(repo, prefix): -# Uses unfiltered repo because it's faster when then prefix is ambiguous/ +def resolvehexnodeidprefix(repo, prefix): +# Uses unfiltered repo because it's faster when prefix is ambiguous/ # This matches the "shortest" template function. node = repo.unfiltered().changelog._partialmatch(prefix) if node is None: diff --git a/mercurial/context.py b/mercurial/context.py --- a/mercurial/context.py +++ b/mercurial/context.py @@ -392,7 +392,7 @@ # * If you know that "x" is a branch or in some other namespace, #use the appropriate mechanism for that namespace # * If you know that "x" is a hex nodeid prefix, use -#repo[scmutil.resolvepartialhexnodeid(repo, x)] +#repo[scmutil.resolvehexnodeidprefix(repo, x)] # * If "x" is a string that can be any of the above, but you don't want #to allow general revsets (perhaps because "x" may come from a remote #user and the revset may be too costly), use scmutil.revsymbol(repo, x) @@ -476,7 +476,7 @@ except KeyError: pass -self._node = scmutil.resolvepartialhexnodeid(repo, changeid) +self._node = scmutil.resolvehexnodeidprefix(repo, changeid) if self._node is not None: self._rev = repo.changelog.rev(self._node) changectxdeprecwarn(repo) diff --git a/hgext/histedit.py b/hgext/histedit.py --- a/hgext/histedit.py +++ b/hgext/histedit.py @@ -443,7 +443,7 @@ """ Verifies semantic correctness of the rule""" repo = self.repo ha = node.hex(self.node) -self.node = scmutil.resolvepartialhexnodeid(repo, ha) +self.node = scmutil.resolvehexnodeidprefix(repo, ha) if self.node is None: raise error.ParseError(_('unknown changeset %s listed') % ha[:12]) self._verifynodeconstraints(prev, expected, seen) diff --git a/hgext/eol.py b/hgext/eol.py --- a/hgext/eol.py +++ b/hgext/eol.py @@ -300,7 +300,7 @@ hook = checkheadshook def preupdate(ui, repo, hooktype, parent1, parent2): -p1node = scmutil.resolvepartialhexnodeid(repo, parent1) +p1node = scmutil.resolvehexnodeidprefix(repo, parent1) repo.loadeol([p1node]) return False To: martinvonz, durin42, #hg-reviewers Cc: mercurial-devel ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
D3313: scmutil: make shortesthexnodeidprefix() use unfiltered repo
martinvonz updated this revision to Diff 8255. REPOSITORY rHG Mercurial CHANGES SINCE LAST UPDATE https://phab.mercurial-scm.org/D3313?vs=8250=8255 REVISION DETAIL https://phab.mercurial-scm.org/D3313 AFFECTED FILES hgext/show.py mercurial/scmutil.py mercurial/templatefuncs.py CHANGE DETAILS diff --git a/mercurial/templatefuncs.py b/mercurial/templatefuncs.py --- a/mercurial/templatefuncs.py +++ b/mercurial/templatefuncs.py @@ -587,11 +587,8 @@ # i18n: "shortest" is a keyword _("shortest() expects an integer minlength")) -# _partialmatch() of filtered changelog could take O(len(repo)) time, -# which would be unacceptably slow. so we look for hash collision in -# unfiltered space, which means some hashes may be slightly longer. repo = context.resource(mapping, 'ctx')._repo -return scmutil.shortesthexnodeidprefix(repo.unfiltered(), node, minlength) +return scmutil.shortesthexnodeidprefix(repo, node, minlength) @templatefunc('strip(text[, chars])') def strip(context, mapping, args): diff --git a/mercurial/scmutil.py b/mercurial/scmutil.py --- a/mercurial/scmutil.py +++ b/mercurial/scmutil.py @@ -436,16 +436,19 @@ def resolvehexnodeidprefix(repo, prefix): # Uses unfiltered repo because it's faster when prefix is ambiguous/ -# This matches the "shortest" template function. +# This matches the shortesthexnodeidprefix() function below. node = repo.unfiltered().changelog._partialmatch(prefix) if node is None: return repo.changelog.rev(node) # make sure node isn't filtered return node def shortesthexnodeidprefix(repo, hexnode, minlength=1): """Find the shortest unambiguous prefix that matches hexnode.""" -return repo.changelog.shortest(hexnode, minlength) +# _partialmatch() of filtered changelog could take O(len(repo)) time, +# which would be unacceptably slow. so we look for hash collision in +# unfiltered space, which means some hashes may be slightly longer. +return repo.unfiltered().changelog.shortest(hexnode, minlength) def isrevsymbol(repo, symbol): """Checks if a symbol exists in the repo. diff --git a/hgext/show.py b/hgext/show.py --- a/hgext/show.py +++ b/hgext/show.py @@ -447,10 +447,8 @@ """ if not revs: return minlen -# don't use filtered repo because it's slow. see templater.shortest(). cl = repo.changelog -return max(len(scmutil.shortesthexnodeidprefix(repo.unfiltered(), - hex(cl.node(r)), +return max(len(scmutil.shortesthexnodeidprefix(repo, hex(cl.node(r)), minlen)) for r in revs) # Adjust the docstring of the show command so it shows all registered views. To: martinvonz, #hg-reviewers Cc: mercurial-devel ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
D3371: scmutil: make shortesthexnodeidprefix() take a full binary nodeid
martinvonz created this revision. Herald added a subscriber: mercurial-devel. Herald added a reviewer: hg-reviewers. REVISION SUMMARY The shortest() template function depended on the behavior of revlog._partialmatch() for these types of inputs: - non-hex strings - ambiguous strings - too long strings revlog._partialmatch() seems to return the input unchanged in these cases, but we shouldn't depend on such a low-level function to match the behavior we want in the user-facing template function. Instead, let's handle these cases in the template function and always pass a binary nodeid to _partialmatch(). REPOSITORY rHG Mercurial REVISION DETAIL https://phab.mercurial-scm.org/D3371 AFFECTED FILES hgext/show.py mercurial/scmutil.py mercurial/templatefuncs.py tests/test-command-template.t CHANGE DETAILS diff --git a/tests/test-command-template.t b/tests/test-command-template.t --- a/tests/test-command-template.t +++ b/tests/test-command-template.t @@ -3900,6 +3900,21 @@ $ hg log -r 'wdir()' -T '{node|shortest}\n' + $ hg log --template '{shortest("f")}\n' -l1 + f + + $ hg log --template '{shortest("0123456789012345678901234567890123456789")}\n' -l1 + 0123456789012345678901234567890123456789 + + $ hg log --template '{shortest("01234567890123456789012345678901234567890123456789")}\n' -l1 + 01234567890123456789012345678901234567890123456789 + + $ hg log --template '{shortest("not a hex string")}\n' -l1 + not a hex string + + $ hg log --template '{shortest("not a hex string, but it'\''s 40 bytes long")}\n' -l1 + not a hex string, but it's 40 bytes long + $ cd .. Test shortest(node) with the repo having short hash collision: diff --git a/mercurial/templatefuncs.py b/mercurial/templatefuncs.py --- a/mercurial/templatefuncs.py +++ b/mercurial/templatefuncs.py @@ -26,6 +26,9 @@ templateutil, util, ) +from .node import ( +bin, +) from .utils import ( dateutil, stringutil, @@ -579,15 +582,29 @@ # i18n: "shortest" is a keyword raise error.ParseError(_("shortest() expects one or two arguments")) -node = evalstring(context, mapping, args[0]) +hexnode = evalstring(context, mapping, args[0]) minlength = 4 if len(args) > 1: minlength = evalinteger(context, mapping, args[1], # i18n: "shortest" is a keyword _("shortest() expects an integer minlength")) repo = context.resource(mapping, 'ctx')._repo +if len(hexnode) > 40: +return hexnode +elif len(hexnode) == 40: +try: +node = bin(hexnode) +except TypeError: +return hexnode +else: +try: +node = scmutil.resolvehexnodeidprefix(repo, hexnode) +except (error.LookupError, error.WdirUnsupported): +return hexnode +if not node: +return hexnode return scmutil.shortesthexnodeidprefix(repo, node, minlength) @templatefunc('strip(text[, chars])') diff --git a/mercurial/scmutil.py b/mercurial/scmutil.py --- a/mercurial/scmutil.py +++ b/mercurial/scmutil.py @@ -443,12 +443,12 @@ repo.changelog.rev(node) # make sure node isn't filtered return node -def shortesthexnodeidprefix(repo, hexnode, minlength=1): +def shortesthexnodeidprefix(repo, node, minlength=1): """Find the shortest unambiguous prefix that matches hexnode.""" # _partialmatch() of filtered changelog could take O(len(repo)) time, # which would be unacceptably slow. so we look for hash collision in # unfiltered space, which means some hashes may be slightly longer. -return repo.unfiltered().changelog.shortest(hexnode, minlength) +return repo.unfiltered().changelog.shortest(hex(node), minlength) def isrevsymbol(repo, symbol): """Checks if a symbol exists in the repo. diff --git a/hgext/show.py b/hgext/show.py --- a/hgext/show.py +++ b/hgext/show.py @@ -448,8 +448,8 @@ if not revs: return minlen cl = repo.changelog -return max(len(scmutil.shortesthexnodeidprefix(repo, hex(cl.node(r)), - minlen)) for r in revs) +return max(len(scmutil.shortesthexnodeidprefix(repo, cl.node(r), minlen)) + for r in revs) # Adjust the docstring of the show command so it shows all registered views. # This is a bit hacky because it runs at the end of module load. When moved To: martinvonz, #hg-reviewers Cc: mercurial-devel ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
Re: [PATCH] dispatch: add a whitelist map of commands to implicitly loaded extensions
On Fri, 13 Apr 2018 23:30:43 -0400, Matt Harbison wrote: > On Fri, 13 Apr 2018 15:10:45 -0400, Gregory Szorc >wrote: > > What we may want instead is to key things off .hg/requires or a > > to-be-invented supplemental requirements-like file that declares soft > > features. localrepository.__init__ could then load trusted extensions at > > repo open time if a requirements/capability was present/requested. i.e. > > if > > you talk to an LFS server, write a semaphore somewhere into .hg/ and have > > something in core look for that and automatically load lfs if present. > > This would get you the "automatically enable LFS when talking to LFS > > servers" > > benefits. > > Sounds promising. One of the things the lfs extension is doing is writing > '[extensions]\nlfs=' to the repo's local hgrc file in a commit hook (it > should probably be handling transactions too). So it would be nice if > this was baked into the core somehow (largefiles could use exactly the > same handling, and I'm assuming narrow will be similar). It's also > manually adding to the requires file, since that doesn't seem to be > updated in exchange. > > Assuming the semaphore is persistent, it could be beneficial to load > extensions indicated by it around the normal load time (e.g., largefiles > wraps the clone command and adds extra switches). > > I'm not sure if this addresses Yuya's concern about long lived processes > though. If the extensions to be loaded are bound to a repo, yes, that should be fine. A well-designed extension should check the repo requirements. What doesn't work in command server is to load extensions per-command basis. ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
D3309: scmutil: rename resolvepartialhexnodeid() to resolvehexnodeidprefix()
martinvonz updated this revision to Diff 8247. martinvonz edited the summary of this revision. REPOSITORY rHG Mercurial CHANGES SINCE LAST UPDATE https://phab.mercurial-scm.org/D3309?vs=8115=8247 REVISION DETAIL https://phab.mercurial-scm.org/D3309 AFFECTED FILES hgext/eol.py hgext/histedit.py mercurial/context.py mercurial/scmutil.py CHANGE DETAILS diff --git a/mercurial/scmutil.py b/mercurial/scmutil.py --- a/mercurial/scmutil.py +++ b/mercurial/scmutil.py @@ -434,8 +434,8 @@ hexfunc = short return '%d:%s' % (rev, hexfunc(node)) -def resolvepartialhexnodeid(repo, prefix): -# Uses unfiltered repo because it's faster when then prefix is ambiguous/ +def resolvehexnodeidprefix(repo, prefix): +# Uses unfiltered repo because it's faster when prefix is ambiguous/ # This matches the "shortest" template function. node = repo.unfiltered().changelog._partialmatch(prefix) if node is None: diff --git a/mercurial/context.py b/mercurial/context.py --- a/mercurial/context.py +++ b/mercurial/context.py @@ -392,7 +392,7 @@ # * If you know that "x" is a branch or in some other namespace, #use the appropriate mechanism for that namespace # * If you know that "x" is a hex nodeid prefix, use -#repo[scmutil.resolvepartialhexnodeid(repo, x)] +#repo[scmutil.resolvehexnodeidprefix(repo, x)] # * If "x" is a string that can be any of the above, but you don't want #to allow general revsets (perhaps because "x" may come from a remote #user and the revset may be too costly), use scmutil.revsymbol(repo, x) @@ -476,7 +476,7 @@ except KeyError: pass -self._node = scmutil.resolvepartialhexnodeid(repo, changeid) +self._node = scmutil.resolvehexnodeidprefix(repo, changeid) if self._node is not None: self._rev = repo.changelog.rev(self._node) changectxdeprecwarn(repo) diff --git a/hgext/histedit.py b/hgext/histedit.py --- a/hgext/histedit.py +++ b/hgext/histedit.py @@ -443,7 +443,7 @@ """ Verifies semantic correctness of the rule""" repo = self.repo ha = node.hex(self.node) -self.node = scmutil.resolvepartialhexnodeid(repo, ha) +self.node = scmutil.resolvehexnodeidprefix(repo, ha) if self.node is None: raise error.ParseError(_('unknown changeset %s listed') % ha[:12]) self._verifynodeconstraints(prev, expected, seen) diff --git a/hgext/eol.py b/hgext/eol.py --- a/hgext/eol.py +++ b/hgext/eol.py @@ -300,7 +300,7 @@ hook = checkheadshook def preupdate(ui, repo, hooktype, parent1, parent2): -p1node = scmutil.resolvepartialhexnodeid(repo, parent1) +p1node = scmutil.resolvehexnodeidprefix(repo, parent1) repo.loadeol([p1node]) return False To: martinvonz, durin42, #hg-reviewers Cc: mercurial-devel ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
D3311: revset: use resolvehexnodeidprefix() in id() predicate (BC)
martinvonz updated this revision to Diff 8248. REPOSITORY rHG Mercurial CHANGES SINCE LAST UPDATE https://phab.mercurial-scm.org/D3311?vs=8117=8248 REVISION DETAIL https://phab.mercurial-scm.org/D3311 AFFECTED FILES mercurial/revset.py tests/test-revset.t CHANGE DETAILS diff --git a/tests/test-revset.t b/tests/test-revset.t --- a/tests/test-revset.t +++ b/tests/test-revset.t @@ -1878,7 +1878,8 @@ [255] BROKEN should be '2' (node lookup uses unfiltered repo since dc25ed84bee8) $ hg debugrevspec '0:wdir() & id(fffb)' - 2 + abort: 00changelog.i@fffb: ambiguous identifier! + [255] $ hg debugrevspec '0:wdir() & 8' 4 $ hg debugrevspec '0:wdir() & f' diff --git a/mercurial/revset.py b/mercurial/revset.py --- a/mercurial/revset.py +++ b/mercurial/revset.py @@ -1333,7 +1333,7 @@ else: rn = None try: -pm = repo.changelog._partialmatch(n) +pm = scmutil.resolvehexnodeidprefix(repo, n) if pm is not None: rn = repo.changelog.rev(pm) except error.WdirUnsupported: To: martinvonz, #hg-reviewers Cc: mercurial-devel ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
D3313: scmutil: make shortesthexnodeidprefix() use unfiltered repo
martinvonz updated this revision to Diff 8250. REPOSITORY rHG Mercurial CHANGES SINCE LAST UPDATE https://phab.mercurial-scm.org/D3313?vs=8119=8250 REVISION DETAIL https://phab.mercurial-scm.org/D3313 AFFECTED FILES hgext/show.py mercurial/scmutil.py mercurial/templatefuncs.py CHANGE DETAILS diff --git a/mercurial/templatefuncs.py b/mercurial/templatefuncs.py --- a/mercurial/templatefuncs.py +++ b/mercurial/templatefuncs.py @@ -587,11 +587,8 @@ # i18n: "shortest" is a keyword _("shortest() expects an integer minlength")) -# _partialmatch() of filtered changelog could take O(len(repo)) time, -# which would be unacceptably slow. so we look for hash collision in -# unfiltered space, which means some hashes may be slightly longer. repo = context.resource(mapping, 'ctx')._repo -return scmutil.shortesthexnodeidprefix(repo.unfiltered(), node, minlength) +return scmutil.shortesthexnodeidprefix(repo, node, minlength) @templatefunc('strip(text[, chars])') def strip(context, mapping, args): diff --git a/mercurial/scmutil.py b/mercurial/scmutil.py --- a/mercurial/scmutil.py +++ b/mercurial/scmutil.py @@ -436,16 +436,19 @@ def resolvehexnodeidprefix(repo, prefix): # Uses unfiltered repo because it's faster when prefix is ambiguous/ -# This matches the "shortest" template function. +# This matches the shortesthexnodeidprefix() function below. node = repo.unfiltered().changelog._partialmatch(prefix) if node is None: return repo.changelog.rev(node) # make sure node isn't filtered return node def shortesthexnodeidprefix(repo, hexnode, minlength=1): """Find the shortest unambiguous prefix that matches hexnode.""" -return repo.changelog.shortest(hexnode) +# _partialmatch() of filtered changelog could take O(len(repo)) time, +# which would be unacceptably slow. so we look for hash collision in +# unfiltered space, which means some hashes may be slightly longer. +return repo.unfiltered().changelog.shortest(hexnode) def isrevsymbol(repo, symbol): """Checks if a symbol exists in the repo. diff --git a/hgext/show.py b/hgext/show.py --- a/hgext/show.py +++ b/hgext/show.py @@ -447,10 +447,8 @@ """ if not revs: return minlen -# don't use filtered repo because it's slow. see templater.shortest(). cl = repo.changelog -return max(len(scmutil.shortesthexnodeidprefix(repo.unfiltered(), - hex(cl.node(r)), +return max(len(scmutil.shortesthexnodeidprefix(repo, hex(cl.node(r)), minlen)) for r in revs) # Adjust the docstring of the show command so it shows all registered views. To: martinvonz, #hg-reviewers Cc: mercurial-devel ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel