copy_tracing.rs
148 lines
| 4.9 KiB
| application/rls-services+xml
|
RustLexer
r46557 | use cpython::ObjectProtocol; | |||
use cpython::PyBool; | ||||
use cpython::PyBytes; | ||||
use cpython::PyDict; | ||||
use cpython::PyList; | ||||
use cpython::PyModule; | ||||
use cpython::PyObject; | ||||
use cpython::PyResult; | ||||
use cpython::PyTuple; | ||||
use cpython::Python; | ||||
use hg::copy_tracing::combine_changeset_copies; | ||||
use hg::copy_tracing::ChangedFiles; | ||||
r46674 | use hg::copy_tracing::DataHolder; | |||
r46557 | use hg::copy_tracing::RevInfo; | |||
r46674 | use hg::copy_tracing::RevInfoMaker; | |||
r46557 | use hg::Revision; | |||
/// Combines copies information contained into revision `revs` to build a copy | ||||
/// map. | ||||
/// | ||||
/// See mercurial/copies.py for details | ||||
pub fn combine_changeset_copies_wrapper( | ||||
py: Python, | ||||
revs: PyList, | ||||
r46764 | children_count: PyDict, | |||
r46557 | target_rev: Revision, | |||
rev_info: PyObject, | ||||
is_ancestor: PyObject, | ||||
) -> PyResult<PyDict> { | ||||
let revs: PyResult<_> = | ||||
revs.iter(py).map(|r| Ok(r.extract(py)?)).collect(); | ||||
// Wrap the `is_ancestor` python callback as a Rust closure | ||||
// | ||||
// No errors are expected from the Python side, and they will should only | ||||
// happens in case of programing error or severe data corruption. Such | ||||
// errors will raise panic and the rust-cpython harness will turn them into | ||||
// Python exception. | ||||
let is_ancestor_wrap = |anc: Revision, desc: Revision| -> bool { | ||||
is_ancestor | ||||
.call(py, (anc, desc), None) | ||||
.expect( | ||||
"rust-copy-tracing: python call to `is_ancestor` \ | ||||
failed", | ||||
) | ||||
.cast_into::<PyBool>(py) | ||||
.expect( | ||||
"rust-copy-tracing: python call to `is_ancestor` \ | ||||
returned unexpected non-Bool value", | ||||
) | ||||
.is_true() | ||||
}; | ||||
// Wrap the `rev_info_maker` python callback as a Rust closure | ||||
// | ||||
// No errors are expected from the Python side, and they will should only | ||||
// happens in case of programing error or severe data corruption. Such | ||||
// errors will raise panic and the rust-cpython harness will turn them into | ||||
// Python exception. | ||||
r46674 | let rev_info_maker: RevInfoMaker<PyBytes> = | |||
Box::new(|rev: Revision, d: &mut DataHolder<PyBytes>| -> RevInfo { | ||||
let res: PyTuple = rev_info | ||||
.call(py, (rev,), None) | ||||
.expect("rust-copy-tracing: python call to `rev_info` failed") | ||||
r46557 | .cast_into(py) | |||
.expect( | ||||
r46674 | "rust-copy_tracing: python call to `rev_info` returned \ | |||
unexpected non-Tuple value", | ||||
r46557 | ); | |||
r46674 | let p1 = res.get_item(py, 0).extract(py).expect( | |||
"rust-copy-tracing: rev_info return is invalid, first item \ | ||||
is a not a revision", | ||||
r46557 | ); | |||
r46674 | let p2 = res.get_item(py, 1).extract(py).expect( | |||
"rust-copy-tracing: rev_info return is invalid, first item \ | ||||
is a not a revision", | ||||
r46557 | ); | |||
r46674 | let files = match res.get_item(py, 2).extract::<PyBytes>(py) { | |||
Ok(raw) => { | ||||
// Give responsability for the raw bytes lifetime to | ||||
// hg-core | ||||
d.data = Some(raw); | ||||
let addrs = d.data.as_ref().expect( | ||||
"rust-copy-tracing: failed to get a reference to the \ | ||||
raw bytes for copy data").data(py); | ||||
ChangedFiles::new(addrs) | ||||
} | ||||
// value was presumably None, meaning they was no copy data. | ||||
Err(_) => ChangedFiles::new_empty(), | ||||
}; | ||||
r46557 | ||||
r46674 | (p1, p2, files) | |||
}); | ||||
r46764 | let children_count: PyResult<_> = children_count | |||
r46557 | .items(py) | |||
.iter() | ||||
r46764 | .map(|(k, v)| Ok((k.extract(py)?, v.extract(py)?))) | |||
r46557 | .collect(); | |||
let res = combine_changeset_copies( | ||||
revs?, | ||||
r46764 | children_count?, | |||
r46557 | target_rev, | |||
r46674 | rev_info_maker, | |||
r46557 | &is_ancestor_wrap, | |||
); | ||||
let out = PyDict::new(py); | ||||
for (dest, source) in res.into_iter() { | ||||
out.set_item( | ||||
py, | ||||
PyBytes::new(py, &dest.into_vec()), | ||||
PyBytes::new(py, &source.into_vec()), | ||||
)?; | ||||
} | ||||
Ok(out) | ||||
} | ||||
/// Create the module, with `__package__` given from parent | ||||
pub fn init_module(py: Python, package: &str) -> PyResult<PyModule> { | ||||
let dotted_name = &format!("{}.copy_tracing", package); | ||||
let m = PyModule::new(py, dotted_name)?; | ||||
m.add(py, "__package__", package)?; | ||||
m.add(py, "__doc__", "Copy tracing - Rust implementation")?; | ||||
m.add( | ||||
py, | ||||
"combine_changeset_copies", | ||||
py_fn!( | ||||
py, | ||||
combine_changeset_copies_wrapper( | ||||
revs: PyList, | ||||
children: PyDict, | ||||
target_rev: Revision, | ||||
rev_info: PyObject, | ||||
is_ancestor: PyObject | ||||
) | ||||
), | ||||
)?; | ||||
let sys = PyModule::import(py, "sys")?; | ||||
let sys_modules: PyDict = sys.get(py, "modules")?.extract(py)?; | ||||
sys_modules.set_item(py, dotted_name, &m)?; | ||||
Ok(m) | ||||
} | ||||