|
|
// 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`
|
|
|
mod copymap;
|
|
|
mod dirs_multiset;
|
|
|
mod dirstate_map;
|
|
|
mod non_normal_entries;
|
|
|
mod status;
|
|
|
use crate::{
|
|
|
dirstate::{
|
|
|
dirs_multiset::Dirs, dirstate_map::DirstateMap, status::status_wrapper,
|
|
|
},
|
|
|
exceptions,
|
|
|
};
|
|
|
use cpython::{
|
|
|
PyBytes, PyDict, PyErr, PyList, PyModule, PyObject, PyResult, Python,
|
|
|
};
|
|
|
use hg::dirstate_tree::on_disk::V2_FORMAT_MARKER;
|
|
|
use hg::DirstateEntry;
|
|
|
use libc::{c_char, c_int};
|
|
|
|
|
|
// 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.
|
|
|
py_capsule_fn!(
|
|
|
from mercurial.cext.parsers import make_dirstate_item_CAPI
|
|
|
as make_dirstate_item_capi
|
|
|
signature (
|
|
|
state: c_char,
|
|
|
mode: c_int,
|
|
|
size: c_int,
|
|
|
mtime: c_int,
|
|
|
) -> *mut RawPyObject
|
|
|
);
|
|
|
|
|
|
pub fn make_dirstate_item(
|
|
|
py: Python,
|
|
|
entry: &DirstateEntry,
|
|
|
) -> PyResult<PyObject> {
|
|
|
// 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 = entry.state().into();
|
|
|
make_dirstate_item_raw(
|
|
|
py,
|
|
|
state_code,
|
|
|
entry.mode(),
|
|
|
entry.size(),
|
|
|
entry.mtime(),
|
|
|
)
|
|
|
}
|
|
|
|
|
|
pub fn make_dirstate_item_raw(
|
|
|
py: Python,
|
|
|
state: u8,
|
|
|
mode: i32,
|
|
|
size: i32,
|
|
|
mtime: i32,
|
|
|
) -> PyResult<PyObject> {
|
|
|
let make = make_dirstate_item_capi::retrieve(py)?;
|
|
|
let maybe_obj = unsafe {
|
|
|
let ptr = make(state as c_char, mode, size, mtime);
|
|
|
PyObject::from_owned_ptr_opt(py, ptr)
|
|
|
};
|
|
|
maybe_obj.ok_or_else(|| PyErr::fetch(py))
|
|
|
}
|
|
|
|
|
|
/// 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)?;
|
|
|
|
|
|
env_logger::init();
|
|
|
|
|
|
m.add(py, "__package__", package)?;
|
|
|
m.add(py, "__doc__", "Dirstate - Rust implementation")?;
|
|
|
|
|
|
m.add(
|
|
|
py,
|
|
|
"FallbackError",
|
|
|
py.get_type::<exceptions::FallbackError>(),
|
|
|
)?;
|
|
|
m.add_class::<Dirs>(py)?;
|
|
|
m.add_class::<DirstateMap>(py)?;
|
|
|
m.add(py, "V2_FORMAT_MARKER", PyBytes::new(py, V2_FORMAT_MARKER))?;
|
|
|
m.add(
|
|
|
py,
|
|
|
"status",
|
|
|
py_fn!(
|
|
|
py,
|
|
|
status_wrapper(
|
|
|
dmap: DirstateMap,
|
|
|
root_dir: PyObject,
|
|
|
matcher: PyObject,
|
|
|
ignorefiles: PyList,
|
|
|
check_exec: bool,
|
|
|
last_normal_time: i64,
|
|
|
list_clean: bool,
|
|
|
list_ignored: bool,
|
|
|
list_unknown: bool,
|
|
|
collect_traversed_dirs: bool
|
|
|
)
|
|
|
),
|
|
|
)?;
|
|
|
|
|
|
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)
|
|
|
}
|
|
|
|