The Python wrapper class dirstatemap can take care of it.
This removes the need to have both _rustmap and _inner_rustmap.
( )
The Python wrapper class dirstatemap can take care of it.
This removes the need to have both _rustmap and _inner_rustmap.
Automatic diff as part of commit; lint not applicable. |
Automatic diff as part of commit; unit tests not applicable. |
While I'm always happy about removing code, what happens in a non-Python context? Are we ripping support for reading/setting parents? Or would that come back in a different form later?
We are removing support in hg-core’s DirstateMap for reading only parents from disk. (The logic for this still exists in hg_core::dirstate::parsers::parse_dirstate_parents) With this changset and the next, creating a DirstateMap means reading the entire dirstate from disk.
Reading the entire dirstate returns a DirstateParents to the caller. (This hasn’t changed.) Serializing an entire dirstate requires the caller to provide a DirstateParents. (This also hasn’t changed).
Path | Packages | |||
---|---|---|---|---|
M | mercurial/dirstate.py (34 lines) | |||
M | rust/hg-core/src/dirstate/dirstate_map.rs (53 lines) | |||
M | rust/hg-core/src/dirstate_tree/dirstate_map.rs (38 lines) | |||
M | rust/hg-core/src/dirstate_tree/dispatch.rs (18 lines) | |||
M | rust/hg-cpython/src/dirstate/dirstate_map.rs (25 lines) |
Status | Author | Revision | |
---|---|---|---|
Abandoned | SimonSapin | ||
Closed | SimonSapin | ||
Closed | SimonSapin | ||
Closed | SimonSapin | ||
Closed | SimonSapin | ||
Closed | SimonSapin | ||
Closed | SimonSapin | ||
Closed | SimonSapin | ||
Closed | SimonSapin | ||
Closed | SimonSapin | ||
Closed | SimonSapin | ||
Closed | SimonSapin | ||
Closed | SimonSapin | ||
Closed | SimonSapin | ||
Closed | SimonSapin | ||
Closed | SimonSapin | ||
Closed | SimonSapin | ||
Closed | SimonSapin | ||
Closed | SimonSapin | ||
Closed | SimonSapin | ||
Closed | SimonSapin | ||
Closed | SimonSapin | ||
Closed | SimonSapin | ||
Closed | SimonSapin | ||
Closed | SimonSapin | ||
Closed | SimonSapin | ||
Closed | SimonSapin | ||
Closed | SimonSapin | ||
Closed | SimonSapin | ||
Closed | SimonSapin | ||
Closed | SimonSapin | ||
Closed | SimonSapin | ||
Closed | SimonSapin | ||
Closed | SimonSapin | ||
Closed | SimonSapin |
class dirstatemap(object): | class dirstatemap(object): | ||||
def __init__(self, ui, opener, root, nodeconstants): | def __init__(self, ui, opener, root, nodeconstants): | ||||
self._nodeconstants = nodeconstants | self._nodeconstants = nodeconstants | ||||
self._ui = ui | self._ui = ui | ||||
self._opener = opener | self._opener = opener | ||||
self._root = root | self._root = root | ||||
self._filename = b'dirstate' | self._filename = b'dirstate' | ||||
self._nodelen = 20 | |||||
self._parents = None | self._parents = None | ||||
self._dirtyparents = False | self._dirtyparents = False | ||||
# for consistent view between _pl() and _read() invocations | # for consistent view between _pl() and _read() invocations | ||||
self._pendingmode = None | self._pendingmode = None | ||||
def addfile(self, *args, **kwargs): | def addfile(self, *args, **kwargs): | ||||
return self._rustmap.addfile(*args, **kwargs) | return self._rustmap.addfile(*args, **kwargs) | ||||
def get(self, *args, **kwargs): | def get(self, *args, **kwargs): | ||||
return self._rustmap.get(*args, **kwargs) | return self._rustmap.get(*args, **kwargs) | ||||
@propertycache | @propertycache | ||||
def _rustmap(self): | def _rustmap(self): | ||||
""" | """ | ||||
Fills the Dirstatemap when called. | Fills the Dirstatemap when called. | ||||
Use `self._inner_rustmap` if reading the dirstate is not necessary. | |||||
""" | |||||
self._rustmap = self._inner_rustmap | |||||
self.read() | |||||
return self._rustmap | |||||
@propertycache | |||||
def _inner_rustmap(self): | |||||
""" | |||||
Does not fill the Dirstatemap when called. This allows for | |||||
optimizations where only setting/getting the parents is needed. | |||||
""" | """ | ||||
use_dirstate_tree = self._ui.configbool( | use_dirstate_tree = self._ui.configbool( | ||||
b"experimental", | b"experimental", | ||||
b"dirstate-tree.in-memory", | b"dirstate-tree.in-memory", | ||||
False, | False, | ||||
) | ) | ||||
self._inner_rustmap = rustmod.DirstateMap(use_dirstate_tree) | self._rustmap = rustmod.DirstateMap(use_dirstate_tree) | ||||
return self._inner_rustmap | self.read() | ||||
return self._rustmap | |||||
@property | @property | ||||
def copymap(self): | def copymap(self): | ||||
return self._rustmap.copymap() | return self._rustmap.copymap() | ||||
def preload(self): | def preload(self): | ||||
self._rustmap | self._rustmap | ||||
def clear(self): | def clear(self): | ||||
self._rustmap.clear() | self._rustmap.clear() | ||||
self._inner_rustmap.clear() | |||||
self.setparents( | self.setparents( | ||||
self._nodeconstants.nullid, self._nodeconstants.nullid | self._nodeconstants.nullid, self._nodeconstants.nullid | ||||
) | ) | ||||
util.clearcachedproperty(self, b"_dirs") | util.clearcachedproperty(self, b"_dirs") | ||||
util.clearcachedproperty(self, b"_alldirs") | util.clearcachedproperty(self, b"_alldirs") | ||||
util.clearcachedproperty(self, b"dirfoldmap") | util.clearcachedproperty(self, b"dirfoldmap") | ||||
def items(self): | def items(self): | ||||
fp.close() | fp.close() | ||||
raise error.Abort( | raise error.Abort( | ||||
_(b'working directory state may be changed parallelly') | _(b'working directory state may be changed parallelly') | ||||
) | ) | ||||
self._pendingmode = mode | self._pendingmode = mode | ||||
return fp | return fp | ||||
def setparents(self, p1, p2): | def setparents(self, p1, p2): | ||||
self._rustmap.setparents(p1, p2) | |||||
self._parents = (p1, p2) | self._parents = (p1, p2) | ||||
self._dirtyparents = True | self._dirtyparents = True | ||||
def parents(self): | def parents(self): | ||||
if not self._parents: | if not self._parents: | ||||
try: | try: | ||||
fp = self._opendirstatefile() | fp = self._opendirstatefile() | ||||
st = fp.read(40) | st = fp.read(40) | ||||
fp.close() | fp.close() | ||||
except IOError as err: | except IOError as err: | ||||
if err.errno != errno.ENOENT: | if err.errno != errno.ENOENT: | ||||
raise | raise | ||||
# File doesn't exist, so the current state is empty | # File doesn't exist, so the current state is empty | ||||
st = b'' | st = b'' | ||||
try: | l = len(st) | ||||
self._parents = self._inner_rustmap.parents(st) | if l == self._nodelen * 2: | ||||
except ValueError: | self._parents = ( | ||||
st[: self._nodelen], | |||||
st[self._nodelen : 2 * self._nodelen], | |||||
) | |||||
elif l == 0: | |||||
self._parents = ( | |||||
self._nodeconstants.nullid, | |||||
self._nodeconstants.nullid, | |||||
) | |||||
else: | |||||
raise error.Abort( | raise error.Abort( | ||||
_(b'working directory state appears damaged!') | _(b'working directory state appears damaged!') | ||||
) | ) | ||||
return self._parents | return self._parents | ||||
def read(self): | def read(self): | ||||
# ignore HG_PENDING because identity is used only for writing | # ignore HG_PENDING because identity is used only for writing |
// dirstate_map.rs | // dirstate_map.rs | ||||
// | // | ||||
// Copyright 2019 Raphaël Gomès <rgomes@octobus.net> | // Copyright 2019 Raphaël Gomès <rgomes@octobus.net> | ||||
// | // | ||||
// This software may be used and distributed according to the terms of the | // This software may be used and distributed according to the terms of the | ||||
// GNU General Public License version 2 or any later version. | // GNU General Public License version 2 or any later version. | ||||
use crate::dirstate::parsers::clear_ambiguous_mtime; | use crate::dirstate::parsers::clear_ambiguous_mtime; | ||||
use crate::dirstate::parsers::Timestamp; | use crate::dirstate::parsers::Timestamp; | ||||
use crate::errors::HgError; | |||||
use crate::revlog::node::NULL_NODE; | |||||
use crate::{ | use crate::{ | ||||
dirstate::{parsers::PARENT_SIZE, EntryState}, | dirstate::EntryState, | ||||
pack_dirstate, parse_dirstate, | pack_dirstate, parse_dirstate, | ||||
utils::hg_path::{HgPath, HgPathBuf}, | utils::hg_path::{HgPath, HgPathBuf}, | ||||
CopyMap, DirsMultiset, DirstateEntry, DirstateError, DirstateMapError, | CopyMap, DirsMultiset, DirstateEntry, DirstateError, DirstateMapError, | ||||
DirstateParents, StateMap, | DirstateParents, StateMap, | ||||
}; | }; | ||||
use micro_timer::timed; | use micro_timer::timed; | ||||
use std::collections::HashSet; | use std::collections::HashSet; | ||||
use std::convert::TryInto; | |||||
use std::iter::FromIterator; | use std::iter::FromIterator; | ||||
use std::ops::Deref; | use std::ops::Deref; | ||||
#[derive(Default)] | #[derive(Default)] | ||||
pub struct DirstateMap { | pub struct DirstateMap { | ||||
state_map: StateMap, | state_map: StateMap, | ||||
pub copy_map: CopyMap, | pub copy_map: CopyMap, | ||||
pub dirs: Option<DirsMultiset>, | pub dirs: Option<DirsMultiset>, | ||||
pub all_dirs: Option<DirsMultiset>, | pub all_dirs: Option<DirsMultiset>, | ||||
non_normal_set: Option<HashSet<HgPathBuf>>, | non_normal_set: Option<HashSet<HgPathBuf>>, | ||||
other_parent_set: Option<HashSet<HgPathBuf>>, | other_parent_set: Option<HashSet<HgPathBuf>>, | ||||
parents: Option<DirstateParents>, | |||||
dirty_parents: bool, | |||||
} | } | ||||
/// Should only really be used in python interface code, for clarity | /// Should only really be used in python interface code, for clarity | ||||
impl Deref for DirstateMap { | impl Deref for DirstateMap { | ||||
type Target = StateMap; | type Target = StateMap; | ||||
fn deref(&self) -> &Self::Target { | fn deref(&self) -> &Self::Target { | ||||
&self.state_map | &self.state_map | ||||
Self::default() | Self::default() | ||||
} | } | ||||
pub fn clear(&mut self) { | pub fn clear(&mut self) { | ||||
self.state_map = StateMap::default(); | self.state_map = StateMap::default(); | ||||
self.copy_map.clear(); | self.copy_map.clear(); | ||||
self.non_normal_set = None; | self.non_normal_set = None; | ||||
self.other_parent_set = None; | self.other_parent_set = None; | ||||
self.set_parents(&DirstateParents { | |||||
p1: NULL_NODE, | |||||
p2: NULL_NODE, | |||||
}) | |||||
} | } | ||||
/// Add a tracked file to the dirstate | /// Add a tracked file to the dirstate | ||||
pub fn add_file( | pub fn add_file( | ||||
&mut self, | &mut self, | ||||
filename: &HgPath, | filename: &HgPath, | ||||
old_state: EntryState, | old_state: EntryState, | ||||
entry: DirstateEntry, | entry: DirstateEntry, | ||||
pub fn has_dir( | pub fn has_dir( | ||||
&mut self, | &mut self, | ||||
directory: &HgPath, | directory: &HgPath, | ||||
) -> Result<bool, DirstateMapError> { | ) -> Result<bool, DirstateMapError> { | ||||
self.set_all_dirs()?; | self.set_all_dirs()?; | ||||
Ok(self.all_dirs.as_ref().unwrap().contains(directory)) | Ok(self.all_dirs.as_ref().unwrap().contains(directory)) | ||||
} | } | ||||
pub fn parents( | |||||
&mut self, | |||||
file_contents: &[u8], | |||||
) -> Result<&DirstateParents, DirstateError> { | |||||
if let Some(ref parents) = self.parents { | |||||
return Ok(parents); | |||||
} | |||||
let parents; | |||||
if file_contents.len() == PARENT_SIZE * 2 { | |||||
parents = DirstateParents { | |||||
p1: file_contents[..PARENT_SIZE].try_into().unwrap(), | |||||
p2: file_contents[PARENT_SIZE..PARENT_SIZE * 2] | |||||
.try_into() | |||||
.unwrap(), | |||||
}; | |||||
} else if file_contents.is_empty() { | |||||
parents = DirstateParents { | |||||
p1: NULL_NODE, | |||||
p2: NULL_NODE, | |||||
}; | |||||
} else { | |||||
return Err( | |||||
HgError::corrupted("Dirstate appears to be damaged").into() | |||||
); | |||||
} | |||||
self.parents = Some(parents); | |||||
Ok(self.parents.as_ref().unwrap()) | |||||
} | |||||
pub fn set_parents(&mut self, parents: &DirstateParents) { | |||||
self.parents = Some(parents.clone()); | |||||
self.dirty_parents = true; | |||||
} | |||||
#[timed] | #[timed] | ||||
pub fn read<'a>( | pub fn read<'a>( | ||||
&mut self, | &mut self, | ||||
file_contents: &'a [u8], | file_contents: &'a [u8], | ||||
) -> Result<Option<&'a DirstateParents>, DirstateError> { | ) -> Result<Option<&'a DirstateParents>, DirstateError> { | ||||
if file_contents.is_empty() { | if file_contents.is_empty() { | ||||
return Ok(None); | return Ok(None); | ||||
} | } | ||||
let (parents, entries, copies) = parse_dirstate(file_contents)?; | let (parents, entries, copies) = parse_dirstate(file_contents)?; | ||||
self.state_map.extend( | self.state_map.extend( | ||||
entries | entries | ||||
.into_iter() | .into_iter() | ||||
.map(|(path, entry)| (path.to_owned(), entry)), | .map(|(path, entry)| (path.to_owned(), entry)), | ||||
); | ); | ||||
self.copy_map.extend( | self.copy_map.extend( | ||||
copies | copies | ||||
.into_iter() | .into_iter() | ||||
.map(|(path, copy)| (path.to_owned(), copy.to_owned())), | .map(|(path, copy)| (path.to_owned(), copy.to_owned())), | ||||
); | ); | ||||
if !self.dirty_parents { | |||||
self.set_parents(&parents); | |||||
} | |||||
Ok(Some(parents)) | Ok(Some(parents)) | ||||
} | } | ||||
pub fn pack( | pub fn pack( | ||||
&mut self, | &mut self, | ||||
parents: DirstateParents, | parents: DirstateParents, | ||||
now: Timestamp, | now: Timestamp, | ||||
) -> Result<Vec<u8>, DirstateError> { | ) -> Result<Vec<u8>, DirstateError> { | ||||
let packed = | let packed = | ||||
pack_dirstate(&mut self.state_map, &self.copy_map, parents, now)?; | pack_dirstate(&mut self.state_map, &self.copy_map, parents, now)?; | ||||
self.dirty_parents = false; | |||||
self.set_non_normal_other_parent_entries(true); | self.set_non_normal_other_parent_entries(true); | ||||
Ok(packed) | Ok(packed) | ||||
} | } | ||||
} | } | ||||
#[cfg(test)] | #[cfg(test)] | ||||
mod tests { | mod tests { | ||||
use super::*; | use super::*; |
use bytes_cast::BytesCast; | use bytes_cast::BytesCast; | ||||
use micro_timer::timed; | use micro_timer::timed; | ||||
use std::convert::TryInto; | use std::convert::TryInto; | ||||
use std::path::PathBuf; | use std::path::PathBuf; | ||||
use super::path_with_basename::WithBasename; | use super::path_with_basename::WithBasename; | ||||
use crate::dirstate::parsers::clear_ambiguous_mtime; | use crate::dirstate::parsers::clear_ambiguous_mtime; | ||||
use crate::dirstate::parsers::pack_entry; | use crate::dirstate::parsers::pack_entry; | ||||
use crate::dirstate::parsers::packed_entry_size; | use crate::dirstate::parsers::packed_entry_size; | ||||
use crate::dirstate::parsers::parse_dirstate_entries; | use crate::dirstate::parsers::parse_dirstate_entries; | ||||
use crate::dirstate::parsers::parse_dirstate_parents; | |||||
use crate::dirstate::parsers::Timestamp; | use crate::dirstate::parsers::Timestamp; | ||||
use crate::matchers::Matcher; | use crate::matchers::Matcher; | ||||
use crate::revlog::node::NULL_NODE; | |||||
use crate::utils::hg_path::{HgPath, HgPathBuf}; | use crate::utils::hg_path::{HgPath, HgPathBuf}; | ||||
use crate::CopyMapIter; | use crate::CopyMapIter; | ||||
use crate::DirstateEntry; | use crate::DirstateEntry; | ||||
use crate::DirstateError; | use crate::DirstateError; | ||||
use crate::DirstateMapError; | use crate::DirstateMapError; | ||||
use crate::DirstateParents; | use crate::DirstateParents; | ||||
use crate::DirstateStatus; | use crate::DirstateStatus; | ||||
use crate::EntryState; | use crate::EntryState; | ||||
use crate::FastHashMap; | use crate::FastHashMap; | ||||
use crate::PatternFileWarning; | use crate::PatternFileWarning; | ||||
use crate::StateMapIter; | use crate::StateMapIter; | ||||
use crate::StatusError; | use crate::StatusError; | ||||
use crate::StatusOptions; | use crate::StatusOptions; | ||||
pub struct DirstateMap { | pub struct DirstateMap { | ||||
parents: Option<DirstateParents>, | |||||
dirty_parents: bool, | |||||
pub(super) root: ChildNodes, | pub(super) root: ChildNodes, | ||||
/// Number of nodes anywhere in the tree that have `.entry.is_some()`. | /// Number of nodes anywhere in the tree that have `.entry.is_some()`. | ||||
nodes_with_entry_count: usize, | nodes_with_entry_count: usize, | ||||
/// Number of nodes anywhere in the tree that have | /// Number of nodes anywhere in the tree that have | ||||
/// `.copy_source.is_some()`. | /// `.copy_source.is_some()`. | ||||
nodes_with_copy_source_count: usize, | nodes_with_copy_source_count: usize, | ||||
&'a WithBasename<HgPathBuf>, | &'a WithBasename<HgPathBuf>, | ||||
&'a mut Option<DirstateEntry>, | &'a mut Option<DirstateEntry>, | ||||
&'a mut Option<HgPathBuf>, | &'a mut Option<HgPathBuf>, | ||||
); | ); | ||||
impl DirstateMap { | impl DirstateMap { | ||||
pub fn new() -> Self { | pub fn new() -> Self { | ||||
Self { | Self { | ||||
parents: None, | |||||
dirty_parents: false, | |||||
root: ChildNodes::default(), | root: ChildNodes::default(), | ||||
nodes_with_entry_count: 0, | nodes_with_entry_count: 0, | ||||
nodes_with_copy_source_count: 0, | nodes_with_copy_source_count: 0, | ||||
} | } | ||||
} | } | ||||
fn get_node(&self, path: &HgPath) -> Option<&Node> { | fn get_node(&self, path: &HgPath) -> Option<&Node> { | ||||
let mut children = &self.root; | let mut children = &self.root; | ||||
None | None | ||||
} | } | ||||
}) | }) | ||||
} | } | ||||
} | } | ||||
impl super::dispatch::DirstateMapMethods for DirstateMap { | impl super::dispatch::DirstateMapMethods for DirstateMap { | ||||
fn clear(&mut self) { | fn clear(&mut self) { | ||||
self.set_parents(&DirstateParents { | |||||
p1: NULL_NODE, | |||||
p2: NULL_NODE, | |||||
}); | |||||
self.root.clear(); | self.root.clear(); | ||||
self.nodes_with_entry_count = 0; | self.nodes_with_entry_count = 0; | ||||
self.nodes_with_copy_source_count = 0; | self.nodes_with_copy_source_count = 0; | ||||
} | } | ||||
fn add_file( | fn add_file( | ||||
&mut self, | &mut self, | ||||
filename: &HgPath, | filename: &HgPath, | ||||
// A node without a `DirstateEntry` was created to hold child | // A node without a `DirstateEntry` was created to hold child | ||||
// nodes, and is therefore a directory. | // nodes, and is therefore a directory. | ||||
Ok(node.entry.is_none()) | Ok(node.entry.is_none()) | ||||
} else { | } else { | ||||
Ok(false) | Ok(false) | ||||
} | } | ||||
} | } | ||||
fn parents( | |||||
&mut self, | |||||
file_contents: &[u8], | |||||
) -> Result<&DirstateParents, DirstateError> { | |||||
if self.parents.is_none() { | |||||
let parents = if !file_contents.is_empty() { | |||||
parse_dirstate_parents(file_contents)?.clone() | |||||
} else { | |||||
DirstateParents { | |||||
p1: NULL_NODE, | |||||
p2: NULL_NODE, | |||||
} | |||||
}; | |||||
self.parents = Some(parents); | |||||
} | |||||
Ok(self.parents.as_ref().unwrap()) | |||||
} | |||||
fn set_parents(&mut self, parents: &DirstateParents) { | |||||
self.parents = Some(parents.clone()); | |||||
self.dirty_parents = true; | |||||
} | |||||
#[timed] | #[timed] | ||||
fn read<'a>( | fn read<'a>( | ||||
&mut self, | &mut self, | ||||
file_contents: &'a [u8], | file_contents: &'a [u8], | ||||
) -> Result<Option<&'a DirstateParents>, DirstateError> { | ) -> Result<Option<&'a DirstateParents>, DirstateError> { | ||||
if file_contents.is_empty() { | if file_contents.is_empty() { | ||||
return Ok(None); | return Ok(None); | ||||
} | } | ||||
node.copy_source = copy_source.map(HgPath::to_owned); | node.copy_source = copy_source.map(HgPath::to_owned); | ||||
self.nodes_with_entry_count += 1; | self.nodes_with_entry_count += 1; | ||||
if copy_source.is_some() { | if copy_source.is_some() { | ||||
self.nodes_with_copy_source_count += 1 | self.nodes_with_copy_source_count += 1 | ||||
} | } | ||||
}, | }, | ||||
)?; | )?; | ||||
if !self.dirty_parents { | |||||
self.set_parents(parents); | |||||
} | |||||
Ok(Some(parents)) | Ok(Some(parents)) | ||||
} | } | ||||
fn pack( | fn pack( | ||||
&mut self, | &mut self, | ||||
parents: DirstateParents, | parents: DirstateParents, | ||||
now: Timestamp, | now: Timestamp, | ||||
) -> Result<Vec<u8>, DirstateError> { | ) -> Result<Vec<u8>, DirstateError> { | ||||
pack_entry( | pack_entry( | ||||
path.full_path(), | path.full_path(), | ||||
entry, | entry, | ||||
copy_source.as_ref(), | copy_source.as_ref(), | ||||
&mut packed, | &mut packed, | ||||
); | ); | ||||
} | } | ||||
} | } | ||||
self.dirty_parents = false; | |||||
Ok(packed) | Ok(packed) | ||||
} | } | ||||
fn set_all_dirs(&mut self) -> Result<(), DirstateMapError> { | fn set_all_dirs(&mut self) -> Result<(), DirstateMapError> { | ||||
// Do nothing, this `DirstateMap` does not a separate `all_dirs` that | // Do nothing, this `DirstateMap` does not a separate `all_dirs` that | ||||
// needs to be recomputed | // needs to be recomputed | ||||
Ok(()) | Ok(()) | ||||
} | } |
directory: &HgPath, | directory: &HgPath, | ||||
) -> Result<bool, DirstateMapError>; | ) -> Result<bool, DirstateMapError>; | ||||
fn has_dir( | fn has_dir( | ||||
&mut self, | &mut self, | ||||
directory: &HgPath, | directory: &HgPath, | ||||
) -> Result<bool, DirstateMapError>; | ) -> Result<bool, DirstateMapError>; | ||||
fn parents( | |||||
&mut self, | |||||
file_contents: &[u8], | |||||
) -> Result<&DirstateParents, DirstateError>; | |||||
fn set_parents(&mut self, parents: &DirstateParents); | |||||
fn read<'a>( | fn read<'a>( | ||||
&mut self, | &mut self, | ||||
file_contents: &'a [u8], | file_contents: &'a [u8], | ||||
) -> Result<Option<&'a DirstateParents>, DirstateError>; | ) -> Result<Option<&'a DirstateParents>, DirstateError>; | ||||
fn pack( | fn pack( | ||||
&mut self, | &mut self, | ||||
parents: DirstateParents, | parents: DirstateParents, | ||||
fn has_dir( | fn has_dir( | ||||
&mut self, | &mut self, | ||||
directory: &HgPath, | directory: &HgPath, | ||||
) -> Result<bool, DirstateMapError> { | ) -> Result<bool, DirstateMapError> { | ||||
self.has_dir(directory) | self.has_dir(directory) | ||||
} | } | ||||
fn parents( | |||||
&mut self, | |||||
file_contents: &[u8], | |||||
) -> Result<&DirstateParents, DirstateError> { | |||||
self.parents(file_contents) | |||||
} | |||||
fn set_parents(&mut self, parents: &DirstateParents) { | |||||
self.set_parents(parents) | |||||
} | |||||
fn read<'a>( | fn read<'a>( | ||||
&mut self, | &mut self, | ||||
file_contents: &'a [u8], | file_contents: &'a [u8], | ||||
) -> Result<Option<&'a DirstateParents>, DirstateError> { | ) -> Result<Option<&'a DirstateParents>, DirstateError> { | ||||
self.read(file_contents) | self.read(file_contents) | ||||
} | } | ||||
fn pack( | fn pack( |
// dirstate_map.rs | // dirstate_map.rs | ||||
// | // | ||||
// Copyright 2019 Raphaël Gomès <rgomes@octobus.net> | // Copyright 2019 Raphaël Gomès <rgomes@octobus.net> | ||||
// | // | ||||
// This software may be used and distributed according to the terms of the | // This software may be used and distributed according to the terms of the | ||||
// GNU General Public License version 2 or any later version. | // GNU General Public License version 2 or any later version. | ||||
//! Bindings for the `hg::dirstate::dirstate_map` file provided by the | //! Bindings for the `hg::dirstate::dirstate_map` file provided by the | ||||
//! `hg-core` package. | //! `hg-core` package. | ||||
use std::cell::{RefCell, RefMut}; | use std::cell::{RefCell, RefMut}; | ||||
use std::convert::TryInto; | use std::convert::TryInto; | ||||
use cpython::{ | use cpython::{ | ||||
exc, ObjectProtocol, PyBool, PyBytes, PyClone, PyDict, PyErr, PyList, | exc, ObjectProtocol, PyBool, PyBytes, PyClone, PyDict, PyErr, PyList, | ||||
PyObject, PyResult, PySet, PyString, PyTuple, Python, PythonObject, | PyObject, PyResult, PySet, PyString, Python, PythonObject, ToPyObject, | ||||
ToPyObject, UnsafePyLeaked, | UnsafePyLeaked, | ||||
}; | }; | ||||
use crate::{ | use crate::{ | ||||
dirstate::copymap::{CopyMap, CopyMapItemsIterator, CopyMapKeysIterator}, | dirstate::copymap::{CopyMap, CopyMapItemsIterator, CopyMapKeysIterator}, | ||||
dirstate::non_normal_entries::{ | dirstate::non_normal_entries::{ | ||||
NonNormalEntries, NonNormalEntriesIterator, | NonNormalEntries, NonNormalEntriesIterator, | ||||
}, | }, | ||||
dirstate::{dirs_multiset::Dirs, make_dirstate_tuple}, | dirstate::{dirs_multiset::Dirs, make_dirstate_tuple}, | ||||
Ok(self.inner(py).borrow_mut() | Ok(self.inner(py).borrow_mut() | ||||
.has_dir(HgPath::new(d.data(py))) | .has_dir(HgPath::new(d.data(py))) | ||||
.map_err(|e| { | .map_err(|e| { | ||||
PyErr::new::<exc::ValueError, _>(py, e.to_string()) | PyErr::new::<exc::ValueError, _>(py, e.to_string()) | ||||
})? | })? | ||||
.to_py_object(py)) | .to_py_object(py)) | ||||
} | } | ||||
def parents(&self, st: PyObject) -> PyResult<PyTuple> { | |||||
self.inner(py).borrow_mut() | |||||
.parents(st.extract::<PyBytes>(py)?.data(py)) | |||||
.map(|parents| dirstate_parents_to_pytuple(py, parents)) | |||||
.or_else(|_| { | |||||
Err(PyErr::new::<exc::OSError, _>( | |||||
py, | |||||
"Dirstate error".to_string(), | |||||
)) | |||||
}) | |||||
} | |||||
def setparents(&self, p1: PyObject, p2: PyObject) -> PyResult<PyObject> { | |||||
let p1 = extract_node_id(py, &p1)?; | |||||
let p2 = extract_node_id(py, &p2)?; | |||||
self.inner(py).borrow_mut() | |||||
.set_parents(&DirstateParents { p1, p2 }); | |||||
Ok(py.None()) | |||||
} | |||||
def read(&self, st: PyObject) -> PyResult<Option<PyObject>> { | def read(&self, st: PyObject) -> PyResult<Option<PyObject>> { | ||||
match self.inner(py).borrow_mut() | match self.inner(py).borrow_mut() | ||||
.read(st.extract::<PyBytes>(py)?.data(py)) | .read(st.extract::<PyBytes>(py)?.data(py)) | ||||
{ | { | ||||
Ok(Some(parents)) => Ok(Some( | Ok(Some(parents)) => Ok(Some( | ||||
dirstate_parents_to_pytuple(py, parents) | dirstate_parents_to_pytuple(py, parents) | ||||
.into_object() | .into_object() | ||||
)), | )), |