rust/hg-cpython/src/utils.rs
author Rapha?l Gom?s <rgomes@octobus.net>
Wed, 02 Oct 2024 20:29:48 +0200
changeset 52046 de317a87ea6a
parent 52042 28a0eb21ff04
child 52185 e698e3e75420
permissions -rw-r--r--
rust-pathauditor: match more of Python's behavior and display messages We will make use of the path auditor when running our update fast-path, and we want to output of it to be close enough.
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
44505
d738b7a18438 rust-nodemap: add utils to create `Node`s from Python objects
Georges Racinet <georges.racinet@octobus.net>
parents: 43251
diff changeset
     1
use cpython::exc::ValueError;
52046
de317a87ea6a rust-pathauditor: match more of Python's behavior and display messages
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52042
diff changeset
     2
use cpython::{
de317a87ea6a rust-pathauditor: match more of Python's behavior and display messages
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52042
diff changeset
     3
    ObjectProtocol, PyBytes, PyDict, PyErr, PyObject, PyResult, PyTuple,
de317a87ea6a rust-pathauditor: match more of Python's behavior and display messages
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52042
diff changeset
     4
    Python, ToPyObject,
de317a87ea6a rust-pathauditor: match more of Python's behavior and display messages
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52042
diff changeset
     5
};
52042
28a0eb21ff04 rust-cpython: add a util to get a `Repo` from a python path
Rapha?l Gom?s <rgomes@octobus.net>
parents: 49631
diff changeset
     6
use hg::config::Config;
28a0eb21ff04 rust-cpython: add a util to get a `Repo` from a python path
Rapha?l Gom?s <rgomes@octobus.net>
parents: 49631
diff changeset
     7
use hg::errors::HgError;
28a0eb21ff04 rust-cpython: add a util to get a `Repo` from a python path
Rapha?l Gom?s <rgomes@octobus.net>
parents: 49631
diff changeset
     8
use hg::repo::{Repo, RepoError};
44505
d738b7a18438 rust-nodemap: add utils to create `Node`s from Python objects
Georges Racinet <georges.racinet@octobus.net>
parents: 43251
diff changeset
     9
use hg::revlog::Node;
52042
28a0eb21ff04 rust-cpython: add a util to get a `Repo` from a python path
Rapha?l Gom?s <rgomes@octobus.net>
parents: 49631
diff changeset
    10
use hg::utils::files::get_path_from_bytes;
28a0eb21ff04 rust-cpython: add a util to get a `Repo` from a python path
Rapha?l Gom?s <rgomes@octobus.net>
parents: 49631
diff changeset
    11
28a0eb21ff04 rust-cpython: add a util to get a `Repo` from a python path
Rapha?l Gom?s <rgomes@octobus.net>
parents: 49631
diff changeset
    12
use crate::exceptions::FallbackError;
43251
970978975574 rust-utils: introduce a debug util to print the python stack trace
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
    13
970978975574 rust-utils: introduce a debug util to print the python stack trace
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
    14
#[allow(unused)]
970978975574 rust-utils: introduce a debug util to print the python stack trace
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
    15
pub fn print_python_trace(py: Python) -> PyResult<PyObject> {
970978975574 rust-utils: introduce a debug util to print the python stack trace
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
    16
    eprintln!("===============================");
970978975574 rust-utils: introduce a debug util to print the python stack trace
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
    17
    eprintln!("Printing Python stack from Rust");
970978975574 rust-utils: introduce a debug util to print the python stack trace
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
    18
    eprintln!("===============================");
970978975574 rust-utils: introduce a debug util to print the python stack trace
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
    19
    let traceback = py.import("traceback")?;
970978975574 rust-utils: introduce a debug util to print the python stack trace
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
    20
    let sys = py.import("sys")?;
970978975574 rust-utils: introduce a debug util to print the python stack trace
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
    21
    let kwargs = PyDict::new(py);
970978975574 rust-utils: introduce a debug util to print the python stack trace
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
    22
    kwargs.set_item(py, "file", sys.get(py, "stderr")?)?;
970978975574 rust-utils: introduce a debug util to print the python stack trace
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
    23
    traceback.call(py, "print_stack", PyTuple::new(py, &[]), Some(&kwargs))
970978975574 rust-utils: introduce a debug util to print the python stack trace
Rapha?l Gom?s <rgomes@octobus.net>
parents:
diff changeset
    24
}
44505
d738b7a18438 rust-nodemap: add utils to create `Node`s from Python objects
Georges Racinet <georges.racinet@octobus.net>
parents: 43251
diff changeset
    25
