[PATCH V5] forget: add --dry-run mode
# HG changeset patch # User Sushil khanchi # Date 1520665399 -19800 # Sat Mar 10 12:33:19 2018 +0530 # Node ID bd9d29c4c929d0495e874d0c35d96cae29f5ff72 # Parent 4c71a26a4009d88590c9ae3d64a5912fd556d82e forget: add --dry-run mode diff -r 4c71a26a4009 -r bd9d29c4c929 mercurial/cmdutil.py --- a/mercurial/cmdutil.py Sun Mar 04 21:16:36 2018 -0500 +++ b/mercurial/cmdutil.py Sat Mar 10 12:33:19 2018 +0530 @@ -1996,7 +1996,7 @@ for subpath in ctx.substate: ctx.sub(subpath).addwebdirpath(serverpath, webconf) -def forget(ui, repo, match, prefix, explicitonly): +def forget(ui, repo, match, prefix, explicitonly, dryrun): join = lambda f: os.path.join(prefix, f) bad = [] badfn = lambda x, y: bad.append(x) or match.bad(x, y) @@ -2012,7 +2012,7 @@ sub = wctx.sub(subpath) try: submatch = matchmod.subdirmatcher(subpath, match) -subbad, subforgot = sub.forget(submatch, prefix) +subbad, subforgot = sub.forget(submatch, prefix, dryrun=dryrun) bad.extend([subpath + '/' + f for f in subbad]) forgot.extend([subpath + '/' + f for f in subforgot]) except error.LookupError: @@ -2039,9 +2039,10 @@ if ui.verbose or not match.exact(f): ui.status(_('removing %s\n') % match.rel(f)) -rejected = wctx.forget(forget, prefix) -bad.extend(f for f in rejected if f in match.files()) -forgot.extend(f for f in forget if f not in rejected) +if not dryrun: +rejected = wctx.forget(forget, prefix) +bad.extend(f for f in rejected if f in match.files()) +forgot.extend(f for f in forget if f not in rejected) return bad, forgot def files(ui, ctx, m, fm, fmt, subrepos): diff -r 4c71a26a4009 -r bd9d29c4c929 mercurial/commands.py --- a/mercurial/commands.py Sun Mar 04 21:16:36 2018 -0500 +++ b/mercurial/commands.py Sat Mar 10 12:33:19 2018 +0530 @@ -2036,7 +2036,10 @@ with ui.formatter('files', opts) as fm: return cmdutil.files(ui, ctx, m, fm, fmt, opts.get('subrepos')) -@command('^forget', walkopts, _('[OPTION]... FILE...'), inferrepo=True) +@command( +'^forget', +walkopts + dryrunopts, +_('[OPTION]... FILE...'), inferrepo=True) def forget(ui, repo, *pats, **opts): """forget the specified files on the next commit @@ -2071,7 +2074,9 @@ raise error.Abort(_('no files specified')) m = scmutil.match(repo[None], pats, opts) -rejected = cmdutil.forget(ui, repo, m, prefix="", explicitonly=False)[0] +dryrun = opts.get(r'dry_run') +rejected = cmdutil.forget(ui, repo, m, prefix="", + explicitonly=False, dryrun=dryrun)[0] return rejected and 1 or 0 @command( diff -r 4c71a26a4009 -r bd9d29c4c929 mercurial/subrepo.py --- a/mercurial/subrepo.py Sun Mar 04 21:16:36 2018 -0500 +++ b/mercurial/subrepo.py Sat Mar 10 12:33:19 2018 +0530 @@ -811,9 +811,10 @@ return ctx.walk(match) @annotatesubrepoerror -def forget(self, match, prefix): +def forget(self, match, prefix, dryrun): return cmdutil.forget(self.ui, self._repo, match, - self.wvfs.reljoin(prefix, self._path), True) + self.wvfs.reljoin(prefix, self._path), + True, dryrun=dryrun) @annotatesubrepoerror def removefiles(self, matcher, prefix, after, force, subrepos, warnings): diff -r 4c71a26a4009 -r bd9d29c4c929 tests/test-commit.t --- a/tests/test-commit.t Sun Mar 04 21:16:36 2018 -0500 +++ b/tests/test-commit.t Sat Mar 10 12:33:19 2018 +0530 @@ -832,3 +832,18 @@ $ cd .. +test --dry-run mode in forget + + $ hg init testdir_forget + $ cd testdir_forget + $ echo foo > foo + $ hg add foo + $ hg commit -m "foo" + $ hg forget foo --dry-run -v + removing foo + $ hg diff + $ hg forget not_exist -n + not_exist: $ENOENT$ + [1] + + $ cd .. ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
D2854: hgweb: str/bytes followups after indygreg's refactoring
indygreg requested changes to this revision. indygreg added a comment. This revision now requires changes to proceed. parsedrequest.headers is supposed to be bytes. One of the goals of this refactor was to make the WSGI code all bytes all the time. So if system strings are making their way to the new request or response objects (i.e. outside request.py), then something is wrong and we should fix that: we shouldn’t need to introduce raw literals outside of the very low level WSGI code. REPOSITORY rHG Mercurial REVISION DETAIL https://phab.mercurial-scm.org/D2854 To: durin42, #hg-reviewers, indygreg Cc: indygreg, mercurial-devel ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
D2776: hgweb: use a multidict for holding query string parameters
martinvonz added inline comments. INLINE COMMENTS > request.py:39-41 > +# Stores (key, value) 2-tuples. This isn't the most efficient. But we > +# don't rely on parameters that much, so it shouldn't be a perf > issue. > +# we can always add dict for fast lookups. Sure, that's probably fine, but why? Wouldn't it be easier to write it as dict of lists anyway? > request.py:45 > +def __getitem__(self, key): > +"""Returns the last set value for a key.""" > +for k, v in reversed(self._items): Would it make sense to make this an error if there isn't exactly one value? REPOSITORY rHG Mercurial REVISION DETAIL https://phab.mercurial-scm.org/D2776 To: indygreg, #hg-reviewers, durin42 Cc: martinvonz, durin42, mercurial-devel ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
Re: [PATCH] peer-request: include more details about batch commands
> On Mar 13, 2018, at 12:39, Boris Feld wrote: > > # HG changeset patch > # User Boris Feld > # Date 1520268508 18000 > # Mon Mar 05 11:48:28 2018 -0500 > # Node ID 025b0a829b1c9a299b76b7303b4d46c269fcba48 > # Parent 31581528f2421dc5d8a567125b8ecc0367b2b906 > # EXP-Topic peer-request.batch > # Available At https://bitbucket.org/octobus/mercurial-devel/ > # hg pull https://bitbucket.org/octobus/mercurial-devel/ -r > 025b0a829b1c > peer-request: include more details about batch commands queued, thanks ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
D2854: hgweb: str/bytes followups after indygreg's refactoring
durin42 created this revision. Herald added a subscriber: mercurial-devel. Herald added a reviewer: hg-reviewers. REVISION SUMMARY As of this change, we're mostly principled about using native strings (so bytes on 2, unicode on 3) for accessing HTTP headers. This restores test-getbundle.t (probably among others) to passing on Python 3. REPOSITORY rHG Mercurial REVISION DETAIL https://phab.mercurial-scm.org/D2854 AFFECTED FILES mercurial/hgweb/common.py mercurial/hgweb/hgweb_mod.py mercurial/hgweb/hgwebdir_mod.py mercurial/hgweb/request.py mercurial/hgweb/server.py mercurial/wireprotoserver.py CHANGE DETAILS diff --git a/mercurial/wireprotoserver.py b/mercurial/wireprotoserver.py --- a/mercurial/wireprotoserver.py +++ b/mercurial/wireprotoserver.py @@ -29,9 +29,9 @@ HTTP_OK = 200 -HGTYPE = 'application/mercurial-0.1' -HGTYPE2 = 'application/mercurial-0.2' -HGERRTYPE = 'application/hg-error' +HGTYPE = r'application/mercurial-0.1' +HGTYPE2 = r'application/mercurial-0.2' +HGERRTYPE = r'application/hg-error' SSHV1 = wireprototypes.SSHV1 SSHV2 = wireprototypes.SSHV2 @@ -44,7 +44,7 @@ chunks = [] i = 1 while True: -v = req.headers.get(b'%s-%d' % (headerprefix, i)) +v = req.headers.get(r'%s-%d' % (headerprefix, i)) if v is None: break chunks.append(pycompat.bytesurl(v)) @@ -79,23 +79,23 @@ def _args(self): args = self._req.qsparams.asdictoflists() -postlen = int(self._req.headers.get(b'X-HgArgs-Post', 0)) +postlen = int(self._req.headers.get(r'X-HgArgs-Post', 0)) if postlen: args.update(urlreq.parseqs( self._req.bodyfh.read(postlen), keep_blank_values=True)) return args -argvalue = decodevaluefromheaders(self._req, b'X-HgArg') +argvalue = decodevaluefromheaders(self._req, r'X-HgArg') args.update(urlreq.parseqs(argvalue, keep_blank_values=True)) return args def forwardpayload(self, fp): # Existing clients *always* send Content-Length. -length = int(self._req.headers[b'Content-Length']) +length = int(self._req.headers[r'Content-Length']) # If httppostargs is used, we need to read Content-Length # minus the amount that was consumed by args. -length -= int(self._req.headers.get(b'X-HgArgs-Post', 0)) +length -= int(self._req.headers.get(r'X-HgArgs-Post', 0)) for s in util.filechunkiter(self._req.bodyfh, limit=length): fp.write(s) @@ -189,7 +189,7 @@ # in this case. We send an HTTP 404 for backwards compatibility reasons. if req.dispatchpath: res.status = hgwebcommon.statusmessage(404) -res.headers['Content-Type'] = HGTYPE +res.headers[r'Content-Type'] = HGTYPE # TODO This is not a good response to issue for this request. This # is mostly for BC for now. res.setbodybytes('0\n%s\n' % b'Not Found') @@ -207,7 +207,7 @@ except hgwebcommon.ErrorResponse as e: for k, v in e.headers: res.headers[k] = v -res.status = hgwebcommon.statusmessage(e.code, pycompat.bytestr(e)) +res.status = hgwebcommon.statusmessage(e.code, e) # TODO This response body assumes the failed command was # "unbundle." That assumption is not always valid. res.setbodybytes('0\n%s\n' % pycompat.bytestr(e)) @@ -271,11 +271,11 @@ def setresponse(code, contenttype, bodybytes=None, bodygen=None): if code == HTTP_OK: -res.status = '200 Script output follows' +res.status = r'200 Script output follows' else: res.status = hgwebcommon.statusmessage(code) -res.headers['Content-Type'] = contenttype +res.headers[r'Content-Type'] = pycompat.strurl(contenttype) if bodybytes is not None: res.setbodybytes(bodybytes) diff --git a/mercurial/hgweb/server.py b/mercurial/hgweb/server.py --- a/mercurial/hgweb/server.py +++ b/mercurial/hgweb/server.py @@ -101,7 +101,7 @@ try: self.do_write() except Exception: -self._start_response("500 Internal Server Error", []) +self._start_response(r"500 Internal Server Error", []) self._write("Internal Server Error") self._done() tb = r"".join(traceback.format_exception(*sys.exc_info())) @@ -136,26 +136,26 @@ env[r'CONTENT_TYPE'] = self.headers.get_default_type() else: env[r'CONTENT_TYPE'] = self.headers.get_content_type() -length = self.headers.get('content-length') +length = self.headers.get(r'content-length') else: if self.headers.typeheader is None: env[r'CONTENT_TYPE'] = self.headers.type else: env[r'CONTENT_TYPE'] = self.headers.typeheader -length = self.hea
D2853: tests: add a cat of `error.log` in subrepo test
durin42 created this revision. Herald added a subscriber: mercurial-devel. Herald added a reviewer: hg-reviewers. REVISION SUMMARY This made some debugging a lot less painful when something was broken, and it costs us almost nothing, so I figure we may as well leave it in. REPOSITORY rHG Mercurial REVISION DETAIL https://phab.mercurial-scm.org/D2853 AFFECTED FILES tests/test-subrepo-deep-nested-change.t CHANGE DETAILS diff --git a/tests/test-subrepo-deep-nested-change.t b/tests/test-subrepo-deep-nested-change.t --- a/tests/test-subrepo-deep-nested-change.t +++ b/tests/test-subrepo-deep-nested-change.t @@ -114,6 +114,7 @@ * "GET /?cmd=batch HTTP/1.1" 200 - * (glob) * "GET /?cmd=getbundle HTTP/1.1" 200 - * (glob) * "GET /../sub1?cmd=capabilities HTTP/1.1" 404 - (glob) + $ cat error.log $ killdaemons.py $ rm hg1.pid error.log access.log 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
D2847: remotenames: work around move of ABCs in collections
durin42 updated this revision to Diff 7021. durin42 edited the summary of this revision. REPOSITORY rHG Mercurial CHANGES SINCE LAST UPDATE https://phab.mercurial-scm.org/D2847?vs=7004&id=7021 REVISION DETAIL https://phab.mercurial-scm.org/D2847 AFFECTED FILES hgext/remotenames.py CHANGE DETAILS diff --git a/hgext/remotenames.py b/hgext/remotenames.py --- a/hgext/remotenames.py +++ b/hgext/remotenames.py @@ -23,6 +23,11 @@ from __future__ import absolute_import import collections +try: +from collections import abc +mutablemapping = abc.MutableMapping +except ImportError: +mutablemapping = collections.MutableMapping from mercurial.i18n import _ @@ -56,7 +61,7 @@ default=True, ) -class lazyremotenamedict(collections.MutableMapping): +class lazyremotenamedict(mutablemapping): """ Read-only dict-like Class to lazily resolve remotename entries 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
D2836: wireproto: define permissions-based routing of HTTPv2 wire protocol
indygreg updated this revision to Diff 7014. REPOSITORY rHG Mercurial CHANGES SINCE LAST UPDATE https://phab.mercurial-scm.org/D2836?vs=7010&id=7014 REVISION DETAIL https://phab.mercurial-scm.org/D2836 AFFECTED FILES mercurial/debugcommands.py mercurial/help/internals/wireprotocol.txt mercurial/wireprotoserver.py tests/test-http-api-httpv2.t CHANGE DETAILS diff --git a/tests/test-http-api-httpv2.t b/tests/test-http-api-httpv2.t --- a/tests/test-http-api-httpv2.t +++ b/tests/test-http-api-httpv2.t @@ -1,3 +1,5 @@ + $ HTTPV2=exp-http-v2-0001 + $ send() { > hg --verbose debugwireproto --peer raw http://$LOCALIP:$HGPORT/ > } @@ -13,7 +15,7 @@ HTTP v2 protocol not enabled by default $ send << EOF - > httprequest GET api/exp-http-v2-0001 + > httprequest GET api/$HTTPV2 > user-agent: test > EOF using raw connection to peer @@ -43,14 +45,14 @@ $ hg -R server serve -p $HGPORT -d --pid-file hg.pid $ cat hg.pid > $DAEMON_PIDS -Requests simply echo their path (for now) +Request to read-only command works out of the box $ send << EOF - > httprequest GET api/exp-http-v2-0001/path1/path2 + > httprequest GET api/$HTTPV2/ro/capabilities > user-agent: test > EOF using raw connection to peer - s> GET /api/exp-http-v2-0001/path1/path2 HTTP/1.1\r\n + s> GET /api/exp-http-v2-0001/ro/capabilities HTTP/1.1\r\n s> Accept-Encoding: identity\r\n s> user-agent: test\r\n s> host: $LOCALIP:$HGPORT\r\n (glob) @@ -60,6 +62,178 @@ s> Server: testing stub value\r\n s> Date: $HTTP_DATE$\r\n s> Content-Type: text/plain\r\n - s> Content-Length: 12\r\n + s> Content-Length: 16\r\n + s> \r\n + s> ro/capabilities\n + +Request to unknown command yields 404 + + $ send << EOF + > httprequest GET api/$HTTPV2/ro/badcommand + > user-agent: test + > EOF + using raw connection to peer + s> GET /api/exp-http-v2-0001/ro/badcommand HTTP/1.1\r\n + s> Accept-Encoding: identity\r\n + s> user-agent: test\r\n + s> host: $LOCALIP:$HGPORT\r\n (glob) + s> \r\n + s> makefile('rb', None) + s> HTTP/1.1 404 Not Found\r\n + s> Server: testing stub value\r\n + s> Date: $HTTP_DATE$\r\n + s> Content-Type: text/plain\r\n + s> Content-Length: 42\r\n + s> \r\n + s> unknown wire protocol command: badcommand\n + +Request to read-write command fails because server is read-only by default + +GET to read-write request not allowed + + $ send << EOF + > httprequest GET api/$HTTPV2/rw/capabilities + > user-agent: test + > EOF + using raw connection to peer + s> GET /api/exp-http-v2-0001/rw/capabilities HTTP/1.1\r\n + s> Accept-Encoding: identity\r\n + s> user-agent: test\r\n + s> host: $LOCALIP:$HGPORT\r\n (glob) + s> \r\n + s> makefile('rb', None) + s> HTTP/1.1 405 push requires POST request\r\n + s> Server: testing stub value\r\n + s> Date: $HTTP_DATE$\r\n + s> Content-Length: 17\r\n + s> \r\n + s> permission denied + +Even for unknown commands + + $ send << EOF + > httprequest GET api/$HTTPV2/rw/badcommand + > user-agent: test + > EOF + using raw connection to peer + s> GET /api/exp-http-v2-0001/rw/badcommand HTTP/1.1\r\n + s> Accept-Encoding: identity\r\n + s> user-agent: test\r\n + s> host: $LOCALIP:$HGPORT\r\n (glob) + s> \r\n + s> makefile('rb', None) + s> HTTP/1.1 405 push requires POST request\r\n + s> Server: testing stub value\r\n + s> Date: $HTTP_DATE$\r\n + s> Content-Length: 17\r\n + s> \r\n + s> permission denied + +SSL required by default + + $ send << EOF + > httprequest POST api/$HTTPV2/rw/capabilities + > user-agent: test + > EOF + using raw connection to peer + s> POST /api/exp-http-v2-0001/rw/capabilities HTTP/1.1\r\n + s> Accept-Encoding: identity\r\n + s> user-agent: test\r\n + s> host: $LOCALIP:$HGPORT\r\n (glob) + s> \r\n + s> makefile('rb', None) + s> HTTP/1.1 403 ssl required\r\n + s> Server: testing stub value\r\n + s> Date: $HTTP_DATE$\r\n + s> Content-Length: 17\r\n s> \r\n - s> path1/path2\n + s> permission denied + +Restart server to allow non-ssl read-write operations + + $ killdaemons.py + $ cat > server/.hg/hgrc << EOF + > [experimental] + > web.apiserver = true + > web.api.http-v2 = true + > [web] + > push_ssl = false + > EOF + + $ hg -R server serve -p $HGPORT -d --pid-file hg.pid + $ cat hg.pid > $DAEMON_PIDS + +Server insists on POST for read-write commands + + $ send << EOF + > httprequest GET api/$HTTPV2/rw/capabilities + > user-agent: test + > EOF + using raw connection to peer + s> GET /api/exp-http-v2-0001/rw/capabilities HTTP/1.1\r\n + s> Accept-Encoding: identity\r\n + s> user-agent: test\r\n + s> host: $LOCALIP:$HGPORT\r\n (glob) + s> \r\n + s> makefile('rb', None) + s> H
D2852: wireproto: implement basic frame reading and processing
indygreg created this revision. Herald added a subscriber: mercurial-devel. Herald added a reviewer: hg-reviewers. REVISION SUMMARY We just implemented support for writing frames. Now let's implement support for reading them. The bulk of the new code is for a class that maintains the state of a server. Essentially, you construct an instance, feed frames to it, and it tells you what you should do next. The design is inspired by the "sans I/O" movement and the reactor pattern. We don't want to perform I/O or any major blocking event during frame ingestion because this arbitrarily limits ways that server pieces can be implemented. For example, it makes it much harder to swap in an alternate implementation based on asyncio or do crazy things like have requests dispatch to other processes. We do still implement readframe() which does I/O. But it is decoupled from the server reactor. Because testing server-side ingest is useful and difficult on running servers, we create a new "debugreflect" endpoint that will echo back to the client what was received and how it was interpreted. This could be useful for a server admin, someone implementing a client. But immediately, it is useful for testing: we're able to demonstrate that frames are parsed correctly and turned into requests to run commands without having to implement command dispatch on the server! REPOSITORY rHG Mercurial REVISION DETAIL https://phab.mercurial-scm.org/D2852 AFFECTED FILES mercurial/configitems.py mercurial/util.py mercurial/wireprotoframing.py mercurial/wireprotoserver.py tests/test-http-api-httpv2.t CHANGE DETAILS diff --git a/tests/test-http-api-httpv2.t b/tests/test-http-api-httpv2.t --- a/tests/test-http-api-httpv2.t +++ b/tests/test-http-api-httpv2.t @@ -261,7 +261,7 @@ > allow-push = * > EOF - $ hg -R server serve -p $HGPORT -d --pid-file hg.pid + $ hg -R server serve -p $HGPORT -d --pid-file hg.pid -E error.log $ cat hg.pid > $DAEMON_PIDS Authorized request for valid read-write command works @@ -314,3 +314,441 @@ s> Content-Length: 42\r\n s> \r\n s> unknown wire protocol command: badcommand\n + +debugreflect isn't enabled by default + + $ send << EOF + > httprequest POST api/$HTTPV2/ro/debugreflect + > user-agent: test + > EOF + using raw connection to peer + s> POST /api/exp-http-v2-0001/ro/debugreflect HTTP/1.1\r\n + s> Accept-Encoding: identity\r\n + s> user-agent: test\r\n + s> host: $LOCALIP:$HGPORT\r\n (glob) + s> \r\n + s> makefile('rb', None) + s> HTTP/1.1 404 Not Found\r\n + s> Server: testing stub value\r\n + s> Date: $HTTP_DATE$\r\n + s> Content-Type: text/plain\r\n + s> Content-Length: 34\r\n + s> \r\n + s> debugreflect service not available + +Restart server to get debugreflect endpoint + + $ killdaemons.py + $ cat > server/.hg/hgrc << EOF + > [experimental] + > web.apiserver = true + > web.api.debugreflect = true + > web.api.http-v2 = true + > [web] + > push_ssl = false + > allow-push = * + > EOF + + $ hg -R server serve -p $HGPORT -d --pid-file hg.pid -E error.log + $ cat hg.pid > $DAEMON_PIDS + +Single command frame is decoded + + $ send << EOF + > httprequest POST api/$HTTPV2/ro/debugreflect + > accept: $MEDIATYPE + > content-type: $MEDIATYPE + > user-agent: test + > frame command-name eos command1 + > EOF + using raw connection to peer + s> POST /api/exp-http-v2-0001/ro/debugreflect HTTP/1.1\r\n + s> Accept-Encoding: identity\r\n + s> accept: application/mercurial-exp-framing-0001\r\n + s> content-type: application/mercurial-exp-framing-0001\r\n + s> user-agent: test\r\n + s> content-length: 12\r\n + s> host: $LOCALIP:$HGPORT\r\n (glob) + s> \r\n + s> \x08\x00\x00\x11command1 + 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: text/plain\r\n + s> Content-Length: 117\r\n + s> \r\n + s> received: 1 1 command1\n + s> {"action": "runcommand", "args": {}, "command": "command1", "data": null}\n + s> received: + +Single argument frame is received + + $ send << EOF + > httprequest POST api/$HTTPV2/ro/debugreflect + > accept: $MEDIATYPE + > content-type: $MEDIATYPE + > user-agent: test + > frame command-name have-args command1 + > frame command-argument eoa \x03\x00\x05\x00foovalue + > EOF + using raw connection to peer + s> POST /api/exp-http-v2-0001/ro/debugreflect HTTP/1.1\r\n + s> Accept-Encoding: identity\r\n + s> accept: application/mercurial-exp-framing-0001\r\n + s> content-type: application/mercurial-exp-framing-0001\r\n + s> user-agent: test\r\n + s> content-length: 28\r\n + s> host: $LOCALIP:$HGPORT\r\n (glob) + s> \r\n + s> \x08\x00\x00\x12command1\x0c\x00\x00"\x03\
D2837: wireproto: require POST for all HTTPv2 requests
indygreg updated this revision to Diff 7015. REPOSITORY rHG Mercurial CHANGES SINCE LAST UPDATE https://phab.mercurial-scm.org/D2837?vs=7011&id=7015 REVISION DETAIL https://phab.mercurial-scm.org/D2837 AFFECTED FILES mercurial/help/internals/wireprotocol.txt mercurial/wireprotoserver.py tests/test-http-api-httpv2.t CHANGE DETAILS diff --git a/tests/test-http-api-httpv2.t b/tests/test-http-api-httpv2.t --- a/tests/test-http-api-httpv2.t +++ b/tests/test-http-api-httpv2.t @@ -48,11 +48,11 @@ Request to read-only command works out of the box $ send << EOF - > httprequest GET api/$HTTPV2/ro/capabilities + > httprequest POST api/$HTTPV2/ro/capabilities > user-agent: test > EOF using raw connection to peer - s> GET /api/exp-http-v2-0001/ro/capabilities HTTP/1.1\r\n + s> POST /api/exp-http-v2-0001/ro/capabilities HTTP/1.1\r\n s> Accept-Encoding: identity\r\n s> user-agent: test\r\n s> host: $LOCALIP:$HGPORT\r\n (glob) @@ -69,11 +69,11 @@ Request to unknown command yields 404 $ send << EOF - > httprequest GET api/$HTTPV2/ro/badcommand + > httprequest POST api/$HTTPV2/ro/badcommand > user-agent: test > EOF using raw connection to peer - s> GET /api/exp-http-v2-0001/ro/badcommand HTTP/1.1\r\n + s> POST /api/exp-http-v2-0001/ro/badcommand HTTP/1.1\r\n s> Accept-Encoding: identity\r\n s> user-agent: test\r\n s> host: $LOCALIP:$HGPORT\r\n (glob) @@ -87,9 +87,30 @@ s> \r\n s> unknown wire protocol command: badcommand\n +GET to read-only command yields a 405 + + $ send << EOF + > httprequest GET api/$HTTPV2/ro/capabilities + > user-agent: test + > EOF + using raw connection to peer + s> GET /api/exp-http-v2-0001/ro/capabilities HTTP/1.1\r\n + s> Accept-Encoding: identity\r\n + s> user-agent: test\r\n + s> host: $LOCALIP:$HGPORT\r\n (glob) + s> \r\n + s> makefile('rb', None) + s> HTTP/1.1 405 Method Not Allowed\r\n + s> Server: testing stub value\r\n + s> Date: $HTTP_DATE$\r\n + s> Allow: POST\r\n + s> Content-Length: 30\r\n + s> \r\n + s> commands require POST requests + Request to read-write command fails because server is read-only by default -GET to read-write request not allowed +GET to read-write request yields 405 $ send << EOF > httprequest GET api/$HTTPV2/rw/capabilities @@ -102,12 +123,13 @@ s> host: $LOCALIP:$HGPORT\r\n (glob) s> \r\n s> makefile('rb', None) - s> HTTP/1.1 405 push requires POST request\r\n + s> HTTP/1.1 405 Method Not Allowed\r\n s> Server: testing stub value\r\n s> Date: $HTTP_DATE$\r\n - s> Content-Length: 17\r\n + s> Allow: POST\r\n + s> Content-Length: 30\r\n s> \r\n - s> permission denied + s> commands require POST requests Even for unknown commands @@ -122,12 +144,13 @@ s> host: $LOCALIP:$HGPORT\r\n (glob) s> \r\n s> makefile('rb', None) - s> HTTP/1.1 405 push requires POST request\r\n + s> HTTP/1.1 405 Method Not Allowed\r\n s> Server: testing stub value\r\n s> Date: $HTTP_DATE$\r\n - s> Content-Length: 17\r\n + s> Allow: POST\r\n + s> Content-Length: 30\r\n s> \r\n - s> permission denied + s> commands require POST requests SSL required by default @@ -158,38 +181,6 @@ > web.api.http-v2 = true > [web] > push_ssl = false - > EOF - - $ hg -R server serve -p $HGPORT -d --pid-file hg.pid - $ cat hg.pid > $DAEMON_PIDS - -Server insists on POST for read-write commands - - $ send << EOF - > httprequest GET api/$HTTPV2/rw/capabilities - > user-agent: test - > EOF - using raw connection to peer - s> GET /api/exp-http-v2-0001/rw/capabilities HTTP/1.1\r\n - s> Accept-Encoding: identity\r\n - s> user-agent: test\r\n - s> host: $LOCALIP:$HGPORT\r\n (glob) - s> \r\n - s> makefile('rb', None) - s> HTTP/1.1 405 push requires POST request\r\n - s> Server: testing stub value\r\n - s> Date: $HTTP_DATE$\r\n - s> Content-Length: 17\r\n - s> \r\n - s> permission denied - - $ killdaemons.py - $ cat > server/.hg/hgrc << EOF - > [experimental] - > web.apiserver = true - > web.api.http-v2 = true - > [web] - > push_ssl = false > allow-push = * > EOF diff --git a/mercurial/wireprotoserver.py b/mercurial/wireprotoserver.py --- a/mercurial/wireprotoserver.py +++ b/mercurial/wireprotoserver.py @@ -299,6 +299,12 @@ res.setbodybytes(_('unknown permission: %s') % permission) return +if req.method != 'POST': +res.status = b'405 Method Not Allowed' +res.headers[b'Allow'] = b'POST' +res.setbodybytes(_('commands require POST requests')) +return + # At some point we'll want to use our own API instead of recycling the # behavior of version 1 of the wire protocol... # TODO return reasonable responses
D2851: wireproto: define and implement protocol for issuing requests
indygreg created this revision. Herald added a subscriber: mercurial-devel. Herald added a reviewer: hg-reviewers. REVISION SUMMARY The existing HTTP and SSH wire protocols suffer from a host of flaws and shortcomings. I've been wanting to rewrite the protocol for a while now. Supporting partial clone - which will require new wire protocol commands and capabilities - and other advanced server functionality will be much easier if we start from a clean slate and don't have to be constrained by limitations of the existing wire protocol. This commit starts to introduce a new data exchange format for use over the wire protocol. The new protocol is built on top of "frames," which are atomic units of metadata + data. Frames will make it easier to implement proxies and other mechanisms that want to inspect data without having to maintain state. The existing frame metadata is very minimal and it will evolve heavily. (We will eventually support things like concurrent requests, out-of-order responses, compression, side-channels for status updates, etc. Some of these will require additions to the frame header.) Another benefit of frames is that all reads are of a fixed size. A reader works by consuming a frame header, extracting the payload length, then reading that many bytes. No lookahead, buffering, or memory reallocations are needed. The new protocol attempts to be transport agnostic. I want all that's required to use the new protocol to be a pair of unidirectional, half-duplex pipes. (Yes, we will eventually make use of full-duplex pipes, but that's for another commit.) Notably, when the SSH transport switches to this new protocol, stderr will be unused. This is by design: the lack of stderr on HTTP harms protocol behavior there. By shoehorning everything into a pair of pipes, we can have more consistent behavior across transports. We currently only define the client side parts of the new protocol, specifically the bits for requesting that a command run. This keeps the new code and feature small and somewhat easy to review. We add support to `hg debugwireproto` for writing frames into HTTP request bodies. Our tests that issue commands to the new HTTP endpoint have been updated to transmit frames. The server bits haven't been touched to consume the frames yet. This will occur in the next commit... Astute readers may notice that the command name is transmitted in both the HTTP request URL and the command request frame. This is partially a kludge from me initially implementing the frame-based protocol for SSH first. But it is also a feature: I intend to eventually support issuing multiple commands per HTTP request. This will allow us to replace the abomination that is the "batch" wire protocol command with a protocol-level mechanism for performing multi-dispatch. Because I want the frame-based protocol to be as similar as possible across transports, I'd rather we (redundantly) include the command name in the frame than differ behavior between transports that have out-of-band routing information (like HTTP) readily available. REPOSITORY rHG Mercurial REVISION DETAIL https://phab.mercurial-scm.org/D2851 AFFECTED FILES mercurial/debugcommands.py mercurial/help/internals/wireprotocol.txt mercurial/wireprotoframing.py mercurial/wireprotoserver.py tests/test-http-api-httpv2.t CHANGE DETAILS diff --git a/tests/test-http-api-httpv2.t b/tests/test-http-api-httpv2.t --- a/tests/test-http-api-httpv2.t +++ b/tests/test-http-api-httpv2.t @@ -1,5 +1,5 @@ $ HTTPV2=exp-http-v2-0001 - $ MEDIATYPE=application/mercurial-tbd + $ MEDIATYPE=application/mercurial-exp-framing-0001 $ send() { > hg --verbose debugwireproto --peer raw http://$LOCALIP:$HGPORT/ @@ -105,9 +105,9 @@ s> Server: testing stub value\r\n s> Date: $HTTP_DATE$\r\n s> Content-Type: text/plain\r\n - s> Content-Length: 72\r\n + s> Content-Length: 85\r\n s> \r\n - s> client MUST specify Accept header with value: application/mercurial-tbd\n + s> client MUST specify Accept header with value: application/mercurial-exp-framing-0001\n Bad Accept header results in 406 @@ -128,9 +128,9 @@ s> Server: testing stub value\r\n s> Date: $HTTP_DATE$\r\n s> Content-Type: text/plain\r\n - s> Content-Length: 72\r\n + s> Content-Length: 85\r\n s> \r\n - s> client MUST specify Accept header with value: application/mercurial-tbd\n + s> client MUST specify Accept header with value: application/mercurial-exp-framing-0001\n Bad Content-Type header results in 415 @@ -143,7 +143,7 @@ using raw connection to peer s> POST /api/exp-http-v2-0001/ro/capabilities HTTP/1.1\r\n s> Accept-Encoding: identity\r\n - s> accept: application/mercurial-tbd\r\n + s> accept: application/mercurial-exp-framing-0001\r\n s> conte
D2850: wireproto: define content negotiation for HTTPv2
indygreg updated this revision to Diff 7016. REPOSITORY rHG Mercurial CHANGES SINCE LAST UPDATE https://phab.mercurial-scm.org/D2850?vs=7013&id=7016 REVISION DETAIL https://phab.mercurial-scm.org/D2850 AFFECTED FILES mercurial/help/internals/wireprotocol.txt mercurial/wireprotoserver.py tests/test-http-api-httpv2.t CHANGE DETAILS diff --git a/tests/test-http-api-httpv2.t b/tests/test-http-api-httpv2.t --- a/tests/test-http-api-httpv2.t +++ b/tests/test-http-api-httpv2.t @@ -1,4 +1,5 @@ $ HTTPV2=exp-http-v2-0001 + $ MEDIATYPE=application/mercurial-tbd $ send() { > hg --verbose debugwireproto --peer raw http://$LOCALIP:$HGPORT/ @@ -45,27 +46,6 @@ $ hg -R server serve -p $HGPORT -d --pid-file hg.pid $ cat hg.pid > $DAEMON_PIDS -Request to read-only command works out of the box - - $ send << EOF - > httprequest POST api/$HTTPV2/ro/capabilities - > user-agent: test - > EOF - using raw connection to peer - s> POST /api/exp-http-v2-0001/ro/capabilities HTTP/1.1\r\n - s> Accept-Encoding: identity\r\n - s> user-agent: test\r\n - s> host: $LOCALIP:$HGPORT\r\n (glob) - 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: text/plain\r\n - s> Content-Length: 16\r\n - s> \r\n - s> ro/capabilities\n - Request to unknown command yields 404 $ send << EOF @@ -108,6 +88,100 @@ s> \r\n s> commands require POST requests +Missing Accept header results in 406 + + $ send << EOF + > httprequest POST api/$HTTPV2/ro/capabilities + > user-agent: test + > EOF + using raw connection to peer + s> POST /api/exp-http-v2-0001/ro/capabilities HTTP/1.1\r\n + s> Accept-Encoding: identity\r\n + s> user-agent: test\r\n + s> host: $LOCALIP:$HGPORT\r\n (glob) + s> \r\n + s> makefile('rb', None) + s> HTTP/1.1 406 Not Acceptable\r\n + s> Server: testing stub value\r\n + s> Date: $HTTP_DATE$\r\n + s> Content-Type: text/plain\r\n + s> Content-Length: 72\r\n + s> \r\n + s> client MUST specify Accept header with value: application/mercurial-tbd\n + +Bad Accept header results in 406 + + $ send << EOF + > httprequest POST api/$HTTPV2/ro/capabilities + > accept: invalid + > user-agent: test + > EOF + using raw connection to peer + s> POST /api/exp-http-v2-0001/ro/capabilities HTTP/1.1\r\n + s> Accept-Encoding: identity\r\n + s> accept: invalid\r\n + s> user-agent: test\r\n + s> host: $LOCALIP:$HGPORT\r\n (glob) + s> \r\n + s> makefile('rb', None) + s> HTTP/1.1 406 Not Acceptable\r\n + s> Server: testing stub value\r\n + s> Date: $HTTP_DATE$\r\n + s> Content-Type: text/plain\r\n + s> Content-Length: 72\r\n + s> \r\n + s> client MUST specify Accept header with value: application/mercurial-tbd\n + +Bad Content-Type header results in 415 + + $ send << EOF + > httprequest POST api/$HTTPV2/ro/capabilities + > accept: $MEDIATYPE + > user-agent: test + > content-type: badmedia + > EOF + using raw connection to peer + s> POST /api/exp-http-v2-0001/ro/capabilities HTTP/1.1\r\n + s> Accept-Encoding: identity\r\n + s> accept: application/mercurial-tbd\r\n + s> content-type: badmedia\r\n + s> user-agent: test\r\n + s> host: $LOCALIP:$HGPORT\r\n (glob) + s> \r\n + s> makefile('rb', None) + s> HTTP/1.1 415 Unsupported Media Type\r\n + s> Server: testing stub value\r\n + s> Date: $HTTP_DATE$\r\n + s> Content-Type: text/plain\r\n + s> Content-Length: 75\r\n + s> \r\n + s> client MUST send Content-Type header with value: application/mercurial-tbd\n + +Request to read-only command works out of the box + + $ send << EOF + > httprequest POST api/$HTTPV2/ro/capabilities + > accept: $MEDIATYPE + > content-type: $MEDIATYPE + > user-agent: test + > EOF + using raw connection to peer + s> POST /api/exp-http-v2-0001/ro/capabilities HTTP/1.1\r\n + s> Accept-Encoding: identity\r\n + s> accept: application/mercurial-tbd\r\n + s> content-type: application/mercurial-tbd\r\n + s> user-agent: test\r\n + s> host: $LOCALIP:$HGPORT\r\n (glob) + 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: text/plain\r\n + s> Content-Length: 16\r\n + s> \r\n + s> ro/capabilities\n + Request to read-write command fails because server is read-only by default GET to read-write request yields 405 @@ -192,10 +266,14 @@ $ send << EOF > httprequest POST api/$HTTPV2/rw/capabilities > user-agent: test + > accept: $MEDIATYPE + > content-type: $MEDIATYPE > EOF using raw connection to peer s> POST /api/exp-http-v2-0001/rw/capabilities HTTP/1.1\r
D2721: util: observable proxy objects for sockets
indygreg updated this revision to Diff 7007. REPOSITORY rHG Mercurial CHANGES SINCE LAST UPDATE https://phab.mercurial-scm.org/D2721?vs=6972&id=7007 REVISION DETAIL https://phab.mercurial-scm.org/D2721 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 @@ -687,6 +687,125 @@ return res +PROXIED_SOCKET_METHODS = { +r'makefile', +r'recv', +r'recvfrom', +r'recvfrom_into', +r'recv_into', +r'send', +r'sendall', +r'sendto', +r'setblocking', +r'settimeout', +r'gettimeout', +r'setsockopt', +} + +class socketproxy(object): +"""A proxy around a socket that tells a watcher when events occur. + +This is like ``fileobjectproxy`` except for sockets. + +This type is intended to only be used for testing purposes. Think hard +before using it in important code. +""" +__slots__ = ( +r'_orig', +r'_observer', +) + +def __init__(self, sock, observer): +object.__setattr__(self, r'_orig', sock) +object.__setattr__(self, r'_observer', observer) + +def __getattribute__(self, name): +if name in PROXIED_SOCKET_METHODS: +return object.__getattribute__(self, name) + +return getattr(object.__getattribute__(self, r'_orig'), name) + +def __delattr__(self, name): +return delattr(object.__getattribute__(self, r'_orig'), name) + +def __setattr__(self, name, value): +return setattr(object.__getattribute__(self, r'_orig'), name, value) + +def __nonzero__(self): +return bool(object.__getattribute__(self, r'_orig')) + +__bool__ = __nonzero__ + +def _observedcall(self, name, *args, **kwargs): +# Call the original object. +orig = object.__getattribute__(self, r'_orig') +res = getattr(orig, name)(*args, **kwargs) + +# Call a method on the observer of the same name with arguments +# so it can react, log, etc. +observer = object.__getattribute__(self, r'_observer') +fn = getattr(observer, name, None) +if fn: +fn(res, *args, **kwargs) + +return res + +def makefile(self, *args, **kwargs): +res = object.__getattribute__(self, r'_observedcall')( +r'makefile', *args, **kwargs) + +# The file object may be used for I/O. So we turn it into a +# proxy using our observer. +observer = object.__getattribute__(self, r'_observer') +return makeloggingfileobject(observer.fh, res, observer.name, + reads=observer.reads, + writes=observer.writes, + logdata=observer.logdata) + +def recv(self, *args, **kwargs): +return object.__getattribute__(self, r'_observedcall')( +r'recv', *args, **kwargs) + +def recvfrom(self, *args, **kwargs): +return object.__getattribute__(self, r'_observedcall')( +r'recvfrom', *args, **kwargs) + +def recvfrom_into(self, *args, **kwargs): +return object.__getattribute__(self, r'_observedcall')( +r'recvfrom_into', *args, **kwargs) + +def recv_into(self, *args, **kwargs): +return object.__getattribute__(self, r'_observedcall')( +r'recv_info', *args, **kwargs) + +def send(self, *args, **kwargs): +return object.__getattribute__(self, r'_observedcall')( +r'send', *args, **kwargs) + +def sendall(self, *args, **kwargs): +return object.__getattribute__(self, r'_observedcall')( +r'sendall', *args, **kwargs) + +def sendto(self, *args, **kwargs): +return object.__getattribute__(self, r'_observedcall')( +r'sendto', *args, **kwargs) + +def setblocking(self, *args, **kwargs): +return object.__getattribute__(self, r'_observedcall')( +r'setblocking', *args, **kwargs) + +def settimeout(self, *args, **kwargs): +return object.__getattribute__(self, r'_observedcall')( +r'settimeout', *args, **kwargs) + +def gettimeout(self, *args, **kwargs): +return object.__getattribute__(self, r'_observedcall')( +r'gettimeout', *args, **kwargs) + +def setsockopt(self, *args, **kwargs): +return object.__getattribute__(self, r'_observedcall')( +r'setsockopt', *args, **kwargs) + DATA_ESCAPE_MAP = {pycompat.bytechr(i): br'\x%02x' % i for i in range(256)} DATA_ESCAPE_MAP.update({ b'\\': b'', @@ -701,15 +820,7 @@ return DATA_ESCAPE_RE.sub(lambda m: DATA_ESCAPE_MAP[m.group(0)], s) -class fileobjectobserver(object): -"""Logs file object activity.""" -def __init__(self, fh, name, reads=True, writes=True, logdata=False): -self.fh = fh -self.name = name -self.logdata = logdata -self.reads = reads -self.writes = writes
D2837: wireproto: require POST for all HTTPv2 requests
indygreg updated this revision to Diff 7011. REPOSITORY rHG Mercurial CHANGES SINCE LAST UPDATE https://phab.mercurial-scm.org/D2837?vs=7000&id=7011 REVISION DETAIL https://phab.mercurial-scm.org/D2837 AFFECTED FILES mercurial/help/internals/wireprotocol.txt mercurial/wireprotoserver.py tests/test-http-api-httpv2.t CHANGE DETAILS diff --git a/tests/test-http-api-httpv2.t b/tests/test-http-api-httpv2.t --- a/tests/test-http-api-httpv2.t +++ b/tests/test-http-api-httpv2.t @@ -48,11 +48,11 @@ Request to read-only command works out of the box $ send << EOF - > httprequest GET api/$HTTPV2/ro/known + > httprequest POST api/$HTTPV2/ro/known > user-agent: test > EOF using raw connection to peer - s> GET /api/exp-http-v2-0001/ro/known HTTP/1.1\r\n + s> POST /api/exp-http-v2-0001/ro/known HTTP/1.1\r\n s> Accept-Encoding: identity\r\n s> user-agent: test\r\n s> host: $LOCALIP:$HGPORT\r\n (glob) @@ -69,11 +69,11 @@ Request to unknown command yields 404 $ send << EOF - > httprequest GET api/$HTTPV2/ro/badcommand + > httprequest POST api/$HTTPV2/ro/badcommand > user-agent: test > EOF using raw connection to peer - s> GET /api/exp-http-v2-0001/ro/badcommand HTTP/1.1\r\n + s> POST /api/exp-http-v2-0001/ro/badcommand HTTP/1.1\r\n s> Accept-Encoding: identity\r\n s> user-agent: test\r\n s> host: $LOCALIP:$HGPORT\r\n (glob) @@ -87,9 +87,30 @@ s> \r\n s> unknown wire protocol command: badcommand\n +GET to read-only command yields a 405 + + $ send << EOF + > httprequest GET api/$HTTPV2/ro/known + > user-agent: test + > EOF + using raw connection to peer + s> GET /api/exp-http-v2-0001/ro/known HTTP/1.1\r\n + s> Accept-Encoding: identity\r\n + s> user-agent: test\r\n + s> host: $LOCALIP:$HGPORT\r\n (glob) + s> \r\n + s> makefile('rb', None) + s> HTTP/1.1 405 Method Not Allowed\r\n + s> Server: testing stub value\r\n + s> Date: $HTTP_DATE$\r\n + s> Allow: POST\r\n + s> Content-Length: 30\r\n + s> \r\n + s> commands require POST requests + Request to read-write command fails because server is read-only by default -GET to read-write request not allowed +GET to read-write request yields 405 $ send << EOF > httprequest GET api/$HTTPV2/rw/known @@ -102,12 +123,13 @@ s> host: $LOCALIP:$HGPORT\r\n (glob) s> \r\n s> makefile('rb', None) - s> HTTP/1.1 405 push requires POST request\r\n + s> HTTP/1.1 405 Method Not Allowed\r\n s> Server: testing stub value\r\n s> Date: $HTTP_DATE$\r\n - s> Content-Length: 17\r\n + s> Allow: POST\r\n + s> Content-Length: 30\r\n s> \r\n - s> permission denied + s> commands require POST requests Even for unknown commands @@ -122,12 +144,13 @@ s> host: $LOCALIP:$HGPORT\r\n (glob) s> \r\n s> makefile('rb', None) - s> HTTP/1.1 405 push requires POST request\r\n + s> HTTP/1.1 405 Method Not Allowed\r\n s> Server: testing stub value\r\n s> Date: $HTTP_DATE$\r\n - s> Content-Length: 17\r\n + s> Allow: POST\r\n + s> Content-Length: 30\r\n s> \r\n - s> permission denied + s> commands require POST requests SSL required by default @@ -158,38 +181,6 @@ > web.api.http-v2 = true > [web] > push_ssl = false - > EOF - - $ hg -R server serve -p $HGPORT -d --pid-file hg.pid - $ cat hg.pid > $DAEMON_PIDS - -Server insists on POST for read-write commands - - $ send << EOF - > httprequest GET api/$HTTPV2/rw/known - > user-agent: test - > EOF - using raw connection to peer - s> GET /api/exp-http-v2-0001/rw/known HTTP/1.1\r\n - s> Accept-Encoding: identity\r\n - s> user-agent: test\r\n - s> host: $LOCALIP:$HGPORT\r\n (glob) - s> \r\n - s> makefile('rb', None) - s> HTTP/1.1 405 push requires POST request\r\n - s> Server: testing stub value\r\n - s> Date: $HTTP_DATE$\r\n - s> Content-Length: 17\r\n - s> \r\n - s> permission denied - - $ killdaemons.py - $ cat > server/.hg/hgrc << EOF - > [experimental] - > web.apiserver = true - > web.api.http-v2 = true - > [web] - > push_ssl = false > allow-push = * > EOF diff --git a/mercurial/wireprotoserver.py b/mercurial/wireprotoserver.py --- a/mercurial/wireprotoserver.py +++ b/mercurial/wireprotoserver.py @@ -299,6 +299,12 @@ res.setbodybytes(_('unknown permission: %s') % permission) return +if req.method != 'POST': +res.status = b'405 Method Not Allowed' +res.headers[b'Allow'] = b'POST' +res.setbodybytes(_('commands require POST requests')) +return + # At some point we'll want to use our own API instead of recycling the # behavior of version 1 of the wire protocol... # TODO return reasonable responses - not responses that overload the diff --git a/mercurial/help/i
D2836: wireproto: define permissions-based routing of HTTPv2 wire protocol
indygreg updated this revision to Diff 7010. REPOSITORY rHG Mercurial CHANGES SINCE LAST UPDATE https://phab.mercurial-scm.org/D2836?vs=6999&id=7010 REVISION DETAIL https://phab.mercurial-scm.org/D2836 AFFECTED FILES mercurial/debugcommands.py mercurial/help/internals/wireprotocol.txt mercurial/wireprotoserver.py tests/test-http-api-httpv2.t CHANGE DETAILS diff --git a/tests/test-http-api-httpv2.t b/tests/test-http-api-httpv2.t --- a/tests/test-http-api-httpv2.t +++ b/tests/test-http-api-httpv2.t @@ -1,3 +1,5 @@ + $ HTTPV2=exp-http-v2-0001 + $ send() { > hg --verbose debugwireproto --peer raw http://$LOCALIP:$HGPORT/ > } @@ -13,7 +15,7 @@ HTTP v2 protocol not enabled by default $ send << EOF - > httprequest GET api/exp-http-v2-0001 + > httprequest GET api/$HTTPV2 > user-agent: test > EOF using raw connection to peer @@ -43,14 +45,14 @@ $ hg -R server serve -p $HGPORT -d --pid-file hg.pid $ cat hg.pid > $DAEMON_PIDS -Requests simply echo their path (for now) +Request to read-only command works out of the box $ send << EOF - > httprequest GET api/exp-http-v2-0001/path1/path2 + > httprequest GET api/$HTTPV2/ro/known > user-agent: test > EOF using raw connection to peer - s> GET /api/exp-http-v2-0001/path1/path2 HTTP/1.1\r\n + s> GET /api/exp-http-v2-0001/ro/known HTTP/1.1\r\n s> Accept-Encoding: identity\r\n s> user-agent: test\r\n s> host: $LOCALIP:$HGPORT\r\n (glob) @@ -60,6 +62,178 @@ s> Server: testing stub value\r\n s> Date: $HTTP_DATE$\r\n s> Content-Type: text/plain\r\n - s> Content-Length: 12\r\n + s> Content-Length: 9\r\n + s> \r\n + s> ro/known\n + +Request to unknown command yields 404 + + $ send << EOF + > httprequest GET api/$HTTPV2/ro/badcommand + > user-agent: test + > EOF + using raw connection to peer + s> GET /api/exp-http-v2-0001/ro/badcommand HTTP/1.1\r\n + s> Accept-Encoding: identity\r\n + s> user-agent: test\r\n + s> host: $LOCALIP:$HGPORT\r\n (glob) + s> \r\n + s> makefile('rb', None) + s> HTTP/1.1 404 Not Found\r\n + s> Server: testing stub value\r\n + s> Date: $HTTP_DATE$\r\n + s> Content-Type: text/plain\r\n + s> Content-Length: 42\r\n + s> \r\n + s> unknown wire protocol command: badcommand\n + +Request to read-write command fails because server is read-only by default + +GET to read-write request not allowed + + $ send << EOF + > httprequest GET api/$HTTPV2/rw/known + > user-agent: test + > EOF + using raw connection to peer + s> GET /api/exp-http-v2-0001/rw/known HTTP/1.1\r\n + s> Accept-Encoding: identity\r\n + s> user-agent: test\r\n + s> host: $LOCALIP:$HGPORT\r\n (glob) + s> \r\n + s> makefile('rb', None) + s> HTTP/1.1 405 push requires POST request\r\n + s> Server: testing stub value\r\n + s> Date: $HTTP_DATE$\r\n + s> Content-Length: 17\r\n + s> \r\n + s> permission denied + +Even for unknown commands + + $ send << EOF + > httprequest GET api/$HTTPV2/rw/badcommand + > user-agent: test + > EOF + using raw connection to peer + s> GET /api/exp-http-v2-0001/rw/badcommand HTTP/1.1\r\n + s> Accept-Encoding: identity\r\n + s> user-agent: test\r\n + s> host: $LOCALIP:$HGPORT\r\n (glob) + s> \r\n + s> makefile('rb', None) + s> HTTP/1.1 405 push requires POST request\r\n + s> Server: testing stub value\r\n + s> Date: $HTTP_DATE$\r\n + s> Content-Length: 17\r\n + s> \r\n + s> permission denied + +SSL required by default + + $ send << EOF + > httprequest POST api/$HTTPV2/rw/known + > user-agent: test + > EOF + using raw connection to peer + s> POST /api/exp-http-v2-0001/rw/known HTTP/1.1\r\n + s> Accept-Encoding: identity\r\n + s> user-agent: test\r\n + s> host: $LOCALIP:$HGPORT\r\n (glob) + s> \r\n + s> makefile('rb', None) + s> HTTP/1.1 403 ssl required\r\n + s> Server: testing stub value\r\n + s> Date: $HTTP_DATE$\r\n + s> Content-Length: 17\r\n s> \r\n - s> path1/path2\n + s> permission denied + +Restart server to allow non-ssl read-write operations + + $ killdaemons.py + $ cat > server/.hg/hgrc << EOF + > [experimental] + > web.apiserver = true + > web.api.http-v2 = true + > [web] + > push_ssl = false + > EOF + + $ hg -R server serve -p $HGPORT -d --pid-file hg.pid + $ cat hg.pid > $DAEMON_PIDS + +Server insists on POST for read-write commands + + $ send << EOF + > httprequest GET api/$HTTPV2/rw/known + > user-agent: test + > EOF + using raw connection to peer + s> GET /api/exp-http-v2-0001/rw/known HTTP/1.1\r\n + s> Accept-Encoding: identity\r\n + s> user-agent: test\r\n + s> host: $LOCALIP:$HGPORT\r\n (glob) + s> \r\n + s> makefile('rb', None) + s> HTTP/1.1 405 push requires POST request\r\n + s> Server: tes
D2849: hgweb: also set Content-Type header
indygreg created this revision. Herald added a subscriber: mercurial-devel. Herald added a reviewer: hg-reviewers. REVISION SUMMARY Our HTTP/WSGI server may convert the Content-Type HTTP request header to the CONTENT_TYPE WSGI environment key and not set HTTP_CONTENT_TYPE. Other WSGI server implementations do this, so I think the behavior is acceptable. So assuming this HTTP request header could get "lost" by the WSGI server, let's restore it on the request object like we do for Content-Length. FWIW, the WSGI server may also *invent* a Content-Type value. The default behavior of Python's RFC 822 message class returns a default media type if Content-Type isn't defined. This is kind of annoying. But RFC 7231 section 3.1.1.5 does say the recipient may assume a media type of application/octet-stream. Python's defaults are for text/plain (given we're using an RFC 822 parser). But whatever. REPOSITORY rHG Mercurial REVISION DETAIL https://phab.mercurial-scm.org/D2849 AFFECTED FILES mercurial/hgweb/request.py CHANGE DETAILS diff --git a/mercurial/hgweb/request.py b/mercurial/hgweb/request.py --- a/mercurial/hgweb/request.py +++ b/mercurial/hgweb/request.py @@ -325,6 +325,9 @@ if 'CONTENT_LENGTH' in env and 'HTTP_CONTENT_LENGTH' not in env: headers['Content-Length'] = env['CONTENT_LENGTH'] +if 'CONTENT_TYPE' in env and 'HTTP_CONTENT_TYPE' not in env: +headers['Content-Type'] = env['CONTENT_TYPE'] + bodyfh = env['wsgi.input'] if 'Content-Length' in headers: bodyfh = util.cappedreader(bodyfh, int(headers['Content-Length'])) 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
D2834: wireproto: support /api/* URL space for exposing APIs
indygreg updated this revision to Diff 7009. REPOSITORY rHG Mercurial CHANGES SINCE LAST UPDATE https://phab.mercurial-scm.org/D2834?vs=6998&id=7009 REVISION DETAIL https://phab.mercurial-scm.org/D2834 AFFECTED FILES mercurial/configitems.py mercurial/hgweb/hgweb_mod.py mercurial/wireprotoserver.py mercurial/wireprototypes.py tests/test-http-api-httpv2.t tests/test-http-api.t CHANGE DETAILS diff --git a/tests/test-http-api.t b/tests/test-http-api.t new file mode 100644 --- /dev/null +++ b/tests/test-http-api.t @@ -0,0 +1,201 @@ + $ send() { + > hg --verbose debugwireproto --peer raw http://$LOCALIP:$HGPORT/ + > } + + $ hg init server + $ hg -R server serve -p $HGPORT -d --pid-file hg.pid + $ cat hg.pid > $DAEMON_PIDS + +Request to /api fails unless web.apiserver is enabled + + $ send << EOF + > httprequest GET api + > user-agent: test + > EOF + using raw connection to peer + s> GET /api HTTP/1.1\r\n + s> Accept-Encoding: identity\r\n + s> user-agent: test\r\n + s> host: $LOCALIP:$HGPORT\r\n (glob) + s> \r\n + s> makefile('rb', None) + s> HTTP/1.1 404 Not Found\r\n + s> Server: testing stub value\r\n + s> Date: $HTTP_DATE$\r\n + s> Content-Type: text/plain\r\n + s> Content-Length: 44\r\n + s> \r\n + s> Experimental API server endpoint not enabled + + $ send << EOF + > httprequest GET api/ + > user-agent: test + > EOF + using raw connection to peer + s> GET /api/ HTTP/1.1\r\n + s> Accept-Encoding: identity\r\n + s> user-agent: test\r\n + s> host: $LOCALIP:$HGPORT\r\n (glob) + s> \r\n + s> makefile('rb', None) + s> HTTP/1.1 404 Not Found\r\n + s> Server: testing stub value\r\n + s> Date: $HTTP_DATE$\r\n + s> Content-Type: text/plain\r\n + s> Content-Length: 44\r\n + s> \r\n + s> Experimental API server endpoint not enabled + +Restart server with support for API server + + $ killdaemons.py + $ cat > server/.hg/hgrc << EOF + > [experimental] + > web.apiserver = true + > EOF + + $ hg -R server serve -p $HGPORT -d --pid-file hg.pid + $ cat hg.pid > $DAEMON_PIDS + +/api lists available APIs (empty since none are available by default) + + $ send << EOF + > httprequest GET api + > user-agent: test + > EOF + using raw connection to peer + s> GET /api HTTP/1.1\r\n + s> Accept-Encoding: identity\r\n + s> user-agent: test\r\n + s> host: $LOCALIP:$HGPORT\r\n (glob) + 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: text/plain\r\n + s> Content-Length: 100\r\n + s> \r\n + s> APIs can be accessed at /api/, where can be one of the following:\n + s> \n + s> (no available APIs)\n + + $ send << EOF + > httprequest GET api/ + > user-agent: test + > EOF + using raw connection to peer + s> GET /api/ HTTP/1.1\r\n + s> Accept-Encoding: identity\r\n + s> user-agent: test\r\n + s> host: $LOCALIP:$HGPORT\r\n (glob) + 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: text/plain\r\n + s> Content-Length: 100\r\n + s> \r\n + s> APIs can be accessed at /api/, where can be one of the following:\n + s> \n + s> (no available APIs)\n + +Accessing an unknown API yields a 404 + + $ send << EOF + > httprequest GET api/unknown + > user-agent: test + > EOF + using raw connection to peer + s> GET /api/unknown HTTP/1.1\r\n + s> Accept-Encoding: identity\r\n + s> user-agent: test\r\n + s> host: $LOCALIP:$HGPORT\r\n (glob) + s> \r\n + s> makefile('rb', None) + s> HTTP/1.1 404 Not Found\r\n + s> Server: testing stub value\r\n + s> Date: $HTTP_DATE$\r\n + s> Content-Type: text/plain\r\n + s> Content-Length: 33\r\n + s> \r\n + s> Unknown API: unknown\n + s> Known APIs: + +Accessing a known but not enabled API yields a different error + + $ send << EOF + > httprequest GET api/exp-http-v2-0001 + > user-agent: test + > EOF + using raw connection to peer + s> GET /api/exp-http-v2-0001 HTTP/1.1\r\n + s> Accept-Encoding: identity\r\n + s> user-agent: test\r\n + s> host: $LOCALIP:$HGPORT\r\n (glob) + s> \r\n + s> makefile('rb', None) + s> HTTP/1.1 404 Not Found\r\n + s> Server: testing stub value\r\n + s> Date: $HTTP_DATE$\r\n + s> Content-Type: text/plain\r\n + s> Content-Length: 33\r\n + s> \r\n + s> API exp-http-v2-0001 not enabled\n + +Restart server with support for HTTP v2 API + + $ killdaemons.py + $ cat > server/.hg/hgrc << EOF + > [experimental] + > web.apiserver = true + > web.api.http-v2 = true + > EOF + + $ hg -R server serve -p $HGPORT -d --pid-file hg.pid + $ cat hg.pid > $DAEMON_PI
D2842: util: don't log low-level I/O calls for HTTP peer
indygreg updated this revision to Diff 7008. REPOSITORY rHG Mercurial CHANGES SINCE LAST UPDATE https://phab.mercurial-scm.org/D2842?vs=6996&id=7008 REVISION DETAIL https://phab.mercurial-scm.org/D2842 AFFECTED FILES mercurial/debugcommands.py mercurial/util.py tests/test-http-protocol.t CHANGE DETAILS diff --git a/tests/test-http-protocol.t b/tests/test-http-protocol.t --- a/tests/test-http-protocol.t +++ b/tests/test-http-protocol.t @@ -175,29 +175,21 @@ > command listkeys > namespace namespaces > EOF - s> sendall(*, 0): (glob) s> GET /?cmd=capabilities HTTP/1.1\r\n s> Accept-Encoding: identity\r\n s> accept: application/mercurial-0.1\r\n s> host: $LOCALIP:$HGPORT\r\n (glob) s> user-agent: mercurial/proto-1.0 (Mercurial *)\r\n (glob) s> \r\n s> makefile('rb', None) - s> readline() -> 36: s> HTTP/1.1 200 Script output follows\r\n - s> readline() -> 28: s> Server: testing stub value\r\n - s> readline() -> *: (glob) s> Date: $HTTP_DATE$\r\n - s> readline() -> 41: s> Content-Type: application/mercurial-0.1\r\n - s> readline() -> 21: s> Content-Length: *\r\n (glob) - s> readline() -> 2: s> \r\n - s> read(*) -> *: lookup branchmap pushkey known getbundle unbundlehash batch changegroupsubset streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN httpheader=1024 httpmediatype=0.1rx,0.1tx,0.2tx compression=$BUNDLE2_COMPRESSIONS$ (glob) + s> lookup branchmap pushkey known getbundle unbundlehash batch changegroupsubset streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN httpheader=1024 httpmediatype=0.1rx,0.1tx,0.2tx compression=$BUNDLE2_COMPRESSIONS$ sending listkeys command - s> sendall(*, 0): (glob) s> GET /?cmd=listkeys HTTP/1.1\r\n s> Accept-Encoding: identity\r\n s> vary: X-HgArg-1,X-HgProto-1\r\n @@ -208,19 +200,12 @@ s> user-agent: mercurial/proto-1.0 (Mercurial *)\r\n (glob) s> \r\n s> makefile('rb', None) - s> readline() -> 36: s> HTTP/1.1 200 Script output follows\r\n - s> readline() -> 28: s> Server: testing stub value\r\n - s> readline() -> *: (glob) s> Date: $HTTP_DATE$\r\n - s> readline() -> 41: s> Content-Type: application/mercurial-0.1\r\n - s> readline() -> 20: s> Content-Length: 30\r\n - s> readline() -> 2: s> \r\n - s> read(30) -> 30: s> bookmarks \n s> namespaces\n s> phases @@ -235,28 +220,20 @@ > x-hgarg-1: namespace=namespaces > EOF using raw connection to peer - s> sendall(*, 0): (glob) s> GET /?cmd=listkeys HTTP/1.1\r\n s> Accept-Encoding: identity\r\n s> accept: application/mercurial-0.1\r\n s> user-agent: mercurial/proto-1.0 (Mercurial 42)\r\n (glob) s> x-hgarg-1: namespace=namespaces\r\n s> host: $LOCALIP:$HGPORT\r\n (glob) s> \r\n s> makefile('rb', None) - s> readline() -> 36: s> HTTP/1.1 200 Script output follows\r\n - s> readline() -> 28: s> Server: testing stub value\r\n - s> readline() -> *: (glob) s> Date: $HTTP_DATE$\r\n - s> readline() -> 41: s> Content-Type: application/mercurial-0.1\r\n - s> readline() -> 20: s> Content-Length: 30\r\n - s> readline() -> 2: s> \r\n - s> read(30) -> 30: s> bookmarks \n s> namespaces\n s> phases diff --git a/mercurial/util.py b/mercurial/util.py --- a/mercurial/util.py +++ b/mercurial/util.py @@ -760,7 +760,8 @@ return makeloggingfileobject(observer.fh, res, observer.name, reads=observer.reads, writes=observer.writes, - logdata=observer.logdata) + logdata=observer.logdata, + logdataapis=observer.logdataapis) def recv(self, *args, **kwargs): return object.__getattribute__(self, r'_observedcall')( @@ -823,26 +824,34 @@ class baseproxyobserver(object): def _writedata(self, data): if not self.logdata: -self.fh.write('\n') +if self.logdataapis: +self.fh.write('\n') return # Simple case writes all data on a single line. if b'\n' not in data: -self.fh.write(': %s\n' % escapedata(data)) +if self.logdataapis: +self.fh.write(': %s\n' % escapedata(data)) +else: +self.fh.write('%s> %s\n' % (self.name, escapedata(data))) return # Data with newlines is written to multiple lines. -self.fh.write(':\n') +if self.logdataapis: +self.fh.write(':\n') + lines = data.splitlines(True) for line in lines: self.fh.write('%s> %s\n' % (self.name
D2850: wireproto: define content negotiation for HTTPv2
indygreg created this revision. Herald added a subscriber: mercurial-devel. Herald added a reviewer: hg-reviewers. REVISION SUMMARY HTTP messages communicate their media types and what media types they can understand via the Content-Type and Accept header, respectively. While I don't want the wire protocol to lean too heavily on HTTP because I'm aiming for the wire protocol to be as transport agnostic as possible, it is nice to play by the spec if possible. This commit defines our media negotiation mechanism for version 2 of the HTTP protocol. Essentially, we mandate the use of a new media type and how clients and servers should react to various headers or lack thereof. The name of the media type is a placeholder. We purposefully don't yet define the format of the new media type because that's a lot of work. I feel pretty strongly that we should use Content-Type. I feel less strongly about Accept. I think it is reasonable for servers to return the media type that was submitted to them. So we may strike this header before the protocol is finished... REPOSITORY rHG Mercurial REVISION DETAIL https://phab.mercurial-scm.org/D2850 AFFECTED FILES mercurial/help/internals/wireprotocol.txt mercurial/wireprotoserver.py tests/test-http-api-httpv2.t CHANGE DETAILS diff --git a/tests/test-http-api-httpv2.t b/tests/test-http-api-httpv2.t --- a/tests/test-http-api-httpv2.t +++ b/tests/test-http-api-httpv2.t @@ -1,4 +1,5 @@ $ HTTPV2=exp-http-v2-0001 + $ MEDIATYPE=application/mercurial-tbd $ send() { > hg --verbose debugwireproto --peer raw http://$LOCALIP:$HGPORT/ @@ -45,27 +46,6 @@ $ hg -R server serve -p $HGPORT -d --pid-file hg.pid $ cat hg.pid > $DAEMON_PIDS -Request to read-only command works out of the box - - $ send << EOF - > httprequest POST api/$HTTPV2/ro/known - > user-agent: test - > EOF - using raw connection to peer - s> POST /api/exp-http-v2-0001/ro/known HTTP/1.1\r\n - s> Accept-Encoding: identity\r\n - s> user-agent: test\r\n - s> host: $LOCALIP:$HGPORT\r\n (glob) - 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: text/plain\r\n - s> Content-Length: 9\r\n - s> \r\n - s> ro/known\n - Request to unknown command yields 404 $ send << EOF @@ -108,6 +88,100 @@ s> \r\n s> commands require POST requests +Missing Accept header results in 406 + + $ send << EOF + > httprequest POST api/$HTTPV2/ro/known + > user-agent: test + > EOF + using raw connection to peer + s> POST /api/exp-http-v2-0001/ro/known HTTP/1.1\r\n + s> Accept-Encoding: identity\r\n + s> user-agent: test\r\n + s> host: $LOCALIP:$HGPORT\r\n (glob) + s> \r\n + s> makefile('rb', None) + s> HTTP/1.1 406 Not Acceptable\r\n + s> Server: testing stub value\r\n + s> Date: $HTTP_DATE$\r\n + s> Content-Type: text/plain\r\n + s> Content-Length: 72\r\n + s> \r\n + s> client MUST specify Accept header with value: application/mercurial-tbd\n + +Bad Accept header results in 406 + + $ send << EOF + > httprequest POST api/$HTTPV2/ro/known + > accept: invalid + > user-agent: test + > EOF + using raw connection to peer + s> POST /api/exp-http-v2-0001/ro/known HTTP/1.1\r\n + s> Accept-Encoding: identity\r\n + s> accept: invalid\r\n + s> user-agent: test\r\n + s> host: $LOCALIP:$HGPORT\r\n (glob) + s> \r\n + s> makefile('rb', None) + s> HTTP/1.1 406 Not Acceptable\r\n + s> Server: testing stub value\r\n + s> Date: $HTTP_DATE$\r\n + s> Content-Type: text/plain\r\n + s> Content-Length: 72\r\n + s> \r\n + s> client MUST specify Accept header with value: application/mercurial-tbd\n + +Bad Content-Type header results in 415 + + $ send << EOF + > httprequest POST api/$HTTPV2/ro/known + > accept: $MEDIATYPE + > user-agent: test + > content-type: badmedia + > EOF + using raw connection to peer + s> POST /api/exp-http-v2-0001/ro/known HTTP/1.1\r\n + s> Accept-Encoding: identity\r\n + s> accept: application/mercurial-tbd\r\n + s> content-type: badmedia\r\n + s> user-agent: test\r\n + s> host: $LOCALIP:$HGPORT\r\n (glob) + s> \r\n + s> makefile('rb', None) + s> HTTP/1.1 415 Unsupported Media Type\r\n + s> Server: testing stub value\r\n + s> Date: $HTTP_DATE$\r\n + s> Content-Type: text/plain\r\n + s> Content-Length: 75\r\n + s> \r\n + s> client MUST send Content-Type header with value: application/mercurial-tbd\n + +Request to read-only command works out of the box + + $ send << EOF + > httprequest POST api/$HTTPV2/ro/known + > accept: $MEDIATYPE + > content-type: $MEDIATYPE + > user-agent: test + > EOF + using raw connection to peer + s> POST /api/exp-http
D2848: xdiff: move stdint.h to xdiff.h
This revision was automatically updated to reflect the committed changes. Closed by commit rHGafebb7588e95: xdiff: move stdint.h to xdiff.h (authored by quark, committed by ). REPOSITORY rHG Mercurial CHANGES SINCE LAST UPDATE https://phab.mercurial-scm.org/D2848?vs=7005&id=7006 REVISION DETAIL https://phab.mercurial-scm.org/D2848 AFFECTED FILES mercurial/thirdparty/xdiff/xdiff.h mercurial/thirdparty/xdiff/xinclude.h CHANGE DETAILS diff --git a/mercurial/thirdparty/xdiff/xinclude.h b/mercurial/thirdparty/xdiff/xinclude.h --- a/mercurial/thirdparty/xdiff/xinclude.h +++ b/mercurial/thirdparty/xdiff/xinclude.h @@ -24,13 +24,6 @@ #define XINCLUDE_H #include -#if !defined(_MSC_VER) || _MSC_VER >= 1600 -#include -#else -/* prior to Visual Studio 2010 */ -typedef long long int64_t; -typedef unsigned long long uint64_t; -#endif #include #include #include diff --git a/mercurial/thirdparty/xdiff/xdiff.h b/mercurial/thirdparty/xdiff/xdiff.h --- a/mercurial/thirdparty/xdiff/xdiff.h +++ b/mercurial/thirdparty/xdiff/xdiff.h @@ -29,6 +29,14 @@ #include /* size_t */ +#if !defined(_MSC_VER) || _MSC_VER >= 1600 +#include +#else +/* prior to Visual Studio 2010 */ +typedef long long int64_t; +typedef unsigned long long uint64_t; +#endif + /* xpparm_t.flags */ #define XDF_NEED_MINIMAL (1 << 0) To: quark, #hg-reviewers, durin42 Cc: mercurial-devel ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
D2848: xdiff: move stdint.h to xdiff.h
quark created this revision. Herald added a subscriber: mercurial-devel. Herald added a reviewer: hg-reviewers. REVISION SUMMARY It's more correct to put it in xdiff.h since that file actually uses int64_t etc and xdiff.h is included by xinclude.h. This should fix the oss-fuzz build. Thanks durin42 for discovering the issue. TEST PLAN `make local` and xdiff related tests still work. REPOSITORY rHG Mercurial REVISION DETAIL https://phab.mercurial-scm.org/D2848 AFFECTED FILES mercurial/thirdparty/xdiff/xdiff.h mercurial/thirdparty/xdiff/xinclude.h CHANGE DETAILS diff --git a/mercurial/thirdparty/xdiff/xinclude.h b/mercurial/thirdparty/xdiff/xinclude.h --- a/mercurial/thirdparty/xdiff/xinclude.h +++ b/mercurial/thirdparty/xdiff/xinclude.h @@ -24,13 +24,6 @@ #define XINCLUDE_H #include -#if !defined(_MSC_VER) || _MSC_VER >= 1600 -#include -#else -/* prior to Visual Studio 2010 */ -typedef long long int64_t; -typedef unsigned long long uint64_t; -#endif #include #include #include diff --git a/mercurial/thirdparty/xdiff/xdiff.h b/mercurial/thirdparty/xdiff/xdiff.h --- a/mercurial/thirdparty/xdiff/xdiff.h +++ b/mercurial/thirdparty/xdiff/xdiff.h @@ -29,6 +29,14 @@ #include /* size_t */ +#if !defined(_MSC_VER) || _MSC_VER >= 1600 +#include +#else +/* prior to Visual Studio 2010 */ +typedef long long int64_t; +typedef unsigned long long uint64_t; +#endif + /* xpparm_t.flags */ #define XDF_NEED_MINIMAL (1 << 0) To: quark, #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 V2] forget: add --dry-run mode
On Tue, 13 Mar 2018 17:30:55 -0400, sushil khanchi wrote: Shall I remove --dry-run from context layer now? It looks like cmdutil.add() and scmutil.addremove() don't pass it along to wctx either, so I guess it's OK to drop for consistency. But the fact that it doesn't seems like a bug- wctx.add() prints out various warnings about portable file names, sizes, etc. I'd think that the whole point of a dry run is to test against that. Maybe the solution to that is to have a mock wctx somehow that simply doesn't flush dirstate to disk? ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
D2620: wireproto: define and implement unified framing protocol for SSH
indygreg abandoned this revision. indygreg added a comment. I'll break this up and send it as multiple commits. REPOSITORY rHG Mercurial REVISION DETAIL https://phab.mercurial-scm.org/D2620 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
D2845: hghave: fix xdiff check on Python 3
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/D2845 AFFECTED FILES tests/hghave.py CHANGE DETAILS diff --git a/tests/hghave.py b/tests/hghave.py --- a/tests/hghave.py +++ b/tests/hghave.py @@ -714,6 +714,6 @@ try: from mercurial import policy bdiff = policy.importmod('bdiff') -return bdiff.xdiffblocks('', '') == [(0, 0, 0, 0)] +return bdiff.xdiffblocks(b'', b'') == [(0, 0, 0, 0)] except (ImportError, AttributeError): return False 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
D2847: remotenames: work around move of ABCs in collections
durin42 created this revision. Herald added a subscriber: mercurial-devel. Herald added a reviewer: hg-reviewers. REVISION SUMMARY This starts warning in Python 3.7, and will break in 3.8. REPOSITORY rHG Mercurial REVISION DETAIL https://phab.mercurial-scm.org/D2847 AFFECTED FILES hgext/remotenames.py CHANGE DETAILS diff --git a/hgext/remotenames.py b/hgext/remotenames.py --- a/hgext/remotenames.py +++ b/hgext/remotenames.py @@ -22,7 +22,12 @@ from __future__ import absolute_import -import collections +try: +from collections import abc +MutableMapping = abc.MutableMapping +except ImportError: +import collections +MutableMapping = collections.MutableMapping from mercurial.i18n import _ @@ -56,7 +61,7 @@ default=True, ) -class lazyremotenamedict(collections.MutableMapping): +class lazyremotenamedict(MutableMapping): """ Read-only dict-like Class to lazily resolve remotename entries 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
D2846: hghave: fix hardlink-whitelisted check on Python 3
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/D2846 AFFECTED FILES tests/hghave.py CHANGE DETAILS diff --git a/tests/hghave.py b/tests/hghave.py --- a/tests/hghave.py +++ b/tests/hghave.py @@ -372,7 +372,7 @@ def has_hardlink_whitelisted(): from mercurial import util try: -fstype = util.getfstype('.') +fstype = util.getfstype(b'.') except OSError: return False return fstype in util._hardlinkfswhitelist 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
D2844: commandserver: prefer first-party selectors module from Python 3 to backport
durin42 created this revision. Herald added a subscriber: mercurial-devel. Herald added a reviewer: hg-reviewers. REVISION SUMMARY Caught by some deprecation warnings on Python 3.7. REPOSITORY rHG Mercurial REVISION DETAIL https://phab.mercurial-scm.org/D2844 AFFECTED FILES mercurial/commandserver.py CHANGE DETAILS diff --git a/mercurial/commandserver.py b/mercurial/commandserver.py --- a/mercurial/commandserver.py +++ b/mercurial/commandserver.py @@ -16,8 +16,13 @@ import struct import traceback +try: +import selectors +selectors.BaseSelector +except ImportError: +from .thirdparty import selectors2 as selectors + from .i18n import _ -from .thirdparty import selectors2 from . import ( encoding, error, @@ -476,8 +481,8 @@ def _mainloop(self): exiting = False h = self._servicehandler -selector = selectors2.DefaultSelector() -selector.register(self._sock, selectors2.EVENT_READ) +selector = selectors.DefaultSelector() +selector.register(self._sock, selectors.EVENT_READ) while True: if not exiting and h.shouldexit(): # clients can no longer connect() to the domain socket, so 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 V2] forget: add --dry-run mode
Shall I remove --dry-run from context layer now? On Tue, Mar 13, 2018 at 7:55 PM, Yuya Nishihara wrote: > On Mon, 12 Mar 2018 18:27:13 -0400, Matt Harbison wrote: > > On Sun, 11 Mar 2018 05:49:26 -0400, Sushil khanchi > > wrote: > > > > > # HG changeset patch > > > # User Sushil khanchi > > > # Date 1520665399 -19800 > > > # Sat Mar 10 12:33:19 2018 +0530 > > > # Node ID a1be8989c0158abc69ebd97ca8a0cc7dc3801be9 > > > # Parent 4c71a26a4009d88590c9ae3d64a5912fd556d82e > > > forget: add --dry-run mode > > > > > > diff -r 4c71a26a4009 -r a1be8989c015 mercurial/cmdutil.py > > > --- a/mercurial/cmdutil.py Sun Mar 04 21:16:36 2018 -0500 > > > +++ b/mercurial/cmdutil.py Sat Mar 10 12:33:19 2018 +0530 > > > @@ -1996,7 +1996,7 @@ > > > for subpath in ctx.substate: > > > ctx.sub(subpath).addwebdirpath(serverpath, webconf) > > > -def forget(ui, repo, match, prefix, explicitonly): > > > +def forget(ui, repo, match, prefix, explicitonly, **opts): > > > join = lambda f: os.path.join(prefix, f) > > > bad = [] > > > badfn = lambda x, y: bad.append(x) or match.bad(x, y) > > > @@ -2039,9 +2039,10 @@ > > > if ui.verbose or not match.exact(f): > > > ui.status(_('removing %s\n') % match.rel(f)) > > > -rejected = wctx.forget(forget, prefix) > > > > Shouldn't --dry-run be passed into wctx.forget() too? Then the warning > > about bad paths there will be emitted, and you won't have to > > conditionalize the following lines here. That in turn won't affect the > > exit code. > > I slightly prefer not to pass --dry-run deep into the context layer > because it's a command-line business. Just my two cents. > ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
D2721: util: observable proxy objects for sockets
mharbison72 added a comment. fileobjectproxy needed `__nonzero__()`/`__bool__()`. Does socketproxy need it for consistency? REPOSITORY rHG Mercurial REVISION DETAIL https://phab.mercurial-scm.org/D2721 To: indygreg, #hg-reviewers Cc: mharbison72, mercurial-devel ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
D2729: copyfile: preserve stat info (mtime, etc.) when doing copies/renames
spectral added a comment. In https://phab.mercurial-scm.org/D2729#45664, @indygreg wrote: > I'm sorry, but we cannot ship this as is. > > The reason is mtime based build systems, like GNU make. > > We can't have version control modifying files without bumping their mtime because this invalidates the target freshness checks of mtime-based build systems. If the user does an `mv` in the shell, at least on Linux, it preserves mtime. If they do a `cp`, it doesn't (the file gets the current timestamp). This includes when overwriting a file. I think I'd be fine with mimicking this behavior (only preserve mtime on `hg mv`) if that would make this safer or easier to reason about. > If we want to preserve mtime on file copy or move, I believe it is safe to do that if and only if the destination file didn't already exist. But if the destination exists, we need to ensure the mtime of the new file is greater than the mtime of the old file. `hg mv` and `hg cp` require `--after` if the destination file already exists; in those cases, we don't seem to touch the working directory at all (including not modifying the mtime, even with my patch). With `--after`, this is purely a VCS operation that afaict "shouldn't" have any effect on build systems, so I think we're safe here for that concern? > Reading this patch, I /think/ the previous behavior was buggy in edge cases because we never ensured the mtime of the replacement was newer than the existing file. In 99.99% of cases, it will be because the existing file was created sometime in the past. But if bad clocks or other wonky things are in play, there's no guarantee that *wall clock now* is greater than the mtime of the existing destination file. The correct thing to do in this situation is read the mtime of the existing file and ensure the mtime of the new file is at least 1s greater than the previous mtime (1s because not all filesystems preserve microsecond or millisecond mtime granularity). REPOSITORY rHG Mercurial REVISION DETAIL https://phab.mercurial-scm.org/D2729 To: spectral, #hg-reviewers, durin42 Cc: indygreg, durin42, mercurial-devel ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
D2721: util: observable proxy objects for sockets
indygreg requested review of this revision. indygreg added a comment. This series should now be ready to review. REPOSITORY rHG Mercurial REVISION DETAIL https://phab.mercurial-scm.org/D2721 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
D2841: debugcommands: support sending HTTP requests with debugwireproto
indygreg created this revision. Herald added a subscriber: mercurial-devel. Herald added a reviewer: hg-reviewers. REVISION SUMMARY We implement an action that can issue an HTTP request. We can define headers via arguments and specify a file to use for the HTTP request body. The request uses the HTTP peer's opener, which is already configured for auth, etc. This is both good and bad. Good in that we get some nice behavior out of the box. Bad in that some HTTP request headers are added automatically. REPOSITORY rHG Mercurial REVISION DETAIL https://phab.mercurial-scm.org/D2841 AFFECTED FILES mercurial/debugcommands.py tests/test-http-protocol.t CHANGE DETAILS diff --git a/tests/test-http-protocol.t b/tests/test-http-protocol.t --- a/tests/test-http-protocol.t +++ b/tests/test-http-protocol.t @@ -226,4 +226,39 @@ s> phases response: bookmarks \nnamespaces\nphases +Same thing, but with "httprequest" command + + $ hg --verbose debugwireproto --peer raw http://$LOCALIP:$HGPORT << EOF + > httprequest GET ?cmd=listkeys + > accept: application/mercurial-0.1 + > user-agent: mercurial/proto-1.0 (Mercurial 42) + > x-hgarg-1: namespace=namespaces + > EOF + using raw connection to peer + s> sendall(*, 0): (glob) + s> GET /?cmd=listkeys HTTP/1.1\r\n + s> Accept-Encoding: identity\r\n + s> accept: application/mercurial-0.1\r\n + s> user-agent: mercurial/proto-1.0 (Mercurial 42)\r\n (glob) + s> x-hgarg-1: namespace=namespaces\r\n + s> host: $LOCALIP:$HGPORT\r\n (glob) + s> \r\n + s> makefile('rb', None) + s> readline() -> 36: + s> HTTP/1.1 200 Script output follows\r\n + s> readline() -> 28: + s> Server: testing stub value\r\n + s> readline() -> *: (glob) + s> Date: $HTTP_DATE$\r\n + s> readline() -> 41: + s> Content-Type: application/mercurial-0.1\r\n + s> readline() -> 20: + s> Content-Length: 30\r\n + s> readline() -> 2: + s> \r\n + s> read(30) -> 30: + s> bookmarks \n + s> namespaces\n + s> phases + $ killdaemons.py diff --git a/mercurial/debugcommands.py b/mercurial/debugcommands.py --- a/mercurial/debugcommands.py +++ b/mercurial/debugcommands.py @@ -14,6 +14,7 @@ import operator import os import random +import re import socket import ssl import stat @@ -2678,6 +2679,24 @@ This action MUST be paired with a ``batchbegin`` action. +httprequest +--- + +(HTTP peer only) + +Send an HTTP request to the peer. + +The HTTP request line follows the ``httprequest`` action. e.g. ``GET /foo``. + +Arguments of the form ``: `` are interpreted as HTTP request +headers to add to the request. e.g. ``Accept: foo``. + +The following arguments are special: + +``BODYFILE`` +The content of the file defined as the value to this argument will be +transferred verbatim as the HTTP request body. + close - @@ -2740,6 +2759,7 @@ stdin = None stdout = None stderr = None +opener = None if opts['localssh']: # We start the SSH server in its own process so there is process @@ -2895,6 +2915,42 @@ ui.status(_('response #%d: %s\n') % (i, util.escapedata(chunk))) batchedcommands = None + +elif action.startswith('httprequest '): +if not opener: +raise error.Abort(_('cannot use httprequest without an HTTP ' +'peer')) + +request = action.split(' ', 2) +if len(request) != 3: +raise error.Abort(_('invalid httprequest: expected format is ' +'"httprequest ')) + +method, httppath = request[1:] +headers = {} +body = None +for line in lines: +line = line.lstrip() +m = re.match(b'^([a-zA-Z0-9_-]+): (.*)$', line) +if m: +headers[m.group(1)] = m.group(2) +continue + +if line.startswith(b'BODYFILE '): +with open(line.split(b' ', 1), 'rb') as fh: +body = fh.read() +else: +raise error.Abort(_('unknown argument to httprequest: %s') % + line) + +url = path + httppath +req = urlmod.urlreq.request(pycompat.strurl(url), body, headers) + +try: +opener.open(req).read() +except util.urlerr.urlerror as e: +e.read() + elif action == 'close': peer.close() elif action == 'readavailable': To: indygreg, #hg-reviewers Cc: mercurial-devel ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercuri
D2842: util: don't log low-level I/O calls for HTTP peer
indygreg created this revision. Herald added a subscriber: mercurial-devel. Herald added a reviewer: hg-reviewers. REVISION SUMMARY `hg debugwireproto` is useful for testing HTTP interactions. Possibly more useful than `get-with-headers.py`. But one thing that makes it annoying for mid-level tests is that it logs all API calls, such as readline(). This makes output - especially headers - overly verbose. This commit teaches our file and socket observers to not log API calls on functions dealing with data. We change the behavior of `hg debugwireproto` to enable this mode by default. --debug can be added to restore the previous behavior. As the test changes demonstrate, this makes tests much easier to read. As a bonus, it also removes some required (glob) over lengths in system call results. One thing that's lacking is knowing which side sent data. But we can fix this in a follow-up once it becomes a problem. REPOSITORY rHG Mercurial REVISION DETAIL https://phab.mercurial-scm.org/D2842 AFFECTED FILES mercurial/debugcommands.py mercurial/util.py tests/test-http-protocol.t CHANGE DETAILS diff --git a/tests/test-http-protocol.t b/tests/test-http-protocol.t --- a/tests/test-http-protocol.t +++ b/tests/test-http-protocol.t @@ -175,29 +175,21 @@ > command listkeys > namespace namespaces > EOF - s> sendall(*, 0): (glob) s> GET /?cmd=capabilities HTTP/1.1\r\n s> Accept-Encoding: identity\r\n s> accept: application/mercurial-0.1\r\n s> host: $LOCALIP:$HGPORT\r\n (glob) s> user-agent: mercurial/proto-1.0 (Mercurial *)\r\n (glob) s> \r\n s> makefile('rb', None) - s> readline() -> 36: s> HTTP/1.1 200 Script output follows\r\n - s> readline() -> 28: s> Server: testing stub value\r\n - s> readline() -> *: (glob) s> Date: $HTTP_DATE$\r\n - s> readline() -> 41: s> Content-Type: application/mercurial-0.1\r\n - s> readline() -> 21: s> Content-Length: *\r\n (glob) - s> readline() -> 2: s> \r\n - s> read(*) -> *: lookup branchmap pushkey known getbundle unbundlehash batch changegroupsubset streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN httpheader=1024 httpmediatype=0.1rx,0.1tx,0.2tx compression=$BUNDLE2_COMPRESSIONS$ (glob) + s> lookup branchmap pushkey known getbundle unbundlehash batch changegroupsubset streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN httpheader=1024 httpmediatype=0.1rx,0.1tx,0.2tx compression=$BUNDLE2_COMPRESSIONS$ sending listkeys command - s> sendall(*, 0): (glob) s> GET /?cmd=listkeys HTTP/1.1\r\n s> Accept-Encoding: identity\r\n s> vary: X-HgArg-1,X-HgProto-1\r\n @@ -208,19 +200,12 @@ s> user-agent: mercurial/proto-1.0 (Mercurial *)\r\n (glob) s> \r\n s> makefile('rb', None) - s> readline() -> 36: s> HTTP/1.1 200 Script output follows\r\n - s> readline() -> 28: s> Server: testing stub value\r\n - s> readline() -> *: (glob) s> Date: $HTTP_DATE$\r\n - s> readline() -> 41: s> Content-Type: application/mercurial-0.1\r\n - s> readline() -> 20: s> Content-Length: 30\r\n - s> readline() -> 2: s> \r\n - s> read(30) -> 30: s> bookmarks \n s> namespaces\n s> phases @@ -235,28 +220,20 @@ > x-hgarg-1: namespace=namespaces > EOF using raw connection to peer - s> sendall(*, 0): (glob) s> GET /?cmd=listkeys HTTP/1.1\r\n s> Accept-Encoding: identity\r\n s> accept: application/mercurial-0.1\r\n s> user-agent: mercurial/proto-1.0 (Mercurial 42)\r\n (glob) s> x-hgarg-1: namespace=namespaces\r\n s> host: $LOCALIP:$HGPORT\r\n (glob) s> \r\n s> makefile('rb', None) - s> readline() -> 36: s> HTTP/1.1 200 Script output follows\r\n - s> readline() -> 28: s> Server: testing stub value\r\n - s> readline() -> *: (glob) s> Date: $HTTP_DATE$\r\n - s> readline() -> 41: s> Content-Type: application/mercurial-0.1\r\n - s> readline() -> 20: s> Content-Length: 30\r\n - s> readline() -> 2: s> \r\n - s> read(30) -> 30: s> bookmarks \n s> namespaces\n s> phases diff --git a/mercurial/util.py b/mercurial/util.py --- a/mercurial/util.py +++ b/mercurial/util.py @@ -755,7 +755,8 @@ return makeloggingfileobject(observer.fh, res, observer.name, reads=observer.reads, writes=observer.writes, - logdata=observer.logdata) + logdata=observer.logdata, + logdataapis=observer.logdataapis) def recv(self, *args, **kwargs): return object.__getattribute__(self, r'_observedcall')( @@ -818,26 +819,34 @@ class baseproxyobserver
D2843: url: support suppressing Accept header
indygreg created this revision. Herald added a subscriber: mercurial-devel. Herald added a reviewer: hg-reviewers. REVISION SUMMARY Sending this header automatically could interfere with future testing and client behavior. Let's add a knob to disable the behavior. We don't have a control for User-Agent because urllib will send it if we don't set something. I don't feel like hacking into the bowels of urllib to figure out how to suppress that. UA shouldn't be used for anything meaningful. So it shouldn't pose any problems beyond non-determinism (since the header has the Mercurial version in it). REPOSITORY rHG Mercurial REVISION DETAIL https://phab.mercurial-scm.org/D2843 AFFECTED FILES mercurial/debugcommands.py mercurial/url.py tests/test-http-protocol.t CHANGE DETAILS diff --git a/tests/test-http-protocol.t b/tests/test-http-protocol.t --- a/tests/test-http-protocol.t +++ b/tests/test-http-protocol.t @@ -215,15 +215,13 @@ $ hg --verbose debugwireproto --peer raw http://$LOCALIP:$HGPORT << EOF > httprequest GET ?cmd=listkeys - > accept: application/mercurial-0.1 - > user-agent: mercurial/proto-1.0 (Mercurial 42) + > user-agent: test > x-hgarg-1: namespace=namespaces > EOF using raw connection to peer s> GET /?cmd=listkeys HTTP/1.1\r\n s> Accept-Encoding: identity\r\n - s> accept: application/mercurial-0.1\r\n - s> user-agent: mercurial/proto-1.0 (Mercurial 42)\r\n (glob) + s> user-agent: test\r\n s> x-hgarg-1: namespace=namespaces\r\n s> host: $LOCALIP:$HGPORT\r\n (glob) s> \r\n diff --git a/mercurial/url.py b/mercurial/url.py --- a/mercurial/url.py +++ b/mercurial/url.py @@ -494,7 +494,7 @@ handlerfuncs = [] def opener(ui, authinfo=None, useragent=None, loggingfh=None, - loggingname=b's', loggingopts=None): + loggingname=b's', loggingopts=None, sendaccept=True): ''' construct an opener suitable for urllib2 authinfo will be added to the password manager @@ -506,6 +506,9 @@ ``loggingname`` denotes the name of the to print when logging. ``loggingopts`` is a dict of keyword arguments to pass to the constructed ``util.socketobserver`` instance. + +``sendaccept`` allows controlling whether the ``Accept`` request header +is sent. The header is sent by default. ''' handlers = [] @@ -562,7 +565,9 @@ # been sent on all requests since forever. We keep sending it for backwards # compatibility reasons. Modern versions of the wire protocol use # X-HgProto- for advertising client support. -opener.addheaders.append((r'Accept', r'application/mercurial-0.1')) +if sendaccept: +opener.addheaders.append((r'Accept', r'application/mercurial-0.1')) + return opener def open(ui, url_, data=None): diff --git a/mercurial/debugcommands.py b/mercurial/debugcommands.py --- a/mercurial/debugcommands.py +++ b/mercurial/debugcommands.py @@ -2832,6 +2832,12 @@ if ui.debugflag: openerargs[r'loggingopts'][r'logdataapis'] = True +# Don't send default headers when in raw mode. This allows us to +# bypass most of the behavior of our URL handling code so we can +# have near complete control over what's sent on the wire. +if opts['peer'] == 'raw': +openerargs[r'sendaccept'] = False + opener = urlmod.opener(ui, authinfo, **openerargs) if opts['peer'] == 'raw': 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
D2834: wireproto: support /api/* URL space for exposing APIs
indygreg updated this revision to Diff 6998. REPOSITORY rHG Mercurial CHANGES SINCE LAST UPDATE https://phab.mercurial-scm.org/D2834?vs=6979&id=6998 REVISION DETAIL https://phab.mercurial-scm.org/D2834 AFFECTED FILES mercurial/configitems.py mercurial/hgweb/hgweb_mod.py mercurial/wireprotoserver.py mercurial/wireprototypes.py tests/test-http-api-httpv2.t tests/test-http-api.t CHANGE DETAILS diff --git a/tests/test-http-api.t b/tests/test-http-api.t new file mode 100644 --- /dev/null +++ b/tests/test-http-api.t @@ -0,0 +1,201 @@ + $ send() { + > hg --verbose debugwireproto --peer raw http://$LOCALIP:$HGPORT/ + > } + + $ hg init server + $ hg -R server serve -p $HGPORT -d --pid-file hg.pid + $ cat hg.pid > $DAEMON_PIDS + +Request to /api fails unless web.apiserver is enabled + + $ send << EOF + > httprequest GET api + > user-agent: test + > EOF + using raw connection to peer + s> GET /api HTTP/1.1\r\n + s> Accept-Encoding: identity\r\n + s> user-agent: test\r\n + s> host: $LOCALIP:$HGPORT\r\n (glob) + s> \r\n + s> makefile('rb', None) + s> HTTP/1.1 404 Not Found\r\n + s> Server: testing stub value\r\n + s> Date: $HTTP_DATE$\r\n + s> Content-Type: text/plain\r\n + s> Content-Length: 44\r\n + s> \r\n + s> Experimental API server endpoint not enabled + + $ send << EOF + > httprequest GET api/ + > user-agent: test + > EOF + using raw connection to peer + s> GET /api/ HTTP/1.1\r\n + s> Accept-Encoding: identity\r\n + s> user-agent: test\r\n + s> host: $LOCALIP:$HGPORT\r\n (glob) + s> \r\n + s> makefile('rb', None) + s> HTTP/1.1 404 Not Found\r\n + s> Server: testing stub value\r\n + s> Date: $HTTP_DATE$\r\n + s> Content-Type: text/plain\r\n + s> Content-Length: 44\r\n + s> \r\n + s> Experimental API server endpoint not enabled + +Restart server with support for API server + + $ killdaemons.py + $ cat > server/.hg/hgrc << EOF + > [experimental] + > web.apiserver = true + > EOF + + $ hg -R server serve -p $HGPORT -d --pid-file hg.pid + $ cat hg.pid > $DAEMON_PIDS + +/api lists available APIs (empty since none are available by default) + + $ send << EOF + > httprequest GET api + > user-agent: test + > EOF + using raw connection to peer + s> GET /api HTTP/1.1\r\n + s> Accept-Encoding: identity\r\n + s> user-agent: test\r\n + s> host: $LOCALIP:$HGPORT\r\n (glob) + 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: text/plain\r\n + s> Content-Length: 100\r\n + s> \r\n + s> APIs can be accessed at /api/, where can be one of the following:\n + s> \n + s> (no available APIs)\n + + $ send << EOF + > httprequest GET api/ + > user-agent: test + > EOF + using raw connection to peer + s> GET /api/ HTTP/1.1\r\n + s> Accept-Encoding: identity\r\n + s> user-agent: test\r\n + s> host: $LOCALIP:$HGPORT\r\n (glob) + 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: text/plain\r\n + s> Content-Length: 100\r\n + s> \r\n + s> APIs can be accessed at /api/, where can be one of the following:\n + s> \n + s> (no available APIs)\n + +Accessing an unknown API yields a 404 + + $ send << EOF + > httprequest GET api/unknown + > user-agent: test + > EOF + using raw connection to peer + s> GET /api/unknown HTTP/1.1\r\n + s> Accept-Encoding: identity\r\n + s> user-agent: test\r\n + s> host: $LOCALIP:$HGPORT\r\n (glob) + s> \r\n + s> makefile('rb', None) + s> HTTP/1.1 404 Not Found\r\n + s> Server: testing stub value\r\n + s> Date: $HTTP_DATE$\r\n + s> Content-Type: text/plain\r\n + s> Content-Length: 33\r\n + s> \r\n + s> Unknown API: unknown\n + s> Known APIs: + +Accessing a known but not enabled API yields a different error + + $ send << EOF + > httprequest GET api/exp-http-v2-0001 + > user-agent: test + > EOF + using raw connection to peer + s> GET /api/exp-http-v2-0001 HTTP/1.1\r\n + s> Accept-Encoding: identity\r\n + s> user-agent: test\r\n + s> host: $LOCALIP:$HGPORT\r\n (glob) + s> \r\n + s> makefile('rb', None) + s> HTTP/1.1 404 Not Found\r\n + s> Server: testing stub value\r\n + s> Date: $HTTP_DATE$\r\n + s> Content-Type: text/plain\r\n + s> Content-Length: 33\r\n + s> \r\n + s> API exp-http-v2-0001 not enabled\n + +Restart server with support for HTTP v2 API + + $ killdaemons.py + $ cat > server/.hg/hgrc << EOF + > [experimental] + > web.apiserver = true + > web.api.http-v2 = true + > EOF + + $ hg -R server serve -p $HGPORT -d --pid-file hg.pid + $ cat hg.pid > $DAEMON_PI
D2840: hgweb: allow defining Server response header for HTTP server
indygreg created this revision. Herald added a subscriber: mercurial-devel. Herald added a reviewer: hg-reviewers. REVISION SUMMARY By default, the string contains the Python version. Server operators may want to change this. Because we like deterministic tests, we change the test harness to always set this value to a known string. Various globs over the server header have now been removed. 1. no-check-commit because we add version_string() REPOSITORY rHG Mercurial REVISION DETAIL https://phab.mercurial-scm.org/D2840 AFFECTED FILES mercurial/configitems.py mercurial/help/config.txt mercurial/hgweb/server.py tests/run-tests.py tests/test-archive.t tests/test-basic.t tests/test-commandserver.t tests/test-hgweb-commands.t tests/test-http-protocol.t CHANGE DETAILS diff --git a/tests/test-http-protocol.t b/tests/test-http-protocol.t --- a/tests/test-http-protocol.t +++ b/tests/test-http-protocol.t @@ -50,41 +50,41 @@ 200 Script output follows content-type: application/mercurial-0.1 date: $HTTP_DATE$ - server: * (glob) + server: testing stub value transfer-encoding: chunked Server should send application/mercurial-0.1 when client says it wants it $ get-with-headers.py --hgproto '0.1' --headeronly $LOCALIP:$HGPORT '?cmd=getbundle&heads=e93700bd72895c5addab234c56d4024b487a362f&common=' - 200 Script output follows content-type: application/mercurial-0.1 date: $HTTP_DATE$ - server: * (glob) + server: testing stub value transfer-encoding: chunked Server should send application/mercurial-0.2 when client says it wants it $ get-with-headers.py --hgproto '0.2' --headeronly $LOCALIP:$HGPORT '?cmd=getbundle&heads=e93700bd72895c5addab234c56d4024b487a362f&common=' - 200 Script output follows content-type: application/mercurial-0.2 date: $HTTP_DATE$ - server: * (glob) + server: testing stub value transfer-encoding: chunked $ get-with-headers.py --hgproto '0.1 0.2' --headeronly $LOCALIP:$HGPORT '?cmd=getbundle&heads=e93700bd72895c5addab234c56d4024b487a362f&common=' - 200 Script output follows content-type: application/mercurial-0.2 date: $HTTP_DATE$ - server: * (glob) + server: testing stub value transfer-encoding: chunked Requesting a compression format that server doesn't support results will fall back to 0.1 $ get-with-headers.py --hgproto '0.2 comp=aa' --headeronly $LOCALIP:$HGPORT '?cmd=getbundle&heads=e93700bd72895c5addab234c56d4024b487a362f&common=' - 200 Script output follows content-type: application/mercurial-0.1 date: $HTTP_DATE$ - server: * (glob) + server: testing stub value transfer-encoding: chunked #if zstd @@ -106,7 +106,7 @@ content-length: 41 content-type: application/mercurial-0.1 date: $HTTP_DATE$ - server: * (glob) + server: testing stub value e93700bd72895c5addab234c56d4024b487a362f diff --git a/tests/test-hgweb-commands.t b/tests/test-hgweb-commands.t --- a/tests/test-hgweb-commands.t +++ b/tests/test-hgweb-commands.t @@ -1923,7 +1923,7 @@ content-length: 12 content-type: application/mercurial-0.1 date: $HTTP_DATE$ - server: * (glob) + server: testing stub value 0 Not Found diff --git a/tests/test-commandserver.t b/tests/test-commandserver.t --- a/tests/test-commandserver.t +++ b/tests/test-commandserver.t @@ -215,6 +215,7 @@ ui.nontty=true web.address=localhost web\.ipv6=(?:True|False) (re) + web.server-header=testing stub value *** runcommand init foo *** runcommand -R foo showconfig ui defaults ui.slash=True diff --git a/tests/test-basic.t b/tests/test-basic.t --- a/tests/test-basic.t +++ b/tests/test-basic.t @@ -12,6 +12,7 @@ ui.promptecho=True web.address=localhost web\.ipv6=(?:True|False) (re) + web.server-header=testing stub value $ hg init t $ cd t diff --git a/tests/test-archive.t b/tests/test-archive.t --- a/tests/test-archive.t +++ b/tests/test-archive.t @@ -128,24 +128,24 @@ content-type: application/x-gzip date: $HTTP_DATE$ etag: W/"*" (glob) - server: * (glob) + server: testing stub value transfer-encoding: chunked body: size=408, sha1=8fa06531bddecc365a9f5edb0f88b65974bfe505 % tar.bz2 and zip disallowed should both give 403 403 Archive type not allowed: bz2 content-type: text/html; charset=ascii date: $HTTP_DATE$ etag: W/"*" (glob) - server: * (glob) + server: testing stub value transfer-encoding: chunked body: size=1451, sha1=4c5cf0f574446c44feb7f88f4e0e2a56bd92c352 403 Archive type not allowed: zip content-type: text/html; charset=ascii date: $HTTP_DATE$ etag: W/"*" (glob) - server: * (glob) + server: testing stub value transfer-encoding: chunked body: size=1451, sha1=cbfa5574b337348bfd0564cc534474d002e7d6c7 @@ -156,24 +156,24 @
D2837: wireproto: require POST for all HTTPv2 requests
indygreg updated this revision to Diff 7000. REPOSITORY rHG Mercurial CHANGES SINCE LAST UPDATE https://phab.mercurial-scm.org/D2837?vs=6983&id=7000 REVISION DETAIL https://phab.mercurial-scm.org/D2837 AFFECTED FILES mercurial/help/internals/wireprotocol.txt mercurial/wireprotoserver.py tests/test-http-api-httpv2.t CHANGE DETAILS diff --git a/tests/test-http-api-httpv2.t b/tests/test-http-api-httpv2.t --- a/tests/test-http-api-httpv2.t +++ b/tests/test-http-api-httpv2.t @@ -48,11 +48,11 @@ Request to read-only command works out of the box $ send << EOF - > httprequest GET api/$HTTPV2/ro/known + > httprequest POST api/$HTTPV2/ro/known > user-agent: test > EOF using raw connection to peer - s> GET /api/exp-http-v2-0001/ro/known HTTP/1.1\r\n + s> POST /api/exp-http-v2-0001/ro/known HTTP/1.1\r\n s> Accept-Encoding: identity\r\n s> user-agent: test\r\n s> host: $LOCALIP:$HGPORT\r\n (glob) @@ -69,11 +69,11 @@ Request to unknown command yields 404 $ send << EOF - > httprequest GET api/$HTTPV2/ro/badcommand + > httprequest POST api/$HTTPV2/ro/badcommand > user-agent: test > EOF using raw connection to peer - s> GET /api/exp-http-v2-0001/ro/badcommand HTTP/1.1\r\n + s> POST /api/exp-http-v2-0001/ro/badcommand HTTP/1.1\r\n s> Accept-Encoding: identity\r\n s> user-agent: test\r\n s> host: $LOCALIP:$HGPORT\r\n (glob) @@ -87,9 +87,30 @@ s> \r\n s> unknown wire protocol command: badcommand\n +GET to read-only command yields a 405 + + $ send << EOF + > httprequest GET api/$HTTPV2/ro/known + > user-agent: test + > EOF + using raw connection to peer + s> GET /api/exp-http-v2-0001/ro/known HTTP/1.1\r\n + s> Accept-Encoding: identity\r\n + s> user-agent: test\r\n + s> host: $LOCALIP:$HGPORT\r\n (glob) + s> \r\n + s> makefile('rb', None) + s> HTTP/1.1 405 Method Not Allowed\r\n + s> Server: testing stub value\r\n + s> Date: $HTTP_DATE$\r\n + s> Allow: POST\r\n + s> Content-Length: 30\r\n + s> \r\n + s> commands require POST requests + Request to read-write command fails because server is read-only by default -GET to read-write request not allowed +GET to read-write request yields 405 $ send << EOF > httprequest GET api/$HTTPV2/rw/known @@ -102,12 +123,13 @@ s> host: $LOCALIP:$HGPORT\r\n (glob) s> \r\n s> makefile('rb', None) - s> HTTP/1.1 405 push requires POST request\r\n + s> HTTP/1.1 405 Method Not Allowed\r\n s> Server: testing stub value\r\n s> Date: $HTTP_DATE$\r\n - s> Content-Length: 17\r\n + s> Allow: POST\r\n + s> Content-Length: 30\r\n s> \r\n - s> permission denied + s> commands require POST requests Even for unknown commands @@ -122,12 +144,13 @@ s> host: $LOCALIP:$HGPORT\r\n (glob) s> \r\n s> makefile('rb', None) - s> HTTP/1.1 405 push requires POST request\r\n + s> HTTP/1.1 405 Method Not Allowed\r\n s> Server: testing stub value\r\n s> Date: $HTTP_DATE$\r\n - s> Content-Length: 17\r\n + s> Allow: POST\r\n + s> Content-Length: 30\r\n s> \r\n - s> permission denied + s> commands require POST requests SSL required by default @@ -158,38 +181,6 @@ > web.api.http-v2 = true > [web] > push_ssl = false - > EOF - - $ hg -R server serve -p $HGPORT -d --pid-file hg.pid - $ cat hg.pid > $DAEMON_PIDS - -Server insists on POST for read-write commands - - $ send << EOF - > httprequest GET api/$HTTPV2/rw/known - > user-agent: test - > EOF - using raw connection to peer - s> GET /api/exp-http-v2-0001/rw/known HTTP/1.1\r\n - s> Accept-Encoding: identity\r\n - s> user-agent: test\r\n - s> host: $LOCALIP:$HGPORT\r\n (glob) - s> \r\n - s> makefile('rb', None) - s> HTTP/1.1 405 push requires POST request\r\n - s> Server: testing stub value\r\n - s> Date: $HTTP_DATE$\r\n - s> Content-Length: 17\r\n - s> \r\n - s> permission denied - - $ killdaemons.py - $ cat > server/.hg/hgrc << EOF - > [experimental] - > web.apiserver = true - > web.api.http-v2 = true - > [web] - > push_ssl = false > allow-push = * > EOF diff --git a/mercurial/wireprotoserver.py b/mercurial/wireprotoserver.py --- a/mercurial/wireprotoserver.py +++ b/mercurial/wireprotoserver.py @@ -299,6 +299,12 @@ res.setbodybytes(_('unknown permission: %s') % permission) return +if req.method != 'POST': +res.status = b'405 Method Not Allowed' +res.headers[b'Allow'] = b'POST' +res.setbodybytes(_('commands require POST requests')) +return + # At some point we'll want to use our own API instead of recycling the # behavior of version 1 of the wire protocol... # TODO return reasonable responses - not responses that overload the diff --git a/mercurial/help/i
D2836: wireproto: define permissions-based routing of HTTPv2 wire protocol
indygreg updated this revision to Diff 6999. REPOSITORY rHG Mercurial CHANGES SINCE LAST UPDATE https://phab.mercurial-scm.org/D2836?vs=6982&id=6999 REVISION DETAIL https://phab.mercurial-scm.org/D2836 AFFECTED FILES mercurial/debugcommands.py mercurial/help/internals/wireprotocol.txt mercurial/wireprotoserver.py tests/test-http-api-httpv2.t CHANGE DETAILS diff --git a/tests/test-http-api-httpv2.t b/tests/test-http-api-httpv2.t --- a/tests/test-http-api-httpv2.t +++ b/tests/test-http-api-httpv2.t @@ -1,3 +1,5 @@ + $ HTTPV2=exp-http-v2-0001 + $ send() { > hg --verbose debugwireproto --peer raw http://$LOCALIP:$HGPORT/ > } @@ -13,7 +15,7 @@ HTTP v2 protocol not enabled by default $ send << EOF - > httprequest GET api/exp-http-v2-0001 + > httprequest GET api/$HTTPV2 > user-agent: test > EOF using raw connection to peer @@ -43,14 +45,14 @@ $ hg -R server serve -p $HGPORT -d --pid-file hg.pid $ cat hg.pid > $DAEMON_PIDS -Requests simply echo their path (for now) +Request to read-only command works out of the box $ send << EOF - > httprequest GET api/exp-http-v2-0001/path1/path2 + > httprequest GET api/$HTTPV2/ro/known > user-agent: test > EOF using raw connection to peer - s> GET /api/exp-http-v2-0001/path1/path2 HTTP/1.1\r\n + s> GET /api/exp-http-v2-0001/ro/known HTTP/1.1\r\n s> Accept-Encoding: identity\r\n s> user-agent: test\r\n s> host: $LOCALIP:$HGPORT\r\n (glob) @@ -60,6 +62,178 @@ s> Server: testing stub value\r\n s> Date: $HTTP_DATE$\r\n s> Content-Type: text/plain\r\n - s> Content-Length: 12\r\n + s> Content-Length: 9\r\n + s> \r\n + s> ro/known/ + +Request to unknown command yields 404 + + $ send << EOF + > httprequest GET api/$HTTPV2/ro/badcommand + > user-agent: test + > EOF + using raw connection to peer + s> GET /api/exp-http-v2-0001/ro/badcommand HTTP/1.1\r\n + s> Accept-Encoding: identity\r\n + s> user-agent: test\r\n + s> host: $LOCALIP:$HGPORT\r\n (glob) + s> \r\n + s> makefile('rb', None) + s> HTTP/1.1 404 Not Found\r\n + s> Server: testing stub value\r\n + s> Date: $HTTP_DATE$\r\n + s> Content-Type: text/plain\r\n + s> Content-Length: 42\r\n + s> \r\n + s> unknown wire protocol command: badcommand\n + +Request to read-write command fails because server is read-only by default + +GET to read-write request not allowed + + $ send << EOF + > httprequest GET api/$HTTPV2/rw/known + > user-agent: test + > EOF + using raw connection to peer + s> GET /api/exp-http-v2-0001/rw/known HTTP/1.1\r\n + s> Accept-Encoding: identity\r\n + s> user-agent: test\r\n + s> host: $LOCALIP:$HGPORT\r\n (glob) + s> \r\n + s> makefile('rb', None) + s> HTTP/1.1 405 push requires POST request\r\n + s> Server: testing stub value\r\n + s> Date: $HTTP_DATE$\r\n + s> Content-Length: 17\r\n + s> \r\n + s> permission denied + +Even for unknown commands + + $ send << EOF + > httprequest GET api/$HTTPV2/rw/badcommand + > user-agent: test + > EOF + using raw connection to peer + s> GET /api/exp-http-v2-0001/rw/badcommand HTTP/1.1\r\n + s> Accept-Encoding: identity\r\n + s> user-agent: test\r\n + s> host: $LOCALIP:$HGPORT\r\n (glob) + s> \r\n + s> makefile('rb', None) + s> HTTP/1.1 405 push requires POST request\r\n + s> Server: testing stub value\r\n + s> Date: $HTTP_DATE$\r\n + s> Content-Length: 17\r\n + s> \r\n + s> permission denied + +SSL required by default + + $ send << EOF + > httprequest POST api/$HTTPV2/rw/known + > user-agent: test + > EOF + using raw connection to peer + s> POST /api/exp-http-v2-0001/rw/known HTTP/1.1\r\n + s> Accept-Encoding: identity\r\n + s> user-agent: test\r\n + s> host: $LOCALIP:$HGPORT\r\n (glob) + s> \r\n + s> makefile('rb', None) + s> HTTP/1.1 403 ssl required\r\n + s> Server: testing stub value\r\n + s> Date: $HTTP_DATE$\r\n + s> Content-Length: 17\r\n s> \r\n - s> path1/path2/ + s> permission denied + +Restart server to allow non-ssl read-write operations + + $ killdaemons.py + $ cat > server/.hg/hgrc << EOF + > [experimental] + > web.apiserver = true + > web.api.http-v2 = true + > [web] + > push_ssl = false + > EOF + + $ hg -R server serve -p $HGPORT -d --pid-file hg.pid + $ cat hg.pid > $DAEMON_PIDS + +Server insists on POST for read-write commands + + $ send << EOF + > httprequest GET api/$HTTPV2/rw/known + > user-agent: test + > EOF + using raw connection to peer + s> GET /api/exp-http-v2-0001/rw/known HTTP/1.1\r\n + s> Accept-Encoding: identity\r\n + s> user-agent: test\r\n + s> host: $LOCALIP:$HGPORT\r\n (glob) + s> \r\n + s> makefile('rb', None) + s> HTTP/1.1 405 push requires POST request\r\n + s> Server: testi
D2726: debugcommands: support connecting to HTTP peers
indygreg updated this revision to Diff 6994. indygreg edited the summary of this revision. REPOSITORY rHG Mercurial CHANGES SINCE LAST UPDATE https://phab.mercurial-scm.org/D2726?vs=6977&id=6994 REVISION DETAIL https://phab.mercurial-scm.org/D2726 AFFECTED FILES mercurial/debugcommands.py tests/test-http-protocol.t CHANGE DETAILS diff --git a/tests/test-http-protocol.t b/tests/test-http-protocol.t --- a/tests/test-http-protocol.t +++ b/tests/test-http-protocol.t @@ -161,3 +161,69 @@ : 32 30 30 20 53 63 72 69 70 74 20 6f 75 74 70 75 |200 Script outpu| 0010: 74 20 66 6f 6c 6c 6f 77 73 0a 0a 04 7a 6c 69 62 |t follows...zlib| 0020: 78 |x| + + $ killdaemons.py + $ cd .. + +Test listkeys for listing namespaces + + $ hg init empty + $ hg -R empty serve -p $HGPORT -d --pid-file hg.pid + $ cat hg.pid > $DAEMON_PIDS + + $ hg --verbose debugwireproto http://$LOCALIP:$HGPORT << EOF + > command listkeys + > namespace namespaces + > EOF + s> sendall(*, 0): (glob) + s> GET /?cmd=capabilities HTTP/1.1\r\n + s> Accept-Encoding: identity\r\n + s> accept: application/mercurial-0.1\r\n + s> host: $LOCALIP:$HGPORT\r\n (glob) + s> user-agent: mercurial/proto-1.0 (Mercurial *)\r\n (glob) + s> \r\n + s> makefile('rb', None) + s> readline() -> 36: + s> HTTP/1.1 200 Script output follows\r\n + s> readline() -> 28: + s> Server: testing stub value\r\n + s> readline() -> *: (glob) + s> Date: $HTTP_DATE$\r\n + s> readline() -> 41: + s> Content-Type: application/mercurial-0.1\r\n + s> readline() -> 21: + s> Content-Length: *\r\n (glob) + s> readline() -> 2: + s> \r\n + s> read(*) -> *: lookup branchmap pushkey known getbundle unbundlehash batch changegroupsubset streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN httpheader=1024 httpmediatype=0.1rx,0.1tx,0.2tx compression=$BUNDLE2_COMPRESSIONS$ (glob) + sending listkeys command + s> sendall(*, 0): (glob) + s> GET /?cmd=listkeys HTTP/1.1\r\n + s> Accept-Encoding: identity\r\n + s> vary: X-HgArg-1,X-HgProto-1\r\n + s> x-hgarg-1: namespace=namespaces\r\n + s> x-hgproto-1: 0.1 0.2 comp=$USUAL_COMPRESSIONS$\r\n + s> accept: application/mercurial-0.1\r\n + s> host: $LOCALIP:$HGPORT\r\n (glob) + s> user-agent: mercurial/proto-1.0 (Mercurial *)\r\n (glob) + s> \r\n + s> makefile('rb', None) + s> readline() -> 36: + s> HTTP/1.1 200 Script output follows\r\n + s> readline() -> 28: + s> Server: testing stub value\r\n + s> readline() -> *: (glob) + s> Date: $HTTP_DATE$\r\n + s> readline() -> 41: + s> Content-Type: application/mercurial-0.1\r\n + s> readline() -> 20: + s> Content-Length: 30\r\n + s> readline() -> 2: + s> \r\n + s> read(30) -> 30: + s> bookmarks \n + s> namespaces\n + s> phases + response: bookmarks \nnamespaces\nphases + + $ killdaemons.py diff --git a/mercurial/debugcommands.py b/mercurial/debugcommands.py --- a/mercurial/debugcommands.py +++ b/mercurial/debugcommands.py @@ -48,6 +48,7 @@ fileset, formatter, hg, +httppeer, localrepo, lock as lockmod, logcmdutil, @@ -2588,9 +2589,9 @@ ('', 'peer', '', _('construct a specific version of the peer')), ('', 'noreadstderr', False, _('do not read from stderr of the remote')), ] + cmdutil.remoteopts, -_('[REPO]'), +_('[PATH]'), optionalrepo=True) -def debugwireproto(ui, repo, **opts): +def debugwireproto(ui, repo, path=None, **opts): """send wire protocol commands to a server This command can be used to issue wire protocol commands to remote @@ -2726,12 +2727,19 @@ raise error.Abort(_('invalid value for --peer'), hint=_('valid values are "raw", "ssh1", and "ssh2"')) +if path and opts['localssh']: +raise error.Abort(_('cannot specify --localssh with an explicit ' +'path')) + if ui.interactive(): ui.write(_('(waiting for commands on stdin)\n')) blocks = list(_parsewirelangblocks(ui.fin)) proc = None +stdin = None +stdout = None +stderr = None if opts['localssh']: # We start the SSH server in its own process so there is process @@ -2779,22 +2787,61 @@ peer = sshpeer.makepeer(ui, url, proc, stdin, stdout, stderr, autoreadstderr=autoreadstderr) +elif path: +# We bypass hg.peer() so we can proxy the sockets. +# TODO consider not doing this because we skip +# ``hg.wirepeersetupfuncs`` and potentially other useful functionality. +u = util.url(path) +if u.scheme != 'http': +raise error.Abort(_('only http:// paths are currently supported')) + +url, authinfo = u.authinfo() +openerargs = {} + +
D2839: tests: use $HTTP_DATE$ for Date header
indygreg created this revision. Herald added a subscriber: mercurial-devel. Herald added a reviewer: hg-reviewers. REVISION SUMMARY Support for the $HTTP_DATE$ substitution was recently added. Let's adopt it more widely. We had to tweak the substitution to be case insensitive, since HTTP headers are case insensitive. I also found a minor test issue not globbing over the length of the Server response header. REPOSITORY rHG Mercurial REVISION DETAIL https://phab.mercurial-scm.org/D2839 AFFECTED FILES tests/common-pattern.py tests/test-archive.t tests/test-hgweb-commands.t tests/test-http-protocol.t CHANGE DETAILS diff --git a/tests/test-http-protocol.t b/tests/test-http-protocol.t --- a/tests/test-http-protocol.t +++ b/tests/test-http-protocol.t @@ -49,41 +49,41 @@ $ get-with-headers.py --headeronly $LOCALIP:$HGPORT '?cmd=getbundle&heads=e93700bd72895c5addab234c56d4024b487a362f&common=' - 200 Script output follows content-type: application/mercurial-0.1 - date: * (glob) + date: $HTTP_DATE$ server: * (glob) transfer-encoding: chunked Server should send application/mercurial-0.1 when client says it wants it $ get-with-headers.py --hgproto '0.1' --headeronly $LOCALIP:$HGPORT '?cmd=getbundle&heads=e93700bd72895c5addab234c56d4024b487a362f&common=' - 200 Script output follows content-type: application/mercurial-0.1 - date: * (glob) + date: $HTTP_DATE$ server: * (glob) transfer-encoding: chunked Server should send application/mercurial-0.2 when client says it wants it $ get-with-headers.py --hgproto '0.2' --headeronly $LOCALIP:$HGPORT '?cmd=getbundle&heads=e93700bd72895c5addab234c56d4024b487a362f&common=' - 200 Script output follows content-type: application/mercurial-0.2 - date: * (glob) + date: $HTTP_DATE$ server: * (glob) transfer-encoding: chunked $ get-with-headers.py --hgproto '0.1 0.2' --headeronly $LOCALIP:$HGPORT '?cmd=getbundle&heads=e93700bd72895c5addab234c56d4024b487a362f&common=' - 200 Script output follows content-type: application/mercurial-0.2 - date: * (glob) + date: $HTTP_DATE$ server: * (glob) transfer-encoding: chunked Requesting a compression format that server doesn't support results will fall back to 0.1 $ get-with-headers.py --hgproto '0.2 comp=aa' --headeronly $LOCALIP:$HGPORT '?cmd=getbundle&heads=e93700bd72895c5addab234c56d4024b487a362f&common=' - 200 Script output follows content-type: application/mercurial-0.1 - date: * (glob) + date: $HTTP_DATE$ server: * (glob) transfer-encoding: chunked @@ -105,7 +105,7 @@ 200 Script output follows content-length: 41 content-type: application/mercurial-0.1 - date: * (glob) + date: $HTTP_DATE$ server: * (glob) e93700bd72895c5addab234c56d4024b487a362f diff --git a/tests/test-hgweb-commands.t b/tests/test-hgweb-commands.t --- a/tests/test-hgweb-commands.t +++ b/tests/test-hgweb-commands.t @@ -1922,7 +1922,7 @@ 404 Not Found content-length: 12 content-type: application/mercurial-0.1 - date: * (glob) + date: $HTTP_DATE$ server: * (glob) 0 diff --git a/tests/test-archive.t b/tests/test-archive.t --- a/tests/test-archive.t +++ b/tests/test-archive.t @@ -126,24 +126,24 @@ 200 Script output follows content-disposition: attachment; filename=test-archive-1701ef1f1510.tar.gz content-type: application/x-gzip - date: * (glob) + date: $HTTP_DATE$ etag: W/"*" (glob) server: * (glob) transfer-encoding: chunked body: size=408, sha1=8fa06531bddecc365a9f5edb0f88b65974bfe505 % tar.bz2 and zip disallowed should both give 403 403 Archive type not allowed: bz2 content-type: text/html; charset=ascii - date: * (glob) + date: $HTTP_DATE$ etag: W/"*" (glob) server: * (glob) transfer-encoding: chunked body: size=1451, sha1=4c5cf0f574446c44feb7f88f4e0e2a56bd92c352 403 Archive type not allowed: zip content-type: text/html; charset=ascii - date: * (glob) + date: $HTTP_DATE$ etag: W/"*" (glob) server: * (glob) transfer-encoding: chunked @@ -154,24 +154,24 @@ 200 Script output follows content-disposition: attachment; filename=test-archive-1701ef1f1510.tar.bz2 content-type: application/x-bzip2 - date: * (glob) + date: $HTTP_DATE$ etag: W/"*" (glob) server: * (glob) transfer-encoding: chunked body: size=426, sha1=8d87f5aba6e14f1bfea6c232985982c278b2fb0b % zip and tar.gz disallowed should both give 403 403 Archive type not allowed: zip content-type: text/html; charset=ascii - date: * (glob) + date: $HTTP_DATE$ etag: W/"*" (glob) server: * (glob) transfer-encoding: chunked body: size=1451, sha1=cbfa5574b337348bfd0564cc534474d002e7d6c7 403 Archive type not allowed: gz content-typ
D2721: util: observable proxy objects for sockets
indygreg planned changes to this revision. indygreg added a comment. I have significant changes to this series in flight. It's worth holding off on review. REPOSITORY rHG Mercurial REVISION DETAIL https://phab.mercurial-scm.org/D2721 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
D2834: wireproto: support /api/* URL space for exposing APIs
mharbison72 added a comment. In https://phab.mercurial-scm.org/D2834#45696, @indygreg wrote: > In https://phab.mercurial-scm.org/D2834#45666, @mharbison72 wrote: > > > Will this cause conflicts with `hg serve -S` or hgwebdir with subrepo/virtual paths that start with 'api'? (This was the reason I used the LFS URI starting with '.hg/', knowing that isn't committable.) > > > Bleh. > > So what I'm hearing is that because of hgwebdir's virtual paths and support for serving subrepos, pretty much the entire URL space is dangerous because it can conflict with the path of a virtual repo or subrepo. I suppose we already have problems with existing URLs, like `/rev/`. I think so. I remember when Yuya suggested putting the `/index` virtual file into hgwebdir a year ago, I had to dance around the fact that 'index' could have been a repo being served up. I'm guessing `/rev/` et al. is less of a problem, because presumably they've existed since the beginning? > I agree that putting things under `.hg/` in the URL space seems to be a viable workaround. > > Changing the URL prefix isn't a big deal as far as the code is concerned. We can make that change at any time since we have no BC guarantees at this juncture. I'm fine with landing this as-is and changing it later if needed. I haven't checked this myself, I was just going on a vague memory of issues that I ran into, and wondered if you had considered it. REPOSITORY rHG Mercurial REVISION DETAIL https://phab.mercurial-scm.org/D2834 To: indygreg, #hg-reviewers Cc: mharbison72, mercurial-devel ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
[PATCH] peer-request: include more details about batch commands
# HG changeset patch # User Boris Feld # Date 1520268508 18000 # Mon Mar 05 11:48:28 2018 -0500 # Node ID 025b0a829b1c9a299b76b7303b4d46c269fcba48 # Parent 31581528f2421dc5d8a567125b8ecc0367b2b906 # EXP-Topic peer-request.batch # Available At https://bitbucket.org/octobus/mercurial-devel/ # hg pull https://bitbucket.org/octobus/mercurial-devel/ -r 025b0a829b1c peer-request: include more details about batch commands A batch commands encapsulate multiple other commands. We display a bit more details about what is actually batched if peer request tracking is set. diff --git a/mercurial/wireproto.py b/mercurial/wireproto.py --- a/mercurial/wireproto.py +++ b/mercurial/wireproto.py @@ -400,6 +400,13 @@ class wirepeer(repository.legacypeer): Returns an iterator of the raw responses from the server. """ +ui = self.ui +if ui.debugflag and ui.configbool('devel', 'debug.peer-request'): +ui.debug('devel-peer-request: batched-content\n') +for op, args in req: +msg = 'devel-peer-request:- %s (%d arguments)\n' +ui.debug(msg % (op, len(args))) + rsp = self._callstream("batch", cmds=encodebatchcmds(req)) chunk = rsp.read(1024) work = [chunk] diff --git a/tests/test-http.t b/tests/test-http.t --- a/tests/test-http.t +++ b/tests/test-http.t @@ -257,6 +257,9 @@ test http authentication http auth: user user, password devel-peer-request: finished in *. seconds (200) (glob) query 1; heads + devel-peer-request: batched-content + devel-peer-request:- heads (0 arguments) + devel-peer-request:- known (1 arguments) sending batch command devel-peer-request: GET http://localhost:$HGPORT2/?cmd=batch devel-peer-request: Vary X-HgArg-1,X-HgProto-1 diff --git a/tests/test-ssh.t b/tests/test-ssh.t --- a/tests/test-ssh.t +++ b/tests/test-ssh.t @@ -501,6 +501,9 @@ debug output remote: capabilities: lookup branchmap pushkey known getbundle unbundlehash batch changegroupsubset streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN remote: 1 (sshv1 !) query 1; heads + devel-peer-request: batched-content + devel-peer-request:- heads (0 arguments) + devel-peer-request:- known (1 arguments) devel-peer-request: batch devel-peer-request: cmds: 141 bytes sending batch command ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
[PATCH 1 of 2] push-discovery: don't turn use generator when comparing bookmarks
# HG changeset patch # User Boris Feld # Date 1520609495 -3600 # Fri Mar 09 16:31:35 2018 +0100 # Node ID 9ecb102cd955e075a6a637f1b8d4f5c8e3015751 # Parent 2cdf47e14c30dbdc2ebc0fd498fc0b85205ce2b3 # EXP-Topic push-book-handling # Available At https://bitbucket.org/octobus/mercurial-devel/ # hg pull https://bitbucket.org/octobus/mercurial-devel/ -r 9ecb102cd955 push-discovery: don't turn use generator when comparing bookmarks We want extensions to be able to implement their own logic. Generators can be consume only once, impractical for this purpose. diff --git a/mercurial/exchange.py b/mercurial/exchange.py --- a/mercurial/exchange.py +++ b/mercurial/exchange.py @@ -620,8 +620,8 @@ def _pushdiscoverybookmarks(pushop): return hex(x) def hexifycompbookmarks(bookmarks): -for b, scid, dcid in bookmarks: -yield b, safehex(scid), safehex(dcid) +return [(b, safehex(scid), safehex(dcid)) +for (b, scid, dcid) in bookmarks] comp = [hexifycompbookmarks(marks) for marks in comp] addsrc, adddst, advsrc, advdst, diverge, differ, invalid, same = comp ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
[PATCH 2 of 2] push-discovery: extract the bookmark comparison logic in its own function
# HG changeset patch # User Boris Feld # Date 1520607221 -3600 # Fri Mar 09 15:53:41 2018 +0100 # Node ID 5b15c9c72bc88931d5a5dc9bfec0935098c04402 # Parent 9ecb102cd955e075a6a637f1b8d4f5c8e3015751 # EXP-Topic push-book-handling # Available At https://bitbucket.org/octobus/mercurial-devel/ # hg pull https://bitbucket.org/octobus/mercurial-devel/ -r 5b15c9c72bc8 push-discovery: extract the bookmark comparison logic in its own function This will help extensions to alter the behavior as they see fit. diff --git a/mercurial/exchange.py b/mercurial/exchange.py --- a/mercurial/exchange.py +++ b/mercurial/exchange.py @@ -624,12 +624,20 @@ def _pushdiscoverybookmarks(pushop): for (b, scid, dcid) in bookmarks] comp = [hexifycompbookmarks(marks) for marks in comp] +return _processcompared(pushop, ancestors, explicit, remotebookmark, comp) + +def _processcompared(pushop, pushed, explicit, remotebms, comp): +"""take decision on bookmark to pull from the remote bookmark + +Exist to help extension who want to alter this behavior.""" addsrc, adddst, advsrc, advdst, diverge, differ, invalid, same = comp +repo = pushop.repo + for b, scid, dcid in advsrc: if b in explicit: explicit.remove(b) -if not ancestors or repo[scid].rev() in ancestors: +if not pushed or repo[scid].rev() in pushed: pushop.outbookmarks.append((b, dcid, scid)) # search added bookmark for b, scid, dcid in addsrc: @@ -655,8 +663,8 @@ def _pushdiscoverybookmarks(pushop): if explicit: explicit = sorted(explicit) # we should probably list all of them -ui.warn(_('bookmark %s does not exist on the local ' - 'or remote repository!\n') % explicit[0]) +pushop.ui.warn(_('bookmark %s does not exist on the local ' + 'or remote repository!\n') % explicit[0]) pushop.bkresult = 2 pushop.outbookmarks.sort() ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
D2833: tests: teach get-with-headers.py to ignore dynamic headers
indygreg abandoned this revision. indygreg added a comment. I like Matt's patch and will do something more deterministic. REPOSITORY rHG Mercurial REVISION DETAIL https://phab.mercurial-scm.org/D2833 To: indygreg, #hg-reviewers Cc: mharbison72, mercurial-devel ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
D2838: util: clear debugstacktrace call
lothiraldan created this revision. Herald added a subscriber: mercurial-devel. Herald added a reviewer: hg-reviewers. REVISION SUMMARY During the renaming of datestr, it seems that I have forget a debugstacktrace in util.py. Remove it. REPOSITORY rHG Mercurial REVISION DETAIL https://phab.mercurial-scm.org/D2838 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 @@ -4027,7 +4027,6 @@ msg = ("'util.datestr' is deprecated, " "use 'utils.dateutil.datestr'") nouideprecwarn(msg, "4.6") -debugstacktrace() return dateutil.datestr(*args, **kwargs) def shortdate(*args, **kwargs): To: lothiraldan, #hg-reviewers Cc: mercurial-devel ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
mercurial@36855: 10 new changesets
10 new changesets in mercurial: https://www.mercurial-scm.org/repo/hg/rev/14f70c44af6c changeset: 36846:14f70c44af6c parent: 36843:31581528f242 user:Gregory Szorc date:Thu Mar 08 16:38:01 2018 -0800 summary: wireprotoserver: access headers through parsed request https://www.mercurial-scm.org/repo/hg/rev/ed0456fde625 changeset: 36847:ed0456fde625 user:Gregory Szorc date:Sat Mar 10 10:45:12 2018 -0800 summary: hgweb: handle CONTENT_LENGTH https://www.mercurial-scm.org/repo/hg/rev/16292bbda39c changeset: 36848:16292bbda39c user:Gregory Szorc date:Sat Mar 10 10:44:56 2018 -0800 summary: hgweb: store and use request method on parsed request https://www.mercurial-scm.org/repo/hg/rev/0bc771bba220 changeset: 36849:0bc771bba220 user:Gregory Szorc date:Thu Mar 08 17:17:48 2018 -0800 summary: wireprotoserver: remove unused argument from _handlehttperror() https://www.mercurial-scm.org/repo/hg/rev/e85574176467 changeset: 36850:e85574176467 user:Gregory Szorc date:Sat Mar 10 10:46:08 2018 -0800 summary: hgweb: remove unused methods on wsgirequest https://www.mercurial-scm.org/repo/hg/rev/d6cd1451212e changeset: 36851:d6cd1451212e user:Gregory Szorc date:Thu Mar 08 17:57:07 2018 -0800 summary: hgweb: remove wsgirequest.read() https://www.mercurial-scm.org/repo/hg/rev/e3f809e0fe8e changeset: 36852:e3f809e0fe8e user:Gregory Szorc date:Thu Mar 08 18:00:04 2018 -0800 summary: hgweb: remove wsgirequest.__iter__ https://www.mercurial-scm.org/repo/hg/rev/7066617187c1 changeset: 36853:7066617187c1 user:Gregory Szorc date:Sat Mar 10 10:47:30 2018 -0800 summary: hgweb: document continuereader https://www.mercurial-scm.org/repo/hg/rev/290fc4c3d1e0 changeset: 36854:290fc4c3d1e0 user:Gregory Szorc date:Sat Mar 10 10:48:34 2018 -0800 summary: hgweb: use a capped reader for WSGI input stream https://www.mercurial-scm.org/repo/hg/rev/2cdf47e14c30 changeset: 36855:2cdf47e14c30 bookmark:@ tag: tip user:Gregory Szorc date:Sat Mar 10 11:03:45 2018 -0800 summary: hgweb: refactor the request draining code -- Repository URL: https://www.mercurial-scm.org/repo/hg ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
D2834: wireproto: support /api/* URL space for exposing APIs
indygreg added a comment. In https://phab.mercurial-scm.org/D2834#45666, @mharbison72 wrote: > Will this cause conflicts with `hg serve -S` or hgwebdir with subrepo/virtual paths that start with 'api'? (This was the reason I used the LFS URI starting with '.hg/', knowing that isn't committable.) Bleh. So what I'm hearing is that because of hgwebdir's virtual paths and support for serving subrepos, pretty much the entire URL space is dangerous because it can conflict with the path of a virtual repo or subrepo. I suppose we already have problems with existing URLs, like `/rev/`. I agree that putting things under `.hg/` in the URL space seems to be a viable workaround. Changing the URL prefix isn't a big deal as far as the code is concerned. We can make that change at any time since we have no BC guarantees at this juncture. REPOSITORY rHG Mercurial REVISION DETAIL https://phab.mercurial-scm.org/D2834 To: indygreg, #hg-reviewers Cc: mharbison72, mercurial-devel ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
Re: [PATCH 1 of 4] pycompat: name maplist() and ziplist() for better traceback message
On Tue, Mar 13, 2018 at 7:25 PM, Yuya Nishihara wrote: > # HG changeset patch > # User Yuya Nishihara > # Date 1520943734 -32400 > # Tue Mar 13 21:22:14 2018 +0900 > # Node ID aa35c6d7caef9ef9f48d0c9c831f9492c1421c45 > # Parent 6aeb076b1321c540db6419fc48c8a3a552fb596b > pycompat: name maplist() and ziplist() for better traceback message Queued the first two patches. Many thanks! ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
mercurial@36845: new changeset (1 on stable)
New changeset (1 on stable) in mercurial: https://www.mercurial-scm.org/repo/hg/rev/ff2370a70fe8 changeset: 36845:ff2370a70fe8 branch: stable tag: tip user:Gregory Szorc date:Mon Mar 12 13:15:00 2018 -0700 summary: hgweb: garbage collect on every request -- Repository URL: https://www.mercurial-scm.org/repo/hg ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
D2810: rebase: inline _performrebasesubset()
This revision was automatically updated to reflect the committed changes. Closed by commit rHG0cc850a43e6c: rebase: inline _performrebasesubset() (authored by martinvonz, committed by ). REPOSITORY rHG Mercurial CHANGES SINCE LAST UPDATE https://phab.mercurial-scm.org/D2810?vs=6875&id=6989 REVISION DETAIL https://phab.mercurial-scm.org/D2810 AFFECTED FILES hgext/rebase.py CHANGE DETAILS diff --git a/hgext/rebase.py b/hgext/rebase.py --- a/hgext/rebase.py +++ b/hgext/rebase.py @@ -425,30 +425,27 @@ total = len(cands) pos = 0 for subset in sortsource(self.destmap): -pos = self._performrebasesubset(tr, subset, pos, total) +sortedrevs = self.repo.revs('sort(%ld, -topo)', subset) +allowdivergence = self.ui.configbool( +'experimental', 'evolution.allowdivergence') +if not allowdivergence: +sortedrevs -= self.repo.revs( +'descendants(%ld) and not %ld', +self.obsoletewithoutsuccessorindestination, +self.obsoletewithoutsuccessorindestination, +) +posholder = [pos] +def progress(ctx): +posholder[0] += 1 +self.repo.ui.progress(_("rebasing"), posholder[0], + ("%d:%s" % (ctx.rev(), ctx)), + _('changesets'), total) +for rev in sortedrevs: +self._rebasenode(tr, rev, allowdivergence, progress) +pos = posholder[0] ui.progress(_('rebasing'), None) ui.note(_('rebase merging completed\n')) -def _performrebasesubset(self, tr, subset, pos, total): -sortedrevs = self.repo.revs('sort(%ld, -topo)', subset) -allowdivergence = self.ui.configbool( -'experimental', 'evolution.allowdivergence') -if not allowdivergence: -sortedrevs -= self.repo.revs( -'descendants(%ld) and not %ld', -self.obsoletewithoutsuccessorindestination, -self.obsoletewithoutsuccessorindestination, -) -posholder = [pos] -def progress(ctx): -posholder[0] += 1 -self.repo.ui.progress(_("rebasing"), posholder[0], - ("%d:%s" % (ctx.rev(), ctx)), _('changesets'), - total) -for rev in sortedrevs: -self._rebasenode(tr, rev, allowdivergence, progress) -return posholder[0] - def _rebasenode(self, tr, rev, allowdivergence, progressfn): repo, ui, opts = self.repo, self.ui, self.opts dest = self.destmap[rev] To: martinvonz, #hg-reviewers, yuja Cc: mercurial-devel ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
D2761: rebase: use configoverride context manager for ui.forcemerge
This revision was automatically updated to reflect the committed changes. Closed by commit rHG6b6d7f127ee5: rebase: use configoverride context manager for ui.forcemerge (authored by martinvonz, committed by ). REPOSITORY rHG Mercurial CHANGES SINCE LAST UPDATE https://phab.mercurial-scm.org/D2761?vs=6873&id=6987 REVISION DETAIL https://phab.mercurial-scm.org/D2761 AFFECTED FILES hgext/rebase.py CHANGE DETAILS diff --git a/hgext/rebase.py b/hgext/rebase.py --- a/hgext/rebase.py +++ b/hgext/rebase.py @@ -481,9 +481,8 @@ if len(repo[None].parents()) == 2: repo.ui.debug('resuming interrupted rebase\n') else: -try: -ui.setconfig('ui', 'forcemerge', opts.get('tool', ''), - 'rebase') +overrides = {('ui', 'forcemerge'): opts.get('tool', '')} +with ui.configoverride(overrides, 'rebase'): stats = rebasenode(repo, rev, p1, base, self.collapsef, dest, wctx=self.wctx) if stats and stats[3] > 0: @@ -493,8 +492,6 @@ raise error.InterventionRequired( _('unresolved conflicts (see hg ' 'resolve, then hg rebase --continue)')) -finally: -ui.setconfig('ui', 'forcemerge', '', 'rebase') if not self.collapsef: merging = p2 != nullrev editform = cmdutil.mergeeditform(merging, 'rebase') To: martinvonz, #hg-reviewers, yuja Cc: mercurial-devel ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
D2759: rebase: fix issue 5494 also with --collapse
This revision was automatically updated to reflect the committed changes. Closed by commit rHG72e58801950a: rebase: fix issue 5494 also with --collapse (authored by martinvonz, committed by ). REPOSITORY rHG Mercurial CHANGES SINCE LAST UPDATE https://phab.mercurial-scm.org/D2759?vs=6787&id=6985 REVISION DETAIL https://phab.mercurial-scm.org/D2759 AFFECTED FILES hgext/rebase.py tests/test-rebase-interruptions.t CHANGE DETAILS diff --git a/tests/test-rebase-interruptions.t b/tests/test-rebase-interruptions.t --- a/tests/test-rebase-interruptions.t +++ b/tests/test-rebase-interruptions.t @@ -479,7 +479,6 @@ $ hg rebase --continue rebasing 2:fdaca8533b86 "b" (tip) saved backup bundle to $TESTTMP/repo/.hg/strip-backup/fdaca8533b86-7fd70513-rebase.hg -BROKEN: the merge state was not cleared $ hg resolve --list - R a $ test -d .hg/merge + [1] diff --git a/hgext/rebase.py b/hgext/rebase.py --- a/hgext/rebase.py +++ b/hgext/rebase.py @@ -579,6 +579,12 @@ editor=editor, keepbranches=self.keepbranchesf, date=self.date) + +if newnode is None: +# If it ended up being a no-op commit, then the normal +# merge state clean-up path doesn't happen, so do it +# here. Fix issue5494 +mergemod.mergestate.clean(repo) if newnode is not None: newrev = repo[newnode].rev() for oldrev in self.state: To: martinvonz, #hg-reviewers, yuja Cc: mercurial-devel ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
D2811: rebase: move constant expressions out of inner loop in _performrebase()
This revision was automatically updated to reflect the committed changes. Closed by commit rHG41d6df958331: rebase: move constant expressions out of inner loop in _performrebase() (authored by martinvonz, committed by ). REPOSITORY rHG Mercurial CHANGES SINCE LAST UPDATE https://phab.mercurial-scm.org/D2811?vs=6876&id=6990 REVISION DETAIL https://phab.mercurial-scm.org/D2811 AFFECTED FILES hgext/rebase.py CHANGE DETAILS diff --git a/hgext/rebase.py b/hgext/rebase.py --- a/hgext/rebase.py +++ b/hgext/rebase.py @@ -423,26 +423,24 @@ cands = [k for k, v in self.state.iteritems() if v == revtodo] total = len(cands) -pos = 0 +posholder = [0] +def progress(ctx): +posholder[0] += 1 +self.repo.ui.progress(_("rebasing"), posholder[0], + ("%d:%s" % (ctx.rev(), ctx)), + _('changesets'), total) +allowdivergence = self.ui.configbool( +'experimental', 'evolution.allowdivergence') for subset in sortsource(self.destmap): sortedrevs = self.repo.revs('sort(%ld, -topo)', subset) -allowdivergence = self.ui.configbool( -'experimental', 'evolution.allowdivergence') if not allowdivergence: sortedrevs -= self.repo.revs( 'descendants(%ld) and not %ld', self.obsoletewithoutsuccessorindestination, self.obsoletewithoutsuccessorindestination, ) -posholder = [pos] -def progress(ctx): -posholder[0] += 1 -self.repo.ui.progress(_("rebasing"), posholder[0], - ("%d:%s" % (ctx.rev(), ctx)), - _('changesets'), total) for rev in sortedrevs: self._rebasenode(tr, rev, allowdivergence, progress) -pos = posholder[0] ui.progress(_('rebasing'), None) ui.note(_('rebase merging completed\n')) To: martinvonz, #hg-reviewers, yuja Cc: mercurial-devel ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
D2728: rebase: also include commit of collapsed commits in single transaction
This revision was automatically updated to reflect the committed changes. Closed by commit rHG67e18654a9eb: rebase: also include commit of collapsed commits in single transaction (authored by martinvonz, committed by ). REPOSITORY rHG Mercurial CHANGES SINCE LAST UPDATE https://phab.mercurial-scm.org/D2728?vs=6768&id=6984 REVISION DETAIL https://phab.mercurial-scm.org/D2728 AFFECTED FILES hgext/rebase.py tests/test-rebase-transaction.t CHANGE DETAILS diff --git a/tests/test-rebase-transaction.t b/tests/test-rebase-transaction.t --- a/tests/test-rebase-transaction.t +++ b/tests/test-rebase-transaction.t @@ -29,11 +29,9 @@ > |/ > A > EOF -- We should only see two status stored messages. One from the start, one from -- the end. +- We should only see one status stored message. It comes from the start. $ hg rebase --debug -b D -d Z | grep 'status stored' rebase status stored - rebase status stored $ hg tglog o 5: D | @@ -64,7 +62,7 @@ > A > EOF - We should only see two status stored messages. One from the start, one from -- the end. +- cmdutil.commitforceeditor() which forces tr.writepending() $ hg rebase --collapse --debug -b D -d Z | grep 'status stored' rebase status stored rebase status stored @@ -162,12 +160,14 @@ rebasing 1:112478962961 "B" (B) rebasing 3:26805aba1e60 "C" (C) rebasing 5:f585351a92f8 "D" (D tip) + transaction abort! + rollback completed abort: edit failed: false exited with status 1 [255] $ hg tglog o 5: D | - | @ 4: Z + | o 4: Z | | o | 3: C | | @@ -178,9 +178,9 @@ o 0: A $ hg rebase --continue - already rebased 1:112478962961 "B" (B) as e9b22a392ce0 - already rebased 3:26805aba1e60 "C" (C) as e9b22a392ce0 - already rebased 5:f585351a92f8 "D" (D tip) as e9b22a392ce0 + rebasing 1:112478962961 "B" (B) + rebasing 3:26805aba1e60 "C" (C) + rebasing 5:f585351a92f8 "D" (D tip) saved backup bundle to $TESTTMP/collapse-cancel-editor/.hg/strip-backup/112478962961-cb2a9b47-rebase.hg $ hg tglog o 3: Collapsed revision diff --git a/hgext/rebase.py b/hgext/rebase.py --- a/hgext/rebase.py +++ b/hgext/rebase.py @@ -573,16 +573,12 @@ keepbranches=self.keepbranchesf, date=self.date, wctx=self.wctx) else: -dsguard = None -if ui.configbool('rebase', 'singletransaction'): -dsguard = dirstateguard.dirstateguard(repo, 'rebase') -with util.acceptintervention(dsguard): -newnode = concludenode(repo, revtoreuse, p1, self.external, -commitmsg=commitmsg, -extrafn=_makeextrafn(self.extrafns), -editor=editor, -keepbranches=self.keepbranchesf, -date=self.date) +newnode = concludenode(repo, revtoreuse, p1, self.external, +commitmsg=commitmsg, +extrafn=_makeextrafn(self.extrafns), +editor=editor, +keepbranches=self.keepbranchesf, +date=self.date) if newnode is not None: newrev = repo[newnode].rev() for oldrev in self.state: @@ -864,8 +860,7 @@ dsguard = dirstateguard.dirstateguard(repo, 'rebase') with util.acceptintervention(dsguard): rbsrt._performrebase(tr) - -rbsrt._finishrebase() +rbsrt._finishrebase() def _definedestmap(ui, repo, rbsrt, destf=None, srcf=None, basef=None, revf=None, destspace=None): To: martinvonz, #hg-reviewers, durham, quark, yuja Cc: mercurial-devel ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
D2809: rebase: extract function for rebasing a single node
This revision was automatically updated to reflect the committed changes. Closed by commit rHGd56e4d78a366: rebase: extract function for rebasing a single node (authored by martinvonz, committed by ). REPOSITORY rHG Mercurial CHANGES SINCE LAST UPDATE https://phab.mercurial-scm.org/D2809?vs=6874&id=6988 REVISION DETAIL https://phab.mercurial-scm.org/D2809 AFFECTED FILES hgext/rebase.py CHANGE DETAILS diff --git a/hgext/rebase.py b/hgext/rebase.py --- a/hgext/rebase.py +++ b/hgext/rebase.py @@ -430,115 +430,122 @@ ui.note(_('rebase merging completed\n')) def _performrebasesubset(self, tr, subset, pos, total): -repo, ui, opts = self.repo, self.ui, self.opts -sortedrevs = repo.revs('sort(%ld, -topo)', subset) +sortedrevs = self.repo.revs('sort(%ld, -topo)', subset) allowdivergence = self.ui.configbool( 'experimental', 'evolution.allowdivergence') if not allowdivergence: -sortedrevs -= repo.revs( +sortedrevs -= self.repo.revs( 'descendants(%ld) and not %ld', self.obsoletewithoutsuccessorindestination, self.obsoletewithoutsuccessorindestination, ) +posholder = [pos] +def progress(ctx): +posholder[0] += 1 +self.repo.ui.progress(_("rebasing"), posholder[0], + ("%d:%s" % (ctx.rev(), ctx)), _('changesets'), + total) for rev in sortedrevs: -dest = self.destmap[rev] -ctx = repo[rev] -desc = _ctxdesc(ctx) -if self.state[rev] == rev: -ui.status(_('already rebased %s\n') % desc) -elif (not allowdivergence - and rev in self.obsoletewithoutsuccessorindestination): -msg = _('note: not rebasing %s and its descendants as ' -'this would cause divergence\n') % desc -repo.ui.status(msg) -self.skipped.add(rev) -elif rev in self.obsoletenotrebased: -succ = self.obsoletenotrebased[rev] -if succ is None: -msg = _('note: not rebasing %s, it has no ' -'successor\n') % desc -else: -succdesc = _ctxdesc(repo[succ]) -msg = (_('note: not rebasing %s, already in ' - 'destination as %s\n') % (desc, succdesc)) -repo.ui.status(msg) -# Make clearrebased aware state[rev] is not a true successor -self.skipped.add(rev) -# Record rev as moved to its desired destination in self.state. -# This helps bookmark and working parent movement. -dest = max(adjustdest(repo, rev, self.destmap, self.state, - self.skipped)) -self.state[rev] = dest -elif self.state[rev] == revtodo: -pos += 1 -ui.status(_('rebasing %s\n') % desc) -ui.progress(_("rebasing"), pos, ("%d:%s" % (rev, ctx)), -_('changesets'), total) -p1, p2, base = defineparents(repo, rev, self.destmap, - self.state, self.skipped, - self.obsoletenotrebased) -self.storestatus(tr=tr) -if len(repo[None].parents()) == 2: -repo.ui.debug('resuming interrupted rebase\n') +self._rebasenode(tr, rev, allowdivergence, progress) +return posholder[0] + +def _rebasenode(self, tr, rev, allowdivergence, progressfn): +repo, ui, opts = self.repo, self.ui, self.opts +dest = self.destmap[rev] +ctx = repo[rev] +desc = _ctxdesc(ctx) +if self.state[rev] == rev: +ui.status(_('already rebased %s\n') % desc) +elif (not allowdivergence + and rev in self.obsoletewithoutsuccessorindestination): +msg = _('note: not rebasing %s and its descendants as ' +'this would cause divergence\n') % desc +repo.ui.status(msg) +self.skipped.add(rev) +elif rev in self.obsoletenotrebased: +succ = self.obsoletenotrebased[rev] +if succ is None: +msg = _('note: not rebasing %s, it has no ' +'successor\n') % desc +else: +succdesc = _ctxdesc(repo[succ]) +msg = (_('note: not rebasing %s, already in ' + 'destination as %s\n') % (desc, succdesc)) +repo.ui.status(msg) +# Make clearrebased aware state[rev] is not a true successor +self.skipped.add(rev) +# Record rev as moved to its desired destination in self.state. +
D2760: rebase: also restore "ui.allowemptycommit" value
This revision was automatically updated to reflect the committed changes. Closed by commit rHG1bfe7e1d65fb: rebase: also restore "ui.allowemptycommit" value (authored by martinvonz, committed by ). REPOSITORY rHG Mercurial CHANGES SINCE LAST UPDATE https://phab.mercurial-scm.org/D2760?vs=6872&id=6986 REVISION DETAIL https://phab.mercurial-scm.org/D2760 AFFECTED FILES hgext/rebase.py CHANGE DETAILS diff --git a/hgext/rebase.py b/hgext/rebase.py --- a/hgext/rebase.py +++ b/hgext/rebase.py @@ -1054,9 +1054,9 @@ destphase = max(ctx.phase(), phases.draft) overrides = {('phases', 'new-commit'): destphase} +if keepbranch: +overrides[('ui', 'allowemptycommit')] = True with repo.ui.configoverride(overrides, 'rebase'): -if keepbranch: -repo.ui.setconfig('ui', 'allowemptycommit', True) # Replicates the empty check in ``repo.commit``. if wctx.isempty() and not repo.ui.configbool('ui', 'allowemptycommit'): return None @@ -1096,9 +1096,9 @@ destphase = max(ctx.phase(), phases.draft) overrides = {('phases', 'new-commit'): destphase} +if keepbranch: +overrides[('ui', 'allowemptycommit')] = True with repo.ui.configoverride(overrides, 'rebase'): -if keepbranch: -repo.ui.setconfig('ui', 'allowemptycommit', True) # Commit might fail if unresolved files exist if date is None: date = ctx.date() To: martinvonz, #hg-reviewers, yuja Cc: mercurial-devel ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
Re: [PATCH V2] forget: add --dry-run mode
On Mon, 12 Mar 2018 18:27:13 -0400, Matt Harbison wrote: > On Sun, 11 Mar 2018 05:49:26 -0400, Sushil khanchi > wrote: > > > # HG changeset patch > > # User Sushil khanchi > > # Date 1520665399 -19800 > > # Sat Mar 10 12:33:19 2018 +0530 > > # Node ID a1be8989c0158abc69ebd97ca8a0cc7dc3801be9 > > # Parent 4c71a26a4009d88590c9ae3d64a5912fd556d82e > > forget: add --dry-run mode > > > > diff -r 4c71a26a4009 -r a1be8989c015 mercurial/cmdutil.py > > --- a/mercurial/cmdutil.py Sun Mar 04 21:16:36 2018 -0500 > > +++ b/mercurial/cmdutil.py Sat Mar 10 12:33:19 2018 +0530 > > @@ -1996,7 +1996,7 @@ > > for subpath in ctx.substate: > > ctx.sub(subpath).addwebdirpath(serverpath, webconf) > > -def forget(ui, repo, match, prefix, explicitonly): > > +def forget(ui, repo, match, prefix, explicitonly, **opts): > > join = lambda f: os.path.join(prefix, f) > > bad = [] > > badfn = lambda x, y: bad.append(x) or match.bad(x, y) > > @@ -2039,9 +2039,10 @@ > > if ui.verbose or not match.exact(f): > > ui.status(_('removing %s\n') % match.rel(f)) > > -rejected = wctx.forget(forget, prefix) > > Shouldn't --dry-run be passed into wctx.forget() too? Then the warning > about bad paths there will be emitted, and you won't have to > conditionalize the following lines here. That in turn won't affect the > exit code. I slightly prefer not to pass --dry-run deep into the context layer because it's a command-line business. Just my two cents. ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
Re: [PATCH 3 of 3] lfs: debug print HTTP headers and JSON payload received from the server
On Tue, 13 Mar 2018 00:00:08 -0400, Matt Harbison wrote: > # HG changeset patch > # User Matt Harbison > # Date 1520910527 14400 > # Mon Mar 12 23:08:47 2018 -0400 > # Node ID d0b66408b224022fd96cb347ff3439e807812b21 > # Parent f28c282005085edb77f64612be503a7cd43ab994 > lfs: debug print HTTP headers and JSON payload received from the server Seems fine, queued, thanks. > +if self.ui.debugflag: > +self.ui.debug('Status: %d\n' % rsp.status) > +# lfs-test-server and hg serve return headers in different order > +self.ui.debug('%s\n' > + % '\n'.join(sorted(str(rsp.info()).splitlines( > + > +if 'objects' in response: > +response['objects'] = sorted(response['objects'], > + key=lambda p: p['oid']) > +self.ui.debug('%s\n' > + % json.dumps(response, indent=2, sort_keys=True)) We'll need some hack for py3 because json is unicode. ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
Re: [PATCH] xdiff: fix a hard crash on Windows
On Mon, 12 Mar 2018 18:55:26 -0700, Jun Wu wrote: > Looks good. Thanks for fixing this! > > Excerpts from Matt Harbison's message of 2018-03-12 21:53:12 -0400: > > # HG changeset patch > > # User Matt Harbison > > # Date 1520905818 14400 > > # Mon Mar 12 21:50:18 2018 -0400 > > # Node ID 60bb2f7dd9ba313f96374470e8419bf1a20454a1 > > # Parent aed445748c7885482cd90e56e81f57a13d4ac95c > > xdiff: fix a hard crash on Windows Queued, thanks. ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
D2834: wireproto: support /api/* URL space for exposing APIs
mharbison72 added a comment. Will this cause conflicts with `hg serve -S` or hgwebdir with subrepo/virtual paths that start with 'api'? (This was the reason I used the LFS URI starting with '.hg/', knowing that isn't committable.) REPOSITORY rHG Mercurial REVISION DETAIL https://phab.mercurial-scm.org/D2834 To: indygreg, #hg-reviewers Cc: mharbison72, mercurial-devel ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
[PATCH 3 of 4] annotate: do not construct attr.s object per line while computing history
# HG changeset patch # User Yuya Nishihara # Date 1520855110 -32400 # Mon Mar 12 20:45:10 2018 +0900 # Node ID 1ce0d903cfa6e8db0112f86cc346751651db1f80 # Parent 95af54712a25c298d5ee63c385f3d498250c1624 annotate: do not construct attr.s object per line while computing history Unfortunately, it's way slower to construct an annotateline() object than creating a plain tuple or a list. This patch changes the internal data structure from row-based to columnar, so the decorate() function can be instant. (original) $ hg annot mercurial/commands.py --time > /dev/null time: real 11.470 secs (user 11.400+0.000 sys 0.070+0.000) $ hg annot mercurial/commands.py --time --line-number > /dev/null time: real 39.590 secs (user 39.500+0.000 sys 0.080+0.000) (this patch) $ hg annot mercurial/commands.py --time > /dev/null time: real 11.780 secs (user 11.710+0.000 sys 0.070+0.000) $ hg annot mercurial/commands.py --time --line-number > /dev/null time: real 12.240 secs (user 12.170+0.000 sys 0.090+0.000) diff --git a/mercurial/dagop.py b/mercurial/dagop.py --- a/mercurial/dagop.py +++ b/mercurial/dagop.py @@ -365,10 +365,19 @@ def blockdescendants(fctx, fromline, tol @attr.s(slots=True, frozen=True) class annotateline(object): fctx = attr.ib() -lineno = attr.ib(default=False) +lineno = attr.ib() # Whether this annotation was the result of a skip-annotate. skip = attr.ib(default=False) +@attr.s(slots=True, frozen=True) +class _annotatedfile(object): +# list indexed by lineno - 1 +fctxs = attr.ib() +linenos = attr.ib() +skips = attr.ib() +# full file content +text = attr.ib() + def _countlines(text): if text.endswith("\n"): return text.count("\n") @@ -385,7 +394,7 @@ def _annotatepair(parents, childfctx, ch See test-annotate.py for unit tests. ''' -pblocks = [(parent, mdiff.allblocks(parent[1], child[1], opts=diffopts)) +pblocks = [(parent, mdiff.allblocks(parent.text, child.text, opts=diffopts)) for parent in parents] if skipchild: @@ -398,7 +407,9 @@ def _annotatepair(parents, childfctx, ch # Changed blocks ('!') or blocks made only of blank lines ('~') # belong to the child. if t == '=': -child[0][b1:b2] = parent[0][a1:a2] +child.fctxs[b1:b2] = parent.fctxs[a1:a2] +child.linenos[b1:b2] = parent.linenos[a1:a2] +child.skips[b1:b2] = parent.skips[a1:a2] if skipchild: # Now try and match up anything that couldn't be matched, @@ -419,9 +430,11 @@ def _annotatepair(parents, childfctx, ch for (a1, a2, b1, b2), _t in blocks: if a2 - a1 >= b2 - b1: for bk in xrange(b1, b2): -if child[0][bk].fctx == childfctx: +if child.fctxs[bk] == childfctx: ak = min(a1 + (bk - b1), a2 - 1) -child[0][bk] = attr.evolve(parent[0][ak], skip=True) +child.fctxs[bk] = parent.fctxs[ak] +child.linenos[bk] = parent.linenos[ak] +child.skips[bk] = True else: remaining[idx][1].append((a1, a2, b1, b2)) @@ -430,9 +443,11 @@ def _annotatepair(parents, childfctx, ch for parent, blocks in remaining: for a1, a2, b1, b2 in blocks: for bk in xrange(b1, b2): -if child[0][bk].fctx == childfctx: +if child.fctxs[bk] == childfctx: ak = min(a1 + (bk - b1), a2 - 1) -child[0][bk] = attr.evolve(parent[0][ak], skip=True) +child.fctxs[bk] = parent.fctxs[ak] +child.linenos[bk] = parent.linenos[ak] +child.skips[bk] = True return child def annotate(base, parents, linenumber=False, skiprevs=None, diffopts=None): @@ -443,11 +458,13 @@ def annotate(base, parents, linenumber=F if linenumber: def decorate(text, fctx): -return ([annotateline(fctx=fctx, lineno=i) - for i in xrange(1, _countlines(text) + 1)], text) +n = _countlines(text) +linenos = pycompat.rangelist(1, n + 1) +return _annotatedfile([fctx] * n, linenos, [False] * n, text) else: def decorate(text, fctx): -return ([annotateline(fctx=fctx)] * _countlines(text), text) +n = _countlines(text) +return _annotatedfile([fctx] * n, [False] * n, [False] * n, text) # This algorithm would prefer to be recursive, but Python is a # bit recursion-hostile. Instead we do an iterative @@ -501,8 +518,10 @@ def annotate(base, parents, linenumber=F hist[f] = curr del pcache[f] -lineattrs, text = hist[base] -return pycompat.ziplist(line
[PATCH 1 of 4] pycompat: name maplist() and ziplist() for better traceback message
# HG changeset patch # User Yuya Nishihara # Date 1520943734 -32400 # Tue Mar 13 21:22:14 2018 +0900 # Node ID aa35c6d7caef9ef9f48d0c9c831f9492c1421c45 # Parent 6aeb076b1321c540db6419fc48c8a3a552fb596b pycompat: name maplist() and ziplist() for better traceback message diff --git a/mercurial/pycompat.py b/mercurial/pycompat.py --- a/mercurial/pycompat.py +++ b/mercurial/pycompat.py @@ -65,8 +65,13 @@ if ispy3: if sysexecutable: sysexecutable = os.fsencode(sysexecutable) stringio = io.BytesIO -maplist = lambda *args: list(map(*args)) -ziplist = lambda *args: list(zip(*args)) + +def maplist(*args): +return list(map(*args)) + +def ziplist(*args): +return list(zip(*args)) + rawinput = input getargspec = inspect.getfullargspec ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
[PATCH 2 of 4] annotate: correct parameter name of decorate() function
# HG changeset patch # User Yuya Nishihara # Date 1520854628 -32400 # Mon Mar 12 20:37:08 2018 +0900 # Node ID 95af54712a25c298d5ee63c385f3d498250c1624 # Parent aa35c6d7caef9ef9f48d0c9c831f9492c1421c45 annotate: correct parameter name of decorate() function diff --git a/mercurial/dagop.py b/mercurial/dagop.py --- a/mercurial/dagop.py +++ b/mercurial/dagop.py @@ -442,12 +442,12 @@ def annotate(base, parents, linenumber=F """ if linenumber: -def decorate(text, rev): -return ([annotateline(fctx=rev, lineno=i) +def decorate(text, fctx): +return ([annotateline(fctx=fctx, lineno=i) for i in xrange(1, _countlines(text) + 1)], text) else: -def decorate(text, rev): -return ([annotateline(fctx=rev)] * _countlines(text), text) +def decorate(text, fctx): +return ([annotateline(fctx=fctx)] * _countlines(text), text) # This algorithm would prefer to be recursive, but Python is a # bit recursion-hostile. Instead we do an iterative diff --git a/tests/test-annotate.py b/tests/test-annotate.py --- a/tests/test-annotate.py +++ b/tests/test-annotate.py @@ -25,8 +25,8 @@ class AnnotateTests(unittest.TestCase): childdata = b'a\nb2\nc\nc2\nd\n' diffopts = mdiff.diffopts() -def decorate(text, rev): -return ([annotateline(fctx=rev, lineno=i) +def decorate(text, fctx): +return ([annotateline(fctx=fctx, lineno=i) for i in range(1, text.count(b'\n') + 1)], text) ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
[PATCH 4 of 4] annotate: drop linenumber flag from fctx.annotate() (API)
# HG changeset patch # User Yuya Nishihara # Date 1520947086 -32400 # Tue Mar 13 22:18:06 2018 +0900 # Node ID 854d59569873317764fb7ff68b7f0051585caed6 # Parent 1ce0d903cfa6e8db0112f86cc346751651db1f80 annotate: drop linenumber flag from fctx.annotate() (API) Now linenumber=True is fast enough to be enabled by default. diff --git a/mercurial/commands.py b/mercurial/commands.py --- a/mercurial/commands.py +++ b/mercurial/commands.py @@ -387,8 +387,8 @@ def annotate(ui, repo, *pats, **opts): continue fm = rootfm.nested('lines') -lines = fctx.annotate(follow=follow, linenumber=linenumber, - skiprevs=skiprevs, diffopts=diffopts) +lines = fctx.annotate(follow=follow, skiprevs=skiprevs, + diffopts=diffopts) if not lines: fm.end() continue diff --git a/mercurial/context.py b/mercurial/context.py --- a/mercurial/context.py +++ b/mercurial/context.py @@ -967,14 +967,13 @@ class basefilectx(object): return p[1] return filectx(self._repo, self._path, fileid=-1, filelog=self._filelog) -def annotate(self, follow=False, linenumber=False, skiprevs=None, - diffopts=None): -'''returns a list of tuples of ((ctx, number), line) for each line -in the file, where ctx is the filectx of the node where -that line was last changed; if linenumber parameter is true, number is -the line number at the first appearance in the managed file, otherwise, -number has a fixed value of False. -''' +def annotate(self, follow=False, skiprevs=None, diffopts=None): +"""Returns a list of tuples of (attr, line) for each line in the file + +- attr.fctx is the filectx of the node where that line was last changed +- attr.lineno is the line number at the first appearance in the managed + file +""" getlog = util.lrucachefunc(lambda x: self._repo.file(x)) def parents(f): @@ -1010,8 +1009,8 @@ class basefilectx(object): ac = cl.ancestors([base.rev()], inclusive=True) base._ancestrycontext = ac -return dagop.annotate(base, parents, linenumber=linenumber, - skiprevs=skiprevs, diffopts=diffopts) +return dagop.annotate(base, parents, skiprevs=skiprevs, + diffopts=diffopts) def ancestors(self, followfirst=False): visit = {} diff --git a/mercurial/dagop.py b/mercurial/dagop.py --- a/mercurial/dagop.py +++ b/mercurial/dagop.py @@ -383,6 +383,11 @@ def _countlines(text): return text.count("\n") return text.count("\n") + int(bool(text)) +def _decoratelines(text, fctx): +n = _countlines(text) +linenos = pycompat.rangelist(1, n + 1) +return _annotatedfile([fctx] * n, linenos, [False] * n, text) + def _annotatepair(parents, childfctx, child, skipchild, diffopts): r''' Given parent and child fctxes and annotate data for parents, for all lines @@ -450,22 +455,12 @@ def _annotatepair(parents, childfctx, ch child.skips[bk] = True return child -def annotate(base, parents, linenumber=False, skiprevs=None, diffopts=None): +def annotate(base, parents, skiprevs=None, diffopts=None): """Core algorithm for filectx.annotate() `parents(fctx)` is a function returning a list of parent filectxs. """ -if linenumber: -def decorate(text, fctx): -n = _countlines(text) -linenos = pycompat.rangelist(1, n + 1) -return _annotatedfile([fctx] * n, linenos, [False] * n, text) -else: -def decorate(text, fctx): -n = _countlines(text) -return _annotatedfile([fctx] * n, [False] * n, [False] * n, text) - # This algorithm would prefer to be recursive, but Python is a # bit recursion-hostile. Instead we do an iterative # depth-first search. @@ -502,7 +497,7 @@ def annotate(base, parents, linenumber=F visit.append(p) if ready: visit.pop() -curr = decorate(f.data(), f) +curr = _decoratelines(f.data(), f) skipchild = False if skiprevs is not None: skipchild = f._changeid in skiprevs diff --git a/mercurial/hgweb/webutil.py b/mercurial/hgweb/webutil.py --- a/mercurial/hgweb/webutil.py +++ b/mercurial/hgweb/webutil.py @@ -186,7 +186,7 @@ def difffeatureopts(req, ui, section): def annotate(req, fctx, ui): diffopts = difffeatureopts(req, ui, 'annotate') -return fctx.annotate(follow=True, linenumber=True, diffopts=diffopts) +return fctx.annotate(follow=True, diffopts=diffopts) def parents(ctx, hide=None): if isinstance(ctx, context.basefilectx): ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.or
Re: [PATCH V4] forget: add --dry-run mode
On Tue, 13 Mar 2018 15:43:02 +0800 Anton Shestakov wrote: > > +rejected = cmdutil.forget(ui, repo, m, prefix="", explicitonly=False, > > dryrun=dryrun)[0] > > This line is too long, don't forget to also run test-check-commit.t. I saw this already fixed, but I'd like to get this right. test-check-code.t is the test that would detect lines of code being too long (not *-commit.t), but running all of the test-check-*.t before sending patches is a good idea. Small issues can be fixed when reviewers queue patches, but not all of check-code.py (as an example) is style checks; some of the rules are important for compatibility (Python 2 vs 3, and running test suite on different OSes), and they are put there because they can be tricky to spot during manual review. ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
Bugzilla stats email
Hello, I've activated the weekly bugzilla stats email on a weekly basics for the mercurial-devel mailing-list. The mail comes from octo...@octobus.net with the subject "bugzilla weekly report". It's for the moment a text version of https://hgbzstats.octobus.net/. I presented it at the sprint and the feedback were good. I've got two improvements requests that are logged here: https://bitbucket.org/octobus/hgbzstats/issues?status=new&status=open, don't hesitate to create new issues and vote on most wanted ones, we will work on them as soon as possible. Cheers, Boris ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
bugzilla weekly report (2018-03-13)
Bug activity report, between 2018-03-06 and 2018-03-13 * urgent+: 4 bugs (1 added) * unconfirmed: 18 bugs (5 added) * new: 7 bugs * closed: 9 bugs * need example: 0 bugs * new details: 0 bugs * active: 31 bugs * long inactive: 5 bugs urgent+ --- Open of urgent or critical bugs. Found 4 bugs with our query (1 added). id summary --- (#5165) can't push long bookmark names with bundle2 (#5748) Unknown exception during commit (#5801) pure-python manifest code produces corrupt unsorted manifests (#5811) fsmonitor returns bogus stat tuples, breaking after cleanup in f unconfirmed --- Bugs with status 'unconfirmed'. Found 18 bugs with our query (5 added). id summary --- (#5592) Obsolete markers for root changes are not exchanged (#5747) Rebase should detect patch that has already been applied. (#5753) Support for inline clone bundles when cloning via ssh (#5766) pull --rebase aborts if working dir not clean even if nothing to (#5772) hg fold doesn't move bookmarks (#5773) evolve extension should specify progress units (#5774) Very slow performance when running commands and fsmonitor instal (#5776) Disabled path conflict checking for unknown files behavior is di (#5785) hg up -C should always fail. (#5792) include bookmarks in bundle2 file generation (#5807) Convert throws "ValueError: I/O operation on closed file" (#5808) `hg next` and `hg prev` do not respect commands.update.check (#5810) warning about overridden commands when both evolve and serveronl (#5813) pull --rebase via hgnested's npull doesn't rebase correctly (#5814) 4.5.2: test hang on NetBSD (#5815) ui.debug=True in a config file may prevent extensions from loadi (#5816) mq doesn't correctly block hg commit --amend on mq-managed commi (#5817) fold should respect experimental.evolve.allowdivergence new --- Bugs opened during the reporting period. Found 7 bugs with our query. id summary --- (#5811) fsmonitor returns bogus stat tuples, breaking after cleanup in f (#5812) paper theme uses inline javascript, making web.csp far less effe (#5813) pull --rebase via hgnested's npull doesn't rebase correctly (#5814) 4.5.2: test hang on NetBSD (#5815) ui.debug=True in a config file may prevent extensions from loadi (#5816) mq doesn't correctly block hg commit --amend on mq-managed commi (#5817) fold should respect experimental.evolve.allowdivergence closed -- Bugs closed during the reporting period. Found 9 bugs with our query. id summary --- (#2137) API: after adding changesets, repo.lookup() does not recognized (#4074) Huge performance issue committing update to large file (#5654) Help text for clone -r option is unclear (#5694) "hg evolve" does nothing on unstable parent, even though "hg evo (#5708) topic-ext: "hg previous" on an obsoleted revision fails unintent (#5779) The files command crashes with "-T ''{files}'" (#5793) Fix for #5675 made it impossible to share repositories containin (#5797) hg config: only 1 config option allowed (#5798) annotate output is broken if the file contains multiple CR in a need example Bugs with 'need_example' status and at least a new comment. Found 0 bugs with our query. id summary --- new details --- Bugs moved out of 'need_example' during the reporting period. Found 0 bugs with our query. id summary --- active -- All bugs with any activity during the reporting period. Found 31 bugs with our query. id summary --- (#2137) API: after adding changesets, repo.lookup() does not recognized (#3885) `hg grep --all -r REV` reports irrelevant diffs (#4074) Huge performance issue committing update to large file (#4318) unshelve refuses to apply on modified MQ pa
[PATCH V4] forget: add --dry-run mode
# HG changeset patch # User Sushil khanchi # Date 1520665399 -19800 # Sat Mar 10 12:33:19 2018 +0530 # Node ID 349b51e3bb04862ff7e516f57509ccd974e1b6a2 # Parent 4c71a26a4009d88590c9ae3d64a5912fd556d82e forget: add --dry-run mode diff -r 4c71a26a4009 -r 349b51e3bb04 mercurial/cmdutil.py --- a/mercurial/cmdutil.py Sun Mar 04 21:16:36 2018 -0500 +++ b/mercurial/cmdutil.py Sat Mar 10 12:33:19 2018 +0530 @@ -1996,7 +1996,7 @@ for subpath in ctx.substate: ctx.sub(subpath).addwebdirpath(serverpath, webconf) -def forget(ui, repo, match, prefix, explicitonly): +def forget(ui, repo, match, prefix, explicitonly, dryrun): join = lambda f: os.path.join(prefix, f) bad = [] badfn = lambda x, y: bad.append(x) or match.bad(x, y) @@ -2012,7 +2012,7 @@ sub = wctx.sub(subpath) try: submatch = matchmod.subdirmatcher(subpath, match) -subbad, subforgot = sub.forget(submatch, prefix) +subbad, subforgot = sub.forget(submatch, prefix, dryrun=dryrun) bad.extend([subpath + '/' + f for f in subbad]) forgot.extend([subpath + '/' + f for f in subforgot]) except error.LookupError: @@ -2039,7 +2039,7 @@ if ui.verbose or not match.exact(f): ui.status(_('removing %s\n') % match.rel(f)) -rejected = wctx.forget(forget, prefix) +rejected = wctx.forget(forget, prefix, dryrun=dryrun) bad.extend(f for f in rejected if f in match.files()) forgot.extend(f for f in forget if f not in rejected) return bad, forgot diff -r 4c71a26a4009 -r 349b51e3bb04 mercurial/commands.py --- a/mercurial/commands.py Sun Mar 04 21:16:36 2018 -0500 +++ b/mercurial/commands.py Sat Mar 10 12:33:19 2018 +0530 @@ -2036,7 +2036,10 @@ with ui.formatter('files', opts) as fm: return cmdutil.files(ui, ctx, m, fm, fmt, opts.get('subrepos')) -@command('^forget', walkopts, _('[OPTION]... FILE...'), inferrepo=True) +@command( +'^forget', +walkopts + dryrunopts, +_('[OPTION]... FILE...'), inferrepo=True) def forget(ui, repo, *pats, **opts): """forget the specified files on the next commit @@ -2071,7 +2074,9 @@ raise error.Abort(_('no files specified')) m = scmutil.match(repo[None], pats, opts) -rejected = cmdutil.forget(ui, repo, m, prefix="", explicitonly=False)[0] +dryrun = opts.get(r'dry_run') +rejected = cmdutil.forget(ui, repo, m, prefix="", + explicitonly=False, dryrun=dryrun)[0] return rejected and 1 or 0 @command( diff -r 4c71a26a4009 -r 349b51e3bb04 mercurial/context.py --- a/mercurial/context.py Sun Mar 04 21:16:36 2018 -0500 +++ b/mercurial/context.py Sat Mar 10 12:33:19 2018 +0530 @@ -1564,7 +1564,7 @@ ds.add(f) return rejected -def forget(self, files, prefix=""): +def forget(self, files, prefix="", dryrun=False): with self._repo.wlock(): ds = self._repo.dirstate uipath = lambda f: ds.pathto(pathutil.join(prefix, f)) @@ -1573,10 +1573,11 @@ if f not in self._repo.dirstate: self._repo.ui.warn(_("%s not tracked!\n") % uipath(f)) rejected.append(f) -elif self._repo.dirstate[f] != 'a': -self._repo.dirstate.remove(f) -else: -self._repo.dirstate.drop(f) +elif not dryrun: +if self._repo.dirstate[f] != 'a': +self._repo.dirstate.remove(f) +else: +self._repo.dirstate.drop(f) return rejected def undelete(self, list): diff -r 4c71a26a4009 -r 349b51e3bb04 mercurial/subrepo.py --- a/mercurial/subrepo.py Sun Mar 04 21:16:36 2018 -0500 +++ b/mercurial/subrepo.py Sat Mar 10 12:33:19 2018 +0530 @@ -811,9 +811,10 @@ return ctx.walk(match) @annotatesubrepoerror -def forget(self, match, prefix): +def forget(self, match, prefix, dryrun): return cmdutil.forget(self.ui, self._repo, match, - self.wvfs.reljoin(prefix, self._path), True) + self.wvfs.reljoin(prefix, self._path), + True, dryrun=dryrun) @annotatesubrepoerror def removefiles(self, matcher, prefix, after, force, subrepos, warnings): diff -r 4c71a26a4009 -r 349b51e3bb04 tests/test-commit.t --- a/tests/test-commit.t Sun Mar 04 21:16:36 2018 -0500 +++ b/tests/test-commit.t Sat Mar 10 12:33:19 2018 +0530 @@ -832,3 +832,18 @@ $ cd .. +test --dry-run mode in forget + + $ hg init testdir_forget + $ cd testdir_forget + $ echo foo > foo + $ hg add foo + $ hg commit -m "foo" + $ hg forget foo --dry-run -v + removing foo + $ hg diff + $ hg forget not_exist -n + not_exist: $ENOENT$ + [1] + + $ cd .. _
Re: [PATCH V4] forget: add --dry-run mode
On Tue, 13 Mar 2018 12:17:41 +0530 Sushil khanchi wrote: > # HG changeset patch > # User Sushil khanchi > # Date 1520665399 -19800 > # Sat Mar 10 12:33:19 2018 +0530 > # Node ID 4134d1f103d8e72e80920cd89cf3d3f576e6a2b5 > # Parent 4c71a26a4009d88590c9ae3d64a5912fd556d82e > forget: add --dry-run mode > > diff -r 4c71a26a4009 -r 4134d1f103d8 mercurial/cmdutil.py > --- a/mercurial/cmdutil.pySun Mar 04 21:16:36 2018 -0500 > +++ b/mercurial/cmdutil.pySat Mar 10 12:33:19 2018 +0530 > @@ -1996,7 +1996,7 @@ > for subpath in ctx.substate: > ctx.sub(subpath).addwebdirpath(serverpath, webconf) > > -def forget(ui, repo, match, prefix, explicitonly): > +def forget(ui, repo, match, prefix, explicitonly, dryrun): > join = lambda f: os.path.join(prefix, f) > bad = [] > badfn = lambda x, y: bad.append(x) or match.bad(x, y) > @@ -2012,7 +2012,7 @@ > sub = wctx.sub(subpath) > try: > submatch = matchmod.subdirmatcher(subpath, match) > -subbad, subforgot = sub.forget(submatch, prefix) > +subbad, subforgot = sub.forget(submatch, prefix, dryrun=dryrun) > bad.extend([subpath + '/' + f for f in subbad]) > forgot.extend([subpath + '/' + f for f in subforgot]) > except error.LookupError: > @@ -2039,7 +2039,7 @@ > if ui.verbose or not match.exact(f): > ui.status(_('removing %s\n') % match.rel(f)) > > -rejected = wctx.forget(forget, prefix) > +rejected = wctx.forget(forget, prefix, dryrun=dryrun) > bad.extend(f for f in rejected if f in match.files()) > forgot.extend(f for f in forget if f not in rejected) > return bad, forgot > diff -r 4c71a26a4009 -r 4134d1f103d8 mercurial/commands.py > --- a/mercurial/commands.py Sun Mar 04 21:16:36 2018 -0500 > +++ b/mercurial/commands.py Sat Mar 10 12:33:19 2018 +0530 > @@ -2036,7 +2036,10 @@ > with ui.formatter('files', opts) as fm: > return cmdutil.files(ui, ctx, m, fm, fmt, opts.get('subrepos')) > > -@command('^forget', walkopts, _('[OPTION]... FILE...'), inferrepo=True) > +@command( > +'^forget', > +walkopts + dryrunopts, > +_('[OPTION]... FILE...'), inferrepo=True) > def forget(ui, repo, *pats, **opts): > """forget the specified files on the next commit > > @@ -2071,7 +2074,8 @@ > raise error.Abort(_('no files specified')) > > m = scmutil.match(repo[None], pats, opts) > -rejected = cmdutil.forget(ui, repo, m, prefix="", explicitonly=False)[0] > +dryrun = opts.get(r'dry_run') > +rejected = cmdutil.forget(ui, repo, m, prefix="", explicitonly=False, > dryrun=dryrun)[0] This line is too long, don't forget to also run test-check-commit.t. > return rejected and 1 or 0 > > @command( > diff -r 4c71a26a4009 -r 4134d1f103d8 mercurial/context.py > --- a/mercurial/context.pySun Mar 04 21:16:36 2018 -0500 > +++ b/mercurial/context.pySat Mar 10 12:33:19 2018 +0530 > @@ -1564,7 +1564,7 @@ > ds.add(f) > return rejected > > -def forget(self, files, prefix=""): > +def forget(self, files, prefix="", dryrun=False): > with self._repo.wlock(): > ds = self._repo.dirstate > uipath = lambda f: ds.pathto(pathutil.join(prefix, f)) > @@ -1573,10 +1573,11 @@ > if f not in self._repo.dirstate: > self._repo.ui.warn(_("%s not tracked!\n") % uipath(f)) > rejected.append(f) > -elif self._repo.dirstate[f] != 'a': > -self._repo.dirstate.remove(f) > -else: > -self._repo.dirstate.drop(f) > +elif not dryrun: > +if self._repo.dirstate[f] != 'a': > +self._repo.dirstate.remove(f) > +else: > +self._repo.dirstate.drop(f) > return rejected > > def undelete(self, list): > diff -r 4c71a26a4009 -r 4134d1f103d8 mercurial/subrepo.py > --- a/mercurial/subrepo.pySun Mar 04 21:16:36 2018 -0500 > +++ b/mercurial/subrepo.pySat Mar 10 12:33:19 2018 +0530 > @@ -811,9 +811,10 @@ > return ctx.walk(match) > > @annotatesubrepoerror > -def forget(self, match, prefix): > +def forget(self, match, prefix, dryrun): > return cmdutil.forget(self.ui, self._repo, match, > - self.wvfs.reljoin(prefix, self._path), True) > + self.wvfs.reljoin(prefix, self._path), > + True, dryrun=dryrun) > > @annotatesubrepoerror > def removefiles(self, matcher, prefix, after, force, subrepos, warnings): > diff -r 4c71a26a4009 -r 4134d1f103d8 tests/test-commit.t > --- a/tests/test-commit.t Sun Mar 04 21:16:36 2018 -0500 > +++ b/tests/test-commit.t Sat Mar 10 12:33:19 2018 +0530 > @@ -832,3 +832,15 @@ > >$ cd .. > > +# test -
mercurial@36844: new changeset (1 on stable)
New changeset (1 on stable) in mercurial: https://www.mercurial-scm.org/repo/hg/rev/eeb87b24aea7 changeset: 36844:eeb87b24aea7 branch: stable tag: tip parent: 36759:9639c433be54 user:Yuya Nishihara date:Sun Mar 11 20:10:38 2018 +0900 summary: amend: abort if unresolved merge conflicts found (issue5805) -- Repository URL: https://www.mercurial-scm.org/repo/hg ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
[PATCH evolve-ext V3] obsdiscovery: include units in ui.progress() calls (issue5773)
# HG changeset patch # User Anton Shestakov # Date 1519388837 -28800 # Fri Feb 23 20:27:17 2018 +0800 # Node ID f30a4131c6f28f355af2c1259632399e05dfca07 # Parent 1f0c88a9dd1cdf11d9eb8db48cc5e6e70022230b obsdiscovery: include units in ui.progress() calls (issue5773) diff --git a/hgext3rd/evolve/obsdiscovery.py b/hgext3rd/evolve/obsdiscovery.py --- a/hgext3rd/evolve/obsdiscovery.py +++ b/hgext3rd/evolve/obsdiscovery.py @@ -95,7 +95,8 @@ def findcommonobsmarkers(ui, local, remo common = set() undecided = set(probeset) totalnb = len(undecided) -ui.progress(_("comparing with other"), 0, total=totalnb) +ui.progress(_("comparing with other"), 0, total=totalnb, +unit=_("changesets")) _takefullsample = setdiscovery._takefullsample if remote.capable('_evoext_obshash_1'): getremotehash = remote.evoext_obshash1 @@ -114,7 +115,7 @@ def findcommonobsmarkers(ui, local, remo roundtrips += 1 ui.progress(_("comparing with other"), totalnb - len(undecided), -total=totalnb) +total=totalnb, unit=_("changesets")) ui.debug("query %i; still undecided: %i, sample size is: %i\n" % (roundtrips, len(undecided), len(sample))) # indices between sample and externalized version must match @@ -175,7 +176,8 @@ def findmissingrange(ui, local, remote, local.obsstore.rangeobshashcache.update(local) querycount = 0 -ui.progress(_("comparing obsmarker with other"), querycount) +ui.progress(_("comparing obsmarker with other"), querycount, +unit=_("queries")) overflow = [] while sample or overflow: if overflow: @@ -230,7 +232,8 @@ def findmissingrange(ui, local, remote, addentry(new) assert nbsample == nbreplies querycount += 1 -ui.progress(_("comparing obsmarker with other"), querycount) +ui.progress(_("comparing obsmarker with other"), querycount, +unit=_("queries")) ui.progress(_("comparing obsmarker with other"), None) local.obsstore.rangeobshashcache.save(local) duration = timer() - starttime @@ -771,7 +774,8 @@ def _obsrelsethashtree(repo, encodeonema cache = [] unfi = repo.unfiltered() markercache = {} -repo.ui.progress(_("preparing locally"), 0, total=len(unfi)) +repo.ui.progress(_("preparing locally"), 0, total=len(unfi), + unit=_("changesets")) for i in unfi: ctx = unfi[i] entry = 0 @@ -801,7 +805,8 @@ def _obsrelsethashtree(repo, encodeonema cache.append((ctx.node(), sha.digest())) else: cache.append((ctx.node(), node.nullid)) -repo.ui.progress(_("preparing locally"), i, total=len(unfi)) +repo.ui.progress(_("preparing locally"), i, total=len(unfi), + unit=_("changesets")) repo.ui.progress(_("preparing locally"), None) return cache ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
Re: [PATCH STABLE] hgweb: garbage collect on every request
> On Mar 12, 2018, at 23:18, Anton Shestakov wrote: > > On Mon, 12 Mar 2018 13:17:21 -0700 > Gregory Szorc wrote: > >> # HG changeset patch >> # User Gregory Szorc >> # Date 1520885700 25200 >> # Mon Mar 12 13:15:00 2018 -0700 >> # Branch stable >> # Node ID 46905416a5f47e9e46aa2db0e2e4f45e7414c979 >> # Parent 9639c433be54191b4136b48fe70fc8344d2b5db2 >> hgweb: garbage collect on every request > > Queued, thanks. > > Unfortunately, this patch doesn't help a lot when evolve extension is > enabled: until I turned it off to test, hgweb consistently consumed > 200MB more on every request (on hg-committed), despite gc.collect(). No > idea why. :( My guess is evolve is storing a reference to a repo or some other large data structure in a module-level variable. Leaks like that are pretty easy to spot using a tool like guppy’s heap snapshots. ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel