dirstate.rs
147 lines
| 4.5 KiB
| application/rls-services+xml
|
RustLexer
Raphaël Gomès
|
r42489 | // dirstate.rs | ||
// | ||||
// Copyright 2019 Raphaël Gomès <rgomes@octobus.net> | ||||
// | ||||
// This software may be used and distributed according to the terms of the | ||||
// GNU General Public License version 2 or any later version. | ||||
//! Bindings for the `hg::dirstate` module provided by the | ||||
//! `hg-core` package. | ||||
//! | ||||
//! From Python, this will be seen as `mercurial.rustext.dirstate` | ||||
Raphaël Gomès
|
r42999 | mod copymap; | ||
Raphaël Gomès
|
r42991 | mod dirs_multiset; | ||
Raphaël Gomès
|
r42999 | mod dirstate_map; | ||
Raphaël Gomès
|
r44779 | mod non_normal_entries; | ||
Raphaël Gomès
|
r43567 | mod status; | ||
Raphaël Gomès
|
r45016 | use crate::{ | ||
dirstate::{ | ||||
dirs_multiset::Dirs, dirstate_map::DirstateMap, status::status_wrapper, | ||||
}, | ||||
exceptions, | ||||
Raphaël Gomès
|
r43567 | }; | ||
Raphaël Gomès
|
r42489 | use cpython::{ | ||
Raphaël Gomès
|
r45016 | exc, PyBytes, PyDict, PyErr, PyList, PyModule, PyObject, PyResult, | ||
PySequence, Python, | ||||
Raphaël Gomès
|
r42489 | }; | ||
Raphaël Gomès
|
r43227 | use hg::{ | ||
utils::hg_path::HgPathBuf, DirstateEntry, DirstateParseError, EntryState, | ||||
StateMap, | ||||
}; | ||||
Raphaël Gomès
|
r42828 | use libc::{c_char, c_int}; | ||
Raphaël Gomès
|
r42994 | use std::convert::TryFrom; | ||
Raphaël Gomès
|
r42489 | |||
Yuya Nishihara
|
r43482 | // C code uses a custom `dirstate_tuple` type, checks in multiple instances | ||
// for this type, and raises a Python `Exception` if the check does not pass. | ||||
// Because this type differs only in name from the regular Python tuple, it | ||||
// would be a good idea in the near future to remove it entirely to allow | ||||
// for a pure Python tuple of the same effective structure to be used, | ||||
// rendering this type and the capsule below useless. | ||||
Yuya Nishihara
|
r43484 | py_capsule_fn!( | ||
from mercurial.cext.parsers import make_dirstate_tuple_CAPI | ||||
as make_dirstate_tuple_capi | ||||
signature ( | ||||
state: c_char, | ||||
mode: c_int, | ||||
size: c_int, | ||||
mtime: c_int, | ||||
) -> *mut RawPyObject | ||||
); | ||||
Raphaël Gomès
|
r42489 | |||
Yuya Nishihara
|
r43479 | pub fn make_dirstate_tuple( | ||
py: Python, | ||||
entry: &DirstateEntry, | ||||
) -> PyResult<PyObject> { | ||||
Yuya Nishihara
|
r43484 | // might be silly to retrieve capsule function in hot loop | ||
let make = make_dirstate_tuple_capi::retrieve(py)?; | ||||
Yuya Nishihara
|
r43479 | |||
let &DirstateEntry { | ||||
state, | ||||
mode, | ||||
size, | ||||
mtime, | ||||
} = entry; | ||||
// Explicitly go through u8 first, then cast to platform-specific `c_char` | ||||
// because Into<u8> has a specific implementation while `as c_char` would | ||||
// just do a naive enum cast. | ||||
let state_code: u8 = state.into(); | ||||
Yuya Nishihara
|
r43480 | |||
Yuya Nishihara
|
r43481 | let maybe_obj = unsafe { | ||
Yuya Nishihara
|
r43480 | let ptr = make(state_code as c_char, mode, size, mtime); | ||
Yuya Nishihara
|
r43481 | PyObject::from_owned_ptr_opt(py, ptr) | ||
}; | ||||
maybe_obj.ok_or_else(|| PyErr::fetch(py)) | ||||
Yuya Nishihara
|
r43479 | } | ||
Raphaël Gomès
|
r42993 | pub fn extract_dirstate(py: Python, dmap: &PyDict) -> Result<StateMap, PyErr> { | ||
Raphaël Gomès
|
r42737 | dmap.items(py) | ||
Raphaël Gomès
|
r42489 | .iter() | ||
.map(|(filename, stats)| { | ||||
let stats = stats.extract::<PySequence>(py)?; | ||||
let state = stats.get_item(py, 0)?.extract::<PyBytes>(py)?; | ||||
Raphaël Gomès
|
r42994 | let state = EntryState::try_from(state.data(py)[0]).map_err( | ||
|e: DirstateParseError| { | ||||
PyErr::new::<exc::ValueError, _>(py, e.to_string()) | ||||
}, | ||||
)?; | ||||
Raphaël Gomès
|
r42489 | let mode = stats.get_item(py, 1)?.extract(py)?; | ||
let size = stats.get_item(py, 2)?.extract(py)?; | ||||
let mtime = stats.get_item(py, 3)?.extract(py)?; | ||||
let filename = filename.extract::<PyBytes>(py)?; | ||||
let filename = filename.data(py); | ||||
Ok(( | ||||
Raphaël Gomès
|
r43227 | HgPathBuf::from(filename.to_owned()), | ||
Raphaël Gomès
|
r42489 | DirstateEntry { | ||
state, | ||||
mode, | ||||
size, | ||||
mtime, | ||||
}, | ||||
)) | ||||
}) | ||||
Raphaël Gomès
|
r42737 | .collect() | ||
} | ||||
Raphaël Gomès
|
r42489 | /// Create the module, with `__package__` given from parent | ||
pub fn init_module(py: Python, package: &str) -> PyResult<PyModule> { | ||||
let dotted_name = &format!("{}.dirstate", package); | ||||
let m = PyModule::new(py, dotted_name)?; | ||||
Raphaël Gomès
|
r42737 | |||
Raphaël Gomès
|
r45027 | simple_logger::init_by_env(); | ||
Raphaël Gomès
|
r42489 | m.add(py, "__package__", package)?; | ||
m.add(py, "__doc__", "Dirstate - Rust implementation")?; | ||||
Raphaël Gomès
|
r45016 | m.add( | ||
py, | ||||
"FallbackError", | ||||
py.get_type::<exceptions::FallbackError>(), | ||||
)?; | ||||
Raphaël Gomès
|
r42737 | m.add_class::<Dirs>(py)?; | ||
Raphaël Gomès
|
r42999 | m.add_class::<DirstateMap>(py)?; | ||
Raphaël Gomès
|
r43567 | m.add( | ||
py, | ||||
"status", | ||||
py_fn!( | ||||
py, | ||||
status_wrapper( | ||||
dmap: DirstateMap, | ||||
root_dir: PyObject, | ||||
Raphaël Gomès
|
r44368 | matcher: PyObject, | ||
Raphaël Gomès
|
r45016 | ignorefiles: PyList, | ||
check_exec: bool, | ||||
Raphaël Gomès
|
r43567 | last_normal_time: i64, | ||
Raphaël Gomès
|
r45016 | list_clean: bool, | ||
list_ignored: bool, | ||||
Raphaël Gomès
|
r45354 | list_unknown: bool, | ||
collect_traversed_dirs: bool | ||||
Raphaël Gomès
|
r43567 | ) | ||
), | ||||
)?; | ||||
Raphaël Gomès
|
r42737 | |||
Raphaël Gomès
|
r42489 | 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) | ||||
} | ||||