52042
28a0eb21ff04 rust-cpython: add a util to get a `Repo` from a python path
Rapha?l Gom?s <rgomes@octobus.net>
parents: 49631
diff changeset
    26
pub fn hgerror_to_pyerr<T>(
28a0eb21ff04 rust-cpython: add a util to get a `Repo` from a python path
Rapha?l Gom?s <rgomes@octobus.net>
parents: 49631
diff changeset
    27
    py: Python,
28a0eb21ff04 rust-cpython: add a util to get a `Repo` from a python path
Rapha?l Gom?s <rgomes@octobus.net>
parents: 49631
diff changeset
    28
    error: Result<T, HgError>,
28a0eb21ff04 rust-cpython: add a util to get a `Repo` from a python path
Rapha?l Gom?s <rgomes@octobus.net>
parents: 49631
diff changeset
    29
) -> PyResult<T> {
28a0eb21ff04 rust-cpython: add a util to get a `Repo` from a python path
Rapha?l Gom?s <rgomes@octobus.net>
parents: 49631
diff changeset
    30
    error.map_err(|e| match e {
28a0eb21ff04 rust-cpython: add a util to get a `Repo` from a python path
Rapha?l Gom?s <rgomes@octobus.net>
parents: 49631
diff changeset
    31
        HgError::IoError { .. } => {
28a0eb21ff04 rust-cpython: add a util to get a `Repo` from a python path
Rapha?l Gom?s <rgomes@octobus.net>
parents: 49631
diff changeset
    32
            PyErr::new::<cpython::exc::IOError, _>(py, e.to_string())
28a0eb21ff04 rust-cpython: add a util to get a `Repo` from a python path
Rapha?l Gom?s <rgomes@octobus.net>
parents: 49631
diff changeset
    33
        }
28a0eb21ff04 rust-cpython: add a util to get a `Repo` from a python path
Rapha?l Gom?s <rgomes@octobus.net>
parents: 49631
diff changeset
    34
        HgError::UnsupportedFeature(e) => {
28a0eb21ff04 rust-cpython: add a util to get a `Repo` from a python path
Rapha?l Gom?s <rgomes@octobus.net>
parents: 49631
diff changeset
    35
            let as_string = e.to_string();
28a0eb21ff04 rust-cpython: add a util to get a `Repo` from a python path
Rapha?l Gom?s <rgomes@octobus.net>
parents: 49631
diff changeset
    36
            log::trace!("Update from null fallback: {}", as_string);
28a0eb21ff04 rust-cpython: add a util to get a `Repo` from a python path
Rapha?l Gom?s <rgomes@octobus.net>
parents: 49631
diff changeset
    37
            PyErr::new::<FallbackError, _>(py, &as_string)
28a0eb21ff04 rust-cpython: add a util to get a `Repo` from a python path
Rapha?l Gom?s <rgomes@octobus.net>
parents: 49631
diff changeset
    38
        }
28a0eb21ff04 rust-cpython: add a util to get a `Repo` from a python path
Rapha?l Gom?s <rgomes@octobus.net>
parents: 49631
diff changeset
    39
        HgError::RaceDetected(_) => {
28a0eb21ff04 rust-cpython: add a util to get a `Repo` from a python path
Rapha?l Gom?s <rgomes@octobus.net>
parents: 49631
diff changeset
    40
            unreachable!("must not surface to the user")
28a0eb21ff04 rust-cpython: add a util to get a `Repo` from a python path
Rapha?l Gom?s <rgomes@octobus.net>
parents: 49631
diff changeset
    41
        }
52046
de317a87ea6a rust-pathauditor: match more of Python's behavior and display messages
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52042
diff changeset
    42
        HgError::Path(path_error) => {
de317a87ea6a rust-pathauditor: match more of Python's behavior and display messages
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52042
diff changeset
    43
            let msg = PyBytes::new(py, path_error.to_string().as_bytes());
de317a87ea6a rust-pathauditor: match more of Python's behavior and display messages
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52042
diff changeset
    44
            let cls = py
de317a87ea6a rust-pathauditor: match more of Python's behavior and display messages
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52042
diff changeset
    45
                .import("mercurial.error")
de317a87ea6a rust-pathauditor: match more of Python's behavior and display messages
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52042
diff changeset
    46
                .and_then(|m| m.get(py, "InputError"))
de317a87ea6a rust-pathauditor: match more of Python's behavior and display messages
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52042
diff changeset
    47
                .unwrap();
de317a87ea6a rust-pathauditor: match more of Python's behavior and display messages
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52042
diff changeset
    48
            PyErr::from_instance(
de317a87ea6a rust-pathauditor: match more of Python's behavior and display messages
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52042
diff changeset
    49
                py,
de317a87ea6a rust-pathauditor: match more of Python's behavior and display messages
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52042
diff changeset
    50
                cls.call(py, (msg,), None).ok().into_py_object(py),
de317a87ea6a rust-pathauditor: match more of Python's behavior and display messages
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52042
diff changeset
    51
            )
de317a87ea6a rust-pathauditor: match more of Python's behavior and display messages
Rapha?l Gom?s <rgomes@octobus.net>
parents: 52042
diff changeset
    52
        }
52042
28a0eb21ff04 rust-cpython: add a util to get a `Repo` from a python path
Rapha?l Gom?s <rgomes@octobus.net>
parents: 49631
diff changeset
    53
        e => PyErr::new::<cpython::exc::RuntimeError, _>(py, e.to_string()),
28a0eb21ff04 rust-cpython: add a util to get a `Repo` from a python path
Rapha?l Gom?s <rgomes@octobus.net>
parents: 49631
diff changeset
    54
    })
28a0eb21ff04 rust-cpython: add a util to get a `Repo` from a python path
Rapha?l Gom?s <rgomes@octobus.net>
parents: 49631
diff changeset
    55
}
28a0eb21ff04 rust-cpython: add a util to get a `Repo` from a python path
Rapha?l Gom?s <rgomes@octobus.net>
parents: 49631
diff changeset
    56
