dirstate_map.rs
682 lines
| 22.0 KiB
| application/rls-services+xml
|
RustLexer
|
r42999 | // dirstate_map.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::dirstate_map` file provided by the | ||||
//! `hg-core` package. | ||||
|
r47882 | use std::cell::{RefCell, RefMut}; | ||
|
r42999 | use std::convert::TryInto; | ||
use cpython::{ | ||||
|
r44836 | exc, ObjectProtocol, PyBool, PyBytes, PyClone, PyDict, PyErr, PyList, | ||
|
r47891 | PyObject, PyResult, PySet, PyString, Python, PythonObject, ToPyObject, | ||
UnsafePyLeaked, | ||||
|
r42999 | }; | ||
use crate::{ | ||||
dirstate::copymap::{CopyMap, CopyMapItemsIterator, CopyMapKeysIterator}, | ||||
r48328 | dirstate::make_dirstate_item, | |||
|
r48483 | dirstate::make_dirstate_item_raw, | ||
|
r44903 | dirstate::non_normal_entries::{ | ||
NonNormalEntries, NonNormalEntriesIterator, | ||||
}, | ||||
|
r48766 | pybytes_deref::PyBytesDeref, | ||
|
r42999 | }; | ||
use hg::{ | ||||
|
r47871 | dirstate::parsers::Timestamp, | ||
r48310 | dirstate::MTIME_UNSET, | |||
dirstate::SIZE_NON_NORMAL, | ||||
|
r48766 | dirstate_tree::dirstate_map::DirstateMap as TreeDirstateMap, | ||
|
r47863 | dirstate_tree::dispatch::DirstateMapMethods, | ||
|
r48126 | dirstate_tree::on_disk::DirstateV2ParseError, | ||
|
r48766 | dirstate_tree::owning::OwningDirstateMap, | ||
|
r47337 | revlog::Node, | ||
|
r47879 | utils::files::normalize_case, | ||
|
r43227 | utils::hg_path::{HgPath, HgPathBuf}, | ||
|
r48271 | DirstateEntry, DirstateError, DirstateMap as RustDirstateMap, | ||
DirstateParents, EntryState, StateMapIter, | ||||
|
r42999 | }; | ||
// TODO | ||||
// This object needs to share references to multiple members of its Rust | ||||
// inner struct, namely `copy_map`, `dirs` and `all_dirs`. | ||||
// Right now `CopyMap` is done, but it needs to have an explicit reference | ||||
// to `RustDirstateMap` which itself needs to have an encapsulation for | ||||
// every method in `CopyMap` (copymapcopy, etc.). | ||||
// This is ugly and hard to maintain. | ||||
// The same logic applies to `dirs` and `all_dirs`, however the `Dirs` | ||||
// `py_class!` is already implemented and does not mention | ||||
// `RustDirstateMap`, rightfully so. | ||||
// All attributes also have to have a separate refcount data attribute for | ||||
// leaks, with all methods that go along for reference sharing. | ||||
py_class!(pub class DirstateMap |py| { | ||||
|
r47863 | @shared data inner: Box<dyn DirstateMapMethods + Send>; | ||
|
r42999 | |||
|
r47892 | /// Returns a `(dirstate_map, parents)` tuple | ||
@staticmethod | ||||
|
r48474 | def new_v1( | ||
|
r48055 | use_dirstate_tree: bool, | ||
on_disk: PyBytes, | ||||
) -> PyResult<PyObject> { | ||||
|
r48474 | let (inner, parents) = if use_dirstate_tree { | ||
|
r48766 | let on_disk = PyBytesDeref::new(py, on_disk); | ||
let mut map = OwningDirstateMap::new_empty(on_disk); | ||||
let (on_disk, map_placeholder) = map.get_mut_pair(); | ||||
let (actual_map, parents) = TreeDirstateMap::new_v1(on_disk) | ||||
|
r48483 | .map_err(|e| dirstate_error(py, e))?; | ||
|
r48766 | *map_placeholder = actual_map; | ||
|
r47892 | (Box::new(map) as _, parents) | ||
|
r47865 | } else { | ||
|
r47893 | let bytes = on_disk.data(py); | ||
|
r47892 | let mut map = RustDirstateMap::default(); | ||
|
r48483 | let parents = map.read(bytes).map_err(|e| dirstate_error(py, e))?; | ||
|
r47892 | (Box::new(map) as _, parents) | ||
|
r47865 | }; | ||
|
r47892 | let map = Self::create_instance(py, inner)?; | ||
|
r48832 | let parents = parents.map(|p| { | ||
let p1 = PyBytes::new(py, p.p1.as_bytes()); | ||||
let p2 = PyBytes::new(py, p.p2.as_bytes()); | ||||
(p1, p2) | ||||
}); | ||||
|
r47892 | Ok((map, parents).to_py_object(py).into_object()) | ||
|
r42999 | } | ||
|
r48474 | /// Returns a DirstateMap | ||
@staticmethod | ||||
def new_v2( | ||||
on_disk: PyBytes, | ||||
|
r48475 | data_size: usize, | ||
|
r48482 | tree_metadata: PyBytes, | ||
|
r48474 | ) -> PyResult<PyObject> { | ||
let dirstate_error = |e: DirstateError| { | ||||
PyErr::new::<exc::OSError, _>(py, format!("Dirstate error: {:?}", e)) | ||||
}; | ||||
|
r48766 | let on_disk = PyBytesDeref::new(py, on_disk); | ||
let mut map = OwningDirstateMap::new_empty(on_disk); | ||||
let (on_disk, map_placeholder) = map.get_mut_pair(); | ||||
*map_placeholder = TreeDirstateMap::new_v2( | ||||
on_disk, data_size, tree_metadata.data(py), | ||||
|
r48482 | ).map_err(dirstate_error)?; | ||
|
r48766 | let map = Self::create_instance(py, Box::new(map))?; | ||
|
r48474 | Ok(map.into_object()) | ||
} | ||||
|
r42999 | def clear(&self) -> PyResult<PyObject> { | ||
|
r44702 | self.inner(py).borrow_mut().clear(); | ||
|
r42999 | Ok(py.None()) | ||
} | ||||
def get( | ||||
&self, | ||||
key: PyObject, | ||||
default: Option<PyObject> = None | ||||
) -> PyResult<Option<PyObject>> { | ||||
let key = key.extract::<PyBytes>(py)?; | ||||
|
r48126 | match self | ||
.inner(py) | ||||
.borrow() | ||||
.get(HgPath::new(key.data(py))) | ||||
.map_err(|e| v2_error(py, e))? | ||||
{ | ||||
|
r42999 | Some(entry) => { | ||
r48328 | Ok(Some(make_dirstate_item(py, &entry)?)) | |||
|
r42999 | }, | ||
None => Ok(default) | ||||
} | ||||
} | ||||
r48492 | def set_v1(&self, path: PyObject, item: PyObject) -> PyResult<PyObject> { | |||
let f = path.extract::<PyBytes>(py)?; | ||||
let filename = HgPath::new(f.data(py)); | ||||
let state = item.getattr(py, "state")?.extract::<PyBytes>(py)?; | ||||
let state = state.data(py)[0]; | ||||
let entry = DirstateEntry { | ||||
state: state.try_into().expect("state is always valid"), | ||||
mtime: item.getattr(py, "mtime")?.extract(py)?, | ||||
size: item.getattr(py, "size")?.extract(py)?, | ||||
mode: item.getattr(py, "mode")?.extract(py)?, | ||||
}; | ||||
self.inner(py).borrow_mut().set_v1(filename, entry); | ||||
Ok(py.None()) | ||||
} | ||||
|
r42999 | def addfile( | ||
&self, | ||||
f: PyObject, | ||||
mode: PyObject, | ||||
size: PyObject, | ||||
r48310 | mtime: PyObject, | |||
r48314 | added: PyObject, | |||
r48316 | merged: PyObject, | |||
r48310 | from_p2: PyObject, | |||
possibly_dirty: PyObject, | ||||
|
r42999 | ) -> PyResult<PyObject> { | ||
r48307 | let f = f.extract::<PyBytes>(py)?; | |||
let filename = HgPath::new(f.data(py)); | ||||
r48314 | let mode = if mode.is_none(py) { | |||
// fallback default value | ||||
0 | ||||
} else { | ||||
mode.extract(py)? | ||||
}; | ||||
r48310 | let size = if size.is_none(py) { | |||
// fallback default value | ||||
SIZE_NON_NORMAL | ||||
} else { | ||||
size.extract(py)? | ||||
}; | ||||
let mtime = if mtime.is_none(py) { | ||||
// fallback default value | ||||
MTIME_UNSET | ||||
} else { | ||||
mtime.extract(py)? | ||||
}; | ||||
r48307 | let entry = DirstateEntry { | |||
r48319 | // XXX Arbitrary default value since the value is determined later | |||
state: EntryState::Normal, | ||||
r48307 | mode: mode, | |||
size: size, | ||||
mtime: mtime, | ||||
}; | ||||
r48314 | let added = added.extract::<PyBool>(py)?.is_true(); | |||
r48316 | let merged = merged.extract::<PyBool>(py)?.is_true(); | |||
r48310 | let from_p2 = from_p2.extract::<PyBool>(py)?.is_true(); | |||
let possibly_dirty = possibly_dirty.extract::<PyBool>(py)?.is_true(); | ||||
|
r44702 | self.inner(py).borrow_mut().add_file( | ||
r48307 | filename, | |||
entry, | ||||
r48314 | added, | |||
r48316 | merged, | |||
r48310 | from_p2, | |||
possibly_dirty | ||||
|
r48126 | ).and(Ok(py.None())).or_else(|e: DirstateError| { | ||
|
r44227 | Err(PyErr::new::<exc::ValueError, _>(py, e.to_string())) | ||
}) | ||||
|
r42999 | } | ||
def removefile( | ||||
&self, | ||||
f: PyObject, | ||||
r48300 | in_merge: PyObject | |||
|
r42999 | ) -> PyResult<PyObject> { | ||
|
r44702 | self.inner(py).borrow_mut() | ||
|
r42999 | .remove_file( | ||
|
r43227 | HgPath::new(f.extract::<PyBytes>(py)?.data(py)), | ||
r48300 | in_merge.extract::<PyBool>(py)?.is_true(), | |||
|
r42999 | ) | ||
.or_else(|_| { | ||||
Err(PyErr::new::<exc::OSError, _>( | ||||
py, | ||||
"Dirstate error".to_string(), | ||||
)) | ||||
})?; | ||||
Ok(py.None()) | ||||
} | ||||
def dropfile( | ||||
&self, | ||||
f: PyObject, | ||||
) -> PyResult<PyBool> { | ||||
|
r44702 | self.inner(py).borrow_mut() | ||
|
r42999 | .drop_file( | ||
|
r43227 | HgPath::new(f.extract::<PyBytes>(py)?.data(py)), | ||
|
r42999 | ) | ||
.and_then(|b| Ok(b.to_py_object(py))) | ||||
|
r46185 | .or_else(|e| { | ||
|
r42999 | Err(PyErr::new::<exc::OSError, _>( | ||
py, | ||||
|
r46185 | format!("Dirstate error: {}", e.to_string()), | ||
|
r42999 | )) | ||
}) | ||||
} | ||||
def clearambiguoustimes( | ||||
&self, | ||||
files: PyObject, | ||||
now: PyObject | ||||
) -> PyResult<PyObject> { | ||||
|
r43227 | let files: PyResult<Vec<HgPathBuf>> = files | ||
|
r42999 | .iter(py)? | ||
.map(|filename| { | ||||
|
r43227 | Ok(HgPathBuf::from_bytes( | ||
filename?.extract::<PyBytes>(py)?.data(py), | ||||
)) | ||||
|
r42999 | }) | ||
.collect(); | ||||
|
r48126 | self.inner(py) | ||
.borrow_mut() | ||||
.clear_ambiguous_times(files?, now.extract(py)?) | ||||
.map_err(|e| v2_error(py, e))?; | ||||
|
r42999 | Ok(py.None()) | ||
} | ||||
|
r44836 | def other_parent_entries(&self) -> PyResult<PyObject> { | ||
|
r44779 | let mut inner_shared = self.inner(py).borrow_mut(); | ||
|
r47653 | let set = PySet::empty(py)?; | ||
|
r47864 | for path in inner_shared.iter_other_parent_paths() { | ||
|
r48126 | let path = path.map_err(|e| v2_error(py, e))?; | ||
|
r47653 | set.add(py, PyBytes::new(py, path.as_bytes()))?; | ||
} | ||||
Ok(set.into_object()) | ||||
|
r44836 | } | ||
def non_normal_entries(&self) -> PyResult<NonNormalEntries> { | ||||
NonNormalEntries::from_inner(py, self.clone_ref(py)) | ||||
} | ||||
def non_normal_entries_contains(&self, key: PyObject) -> PyResult<bool> { | ||||
let key = key.extract::<PyBytes>(py)?; | ||||
|
r48126 | self.inner(py) | ||
|
r44779 | .borrow_mut() | ||
|
r48126 | .non_normal_entries_contains(HgPath::new(key.data(py))) | ||
.map_err(|e| v2_error(py, e)) | ||||
|
r44836 | } | ||
def non_normal_entries_display(&self) -> PyResult<PyString> { | ||||
|
r48126 | let mut inner = self.inner(py).borrow_mut(); | ||
let paths = inner | ||||
.iter_non_normal_paths() | ||||
.collect::<Result<Vec<_>, _>>() | ||||
.map_err(|e| v2_error(py, e))?; | ||||
let formatted = format!("NonNormalEntries: {}", hg::utils::join_display(paths, ", ")); | ||||
Ok(PyString::new(py, &formatted)) | ||||
|
r44836 | } | ||
def non_normal_entries_remove(&self, key: PyObject) -> PyResult<PyObject> { | ||||
let key = key.extract::<PyBytes>(py)?; | ||||
r48492 | let key = key.data(py); | |||
let was_present = self | ||||
.inner(py) | ||||
.borrow_mut() | ||||
.non_normal_entries_remove(HgPath::new(key)); | ||||
if !was_present { | ||||
let msg = String::from_utf8_lossy(key); | ||||
Err(PyErr::new::<exc::KeyError, _>(py, msg)) | ||||
} else { | ||||
Ok(py.None()) | ||||
} | ||||
} | ||||
def non_normal_entries_discard(&self, key: PyObject) -> PyResult<PyObject> | ||||
{ | ||||
let key = key.extract::<PyBytes>(py)?; | ||||
|
r44836 | self | ||
|
r44779 | .inner(py) | ||
.borrow_mut() | ||||
|
r44836 | .non_normal_entries_remove(HgPath::new(key.data(py))); | ||
Ok(py.None()) | ||||
} | ||||
r48492 | def non_normal_entries_add(&self, key: PyObject) -> PyResult<PyObject> { | |||
let key = key.extract::<PyBytes>(py)?; | ||||
self | ||||
.inner(py) | ||||
.borrow_mut() | ||||
.non_normal_entries_add(HgPath::new(key.data(py))); | ||||
Ok(py.None()) | ||||
} | ||||
|
r47864 | def non_normal_or_other_parent_paths(&self) -> PyResult<PyList> { | ||
let mut inner = self.inner(py).borrow_mut(); | ||||
|
r44836 | |||
let ret = PyList::new(py, &[]); | ||||
|
r47864 | for filename in inner.non_normal_or_other_parent_paths() { | ||
|
r48126 | let filename = filename.map_err(|e| v2_error(py, e))?; | ||
|
r44836 | let as_pystring = PyBytes::new(py, filename.as_bytes()); | ||
|
r44779 | ret.append(py, as_pystring.into_object()); | ||
|
r44836 | } | ||
Ok(ret) | ||||
|
r42999 | } | ||
|
r44903 | def non_normal_entries_iter(&self) -> PyResult<NonNormalEntriesIterator> { | ||
// Make sure the sets are defined before we no longer have a mutable | ||||
// reference to the dmap. | ||||
self.inner(py) | ||||
.borrow_mut() | ||||
.set_non_normal_other_parent_entries(false); | ||||
let leaked_ref = self.inner(py).leak_immutable(); | ||||
NonNormalEntriesIterator::from_inner(py, unsafe { | ||||
leaked_ref.map(py, |o| { | ||||
|
r47864 | o.iter_non_normal_paths_panic() | ||
|
r44903 | }) | ||
}) | ||||
} | ||||
|
r42999 | def hastrackeddir(&self, d: PyObject) -> PyResult<PyBool> { | ||
let d = d.extract::<PyBytes>(py)?; | ||||
|
r44702 | Ok(self.inner(py).borrow_mut() | ||
|
r43227 | .has_tracked_dir(HgPath::new(d.data(py))) | ||
|
r44315 | .map_err(|e| { | ||
PyErr::new::<exc::ValueError, _>(py, e.to_string()) | ||||
})? | ||||
|
r42999 | .to_py_object(py)) | ||
} | ||||
def hasdir(&self, d: PyObject) -> PyResult<PyBool> { | ||||
let d = d.extract::<PyBytes>(py)?; | ||||
|
r44702 | Ok(self.inner(py).borrow_mut() | ||
|
r43227 | .has_dir(HgPath::new(d.data(py))) | ||
|
r44315 | .map_err(|e| { | ||
PyErr::new::<exc::ValueError, _>(py, e.to_string()) | ||||
})? | ||||
|
r42999 | .to_py_object(py)) | ||
} | ||||
|
r48474 | def write_v1( | ||
|
r42999 | &self, | ||
p1: PyObject, | ||||
p2: PyObject, | ||||
now: PyObject | ||||
) -> PyResult<PyBytes> { | ||||
|
r47871 | let now = Timestamp(now.extract(py)?); | ||
|
r48474 | |||
let mut inner = self.inner(py).borrow_mut(); | ||||
|
r42999 | let parents = DirstateParents { | ||
|
r43068 | p1: extract_node_id(py, &p1)?, | ||
p2: extract_node_id(py, &p2)?, | ||||
|
r42999 | }; | ||
|
r48474 | let result = inner.pack_v1(parents, now); | ||
match result { | ||||
Ok(packed) => Ok(PyBytes::new(py, &packed)), | ||||
Err(_) => Err(PyErr::new::<exc::OSError, _>( | ||||
py, | ||||
"Dirstate error".to_string(), | ||||
)), | ||||
} | ||||
} | ||||
|
r48478 | /// Returns new data together with whether that data should be appended to | ||
/// the existing data file whose content is at `self.on_disk` (True), | ||||
/// instead of written to a new data file (False). | ||||
|
r48474 | def write_v2( | ||
&self, | ||||
|
r48478 | now: PyObject, | ||
can_append: bool, | ||||
) -> PyResult<PyObject> { | ||||
|
r48474 | let now = Timestamp(now.extract(py)?); | ||
|
r42999 | |||
|
r48055 | let mut inner = self.inner(py).borrow_mut(); | ||
|
r48478 | let result = inner.pack_v2(now, can_append); | ||
|
r48055 | match result { | ||
|
r48482 | Ok((packed, tree_metadata, append)) => { | ||
|
r48478 | let packed = PyBytes::new(py, &packed); | ||
|
r48482 | let tree_metadata = PyBytes::new(py, &tree_metadata); | ||
let tuple = (packed, tree_metadata, append); | ||||
Ok(tuple.to_py_object(py).into_object()) | ||||
|
r48478 | }, | ||
|
r42999 | Err(_) => Err(PyErr::new::<exc::OSError, _>( | ||
py, | ||||
"Dirstate error".to_string(), | ||||
)), | ||||
} | ||||
} | ||||
def filefoldmapasdict(&self) -> PyResult<PyDict> { | ||||
let dict = PyDict::new(py); | ||||
|
r48126 | for item in self.inner(py).borrow_mut().iter() { | ||
let (path, entry) = item.map_err(|e| v2_error(py, e))?; | ||||
|
r47879 | if entry.state != EntryState::Removed { | ||
let key = normalize_case(path); | ||||
let value = path; | ||||
dict.set_item( | ||||
py, | ||||
PyBytes::new(py, key.as_bytes()).into_object(), | ||||
PyBytes::new(py, value.as_bytes()).into_object(), | ||||
)?; | ||||
} | ||||
|
r42999 | } | ||
Ok(dict) | ||||
} | ||||
def __len__(&self) -> PyResult<usize> { | ||||
|
r44702 | Ok(self.inner(py).borrow().len()) | ||
|
r42999 | } | ||
def __contains__(&self, key: PyObject) -> PyResult<bool> { | ||||
let key = key.extract::<PyBytes>(py)?; | ||||
|
r48126 | self.inner(py) | ||
.borrow() | ||||
.contains_key(HgPath::new(key.data(py))) | ||||
.map_err(|e| v2_error(py, e)) | ||||
|
r42999 | } | ||
def __getitem__(&self, key: PyObject) -> PyResult<PyObject> { | ||||
let key = key.extract::<PyBytes>(py)?; | ||||
|
r43227 | let key = HgPath::new(key.data(py)); | ||
|
r48126 | match self | ||
.inner(py) | ||||
.borrow() | ||||
.get(key) | ||||
.map_err(|e| v2_error(py, e))? | ||||
{ | ||||
|
r42999 | Some(entry) => { | ||
r48328 | Ok(make_dirstate_item(py, &entry)?) | |||
|
r42999 | }, | ||
None => Err(PyErr::new::<exc::KeyError, _>( | ||||
py, | ||||
|
r43227 | String::from_utf8_lossy(key.as_bytes()), | ||
|
r42999 | )), | ||
} | ||||
} | ||||
def keys(&self) -> PyResult<DirstateMapKeysIterator> { | ||||
|
r44702 | let leaked_ref = self.inner(py).leak_immutable(); | ||
|
r42999 | DirstateMapKeysIterator::from_inner( | ||
py, | ||||
|
r43579 | unsafe { leaked_ref.map(py, |o| o.iter()) }, | ||
|
r42999 | ) | ||
} | ||||
def items(&self) -> PyResult<DirstateMapItemsIterator> { | ||||
|
r44702 | let leaked_ref = self.inner(py).leak_immutable(); | ||
|
r42999 | DirstateMapItemsIterator::from_inner( | ||
py, | ||||
|
r43579 | unsafe { leaked_ref.map(py, |o| o.iter()) }, | ||
|
r42999 | ) | ||
} | ||||
def __iter__(&self) -> PyResult<DirstateMapKeysIterator> { | ||||
|
r44702 | let leaked_ref = self.inner(py).leak_immutable(); | ||
|
r42999 | DirstateMapKeysIterator::from_inner( | ||
py, | ||||
|
r43579 | unsafe { leaked_ref.map(py, |o| o.iter()) }, | ||
|
r42999 | ) | ||
} | ||||
// TODO all copymap* methods, see docstring above | ||||
def copymapcopy(&self) -> PyResult<PyDict> { | ||||
let dict = PyDict::new(py); | ||||
|
r48126 | for item in self.inner(py).borrow().copy_map_iter() { | ||
let (key, value) = item.map_err(|e| v2_error(py, e))?; | ||||
|
r43227 | dict.set_item( | ||
py, | ||||
|
r45500 | PyBytes::new(py, key.as_bytes()), | ||
PyBytes::new(py, value.as_bytes()), | ||||
|
r43227 | )?; | ||
|
r42999 | } | ||
Ok(dict) | ||||
} | ||||
def copymapgetitem(&self, key: PyObject) -> PyResult<PyBytes> { | ||||
let key = key.extract::<PyBytes>(py)?; | ||||
|
r48126 | match self | ||
.inner(py) | ||||
.borrow() | ||||
.copy_map_get(HgPath::new(key.data(py))) | ||||
.map_err(|e| v2_error(py, e))? | ||||
{ | ||||
|
r45500 | Some(copy) => Ok(PyBytes::new(py, copy.as_bytes())), | ||
|
r42999 | None => Err(PyErr::new::<exc::KeyError, _>( | ||
py, | ||||
String::from_utf8_lossy(key.data(py)), | ||||
)), | ||||
} | ||||
} | ||||
def copymap(&self) -> PyResult<CopyMap> { | ||||
CopyMap::from_inner(py, self.clone_ref(py)) | ||||
} | ||||
def copymaplen(&self) -> PyResult<usize> { | ||||
|
r47863 | Ok(self.inner(py).borrow().copy_map_len()) | ||
|
r42999 | } | ||
def copymapcontains(&self, key: PyObject) -> PyResult<bool> { | ||||
let key = key.extract::<PyBytes>(py)?; | ||||
|
r48126 | self.inner(py) | ||
|
r43227 | .borrow() | ||
|
r48126 | .copy_map_contains_key(HgPath::new(key.data(py))) | ||
.map_err(|e| v2_error(py, e)) | ||||
|
r42999 | } | ||
def copymapget( | ||||
&self, | ||||
key: PyObject, | ||||
default: Option<PyObject> | ||||
) -> PyResult<Option<PyObject>> { | ||||
let key = key.extract::<PyBytes>(py)?; | ||||
|
r43227 | match self | ||
|
r44702 | .inner(py) | ||
|
r43227 | .borrow() | ||
|
r47863 | .copy_map_get(HgPath::new(key.data(py))) | ||
|
r48126 | .map_err(|e| v2_error(py, e))? | ||
|
r43227 | { | ||
Some(copy) => Ok(Some( | ||||
|
r45500 | PyBytes::new(py, copy.as_bytes()).into_object(), | ||
|
r43227 | )), | ||
|
r42999 | None => Ok(default), | ||
} | ||||
} | ||||
def copymapsetitem( | ||||
&self, | ||||
key: PyObject, | ||||
value: PyObject | ||||
) -> PyResult<PyObject> { | ||||
let key = key.extract::<PyBytes>(py)?; | ||||
let value = value.extract::<PyBytes>(py)?; | ||||
|
r48126 | self.inner(py) | ||
.borrow_mut() | ||||
.copy_map_insert( | ||||
HgPathBuf::from_bytes(key.data(py)), | ||||
HgPathBuf::from_bytes(value.data(py)), | ||||
) | ||||
.map_err(|e| v2_error(py, e))?; | ||||
|
r42999 | Ok(py.None()) | ||
} | ||||
def copymappop( | ||||
&self, | ||||
key: PyObject, | ||||
default: Option<PyObject> | ||||
) -> PyResult<Option<PyObject>> { | ||||
let key = key.extract::<PyBytes>(py)?; | ||||
|
r43227 | match self | ||
|
r44702 | .inner(py) | ||
|
r44685 | .borrow_mut() | ||
|
r47863 | .copy_map_remove(HgPath::new(key.data(py))) | ||
|
r48126 | .map_err(|e| v2_error(py, e))? | ||
|
r43227 | { | ||
|
r42999 | Some(_) => Ok(None), | ||
None => Ok(default), | ||||
} | ||||
} | ||||
def copymapiter(&self) -> PyResult<CopyMapKeysIterator> { | ||||
|
r44702 | let leaked_ref = self.inner(py).leak_immutable(); | ||
|
r42999 | CopyMapKeysIterator::from_inner( | ||
py, | ||||
|
r47863 | unsafe { leaked_ref.map(py, |o| o.copy_map_iter()) }, | ||
|
r42999 | ) | ||
} | ||||
def copymapitemsiter(&self) -> PyResult<CopyMapItemsIterator> { | ||||
|
r44702 | let leaked_ref = self.inner(py).leak_immutable(); | ||
|
r42999 | CopyMapItemsIterator::from_inner( | ||
py, | ||||
|
r47863 | unsafe { leaked_ref.map(py, |o| o.copy_map_iter()) }, | ||
|
r42999 | ) | ||
} | ||||
|
r48483 | def tracked_dirs(&self) -> PyResult<PyList> { | ||
|
r48140 | let dirs = PyList::new(py, &[]); | ||
|
r48483 | for path in self.inner(py).borrow_mut().iter_tracked_dirs() | ||
.map_err(|e |dirstate_error(py, e))? | ||||
{ | ||||
let path = path.map_err(|e| v2_error(py, e))?; | ||||
|
r48140 | let path = PyBytes::new(py, path.as_bytes()); | ||
|
r48483 | dirs.append(py, path.into_object()) | ||
|
r48140 | } | ||
Ok(dirs) | ||||
} | ||||
|
r48483 | def debug_iter(&self) -> PyResult<PyList> { | ||
let dirs = PyList::new(py, &[]); | ||||
for item in self.inner(py).borrow().debug_iter() { | ||||
let (path, (state, mode, size, mtime)) = | ||||
item.map_err(|e| v2_error(py, e))?; | ||||
let path = PyBytes::new(py, path.as_bytes()); | ||||
let item = make_dirstate_item_raw(py, state, mode, size, mtime)?; | ||||
dirs.append(py, (path, item).to_py_object(py).into_object()) | ||||
} | ||||
Ok(dirs) | ||||
} | ||||
|
r42999 | }); | ||
impl DirstateMap { | ||||
|
r47882 | pub fn get_inner_mut<'a>( | ||
|
r43567 | &'a self, | ||
py: Python<'a>, | ||||
|
r47882 | ) -> RefMut<'a, Box<dyn DirstateMapMethods + Send>> { | ||
self.inner(py).borrow_mut() | ||||
|
r43567 | } | ||
|
r42999 | fn translate_key( | ||
py: Python, | ||||
|
r48126 | res: Result<(&HgPath, DirstateEntry), DirstateV2ParseError>, | ||
|
r42999 | ) -> PyResult<Option<PyBytes>> { | ||
|
r48126 | let (f, _entry) = res.map_err(|e| v2_error(py, e))?; | ||
Ok(Some(PyBytes::new(py, f.as_bytes()))) | ||||
|
r42999 | } | ||
fn translate_key_value( | ||||
py: Python, | ||||
|
r48126 | res: Result<(&HgPath, DirstateEntry), DirstateV2ParseError>, | ||
|
r42999 | ) -> PyResult<Option<(PyBytes, PyObject)>> { | ||
|
r48126 | let (f, entry) = res.map_err(|e| v2_error(py, e))?; | ||
|
r42999 | Ok(Some(( | ||
|
r45500 | PyBytes::new(py, f.as_bytes()), | ||
r48328 | make_dirstate_item(py, &entry)?, | |||
|
r46185 | ))) | ||
} | ||||
|
r42999 | } | ||
|
r43159 | py_shared_iterator!( | ||
|
r42999 | DirstateMapKeysIterator, | ||
|
r44703 | UnsafePyLeaked<StateMapIter<'static>>, | ||
|
r42999 | DirstateMap::translate_key, | ||
Option<PyBytes> | ||||
); | ||||
|
r43159 | py_shared_iterator!( | ||
|
r42999 | DirstateMapItemsIterator, | ||
|
r44703 | UnsafePyLeaked<StateMapIter<'static>>, | ||
|
r42999 | DirstateMap::translate_key_value, | ||
Option<(PyBytes, PyObject)> | ||||
); | ||||
|
r43068 | |||
|
r47337 | fn extract_node_id(py: Python, obj: &PyObject) -> PyResult<Node> { | ||
|
r43068 | let bytes = obj.extract::<PyBytes>(py)?; | ||
match bytes.data(py).try_into() { | ||||
Ok(s) => Ok(s), | ||||
Err(e) => Err(PyErr::new::<exc::ValueError, _>(py, e.to_string())), | ||||
} | ||||
} | ||||
|
r48126 | |||
pub(super) fn v2_error(py: Python<'_>, _: DirstateV2ParseError) -> PyErr { | ||||
PyErr::new::<exc::ValueError, _>(py, "corrupted dirstate-v2") | ||||
} | ||||
|
r48483 | |||
fn dirstate_error(py: Python<'_>, e: DirstateError) -> PyErr { | ||||
PyErr::new::<exc::OSError, _>(py, format!("Dirstate error: {:?}", e)) | ||||
} | ||||