Sat, 14 Apr 2018 11:46:08 -0700 wireprotov2: establish a type for representing command response
Gregory Szorc <gregory.szorc@gmail.com> [Sat, 14 Apr 2018 11:46:08 -0700] rev 37720
wireprotov2: establish a type for representing command response It will be desirable to have a higher-level type for representing command responses. This will allow us to do nicer things. For now, the instance encapsulates existing logic. It is still a bit primitive. But we're slowly making things better. Version 1 protocols have a wrapping layer that decodes the raw string data into a data structure and that data structure is sent to the future. Version 2 doesn't yet have this layer and the future is receiving the raw wire response. Hence why debugcommands needed to be taught about the response type. Differential Revision: https://phab.mercurial-scm.org/D3380
Sat, 14 Apr 2018 11:50:19 -0700 wireprotov2: move response handling out of httppeer
Gregory Szorc <gregory.szorc@gmail.com> [Sat, 14 Apr 2018 11:50:19 -0700] rev 37719
wireprotov2: move response handling out of httppeer And fix some bugs while we're here. The code for processing response data from the unified framing protocol is mostly peer agnostic. The peer-specific bits are the configuration of the client reactor and how I/O is performed. I initially implemented things in httppeer for expediency. This commit establishes a module for holding the peer API level code for the framing based protocol. Inside this module we have a class to help coordinate higher-level activities, such as managing response object. The client handler bits could be rolled into clientreactor. However, I want clientreactor to be sans I/O and I want it to only be concerned with protocol-level details, not higher-level concepts like how protocol events are converted into peer API concepts. I want clientreactor to receive a frame and then tell the caller what should probably be done about it. If we start putting things like future resolution into clientreactor, we'll constrain how the protocol can be used (e.g. by requiring futures). The new code is loosely based on what was in httppeer before. I changed things a bit around response handling. We now buffer the entire response "body" and then handle it as one atomic unit. This fixed a bug around decoding CBOR data that spanned multiple frames. I also fixed an off-by-one bug where we failed to read a single byte CBOR value at the end of the stream. That's why tests have changed. The new state of httppeer is much cleaner. It is largely agnostic about framing protocol implementation details. That's how it should be: the framing protocol is designed to be largely transport agnostic. We want peers merely putting bytes on the wire and telling the framing protocol where to read response data from. There's still a bit of work to be done here, especially for representing responses. But at least we're a step closer to having a higher-level peer interface that can be plugged into the SSH peer someday. I initially added this class to wireprotoframing. However, we'll eventually need version 2 specific functions to convert CBOR responses into data structures expected by the code calling commands. This needs to live somewhere. Since that code would be shared across peers, we need a common module. We have wireprotov1peer for the equivalent version 1 code. So I decided to establish wireprotov2peer. Differential Revision: https://phab.mercurial-scm.org/D3379
Sat, 14 Apr 2018 11:49:57 -0700 debugcommands: ability to suppress logging of handshake
Gregory Szorc <gregory.szorc@gmail.com> [Sat, 14 Apr 2018 11:49:57 -0700] rev 37718
debugcommands: ability to suppress logging of handshake The tests for calling wire protocol commands were getting quite verbose because they included the results of the capabilities request. Furthermore, it was annoying to have to update several tests every time the capabilities response changed. The only tests that really care about the low-level details of the capabilities requests are those testing the protocol handshake. And those are mostly not instantiating peer instances or are contained to limited files. This commit adds an option to `hg debugwireproto` to suppress logging of the handshake. The shell helper function to perform HTTP tests has been updated to use this by default. Lots of excessive test output has gone away. Differential Revision: https://phab.mercurial-scm.org/D3378
Sat, 14 Apr 2018 09:57:44 -0700 hg: pass command intents to repo/peer creation (API)
Gregory Szorc <gregory.szorc@gmail.com> [Sat, 14 Apr 2018 09:57:44 -0700] rev 37717
hg: pass command intents to repo/peer creation (API) The previous commit introduced a mechanism to declare command intents. This commit changes the repository and peer instantiation mechanism so the intents are passed down to each repository and peer type so they can do with them whatever they please. Currently, nobody does anything with any intent. Differential Revision: https://phab.mercurial-scm.org/D3377
Sat, 14 Apr 2018 09:23:48 -0700 registrar: replace "cmdtype" with an intent-based mechanism (API)
Gregory Szorc <gregory.szorc@gmail.com> [Sat, 14 Apr 2018 09:23:48 -0700] rev 37716
registrar: replace "cmdtype" with an intent-based mechanism (API) Commands perform varied actions and repositories vary in their capabilities. Historically, the .hg/requires file has been used to lock out clients lacking a requirement. But this is a very heavy-handed approach and is typically reserved for cases where the on-disk storage format changes and we want to prevent incompatible clients from operating on a repo. Outside of the .hg/requires file, we tend to deal with things like optional, extension-provided features via checking at call sites. We'll either have checks in core or extensions will monkeypatch functions in core disabling incompatible features, enabling new features, etc. Things are somewhat tolerable today. But once we introduce alternate storage backends with varying support for repository features and vastly different modes of behavior, the current model will quickly grow unwieldy. For example, the implementation of the "simple store" required a lot of hacks to deal with stripping and verify because various parts of core assume things are implemented a certain way. Partial clone will require new ways of modeling file data retrieval, because we can no longer assume that all file data is already local. In this new world, some commands might not make any sense for certain types of repositories. What we need is a mechanism to affect the construction of repository (and eventually peer) instances so the requirements/capabilities needed for the current operation can be taken into account. "Current operation" can almost certainly be defined by a command. So it makes sense for commands to declare their intended actions. This commit introduces the "intents" concept on the command registrar. "intents" captures a set of strings that declare actions that are anticipated to be taken, requirements the repository must possess, etc. These intents will be passed into hg.repo(), which will pass them into localrepository, where they can be used to influence the object being created. Some use cases for this include: * For read-only intents, constructing a repository object that doesn't expose methods that can mutate the repository. Its VFS instances don't even allow opening a file with write access. * For read-only intents, constructing a repository object without cache invalidation logic. If the repo never changes during its lifetime, nothing ever needs to be invalidated and we don't need to do expensive things like verify the changelog's hidden revisions state is accurate every time we access repo.changelog. * We can automatically hide commands from `hg help` when the current repository doesn't provide that command. For example, an alternate storage backend may not support `hg commit`, so we can hide that command or anything else that would perform local commits. We already kind of had an "intents" mechanism on the registrar in the form of "cmdtype." However, it was never used. And it was limited to a single value. We really need something that supports multiple intents. And because intents may be defined by extensions and at this point are advisory, I think it is best to define them in a set rather than as separate arguments/attributes on the command. Differential Revision: https://phab.mercurial-scm.org/D3376
Sat, 14 Apr 2018 11:20:38 -0400 cleanup: polyfill assertRaisesRegex so we can avoid assertRaisesRegexp
Augie Fackler <augie@google.com> [Sat, 14 Apr 2018 11:20:38 -0400] rev 37715
cleanup: polyfill assertRaisesRegex so we can avoid assertRaisesRegexp The latter is deprecated on Python 3.7 and causes our tests to fail due to the warning. Differential Revision: https://phab.mercurial-scm.org/D3375
Sat, 14 Apr 2018 11:07:24 -0400 tests: add b prefixes to test-hg-parseurl.py
Augie Fackler <augie@google.com> [Sat, 14 Apr 2018 11:07:24 -0400] rev 37714
tests: add b prefixes to test-hg-parseurl.py Now passes on Python 3. Differential Revision: https://phab.mercurial-scm.org/D3374
Sat, 14 Apr 2018 11:04:58 -0400 tests: port test-hg-parseurl.py to unittest
Augie Fackler <augie@google.com> [Sat, 14 Apr 2018 11:04:58 -0400] rev 37713
tests: port test-hg-parseurl.py to unittest Differential Revision: https://phab.mercurial-scm.org/D3373
Sat, 14 Apr 2018 01:12:55 -0400 hgwebdir: un-bytes the env dict before re-parsing env
Augie Fackler <augie@google.com> [Sat, 14 Apr 2018 01:12:55 -0400] rev 37712
hgwebdir: un-bytes the env dict before re-parsing env Not the most elegant, but it restores test-subrepo-deep-nested-change.t to passing on Python 3. Differential Revision: https://phab.mercurial-scm.org/D3367
Sat, 14 Apr 2018 16:36:15 -0700 cborutil: implement support for streaming encoding, bytestring decoding
Gregory Szorc <gregory.szorc@gmail.com> [Sat, 14 Apr 2018 16:36:15 -0700] rev 37711
cborutil: implement support for streaming encoding, bytestring decoding The vendored cbor2 package is... a bit disappointing. On the encoding side, it insists that you pass it something with a write() to send data to. That means if you want to emit data to a generator, you have to construct an e.g. io.BytesIO(), write() to it, then get the data back out. There can be non-trivial overhead involved. The encoder also doesn't support indefinite types - bytestrings, arrays, and maps that don't have a known length. Again, this is really unfortunate because it requires you to buffer the entire source and destination in memory to encode large things. On the decoding side, it supports reading indefinite length types. But it buffers them completely before returning. More sadness. This commit implements "streaming" encoders for various CBOR types. Encoding emits a generator of hunks. So you can efficiently stream encoded data elsewhere. It also implements support for emitting indefinite length bytestrings, arrays, and maps. On the decoding side, we only implement support for decoding an indefinite length bytestring from a file object. It will emit a generator of raw chunks from the source. I didn't want to reinvent so many wheels. But profiling the wire protocol revealed that the overhead of constructing io.BytesIO() instances to temporarily hold results has a non-trivial overhead. We're talking >15% of execution time for operations like "transfer the fulltexts of all files in a revision." So I can justify this effort. Fortunately, CBOR is a relatively straightforward format. And we have a reference implementation in the repo we can test against. Differential Revision: https://phab.mercurial-scm.org/D3303
(0) -30000 -10000 -3000 -1000 -300 -100 -10 +10 +100 +300 +1000 +3000 +10000 tip