28a0eb21ff04 rust-cpython: add a util to get a `Repo` from a python path
Rapha?l Gom?s <rgomes@octobus.net>
parents: 49631
diff changeset
    57
pub fn repo_error_to_pyerr<T>(
28a0eb21ff04 rust-cpython: add a util to get a `Repo` from a python path
Rapha?l Gom?s <rgomes@octobus.net>
parents: 49631
diff changeset
    58
    py: Python,
28a0eb21ff04 rust-cpython: add a util to get a `Repo` from a python path
Rapha?l Gom?s <rgomes@octobus.net>
parents: 49631
diff changeset
    59
    error: Result<T, RepoError>,
28a0eb21ff04 rust-cpython: add a util to get a `Repo` from a python path
Rapha?l Gom?s <rgomes@octobus.net>
parents: 49631
diff changeset
    60
) -> PyResult<T> {
28a0eb21ff04 rust-cpython: add a util to get a `Repo` from a python path
Rapha?l Gom?s <rgomes@octobus.net>
parents: 49631
diff changeset
    61
    hgerror_to_pyerr(py, error.map_err(HgError::from))
28a0eb21ff04 rust-cpython: add a util to get a `Repo` from a python path
Rapha?l Gom?s <rgomes@octobus.net>
parents: 49631
diff changeset
    62
}
28a0eb21ff04 rust-cpython: add a util to get a `Repo` from a python path
Rapha?l Gom?s <rgomes@octobus.net>
parents: 49631
diff changeset
    63
28a0eb21ff04 rust-cpython: add a util to get a `Repo` from a python path
Rapha?l Gom?s <rgomes@octobus.net>
parents: 49631
diff changeset
    64
/// Get a repository from a given [`PyObject`] path, and bubble up any error
28a0eb21ff04 rust-cpython: add a util to get a `Repo` from a python path
Rapha?l Gom?s <rgomes@octobus.net>
parents: 49631
diff changeset
    65
