Sat, 10 Mar 2018 18:42:00 -0800 hgweb: refactor 304 handling code
Gregory Szorc <gregory.szorc@gmail.com> [Sat, 10 Mar 2018 18:42:00 -0800] rev 36884
hgweb: refactor 304 handling code We had generic code in wsgirequest for handling HTTP 304 responses. We also had a special case for it in the catch all exception handler in the WSGI application. We only ever raise 304 in one place. So, we don't need to treat it specially in the catch all exception handler. But it is useful to validate behavior of 304 responses. We port the code that sends a 304 to use the new response API. We then move the code for screening 304 sanity into the new response API. As part of doing so, we discovered that we would send Content-Length: 0. This is not allowed. So, we fix our response code to not emit that header for empty response bodies. Differential Revision: https://phab.mercurial-scm.org/D2794
Sat, 10 Mar 2018 18:19:27 -0800 hgweb: transition permissions hooks to modern request type (API)
Gregory Szorc <gregory.szorc@gmail.com> [Sat, 10 Mar 2018 18:19:27 -0800] rev 36883
hgweb: transition permissions hooks to modern request type (API) We're trying to remove ``wsgirequest``. The permissions hooks don't do anything they can't do with our new request type. So let's pass that in. This was the last use of ``wsgirequest`` in the wire protocol code! .. api:: hgweb.hgweb_mod.permhooks no longer take a ``wsgirequest`` instance as an argument. Differential Revision: https://phab.mercurial-scm.org/D2793
Sat, 10 Mar 2018 20:16:20 -0800 hgweb: port archive command to modern response API
Gregory Szorc <gregory.szorc@gmail.com> [Sat, 10 Mar 2018 20:16:20 -0800] rev 36882
hgweb: port archive command to modern response API Well, I tried to go with PEP 3333's recommendations and only allow our WSGI application to emit data via a response generator. Unfortunately, the "archive" command calls into the zipfile and tarfile modules and these operator on file objects and must send their data to an object with write(). There's no easy way turn these write() calls into a generator. So, we teach our response type how to expose a file object like object that can be used to write() output. We try to keep the API consistent with how things work currently: callers must call a setbody*(), then sendresponse() to trigger sending of headers, and only then can they get a handle on the object to perform writing. This required overloading the return value of @webcommand functions even more. Fortunately, we're almost completely ported off the legacy API. So we should be able to simplify matters in the near future. A test relying on this functionality has also been updated to use the new API. Differential Revision: https://phab.mercurial-scm.org/D2792
Sat, 10 Mar 2018 16:17:51 -0800 hgweb: refactor fake file object proxy for archiving
Gregory Szorc <gregory.szorc@gmail.com> [Sat, 10 Mar 2018 16:17:51 -0800] rev 36881
hgweb: refactor fake file object proxy for archiving Python's zip file writer operates on a file object. When doing work, it periodically calls write(), flush(), and tell() on that object. In WSGI contexts, the start_response function returns a write() function. That's a function to write data, not a full file object. So, when the archival code was first introduced in 2b03c6733efa in 2006, someone invented a proxy "tellable" type that wrapped a file object like object and kept track of write count so it could implement tell() and satisfy zipfile's needs. When our archival code runs, it attempts to tell() the destination and if that fails, converts it to a "tellable" instance. Our WSGI application passes the "wsgirequest" instance to the archival function. It fails the tell() test and is converted to a "tellable." It's worth noting that "wsgirequest" implements flush(), so "tellable" doesn't. This hackery all seems very specific to the WSGI code. So this commit moves the "tellable" type and the conversion of the destination file object into the WSGI code. There's a chance some other caller may be passing a file object like object that doesn't implement tell(). But I doubt it. As part of the refactor, our new type implements flush() and doesn't implement __getattr__. Given the intended limited use of this type, I want things to fail fast if there is an attempt to access attributes because I think it is important to document which attributes are being used for what purposes. Differential Revision: https://phab.mercurial-scm.org/D2791
Sat, 10 Mar 2018 16:27:01 -0800 tests: additional test coverage of archive web command
Gregory Szorc <gregory.szorc@gmail.com> [Sat, 10 Mar 2018 16:27:01 -0800] rev 36880
tests: additional test coverage of archive web command This command is special in a few ways. First, it is the only command using the write() function from WSGI's start_response() function. Second, it is setting a custom content-disposition header. We change the test so it prints out full details of the HTTP response. We also save the response body to a file so we can verify its size and hash. The hash check will help ensure that archive generation is deterministic. Differential Revision: https://phab.mercurial-scm.org/D2790
Sat, 10 Mar 2018 15:46:29 -0800 hgweb: port static file handling to new response API
Gregory Szorc <gregory.szorc@gmail.com> [Sat, 10 Mar 2018 15:46:29 -0800] rev 36879
hgweb: port static file handling to new response API hgwebdir_mod hasn't received as much porting effort. So we had to do some minor plumbing to get it to match hgweb_mod and to support the new response object. Differential Revision: https://phab.mercurial-scm.org/D2789
Sat, 10 Mar 2018 15:37:29 -0800 hgweb: remove one-off routing for file?style=raw
Gregory Szorc <gregory.szorc@gmail.com> [Sat, 10 Mar 2018 15:37:29 -0800] rev 36878
hgweb: remove one-off routing for file?style=raw Now that both functions are using the same API, we can unify how the command is called and perform command-specific behavior in the command itself instead of in the high-level router. Differential Revision: https://phab.mercurial-scm.org/D2788
Sat, 10 Mar 2018 20:36:34 -0800 hgweb: port most @webcommand to use modern response type
Gregory Szorc <gregory.szorc@gmail.com> [Sat, 10 Mar 2018 20:36:34 -0800] rev 36877
hgweb: port most @webcommand to use modern response type This only focused on porting the return value. raw file requests are wonky because they go through a separate code path at the dispatch layer. Now that everyone is using the same API, we could clean this up. It's worth noting that wsgirequest.respond() allows sending the Content-Disposition header, but the only user of that feature was removed as part of this change (with the setting of the header now being performed inline). A few @webcommand are not as straightforward as the others and they have not been ported yet. Differential Revision: https://phab.mercurial-scm.org/D2787
Sat, 10 Mar 2018 17:02:57 -0800 hgweb: support using new response object for web commands
Gregory Szorc <gregory.szorc@gmail.com> [Sat, 10 Mar 2018 17:02:57 -0800] rev 36876
hgweb: support using new response object for web commands We have a "requestcontext" type for holding state for the current request. Why we pass in the wsgirequest and templater instance to @webcommand functions, I don't know. I like the idea of standardizing on using "requestcontext" for passing all state to @webcommand functions because that scales well without API changes every time you want to pass a new piece of data. So, we add our new request and response instances to "requestcontext" so @webcommand functions can access them. We also teach our command dispatcher to recognize a new calling convention. Instead of returning content from the @webcommand function, we return our response object. This signals that this response object is to be used for sending output. The keyword extension was wrapping various @webcommand and assuming the output was iterable, so we had to teach it about the new calling convention. To prove everything works, we convert the "filelog" @webcommand to use the new convention. The new calling convention is a bit wonky. I intend to improve this once all commands are ported to use the new response object. Differential Revision: https://phab.mercurial-scm.org/D2786
Sat, 10 Mar 2018 14:19:27 -0800 hgweb: inline caching() and port to modern mechanisms
Gregory Szorc <gregory.szorc@gmail.com> [Sat, 10 Mar 2018 14:19:27 -0800] rev 36875
hgweb: inline caching() and port to modern mechanisms We only had one consumer of this simple function. While it could be a generic function, let's not over abstract the code. As part of inlining, we port it off wsgirequest, fix some Python 3 issues, and set a response header on our new response object so it is ready once we start using it to send responses. Differential Revision: https://phab.mercurial-scm.org/D2785
Sat, 10 Mar 2018 14:06:58 -0800 hgweb: expose repo name on parsedrequest
Gregory Szorc <gregory.szorc@gmail.com> [Sat, 10 Mar 2018 14:06:58 -0800] rev 36874
hgweb: expose repo name on parsedrequest I'm not a fan of doing this because I want to find a better solution to the REPO_NAME hack. But this change gets us a few steps closer to eliminating use of wsgirequest. We can worry about fixing REPO_NAME once wsgirequest is gone. Differential Revision: https://phab.mercurial-scm.org/D2784
Sat, 10 Mar 2018 14:00:40 -0800 hgweb: expose URL scheme and REMOTE_* attributes
Gregory Szorc <gregory.szorc@gmail.com> [Sat, 10 Mar 2018 14:00:40 -0800] rev 36873
hgweb: expose URL scheme and REMOTE_* attributes These are consulted by the HTTP wire protocol handler by reading from the env dict. Let's expose them as attributes instead. With the wire protocol handler updates to use the new attributes, we no longer have any consumers of the legacy wsgirequest type in the wire protocol code (outside of a proxied call to the permissions checker). So, we remove most references to it. Differential Revision: https://phab.mercurial-scm.org/D2783
Sat, 10 Mar 2018 12:31:11 -0800 hgweb: remove wsgirequest.form (API)
Gregory Szorc <gregory.szorc@gmail.com> [Sat, 10 Mar 2018 12:31:11 -0800] rev 36872
hgweb: remove wsgirequest.form (API) Now that everything is ported to consume from parsedrequest.qsparams, we no longer have a need for wsgirequest.form. Let's remove all references to it. .. api:: The WSGI request object no longer exposes a ``form`` attribute containing parsed query string data. Use the ``qsparams`` attribute instead. Differential Revision: https://phab.mercurial-scm.org/D2782
Sat, 10 Mar 2018 12:36:36 -0800 hgweb: perform all parameter lookup via qsparams
Gregory Szorc <gregory.szorc@gmail.com> [Sat, 10 Mar 2018 12:36:36 -0800] rev 36871
hgweb: perform all parameter lookup via qsparams I think I managed to update all call sites using wsgirequest.form to use parsedrequest.qsparams. Since behavior of qsparams is to retrieve last value, behavior will change if a parameter was specified multiple times. But I think this is acceptable. I'm not a fan of the `req.req.qsparams` pattern. And some of the modified code could be written better. But I was aiming for a straight port with this change. Cleanup can come later. Differential Revision: https://phab.mercurial-scm.org/D2781
Sat, 10 Mar 2018 12:11:26 -0800 hgweb: set variables in qsparams
Gregory Szorc <gregory.szorc@gmail.com> [Sat, 10 Mar 2018 12:11:26 -0800] rev 36870
hgweb: set variables in qsparams We currently mutate wsgireq.form in a few places. Since it is independent from req.qsparams, we will need to make changes on req.qsparams as well before consumers can use qsparams. So let's do that. Eventually, we'll delete wsgireq.form and all references to it. Differential Revision: https://phab.mercurial-scm.org/D2780
Sat, 10 Mar 2018 11:46:52 -0800 hgweb: use our new request object for "style" parameter
Gregory Szorc <gregory.szorc@gmail.com> [Sat, 10 Mar 2018 11:46:52 -0800] rev 36869
hgweb: use our new request object for "style" parameter The "style" parameter is kind of wonky because it is explicitly set and has lookups in random locations. Let's port it to qsparams first because it isn't straightforward. There is subtle change in behavior. But I don't think it is worth calling out in a BC. Our multidict's __getitem__ returns the last set value for a key, not the first. So if the query string set a variable multiple times, before we would get the first value and now we would get the last value. It makes no sense to specify these things multiple times. And I think last write wins is more sensible than first write wins. Differential Revision: https://phab.mercurial-scm.org/D2779
Sat, 10 Mar 2018 12:35:38 -0800 hgweb: use a multidict for holding query string parameters
Gregory Szorc <gregory.szorc@gmail.com> [Sat, 10 Mar 2018 12:35:38 -0800] rev 36868
hgweb: use a multidict for holding query string parameters My intention with refactoring the WSGI code was to make it easier to read. I initially wanted to vendor and use WebOb, because it seems to be a pretty reasonable abstraction layer for WSGI. However, it isn't using relative imports and I didn't want to deal with the hassle of patching it. But that doesn't mean we can't use good ideas from WebOb. WebOb has a "multidict" data structure for holding parsed query string and POST form data. It quacks like a dict but allows you to store multiple values for each key. It offers mechanisms to return just one value, all values, or return 1 value asserting that only 1 value is set. I quite like its API. This commit implements a read-only "multidict" in the spirit of WebOb's multidict. We replace the query string attributes of our parsed request with an instance of it. Differential Revision: https://phab.mercurial-scm.org/D2776
Sat, 10 Mar 2018 11:23:05 -0800 hgweb: create dedicated type for WSGI responses
Gregory Szorc <gregory.szorc@gmail.com> [Sat, 10 Mar 2018 11:23:05 -0800] rev 36867
hgweb: create dedicated type for WSGI responses We have refactored the request side of WSGI processing into a dedicated type. Now let's do the same thing for the response side. We invent a ``wsgiresponse`` type. It takes an instance of a request (for consulation) and the WSGI application's "start_response" handler. The type basically allows setting the HTTP status line, response headers, and the response body. The WSGI application calls sendresponse() to start sending output. Output is emitted as a generator to be fed through the WSGI application. According to PEP 3333, this is the preferred way for output to be transmitted. (Our legacy ``wsgirequest`` exposed a write() to send data. We do not wish to support this API because it isn't recommended by PEP 3333.) The wire protocol code has been ported to use the new API. Differential Revision: https://phab.mercurial-scm.org/D2775
Sat, 10 Mar 2018 11:15:05 -0800 tests: add test for a wire protocol request to wrong base URL
Gregory Szorc <gregory.szorc@gmail.com> [Sat, 10 Mar 2018 11:15:05 -0800] rev 36866
tests: add test for a wire protocol request to wrong base URL We have code that validates that wire protocol commands (which are specified via query string) must occur at the base URL of a repo. But we have no test coverage for this behavior. Let's add some. Differential Revision: https://phab.mercurial-scm.org/D2778
Fri, 09 Mar 2018 17:10:36 -0800 hgweb: remove support for short query string based aliases (BC)
Gregory Szorc <gregory.szorc@gmail.com> [Fri, 09 Mar 2018 17:10:36 -0800] rev 36865
hgweb: remove support for short query string based aliases (BC) Form data exposed by hgweb is post-processed to expand certain shortcuts. For example, URLs with "?cs=@" is essentially expanded to "?cmd=changeset&node=@". And the URL router treats this the same as "/changeset/@". These shortcuts were initially added in 2005 in 34cb3957d875 and 964baa35faf8. They have rarely been touched in the last decade (just moving code around a bit). We have almost no test coverage of this feature. AFAICT no templates reference URLs of this form. I even looked at the initial version of paper and coal from ~2008 and they use the "/command/params" URL form and not these shortcuts. Furthermore, I couldn't even get some shortcuts to work! For example, "?sl=@" attempts to do a revision search instead of showing shortlog starting at revision @. Maybe I'm just doing it wrong? Because this is ancient, mostly untested code, there is a migration path to something better, and because anyone passionate enough to preserve URLs can install URL redirects, let's nuke the feature. .. bc:: Query string shorts in hgweb like ``?cs=@`` have been removed. Use URLs of the form ``/:cmd`` instead. Differential Revision: https://phab.mercurial-scm.org/D2773
Sat, 10 Mar 2018 11:07:53 -0800 hgweb: remove support for POST form data (BC)
Gregory Szorc <gregory.szorc@gmail.com> [Sat, 10 Mar 2018 11:07:53 -0800] rev 36864
hgweb: remove support for POST form data (BC) Previously, we called out to cgi.parse(), which for POST requests parsed multipart/form-data and application/x-www-form-urlencoded Content-Type requests for form data, combined it with query string parameters, returned a union of the values. As far as I know, nothing in Mercurial actually uses this mechanism to submit data to the HTTP server. The wire protocol has its own mechanism for passing parameters. And the web interface only does GET requests. Removing support for parsing POST data doesn't break any tests. Another reason to not like this feature is that cgi.parse() may modify the QUERY_STRING environment variable as a side-effect. In addition, it merges both POST data and the query string into one data structure. This prevents consumers from knowing whether a variable came from the query string or POST data. That can matter for some operations. I suspect we use cgi.parse() because back when this code was initially implemented, it was the function that was readily available. In other words, I don't think there was conscious choice to support POST data: we just got it because cgi.parse() supported it. Since nothing uses the feature and it is untested, let's remove support for parsing POST form data. We can add it back in easily enough if we need it in the future. .. bc:: Hgweb no longer reads form data in POST requests from multipart/form-data and application/x-www-form-urlencoded requests. Arguments should be specified as URL path components or in the query string in the URL instead. Differential Revision: https://phab.mercurial-scm.org/D2774
Sat, 10 Mar 2018 11:06:13 -0800 hgweb: expose input stream on parsed WSGI request object
Gregory Szorc <gregory.szorc@gmail.com> [Sat, 10 Mar 2018 11:06:13 -0800] rev 36863
hgweb: expose input stream on parsed WSGI request object Our next step towards moving away from wsgirequest to our newer, friendlier parsedrequest type is input stream access. This commit exposes the input stream on the instance. Consumers in the HTTP protocol server switch to it. Because there were very few consumers of the input stream, we stopped storing a reference to the input stream on wsgirequest directly. All access now goes through parsedrequest. However, wsgirequest still may read from this stream as part of cgi.parse(). So we still need to create the stream from wsgirequest. Differential Revision: https://phab.mercurial-scm.org/D2771
Sat, 10 Mar 2018 10:56:10 -0800 hgweb: make parsedrequest part of wsgirequest
Gregory Szorc <gregory.szorc@gmail.com> [Sat, 10 Mar 2018 10:56:10 -0800] rev 36862
hgweb: make parsedrequest part of wsgirequest This is kind of ugly. But an upcoming commit will teach parsedrequest about the input stream. Because the input stream is global state and can't be accessed without side-effects, we need to take actions to ensure that multiple consumers don't read from it independently. The easiest way to do this is for one object to hold a reference to both items having access to the input stream so that when a copy is made, we can remove the attribute from the other instance. So we create our parsed request instance from the wsgirequest constructor and hold a reference to it there. This is better than our new type holding a reference to wsgirequest because all the code for managing access will be temporary and we shouldn't pollute parsedrequest with this ugly history. Differential Revision: https://phab.mercurial-scm.org/D2770
Sat, 10 Mar 2018 11:03:45 -0800 hgweb: refactor the request draining code
Gregory Szorc <gregory.szorc@gmail.com> [Sat, 10 Mar 2018 11:03:45 -0800] rev 36861
hgweb: refactor the request draining code The previous code for draining was only invoked in a few places in the wire protocol. Behavior wasn't consist. Furthermore, it was difficult to reason about. With us converting the input stream to a capped reader, it is now safe to always drain the input stream when its size is known because we can never overrun the input and read into the next HTTP request. The only question is "should we?" This commit changes the draining code so every request is examined. Draining now kicks in for a few requests where it wouldn't before. But I think the code is sufficiently restricted so the behavior is safe. Possibly the most dangerous part of this code is the issuing of Connection: close for POST and PUT requests that don't have a Content-Length. I don't think there are any such uses in our WSGI application, so this should be safe. In the near future, I plan to significantly refactor the WSGI response handling. I anticipate this code evolving a bit. So any minor regressions around draining or connection closing behavior might be fixed as a result of that work. All tests pass with this change. That scares me a bit because it means we are lacking low-level tests for the HTTP protocol. Differential Revision: https://phab.mercurial-scm.org/D2769
Sat, 10 Mar 2018 10:48:34 -0800 hgweb: use a capped reader for WSGI input stream
Gregory Szorc <gregory.szorc@gmail.com> [Sat, 10 Mar 2018 10:48:34 -0800] rev 36860
hgweb: use a capped reader for WSGI input stream Per PEP 3333, the input stream from WSGI should respect EOF and prevent reads past the end of the request body. However, not all WSGI servers guarantee this. Notably, our BaseHTTPServer based built-in HTTP server doesn't. Instead, it exposes the raw socket and you can read() from it all you want, getting the connection in a bad state by doing so. We have a "cappedreader" utility class that proxies a file object and prevents reading past a limit. This commit converts the WSGI input stream into a capped reader when the input length is advertised via Content-Length headers. "cappedreader" only exposes a read() method. PEP 3333 states that the input stream MUST also support readline(), readlines(hint), and __iter__(). However, since our WSGI application code only calls read() and since we're not manipulating the stream exposed by the WSGI server, we're not violating the spec here. Differential Revision: https://phab.mercurial-scm.org/D2768
Sat, 10 Mar 2018 10:47:30 -0800 hgweb: document continuereader
Gregory Szorc <gregory.szorc@gmail.com> [Sat, 10 Mar 2018 10:47:30 -0800] rev 36859
hgweb: document continuereader Differential Revision: https://phab.mercurial-scm.org/D2767
Thu, 08 Mar 2018 18:00:04 -0800 hgweb: remove wsgirequest.__iter__
Gregory Szorc <gregory.szorc@gmail.com> [Thu, 08 Mar 2018 18:00:04 -0800] rev 36858
hgweb: remove wsgirequest.__iter__ This was added in d0db3462d568 in 2006. I can't find a justification for this method in PEP 3333. I suspect we were originally intending to use this type as the WSGI application (which should be iterable)? The tests all pass without this method. So let's nuke it. Differential Revision: https://phab.mercurial-scm.org/D2749
Thu, 08 Mar 2018 17:57:07 -0800 hgweb: remove wsgirequest.read()
Gregory Szorc <gregory.szorc@gmail.com> [Thu, 08 Mar 2018 17:57:07 -0800] rev 36857
hgweb: remove wsgirequest.read() This was just a proxy to self.inp.read(). This method serves little value. Let's nuke it. Callers in the wire protocol server have been updated accordingly. Differential Revision: https://phab.mercurial-scm.org/D2748
Sat, 10 Mar 2018 10:46:08 -0800 hgweb: remove unused methods on wsgirequest
Gregory Szorc <gregory.szorc@gmail.com> [Sat, 10 Mar 2018 10:46:08 -0800] rev 36856
hgweb: remove unused methods on wsgirequest writelines() isn't used in our code base. close() was a no-op. It is an optional method per PEP 3333. My eventual goal is to kill the wsgirequest class, hence why I'm removing code. Differential Revision: https://phab.mercurial-scm.org/D2747
Thu, 08 Mar 2018 17:17:48 -0800 wireprotoserver: remove unused argument from _handlehttperror()
Gregory Szorc <gregory.szorc@gmail.com> [Thu, 08 Mar 2018 17:17:48 -0800] rev 36855
wireprotoserver: remove unused argument from _handlehttperror() Differential Revision: https://phab.mercurial-scm.org/D2746
Sat, 10 Mar 2018 10:44:56 -0800 hgweb: store and use request method on parsed request
Gregory Szorc <gregory.szorc@gmail.com> [Sat, 10 Mar 2018 10:44:56 -0800] rev 36854
hgweb: store and use request method on parsed request PEP 3333 says that REQUEST_METHOD is always defined. Differential Revision: https://phab.mercurial-scm.org/D2745
Sat, 10 Mar 2018 10:45:12 -0800 hgweb: handle CONTENT_LENGTH
Gregory Szorc <gregory.szorc@gmail.com> [Sat, 10 Mar 2018 10:45:12 -0800] rev 36853
hgweb: handle CONTENT_LENGTH PEP 3333 says CONTENT_LENGTH may be set. I /think/ WSGI servers are allowed to invent this key even if the client didn't send it. We had code in wireprotoserver looking for this key. So let's just automagically convert this key to an HTTP request header when parsing the request. Differential Revision: https://phab.mercurial-scm.org/D2744
Thu, 08 Mar 2018 16:38:01 -0800 wireprotoserver: access headers through parsed request
Gregory Szorc <gregory.szorc@gmail.com> [Thu, 08 Mar 2018 16:38:01 -0800] rev 36852
wireprotoserver: access headers through parsed request Now that we can access headers via the parsed request object, let's do that. Since the new object uses bytes, hyphens, and is case-insensitive, a bit of code around normalizing values has been removed. I think the new code is much more intuitive because it more closely matches what is going out over the wire. Differential Revision: https://phab.mercurial-scm.org/D2743
Mon, 12 Mar 2018 22:47:33 +0900 debugwireproto: close the write end before consuming all available data
Yuya Nishihara <yuya@tcha.org> [Mon, 12 Mar 2018 22:47:33 +0900] rev 36851
debugwireproto: close the write end before consuming all available data And make it read all available data deterministically. Otherwise util.poll() may deadlock because both stdout and stderr could have no data. Spotted by the next patch which removes stderr from the fds.
Fri, 09 Mar 2018 15:57:16 +0100 graft: check for missing revision first before scanning working copy
Joerg Sonnenberger <joerg@bec.de> [Fri, 09 Mar 2018 15:57:16 +0100] rev 36850
graft: check for missing revision first before scanning working copy Differential Revision: https://phab.mercurial-scm.org/D2753
Sat, 10 Mar 2018 22:02:58 -0500 hook: ensure stderr is flushed when an exception is raised, for test stability
Matt Harbison <matt_harbison@yahoo.com> [Sat, 10 Mar 2018 22:02:58 -0500] rev 36849
hook: ensure stderr is flushed when an exception is raised, for test stability Windows has had issues with output order in test-ssh-proto-unbundle.t[1] since it was created a few weeks ago. Each of the problems occurred when an exception was thrown out of the hook. Now the only thing blocking D2720 is the fact that the "abort: ..." lines on stderr are totally AWOL. I have no idea where there are. [1] https://buildbot.mercurial-scm.org/builders/Win7%20x86_64%20hg%20tests/builds/541/steps/run-tests.py%20%28python%202.7.13%29/logs/stdio
Sat, 10 Mar 2018 10:27:56 -0800 wireproto: raise ProgrammingError instead of Abort
Gregory Szorc <gregory.szorc@gmail.com> [Sat, 10 Mar 2018 10:27:56 -0800] rev 36848
wireproto: raise ProgrammingError instead of Abort This isn't a user-facing error and can only be caused by bad Python code. Thanks to Yuya for spotting this. Differential Revision: https://phab.mercurial-scm.org/D2777
Sat, 10 Mar 2018 19:56:47 +0900 py3: make test-commit-interactive.t byte-safe
Yuya Nishihara <yuya@tcha.org> [Sat, 10 Mar 2018 19:56:47 +0900] rev 36847
py3: make test-commit-interactive.t byte-safe
Sat, 10 Mar 2018 19:49:09 +0900 py3: open patch file in binary mode and convert eol manually
Yuya Nishihara <yuya@tcha.org> [Sat, 10 Mar 2018 19:49:09 +0900] rev 36846
py3: open patch file in binary mode and convert eol manually Here we don't introduce a reader wrapper since it wouldn't be easy to make read(n) handle partial data and length correctly.
Tue, 06 Mar 2018 07:45:57 -0600 py3: wrap file object to write patch in native eol preserving byte-ness
Yuya Nishihara <yuya@tcha.org> [Tue, 06 Mar 2018 07:45:57 -0600] rev 36845
py3: wrap file object to write patch in native eol preserving byte-ness
Tue, 06 Mar 2018 07:24:12 -0600 py3: drop b'' from debug message "moving bookmarks"
Yuya Nishihara <yuya@tcha.org> [Tue, 06 Mar 2018 07:24:12 -0600] rev 36844
py3: drop b'' from debug message "moving bookmarks"
Sat, 10 Mar 2018 15:57:16 +0900 py3: use r'' instead of sysstr('') to get around code transformer
Yuya Nishihara <yuya@tcha.org> [Sat, 10 Mar 2018 15:57:16 +0900] rev 36843
py3: use r'' instead of sysstr('') to get around code transformer Fewer function calls should be better.
Sat, 10 Mar 2018 15:50:09 +0900 ui: remove any combinations of CR|LF from prompt response
Yuya Nishihara <yuya@tcha.org> [Sat, 10 Mar 2018 15:50:09 +0900] rev 36842
ui: remove any combinations of CR|LF from prompt response On Windows, we have to accept both CR+LF and LF. This patch simply makes any trailing CRs and LFs removed from a user input instead of doing stricter parsing, as an input must be a readable text.
Sat, 10 Mar 2018 12:45:10 -0500 sshpeer: check pipe validity before forwarding output from it
Matt Harbison <matt_harbison@yahoo.com> [Sat, 10 Mar 2018 12:45:10 -0500] rev 36841
sshpeer: check pipe validity before forwarding output from it After the previous fix, fileobjectproxy._observedcall() (called when win32.peekpipe() accesses .fileno) started exploding. With this fix, similar checks are needed inside debugwireproto(). Since that is hardcoded to not use os.devnull, IDK if those are worth fixing.
Sat, 10 Mar 2018 12:22:08 -0500 util: forward __bool__()/__nonzero__() on fileobjectproxy
Matt Harbison <matt_harbison@yahoo.com> [Sat, 10 Mar 2018 12:22:08 -0500] rev 36840
util: forward __bool__()/__nonzero__() on fileobjectproxy In trying to debug the Windows process hang in D2720, I changed the stderr pipe to the peer to be os.devnull instead. That caused sshpeer._cleanuppipes()[1] to explode, complaining NoneType has no __iter__ attribute, even though the previous line checked for None. [1] https://www.mercurial-scm.org/repo/hg/file/b434965f984e/mercurial/sshpeer.py#l133
Tue, 06 Mar 2018 07:16:41 -0600 py3: fix slicing of bisect label in templatefilters.shortbisect()
Yuya Nishihara <yuya@tcha.org> [Tue, 06 Mar 2018 07:16:41 -0600] rev 36839
py3: fix slicing of bisect label in templatefilters.shortbisect()
Tue, 06 Mar 2018 07:15:01 -0600 templatefilters: inline hbisect.shortlabel()
Yuya Nishihara <yuya@tcha.org> [Tue, 06 Mar 2018 07:15:01 -0600] rev 36838
templatefilters: inline hbisect.shortlabel() It's pretty simple. I don't think the business logic has to be placed in hbisect.py.
Tue, 06 Mar 2018 07:11:24 -0600 py3: make test-bisect.t bytes-safe
Yuya Nishihara <yuya@tcha.org> [Tue, 06 Mar 2018 07:11:24 -0600] rev 36837
py3: make test-bisect.t bytes-safe
Tue, 06 Mar 2018 07:10:50 -0600 py3: fix integer formatting in bisect error
Yuya Nishihara <yuya@tcha.org> [Tue, 06 Mar 2018 07:10:50 -0600] rev 36836
py3: fix integer formatting in bisect error
Sat, 10 Mar 2018 16:55:54 +0900 py3: silence f.write() in test-annotate.t
Yuya Nishihara <yuya@tcha.org> [Sat, 10 Mar 2018 16:55:54 +0900] rev 36835
py3: silence f.write() in test-annotate.t
Fri, 09 Mar 2018 14:52:36 -0800 xdiff: resolve signed unsigned comparison warning
Jun Wu <quark@fb.com> [Fri, 09 Mar 2018 14:52:36 -0800] rev 36834
xdiff: resolve signed unsigned comparison warning Since the value won't be changed inside the code (because context lines feature was removed by D2705), let's just remove the variable and inline the 0 value. The code might be potentially further simplified. But I'd like to make sure correctness is easily verifiable in this patch. Differential Revision: https://phab.mercurial-scm.org/D2766
Fri, 09 Mar 2018 14:47:29 -0800 xdiff: use int64 for hash table size
Jun Wu <quark@fb.com> [Fri, 09 Mar 2018 14:47:29 -0800] rev 36833
xdiff: use int64 for hash table size Follow-up of the previous "long" -> "int64" change. Now xdiff only uses int for return values and small integers (ex. booleans, shifting score, bits in hash table size, etc) so it should be able to handle large input. Differential Revision: https://phab.mercurial-scm.org/D2765
Fri, 09 Mar 2018 14:39:35 -0800 xdiff: remove unused xpp and xecfg parameters
Jun Wu <quark@fb.com> [Fri, 09 Mar 2018 14:39:35 -0800] rev 36832
xdiff: remove unused xpp and xecfg parameters They are unused. Thus removed. Differential Revision: https://phab.mercurial-scm.org/D2764
Fri, 09 Mar 2018 14:37:55 -0800 xdiff: remove unused flags parameter
Jun Wu <quark@fb.com> [Fri, 09 Mar 2018 14:37:55 -0800] rev 36831
xdiff: remove unused flags parameter After D2683, the flags parameter in some functions is no longer needed. Thus removed. Differential Revision: https://phab.mercurial-scm.org/D2763
Fri, 09 Mar 2018 14:24:27 -0800 xdiff: replace {unsigned ,}long with {u,}int64_t
Jun Wu <quark@fb.com> [Fri, 09 Mar 2018 14:24:27 -0800] rev 36830
xdiff: replace {unsigned ,}long with {u,}int64_t MSVC treats "long" as 4-byte. That could cause overflows since the xdiff code uses "long" in places where "size_t" or "ssize_t" should be used. Let's use explicit 8 byte integers to avoid FWIW git avoids that overflow by limiting diff size to 1GB [1]. After examining the code, I think the remaining risk (the use of "int") is low since "int" is only used for return values and hash table size. Although a wrong hash table size would not affect the correctness of the code, but that could make the code extremely slow. The next patch will change hash table size to 8-byte integer so the 1GB limit is unlikely needed. This patch was done by using `sed`. [1]: https://github.com/git/git/commit/dcd1742e56ebb944c4ff62346da4548e1e3be67 Differential Revision: https://phab.mercurial-scm.org/D2762
Sun, 04 Mar 2018 11:30:16 -0800 xdiff: add comments for fields in xdfile_t
Jun Wu <quark@fb.com> [Sun, 04 Mar 2018 11:30:16 -0800] rev 36829
xdiff: add comments for fields in xdfile_t This makes the related code easier to understand. Differential Revision: https://phab.mercurial-scm.org/D2685
Wed, 07 Mar 2018 14:45:31 -0800 xdiff: add a preprocessing step that trims files
Jun Wu <quark@fb.com> [Wed, 07 Mar 2018 14:45:31 -0800] rev 36828
xdiff: add a preprocessing step that trims files xdiff has a `xdl_trim_ends` step that removes common lines, unmatchable lines. That is in theory good, but happens too late - after splitting, hashing, and adjusting the hash values so they are unique. Those splitting, hashing and adjusting hash values steps could have noticeable overhead. Diffing two large files with minor (one-line-ish) changes are not uncommon. In that case, the raw performance of those preparation steps seriously matter. Even allocating an O(N) array and storing line offsets to it is expensive. Therefore my previous attempts [1] [2] cannot be good enough since they do not remove the O(N) array assignment. This patch adds a preprocessing step - `xdl_trim_files` that runs before other preprocessing steps. It counts common prefix and suffix and lines in them (needed for displaying line number), without doing anything else. Testing with a crafted large (169MB) file, with minor change: ``` open('a','w').write(''.join('%s\n' % (i % 100000) for i in xrange(30000000) if i != 6000000)) open('b','w').write(''.join('%s\n' % (i % 100000) for i in xrange(30000000) if i != 6003000)) ``` Running xdiff by a simple binary [3], this patch improves the xdiff perf by more than 10x for the above case: ``` # xdiff before this patch 2.41s user 1.13s system 98% cpu 3.592 total # xdiff after this patch 0.14s user 0.16s system 98% cpu 0.309 total # gnu diffutils 0.12s user 0.15s system 98% cpu 0.272 total # (best of 20 runs) ``` It's still slightly slower than GNU diffutils. But it's pretty close now. Testing with real repo data: For the whole repo, this patch makes xdiff 25% faster: ``` # hg perfbdiff --count 100 --alldata -c d334afc585e2 --blocks [--xdiff] # xdiff, after ! wall 0.058861 comb 0.050000 user 0.050000 sys 0.000000 (best of 100) # xdiff, before ! wall 0.077816 comb 0.080000 user 0.080000 sys 0.000000 (best of 91) # bdiff ! wall 0.117473 comb 0.120000 user 0.120000 sys 0.000000 (best of 67) ``` For files that are long (ex. commands.py), the speedup is more than 3x, very significant: ``` # hg perfbdiff --count 3000 --blocks commands.py.i 1 [--xdiff] # xdiff, after ! wall 0.690583 comb 0.690000 user 0.690000 sys 0.000000 (best of 12) # xdiff, before ! wall 2.240361 comb 2.210000 user 2.210000 sys 0.000000 (best of 4) # bdiff ! wall 2.469852 comb 2.440000 user 2.440000 sys 0.000000 (best of 4) ``` [1]: https://phab.mercurial-scm.org/D2631 [2]: https://phab.mercurial-scm.org/D2634 [3]: ``` // Code to run xdiff from command line. No proper error handling. #include <stdlib.h> #include <unistd.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include "mercurial/thirdparty/xdiff/xdiff.h" #define ensure(x) if (!(x)) exit(255); mmfile_t readfile(const char *path) { struct stat st; int fd = open(path, O_RDONLY); fstat(fd, &st); mmfile_t file = { malloc(st.st_size), st.st_size }; ensure(read(fd, file.ptr, st.st_size) == st.st_size); close(fd); return file; } int main(int argc, char const *argv[]) { mmfile_t a = readfile(argv[1]), b = readfile(argv[2]); xpparam_t xpp = {0}; xdemitconf_t xecfg = {0}; xdemitcb_t ecb = {0}; xdl_diff(&a, &b, &xpp, &xecfg, &ecb); return 0; } ``` Differential Revision: https://phab.mercurial-scm.org/D2686
Fri, 09 Mar 2018 14:30:15 -0800 transaction: add a name and a __repr__ implementation (API)
Martin von Zweigbergk <martinvonz@google.com> [Fri, 09 Mar 2018 14:30:15 -0800] rev 36827
transaction: add a name and a __repr__ implementation (API) This has been useful for me for debugging. Differential Revision: https://phab.mercurial-scm.org/D2758
Fri, 09 Mar 2018 16:10:55 +0100 phabricator: update doc string for deprecated token argument
Joerg Sonnenberger <joerg@bec.de> [Fri, 09 Mar 2018 16:10:55 +0100] rev 36826
phabricator: update doc string for deprecated token argument Differential Revision: https://phab.mercurial-scm.org/D2755
Fri, 09 Mar 2018 16:09:27 +0100 phabricator: print deprecation warning only once
Joerg Sonnenberger <joerg@bec.de> [Fri, 09 Mar 2018 16:09:27 +0100] rev 36825
phabricator: print deprecation warning only once Differential Revision: https://phab.mercurial-scm.org/D2754
(0) -30000 -10000 -3000 -1000 -300 -100 -60 +60 +100 +300 +1000 +3000 +10000 tip