rust/hg-cpython/src/utils.rs
changeset 52046 28a0eb21ff04
parent 49631 c7fb9b74e753
child 52050 de317a87ea6a
--- 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;