Summary:
Introduce taggederror-util, which provides a new trait `AnyhowEdenExt`, which provides a method `eden_metadata` for anyhow errors and results. This method works much like `AnyhowExt::common_metadata`, but additionally supports extracting default error metadata from known `Tagged` types which are listed explicitly in the method implementation.
Extend `FilteredAnyhow` to support a configuration "metadata function", which allows swapping out `eden_metadata` for the standard `common_metadata`.
Modify Rust dispatch and Python bindings to use `AnyhowEdenExt` for metadata extraction and printing.
Modify `intentional_error` to rely on `AnyhowEdenExt` for tagging (removes `.tagged` call, no tags will be visible if `AnyhowEdenExt` is not used).
Reviewed By: DurhamG
Differential Revision: D22927203
fbshipit-source-id: 04b36fdfaa24af591118acb9e418d1ed7ae33f91
Summary:
Implements based Rust-Python binding layer for error metadata propagation.
We introduce a new type, `TaggedExceptionData`, which carries CommonMetadata and the original (without metadata) error message for a Rust Anyhow error. This class is passed to RustError and can be accessed in Python (somewhat awkwardly) via indexing:
```
except error.RustError as e:
fault = e.args[0].fault()
typename = e.args[0].typename()
message = e.args[0].message()
```
As far as I can tell, due to limitations in cpython-rs, this can't be made more ergonomic without introducing a Python shim around the Rust binding layer, which could adapt the cpython-rs classes to use whatever API we'd like.
Currently, anyhow errors that are not otherwise special-cased will be converted into RustError, with both the original error message and any attached metadata printed as shown below
```
abort: intentional error for debugging with message 'intentional_error'
error has type name taggederror::IntentionalError and fault None
```
We can of course re-raise the error if desired to maintain the previous behavior for handling a RustError.
If we'd like other, specialized Rust Python Exception types to carry metadata (such as `IndexedLogError`), we'll need to modify them to accept a `TaggedExceptionData` like `RustError`.
Renamed the "cause an error in pure rust command" function to `debugcauserusterror`, and instead used the name `debugthrowrustexception` for a command which causes an error in rust which is converted to a Python exception across the binding layer.
Introduced a simple integration test which exercises `debugthrowrustexception`.
Added a basic handler for RustError to scmutil.py
Reviewed By: DurhamG
Differential Revision: D22517796
fbshipit-source-id: 0409489243fe739a26958aad48f608890eb93aa0
Summary: Per comments on D22429347, add a new `ExtractInnerRef` trait that is similar to `ExtractInner`, but returns a reference to the underlying value. A default implementation is provided for types whose inner value is `Clone + 'static`, so in practice most types will only need to implement `ExtractInnerRef`, whereas the callsite may choose whether it needs a reference or an owned value.
Reviewed By: quark-zju
Differential Revision: D22464158
fbshipit-source-id: 7b97329aedcddb0e51fd242b519e79eba2eed350
Summary:
A common pattern in Mercurial's data storage layer Python bindings is to have a Python object that wraps a Rust object. These Python objects are often passed across the FFI boundary to Rust code, which then may need to access the underlying Rust value.
Previously, the objects that used this pattern did so in an ad-hoc manner, typically by providing an `into_inner` or `to_inner` inherent method. This diff introduces a new `ExtractInner` trait that standardizes this pattern into a single interface, which in turn allows this pattern to be used with generics.
Reviewed By: quark-zju
Differential Revision: D22429347
fbshipit-source-id: cab4c24b8b98c6ef8307f72a9b4726aabdc829cc
Summary: Replaces usages of whitelist/blacklist with include/exclude/allow. These terms are more descriptive and less likely to contribute to racial stereotyping. More context: https://fb.workplace.com/groups/sourcecontrolteam/permalink/2926049127516414/
Reviewed By: farnz
Differential Revision: D22039299
fbshipit-source-id: d5b4cdeca681e1f4c992f7ef0b9f772b2ae1abd3
Summary:
Sometimes the Rust io::Error is generated without an errno (ex. pipe
0.2 would generate BrokenPipe error without an errno). The Python
land uses errno to check error type (Python does not have io::ErrorKind).
Therefore attempt to translate ErrorKind to Python errno. Without this
exiting the rust pager early would crash like:
StdioError: [Errno None] pipe reader has been dropped
abort: pipe reader has been dropped
Reviewed By: markbt
Differential Revision: D20898559
fbshipit-source-id: ef863617e0e500d878ea0f9aeac06b4d87ffbcf2
Summary:
According to the anyhow documentation[0], the behavior of `.to_string()` is to
only stringify the top-level errors, hiding all the context of the error.
Instead, the debug format allows all the context to be displayed, and, if
available the backtrace.
This should significantly help debug Rust errors when context is available,
which we should strive to have everywhere!
[0]: https://docs.rs/anyhow/1.0.27/anyhow/struct.Error.html#display-representations
Reviewed By: sfilipco
Differential Revision: D20575944
fbshipit-source-id: 2968d7fb755edec7f7e5151138e8049ded181c1b
Summary:
Previously Rust str was serialized into bytes. To be Python 3 friendly, let's
serialize it into `str`.
Reviewed By: markbt
Differential Revision: D19797706
fbshipit-source-id: 388eb044dc7e25cdc438f0c3d6fa5a5740f22e3d
Summary:
The library already has a way to wrap a Python object into a Rust object that
exposes the Rust Read/Write interface. This is the reverse direction for
the Write interface.
The initial intention is to expose Rust stdout as described in D19702533.
However, I found Python's `sys.stdout.buffer` also enforces utf-8 encoding
on Windows (unless PYTHONLEGACYWINDOWSSTDIO is set). So Python's
stdout actually behaves similarly with Rust's stdout on Windows and is okay
to use. That said, it's still useful to have this abstraction, for streampager [1]
integration.
[1]: https://github.com/markbt/streampager/
Reviewed By: sfilipco
Differential Revision: D19716127
fbshipit-source-id: ba39898122561d9a49b7080ee95d7c940540eb40
Summary: `PyPath` is to `PyPathBuf` as `Path` is to `PathBuf` and `str` is to `String`.
Reviewed By: quark-zju
Differential Revision: D19647995
fbshipit-source-id: 841a5f6fea295bc72b00da028ae256ca38578504
Summary: Add `PyNone`. This is a marker struct that indicates that a python function can only return `PyNone`.
Reviewed By: xavierd
Differential Revision: D19644338
fbshipit-source-id: f846b146237ebf7de996177494934fec662cde0f
Summary:
`PyPath` is the type that owns the data. Rename it to `PyPathBuf` for analogy
with `PathBuf` and `RepoPathBuf`, and to allow us to introduce a reference type
named `PyPath`.
Reviewed By: xavierd
Differential Revision: D19643797
fbshipit-source-id: 56d80fea5677f7223e967b0723039d1763b26f68
Summary:
Make the type easier to use. Namely, the treestate bindings want PyPath <->
bytes since treestate internally uses bytes.
Reviewed By: xavierd
Differential Revision: D19635357
fbshipit-source-id: 37d1889b5da1d7f3869bb7820de0219b87b71a8b
Summary:
Set up the `cpython-ext` and `hgcommands` libraries so that they can compile
against py2 and py3 versions of rust-cpython. Make py2 the default so
that cargo test still works.
Reviewed By: singhsrb
Differential Revision: D19615656
fbshipit-source-id: 3403e7077deb3c0a9dfe0e3b7d4f4ad1da73bba3
Summary: This is incorrectly removed due to a bad rebase / merge.
Reviewed By: DurhamG
Differential Revision: D19607801
fbshipit-source-id: a6ee7a3f184ff1882eb1f1513f7fed74a7108727
Summary:
This makes `make hg3` work. It requires cleaning up the `build` directory when
switching between py2 and py3 build, which will be fixed later.
Reviewed By: DurhamG
Differential Revision: D19604824
fbshipit-source-id: 060ff313420126a5dba935c4451b45dc9af45f13
Summary: Add methods to convert to a `Str` object from `String` and from `Vec[u8]`
Reviewed By: xavierd
Differential Revision: D19596743
fbshipit-source-id: 6499f7f1b8329f4d14ce8179a41ed46982a85c8e
Summary: Update to the new version of rust-cpython. This supports `list.append`, so make use of it.
Reviewed By: xavierd
Differential Revision: D19590905
fbshipit-source-id: 03609d4f698ae8e4380e82b8144caaa205b4c2d4
Summary:
This is optional, but it helps investigating Python errors chained with other
Rust errors.
For example:
error.RustError: failed fetching from store (, cc38739855a7f356b4a2aaac0a0a858fd646e6bf)
Caused by:
TypeError()
Traceback (most recent call last):
File "scm3/edenscm/hgext/remotefilelog/contentstore.py", line 53, in get
chain = self.getdeltachain(name, node)
File "scm3/edenscm/hgext/remotefilelog/contentstore.py", line 91, in getdeltachain
chain = self._getpartialchain(name, node)
File "scm3/edenscm/hgext/remotefilelog/contentstore.py", line 125, in _getpartialchain
return store.getdeltachain(name, node)
TypeError
Without this diff there is only "TypeError()" without the traceback.
This can be turned off by unsetting RUST_BACKTRACE.
Reviewed By: markbt
Differential Revision: D19581173
fbshipit-source-id: 74605b78146b6b1c9ddd5ad720dcd19ff73908a8
Summary: The format_err is used in shared code too, we need to import it.
Reviewed By: quark-zju
Differential Revision: D19592591
fbshipit-source-id: bd344bf3c295473f4647235a98432d11c9678bf9
Summary:
This will be used as an argument to the Rust bindings when using paths. This
type is either a PyBytes in Python2 and uses the various encoding function to
convert into a String, or a PyUnicode in Python3 with no encoding change.
Reviewed By: farnz
Differential Revision: D19587890
fbshipit-source-id: 58903426585693193754691fe3c756b9097b35f6
Summary:
Without this, Rust code using the feature (ex. lz4, used by lz4revlog) will
panic.
Reviewed By: sfilipco
Differential Revision: D19581188
fbshipit-source-id: b499449df4fede27fe66cf8e5af57e8347a0dd48
Summary: This converts to bytes on Python 2, but unicode on Python 3.
Reviewed By: markbt
Differential Revision: D19581180
fbshipit-source-id: 0de9056a01ae30810a72352387de5a940b37d7ab
Summary:
The Python `datatime` stdlib has limitations:
- `datetime.datetime` can only express year 1 to 9999.
- `strptime` requires year >= 1900.
Limit the `HgTime` to 1900 ..= 9999 range to be consistent.
Note: Mercurial has an `i32` range limit, which seems to problematic
since `i32::MAX` is Jan 19, 2038. So I kept using `i64`.
This addressed some XXX comments about not returning errors.
The code change is mostly because added error handling.
Reviewed By: sfilipco
Differential Revision: D18946333
fbshipit-source-id: 0e4756457b0f13451dc5008ef19d4670a7aaa7fb
Summary:
Make cpython-ext free from business logic. This adds a bit overhead.
But it should be fine given the error cases are considered rare.
Reviewed By: markbt
Differential Revision: D19186692
fbshipit-source-id: daaffc1369a36c781d1badea822bf62a144eb54e
Summary: We no longer use the `failure` crate. Rename related methods and traits.
Reviewed By: markbt
Differential Revision: D19186694
fbshipit-source-id: 1c83a90ee12db431b7d8e09a9c2cf1d43a4c0f93
Summary:
We no longer use the `failure` crate. Rename the module.
`cpython-failure` is dropped since it was merged into `cpython-ext`.
Reviewed By: markbt
Differential Revision: D19186693
fbshipit-source-id: 410d1491bcadd8d3272c7e2df08ecbe66fc0fef2
Summary:
The `map_pyerr<PE>` API is kind of hard to use correctly since the
code that calls `map_pyerr` does not really know the best suitable error type.
The existing code also "encourage"s the use of stdlib error types like
RuntimeError, ValueError, etc since the code is shorter, which is not great.
Error types from `mercurial.error` are better choices.
With previous diffs in this stack, we now decide the Python error type based
on the Rust error type. It's no longer necessary to specify an error type
with `map_pyerr<PE>`. So let's just drop the type parameter.
A `RustError` was added for error types that `cpython-ext` does not know how
to convert. We should avoid leaking it to the Python land by just implementing
how to convert `anyhow::Error` to `PyErr` in `cpython-ext`.
Reviewed By: markbt
Differential Revision: D19169527
fbshipit-source-id: f4563c36174cd51201b526bbc92a3f1c8a3da864
Summary:
Convert indexedlog error and IOError to dedicated Python types so the Python
world can match them meaningfully by type and handle them accordingly.
Reviewed By: markbt
Differential Revision: D19169210
fbshipit-source-id: 1e7bfdf7cbaf917098efdcd63d600483a9427d33
Summary:
This diff replaces eden's dependencies on failure::Error with anyhow::Error.
Failure's error type requires all errors to have an implementation of failure's own failure::Fail trait in order for cause chains and backtraces to work. The necessary methods for this functionality have made their way into the standard library error trait, so modern error libraries build directly on std::error::Error rather than something like failure::Fail. Once we are no longer tied to failure 0.1's Fail trait, different parts of the codebase will be free to use any std::error::Error-based libraries they like while still working nicely together.
Reviewed By: xavierd
Differential Revision: D18576093
fbshipit-source-id: e2d862b659450f2969520d9b74877913fabb2e5d
Summary:
This diff is preparation for migrating off of failure::Fail / failure::Error for errors in favor of errors that implement std::error::Error. The Fallible terminology is unique to failure and in non-failure code we should be using Result<T>. To minimize the size of the eventual diff that removes failure, this codemod replaces all use of Fallible with Result by:
- In modules that do not use Result<T, E>, we import `failure::Fallible as Result`;
- In modules that use a mix of Result<T, E> and Fallible<T> (only 5) we define `type Result<T, E = failure::Error> = std::result::Result<T, E>` to allow both Result<T> and Result<T, E> to work simultaneously.
Reviewed By: Imxset21
Differential Revision: D18499758
fbshipit-source-id: 9f5a54c47f81fdeedbc6003cef42a1194eee55bf
Summary:
In preparation for merging fb-mercurial sources to the Eden repository,
move everything from the top-level directory into an `eden/scm`
subdirectory.