/// that comes up.
28a0eb21ff04 rust-cpython: add a util to get a `Repo` from a python path
Rapha?l Gom?s <rgomes@octobus.net>
parents: 49631
diff changeset
    66
pub fn repo_from_path(py: Python, repo_path: PyObject) -> Result<Repo, PyErr> {
28a0eb21ff04 rust-cpython: add a util to get a `Repo` from a python path
Rapha?l Gom?s <rgomes@octobus.net>
parents: 49631
diff changeset
    67
    let config =
28a0eb21ff04 rust-cpython: add a util to get a `Repo` from a python path
Rapha?l Gom?s <rgomes@octobus.net>
parents: 49631
diff changeset
    68
        hgerror_to_pyerr(py, Config::load_non_repo().map_err(HgError::from))?;
28a0eb21ff04 rust-cpython: add a util to get a `Repo` from a python path
Rapha?l Gom?s <rgomes@octobus.net>
parents: 49631
diff changeset
    69
    let py_bytes = &repo_path.extract::<PyBytes>(py)?;
28a0eb21ff04 rust-cpython: add a util to get a `Repo` from a python path
Rapha?l Gom?s <rgomes@octobus.net>
parents: 49631
diff changeset
    70
    let repo_path = py_bytes.data(py);
28a0eb21ff04 rust-cpython: add a util to get a `Repo` from a python path
Rapha?l Gom?s <rgomes@octobus.net>
parents: 49631
diff changeset
    71
    let repo = repo_error_to_pyerr(
28a0eb21ff04 rust-cpython: add a util to get a `Repo` from a python path
Rapha?l Gom?s <rgomes@octobus.net>
parents: 49631
diff changeset
    72
        py,
28a0eb21ff04 rust-cpython: add a util to get a `Repo` from a python path
Rapha?l Gom?s <rgomes@octobus.net>
parents: 49631
diff changeset
    73
        Repo::find(&config, Some(get_path_from_bytes(repo_path).to_owned())),
28a0eb21ff04 rust-cpython: add a util to get a `Repo` from a python path
Rapha?l Gom?s <rgomes@octobus.net>
parents: 49631
diff changeset
    74
    )?;
28a0eb21ff04 rust-cpython: add a util to get a `Repo` from a python path
Rapha?l Gom?s <rgomes@octobus.net>
parents: 49631
diff changeset
    75
    Ok(repo)
28a0eb21ff04 rust-cpython: add a util to get a `Repo` from a python path
Rapha?l Gom?s <rgomes@octobus.net>
parents: 49631
diff changeset
    76
}
28a0eb21ff04 rust-cpython: add a util to get a `Repo` from a python path
Rapha?l Gom?s <rgomes@octobus.net>
parents: 49631
diff changeset
    77
44505
d738b7a18438 rust-nodemap: add utils to create `Node`s from Python objects
Georges Racinet <georges.racinet@octobus.net>
parents: 43251
diff changeset
    78
// Necessary evil for the time being, could maybe be moved to
d738b7a18438 rust-nodemap: add utils to create `Node`s from Python objects
Georges Racinet <georges.racinet@octobus.net>
parents: 43251
diff changeset
    79
// a TryFrom in Node itself
d738b7a18438 rust-nodemap: add utils to create `Node`s from Python objects
Georges Racinet <georges.racinet@octobus.net>
parents: 43251
diff changeset
    80
const NODE_BYTES_LENGTH: usize = 20;
d738b7a18438 rust-nodemap: add utils to create `Node`s from Python objects
Georges Racinet <georges.racinet@octobus.net>
parents: 43251
diff changeset
    81
type NodeData = [u8; NODE_BYTES_LENGTH];
d738b7a18438 rust-nodemap: add utils to create `Node`s from Python objects
Georges Racinet <georges.racinet@octobus.net>
parents: 43251
diff changeset
    82
d738b7a18438 rust-nodemap: add utils to create `Node`s from Python objects
Georges Racinet <georges.racinet@octobus.net>
parents: 43251
diff changeset
    83
/// Copy incoming Python bytes given as `PyObject` into `Node`,
d738b7a18438 rust-nodemap: add utils to create `Node`s from Python objects
Georges Racinet <georges.racinet@octobus.net>
parents: 43251
diff changeset
    84
