rust/README.rst
author Gregory Szorc <gregory.szorc@gmail.com>
Wed, 14 Mar 2018 22:19:00 -0700
changeset 37063 0a6c5cc09a88
parent 35569 964212780daf
child 44114 8a3b045d9086
permissions -rw-r--r--
wireproto: define human output side channel frame Currently, the SSH protocol delivers output tailored for people over the stderr file descriptor. The HTTP protocol doesn't have this file descriptor (because it only has an input and output pipe). So it encodes textual output intended for humans within the protocol responses. So response types have a facility for capturing output to be printed to users. Some don't. And sometimes the implementation of how that output is conveyed is super hacky. On top of that, bundle2 has an "output" part that is used to store output that should be printed when this part is encountered. bundle2 also has the concept of "interrupt" chunks, which can be used to signal that the regular bundle2 stream is to be preempted by an out-of-band part that should be processed immediately. This "interrupt" part can be an "output" part and can be used to print data on the receiver. The status quo is inconsistent and insane. We can do better. This commit introduces a dedicated frame type on the frame-based protocol for denoting textual data that should be printed on the receiver. This frame type effectively constitutes a side-channel by which textual data can be printed on the receiver without interfering with other in-progress transmissions, such as the transmission of command responses. But wait - there's more! Previous implementations that transferred textual data basically instructed the client to "print these bytes." This suffered from a few problems. First, the text data that was transmitted and eventually printed originated from a server with a specic i18n configuration. This meant that clients would see text using whatever the i18n settings were on the server. Someone in France could connect to a server in Japan and see unlegible Japanese glyphs - or maybe even mojibake. Second, the normalization of all text data originated on servers resulted in the loss of the ability to apply formatting to that data. Local Mercurial clients can apply specific formatting settings to individual atoms of text. For example, a revision can be colored differently from a commit message. With data over the wire, the potential for this rich formatting was lost. The best you could do (without parsing the text to be printed), was apply a universal label to it and e.g. color it specially. The new mechanism for instructing the peer to print data does not have these limitations. Frames instructing the peer to print text are composed of a formatting string plus arguments. In other words, receivers can plug the formatting string into the i18n database to see if a local translation is available. In addition, each atom being instructed to print has a series of "labels" associated with it. These labels can be mapped to the Mercurial UI's labels so locally configured coloring, styling, etc settings can be applied. What this all means is that textual messages originating on servers can be localized on the client and richly formatted, all while respecting the client's settings. This is slightly more complicated than "print these bytes." But it is vastly more user friendly. FWIW, I'm not aware of other protocols that attempt to encode i18n and textual styling in this manner. You could lobby the claim that this feature is over-engineered. However, if I were to sit in the shoes of a non-English speaker learning how to use version control, I think I would *love* this feature because it would enable me to see richly formatted text in my chosen locale. Anyway, we only implement support for encoding frames of this type and basic tests for that encoding. We'll still need to hook up the server and its ui instance to emit these frames. I recognize this feature may be a bit more controversial than other aspects of the wire protocol because it is a bit "radical." So I'd figured I'd start small to test the waters and see if others feel this feature is worthwhile. Differential Revision: https://phab.mercurial-scm.org/D2872

===================
Mercurial Rust Code
===================

This directory contains various Rust code for the Mercurial project.

The top-level ``Cargo.toml`` file defines a workspace containing
all primary Mercurial crates.

Building
========

To build the Rust components::

   $ cargo build

If you prefer a non-debug / release configuration::

   $ cargo build --release

Features
--------

The following Cargo features are available:

localdev (default)
   Produce files that work with an in-source-tree build.

   In this mode, the build finds and uses a ``python2.7`` binary from
   ``PATH``. The ``hg`` binary assumes it runs from ``rust/target/<target>hg``
   and it finds Mercurial files at ``dirname($0)/../../../``.

Build Mechanism
---------------

The produced ``hg`` binary is *bound* to a CPython installation. The
binary links against and loads a CPython library that is discovered
at build time (by a ``build.rs`` Cargo build script). The Python
standard library defined by this CPython installation is also used.

Finding the appropriate CPython installation to use is done by
the ``python27-sys`` crate's ``build.rs``. Its search order is::

1. ``PYTHON_SYS_EXECUTABLE`` environment variable.
2. ``python`` executable on ``PATH``
3. ``python2`` executable on ``PATH``
4. ``python2.7`` executable on ``PATH``

Additional verification of the found Python will be performed by our
``build.rs`` to ensure it meets Mercurial's requirements.

Details about the build-time configured Python are built into the
produced ``hg`` binary. This means that a built ``hg`` binary is only
suitable for a specific, well-defined role. These roles are controlled
by Cargo features (see above).

Running
=======

The ``hgcli`` crate produces an ``hg`` binary. You can run this binary
via ``cargo run``::

   $ cargo run --manifest-path hgcli/Cargo.toml

Or directly::

   $ target/debug/hg
   $ target/release/hg

You can also run the test harness with this binary::

   $ ./run-tests.py --with-hg ../rust/target/debug/hg

.. note::

   Integration with the test harness is still preliminary. Remember to
   ``cargo build`` after changes because the test harness doesn't yet
   automatically build Rust code.