rust-dirstatemap: add Rust implementation of `reset_state`
This is the new API which has already been defined in Python
Differential Revision: https://phab.mercurial-scm.org/D12499
--- a/rust/hg-core/src/dirstate/entry.rs Wed Mar 23 17:38:59 2022 +0100
+++ b/rust/hg-core/src/dirstate/entry.rs Wed Mar 23 17:27:58 2022 +0100
@@ -259,6 +259,12 @@
pub fallback_symlink: Option<bool>,
}
+#[derive(Debug, Default, Copy, Clone)]
+pub struct ParentFileData {
+ pub mode_size: Option<(u32, u32)>,
+ pub mtime: Option<TruncatedTimestamp>,
+}
+
impl DirstateEntry {
pub fn from_v2_data(v2_data: DirstateV2Data) -> Self {
let DirstateV2Data {
--- a/rust/hg-core/src/dirstate_tree/dirstate_map.rs Wed Mar 23 17:38:59 2022 +0100
+++ b/rust/hg-core/src/dirstate_tree/dirstate_map.rs Wed Mar 23 17:27:58 2022 +0100
@@ -11,6 +11,8 @@
use crate::dirstate::parsers::packed_entry_size;
use crate::dirstate::parsers::parse_dirstate_entries;
use crate::dirstate::CopyMapIter;
+use crate::dirstate::DirstateV2Data;
+use crate::dirstate::ParentFileData;
use crate::dirstate::StateMapIter;
use crate::dirstate::TruncatedTimestamp;
use crate::dirstate::SIZE_FROM_OTHER_PARENT;
@@ -606,6 +608,73 @@
}
}
+ fn reset_state(
+ &mut self,
+ filename: &HgPath,
+ old_entry_opt: Option<DirstateEntry>,
+ wc_tracked: bool,
+ p1_tracked: bool,
+ p2_info: bool,
+ has_meaningful_mtime: bool,
+ parent_file_data_opt: Option<ParentFileData>,
+ ) -> Result<(), DirstateError> {
+ let (had_entry, was_tracked) = match old_entry_opt {
+ Some(old_entry) => (true, old_entry.tracked()),
+ None => (false, false),
+ };
+ let node = Self::get_or_insert_node(
+ self.on_disk,
+ &mut self.unreachable_bytes,
+ &mut self.root,
+ filename,
+ WithBasename::to_cow_owned,
+ |ancestor| {
+ if !had_entry {
+ ancestor.descendants_with_entry_count += 1;
+ }
+ if was_tracked {
+ if !wc_tracked {
+ ancestor.tracked_descendants_count = ancestor
+ .tracked_descendants_count
+ .checked_sub(1)
+ .expect("tracked count to be >= 0");
+ }
+ } else {
+ if wc_tracked {
+ ancestor.tracked_descendants_count += 1;
+ }
+ }
+ },
+ )?;
+
+ let v2_data = if let Some(parent_file_data) = parent_file_data_opt {
+ DirstateV2Data {
+ wc_tracked,
+ p1_tracked,
+ p2_info,
+ mode_size: parent_file_data.mode_size,
+ mtime: if has_meaningful_mtime {
+ parent_file_data.mtime
+ } else {
+ None
+ },
+ ..Default::default()
+ }
+ } else {
+ DirstateV2Data {
+ wc_tracked,
+ p1_tracked,
+ p2_info,
+ ..Default::default()
+ }
+ };
+ if !had_entry {
+ self.nodes_with_entry_count += 1;
+ }
+ node.data = NodeData::Entry(DirstateEntry::from_v2_data(v2_data));
+ Ok(())
+ }
+
fn set_tracked(
&mut self,
filename: &HgPath,
@@ -812,6 +881,34 @@
self.with_dmap_mut(|map| map.set_tracked(filename, old_entry_opt))
}
+ pub fn reset_state(
+ &mut self,
+ filename: &HgPath,
+ wc_tracked: bool,
+ p1_tracked: bool,
+ p2_info: bool,
+ has_meaningful_mtime: bool,
+ parent_file_data_opt: Option<ParentFileData>,
+ ) -> Result<(), DirstateError> {
+ if !(p1_tracked || p2_info || wc_tracked) {
+ self.drop_entry_and_copy_source(filename)?;
+ return Ok(());
+ }
+ self.copy_map_remove(filename)?;
+ let old_entry_opt = self.get(filename)?;
+ self.with_dmap_mut(|map| {
+ map.reset_state(
+ filename,
+ old_entry_opt,
+ wc_tracked,
+ p1_tracked,
+ p2_info,
+ has_meaningful_mtime,
+ parent_file_data_opt,
+ )
+ })
+ }
+
pub fn remove_file(
&mut self,
filename: &HgPath,
--- a/rust/hg-cpython/src/dirstate/dirstate_map.rs Wed Mar 23 17:38:59 2022 +0100
+++ b/rust/hg-cpython/src/dirstate/dirstate_map.rs Wed Mar 23 17:27:58 2022 +0100
@@ -15,6 +15,7 @@
exc, PyBool, PyBytes, PyClone, PyDict, PyErr, PyList, PyNone, PyObject,
PyResult, Python, PythonObject, ToPyObject, UnsafePyLeaked,
};
+use hg::dirstate::{ParentFileData, TruncatedTimestamp};
use crate::{
dirstate::copymap::{CopyMap, CopyMapItemsIterator, CopyMapKeysIterator},
@@ -141,6 +142,55 @@
Ok(was_tracked.to_py_object(py))
}
+ def reset_state(
+ &self,
+ f: PyObject,
+ wc_tracked: bool,
+ p1_tracked: bool,
+ p2_info: bool,
+ has_meaningful_mtime: bool,
+ parentfiledata: Option<(u32, u32, Option<(i64, u32, bool)>)>,
+ ) -> PyResult<PyNone> {
+ let mut has_meaningful_mtime = has_meaningful_mtime;
+ let parent_file_data = match parentfiledata {
+ None => {
+ has_meaningful_mtime = false;
+ None
+ },
+ Some(data) => {
+ let (mode, size, mtime_info) = data;
+ let mtime = if let Some(mtime_info) = mtime_info {
+ let (mtime_s, mtime_ns, second_ambiguous) = mtime_info;
+ let timestamp = TruncatedTimestamp::new_truncate(
+ mtime_s, mtime_ns, second_ambiguous
+ );
+ Some(timestamp)
+ } else {
+ has_meaningful_mtime = false;
+ None
+ };
+ Some(ParentFileData {
+ mode_size: Some((mode, size)),
+ mtime,
+ })
+ }
+ };
+ let bytes = f.extract::<PyBytes>(py)?;
+ let path = HgPath::new(bytes.data(py));
+ let res = self.inner(py).borrow_mut().reset_state(
+ path,
+ wc_tracked,
+ p1_tracked,
+ p2_info,
+ has_meaningful_mtime,
+ parent_file_data,
+ );
+ res.or_else(|_| {
+ Err(PyErr::new::<exc::OSError, _>(py, "Dirstate error".to_string()))
+ })?;
+ Ok(PyNone)
+ }
+
def removefile(
&self,
f: PyObject,