/// doing the necessary checks
d738b7a18438 rust-nodemap: add utils to create `Node`s from Python objects
Georges Racinet <georges.racinet@octobus.net>
parents: 43251
diff changeset
    85
pub fn node_from_py_object<'a>(
d738b7a18438 rust-nodemap: add utils to create `Node`s from Python objects
Georges Racinet <georges.racinet@octobus.net>
parents: 43251
diff changeset
    86
    py: Python,
d738b7a18438 rust-nodemap: add utils to create `Node`s from Python objects
Georges Racinet <georges.racinet@octobus.net>
parents: 43251
diff changeset
    87
    bytes: &'a PyObject,
d738b7a18438 rust-nodemap: add utils to create `Node`s from Python objects
Georges Racinet <georges.racinet@octobus.net>
parents: 43251
diff changeset
    88
) -> PyResult<Node> {
d738b7a18438 rust-nodemap: add utils to create `Node`s from Python objects
Georges Racinet <georges.racinet@octobus.net>
parents: 43251
diff changeset
    89
    let as_py_bytes: &'a PyBytes = bytes.extract(py)?;
d738b7a18438 rust-nodemap: add utils to create `Node`s from Python objects
Georges Racinet <georges.racinet@octobus.net>
parents: 43251
diff changeset
    90
    node_from_py_bytes(py, as_py_bytes)
d738b7a18438 rust-nodemap: add utils to create `Node`s from Python objects
Georges Racinet <georges.racinet@octobus.net>
parents: 43251
diff changeset
    91
}
d738b7a18438 rust-nodemap: add utils to create `Node`s from Python objects
Georges Racinet <georges.racinet@octobus.net>
parents: 43251
diff changeset
    92
d738b7a18438 rust-nodemap: add utils to create `Node`s from Python objects
Georges Racinet <georges.racinet@octobus.net>
parents: 43251
diff changeset
    93
/// Clone incoming Python bytes given as `PyBytes` as a `Node`,
d738b7a18438 rust-nodemap: add utils to create `Node`s from Python objects
Georges Racinet <georges.racinet@octobus.net>
parents: 43251
diff changeset
    94
/// doing the necessary checks.
44973
26114bd6ec60 rust: do a clippy pass
Rapha?l Gom?s <rgomes@octobus.net>
parents: 44505
diff changeset
    95
pub fn node_from_py_bytes(py: Python, bytes: &PyBytes) -> PyResult<Node> {
44505
d738b7a18438 rust-nodemap: add utils to create `Node`s from Python objects
Georges Racinet <georges.racinet@octobus.net>
parents: 43251
diff changeset
    96
    <NodeData>::try_from(bytes.data(py))
d738b7a18438 rust-nodemap: add utils to create `Node`s from Python objects
Georges Racinet <georges.racinet@octobus.net>
parents: 43251
diff changeset
    97
        .map_err(|_| {
d738b7a18438 rust-nodemap: add utils to create `Node`s from Python objects
Georges Racinet <georges.racinet@octobus.net>
parents: 43251
diff changeset
    98
            PyErr::new::<ValueError, _>(
d738b7a18438 rust-nodemap: add utils to create `Node`s from Python objects
Georges Racinet <georges.racinet@octobus.net>
parents: 43251
diff changeset
    99
                py,
d738b7a18438 rust-nodemap: add utils to create `Node`s from Python objects
Georges Racinet <georges.racinet@octobus.net>
parents: 43251
diff changeset
   100
                format!("{}-byte hash required", NODE_BYTES_LENGTH),
d738b7a18438 rust-nodemap: add utils to create `Node`s from Python objects
Georges Racinet <georges.racinet@octobus.net>
parents: 43251
diff changeset
   101
            )
d738b7a18438 rust-nodemap: add utils to create `Node`s from Python objects
Georges Racinet <georges.racinet@octobus.net>
parents: 43251
diff changeset
   102
        })
44973
26114bd6ec60 rust: do a clippy pass
Rapha?l Gom?s <rgomes@octobus.net>
parents: 44505
diff changeset
   103
        .map(Into::into)
44505
d738b7a18438 rust-nodemap: add utils to create `Node`s from Python objects
Georges Racinet <georges.racinet@octobus.net>
parents: 43251
diff changeset
   104
}