--- a/rust/hg-cpython/src/utils.rs Tue Oct 01 13:20:40 2024 +0200
+++ b/rust/hg-cpython/src/utils.rs Tue Oct 01 13:45:18 2024 +0200
@@ -1,6 +1,12 @@
use cpython::exc::ValueError;
use cpython::{PyBytes, PyDict, PyErr, PyObject, PyResult, PyTuple, Python};
+use hg::config::Config;
+use hg::errors::HgError;
+use hg::repo::{Repo, RepoError};
use hg::revlog::Node;
+use hg::utils::files::get_path_from_bytes;
+
+use crate::exceptions::FallbackError;
#[allow(unused)]
pub fn print_python_trace(py: Python) -> PyResult<PyObject> {
@@ -14,6 +20,47 @@
traceback.call(py, "print_stack", PyTuple::new(py, &[]), Some(&kwargs))
}
+pub fn hgerror_to_pyerr<T>(
+ py: Python,
+ error: Result<T, HgError>,
+) -> PyResult<T> {
+ error.map_err(|e| match e {
+ HgError::IoError { .. } => {
+ PyErr::new::<cpython::exc::IOError, _>(py, e.to_string())
+ }
+ HgError::UnsupportedFeature(e) => {
+ let as_string = e.to_string();
+ log::trace!("Update from null fallback: {}", as_string);
+ PyErr::new::<FallbackError, _>(py, &as_string)
+ }
+ HgError::RaceDetected(_) => {
+ unreachable!("must not surface to the user")
+ }
+ e => PyErr::new::<cpython::exc::RuntimeError, _>(py, e.to_string()),
+ })
+}
+
+pub fn repo_error_to_pyerr<T>(
+ py: Python,
+ error: Result<T, RepoError>,
+) -> PyResult<T> {
+ hgerror_to_pyerr(py, error.map_err(HgError::from))
+}
+
+/// Get a repository from a given [`PyObject`] path, and bubble up any error
+/// that comes up.
+pub fn repo_from_path(py: Python, repo_path: PyObject) -> Result<Repo, PyErr> {
+ let config =
+ hgerror_to_pyerr(py, Config::load_non_repo().map_err(HgError::from))?;
+ let py_bytes = &repo_path.extract::<PyBytes>(py)?;
+ let repo_path = py_bytes.data(py);
+ let repo = repo_error_to_pyerr(
+ py,
+ Repo::find(&config, Some(get_path_from_bytes(repo_path).to_owned())),
+ )?;
+ Ok(repo)
+}
+
// Necessary evil for the time being, could maybe be moved to
// a TryFrom in Node itself
const NODE_BYTES_LENGTH: usize = 20;