--- a/mercurial/configitems.py Tue Sep 28 20:00:19 2021 +0200
+++ b/mercurial/configitems.py Mon Sep 27 12:09:15 2021 +0200
@@ -964,11 +964,6 @@
)
coreconfigitem(
b'experimental',
- b'dirstate-tree.in-memory',
- default=False,
-)
-coreconfigitem(
- b'experimental',
b'editortmpinhg',
default=False,
)
--- a/mercurial/dirstatemap.py Tue Sep 28 20:00:19 2021 +0200
+++ b/mercurial/dirstatemap.py Mon Sep 27 12:09:15 2021 +0200
@@ -493,12 +493,6 @@
# for consistent view between _pl() and _read() invocations
self._pendingmode = None
- self._use_dirstate_tree = self._ui.configbool(
- b"experimental",
- b"dirstate-tree.in-memory",
- False,
- )
-
def addfile(
self,
f,
@@ -818,7 +812,7 @@
parents = self.docket.parents
else:
self._rustmap, parents = rustmod.DirstateMap.new_v1(
- self._use_dirstate_tree, self._readdirstatefile()
+ self._readdirstatefile()
)
if parents and not self._dirtyparents:
--- a/mercurial/upgrade_utils/engine.py Tue Sep 28 20:00:19 2021 +0200
+++ b/mercurial/upgrade_utils/engine.py Mon Sep 27 12:09:15 2021 +0200
@@ -638,7 +638,6 @@
)
assert srcrepo.dirstate._use_dirstate_v2 == (old == b'v2')
- srcrepo.dirstate._map._use_dirstate_tree = True
srcrepo.dirstate._map.preload()
srcrepo.dirstate._use_dirstate_v2 = new == b'v2'
srcrepo.dirstate._map._use_dirstate_v2 = srcrepo.dirstate._use_dirstate_v2
--- a/rust/hg-core/src/dirstate.rs Tue Sep 28 20:00:19 2021 +0200
+++ b/rust/hg-core/src/dirstate.rs Mon Sep 27 12:09:15 2021 +0200
@@ -8,12 +8,10 @@
use crate::dirstate_tree::on_disk::DirstateV2ParseError;
use crate::revlog::node::NULL_NODE;
use crate::revlog::Node;
-use crate::utils::hg_path::{HgPath, HgPathBuf};
-use crate::FastHashMap;
+use crate::utils::hg_path::HgPath;
use bytes_cast::BytesCast;
pub mod dirs_multiset;
-pub mod dirstate_map;
pub mod entry;
pub mod parsers;
pub mod status;
@@ -34,7 +32,6 @@
};
}
-pub type StateMap = FastHashMap<HgPathBuf, DirstateEntry>;
pub type StateMapIter<'a> = Box<
dyn Iterator<
Item = Result<(&'a HgPath, DirstateEntry), DirstateV2ParseError>,
@@ -42,7 +39,6 @@
+ 'a,
>;
-pub type CopyMap = FastHashMap<HgPathBuf, HgPathBuf>;
pub type CopyMapIter<'a> = Box<
dyn Iterator<Item = Result<(&'a HgPath, &'a HgPath), DirstateV2ParseError>>
+ Send
--- a/rust/hg-core/src/dirstate/dirs_multiset.rs Tue Sep 28 20:00:19 2021 +0200
+++ b/rust/hg-core/src/dirstate/dirs_multiset.rs Mon Sep 27 12:09:15 2021 +0200
@@ -216,7 +216,6 @@
#[cfg(test)]
mod tests {
use super::*;
- use crate::StateMap;
#[test]
fn test_delete_path_path_not_found() {
@@ -341,8 +340,8 @@
};
assert_eq!(expected, new);
- let new = DirsMultiset::from_dirstate(
- StateMap::default().into_iter().map(Ok),
+ let new = DirsMultiset::from_dirstate::<_, HgPathBuf>(
+ std::iter::empty(),
false,
)
.unwrap();
--- a/rust/hg-core/src/dirstate/dirstate_map.rs Tue Sep 28 20:00:19 2021 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,263 +0,0 @@
-// 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.
-
-use crate::dirstate::parsers::Timestamp;
-use crate::errors::HgError;
-use crate::{
- dirstate::EntryState,
- dirstate::SIZE_FROM_OTHER_PARENT,
- dirstate::SIZE_NON_NORMAL,
- pack_dirstate, parse_dirstate,
- utils::hg_path::{HgPath, HgPathBuf},
- CopyMap, DirsMultiset, DirstateEntry, DirstateError, DirstateParents,
- StateMap,
-};
-use micro_timer::timed;
-use std::iter::FromIterator;
-use std::ops::Deref;
-
-#[derive(Default)]
-pub struct DirstateMap {
- state_map: StateMap,
- pub copy_map: CopyMap,
- pub dirs: Option<DirsMultiset>,
- pub all_dirs: Option<DirsMultiset>,
-}
-
-/// Should only really be used in python interface code, for clarity
-impl Deref for DirstateMap {
- type Target = StateMap;
-
- fn deref(&self) -> &Self::Target {
- &self.state_map
- }
-}
-
-impl FromIterator<(HgPathBuf, DirstateEntry)> for DirstateMap {
- fn from_iter<I: IntoIterator<Item = (HgPathBuf, DirstateEntry)>>(
- iter: I,
- ) -> Self {
- Self {
- state_map: iter.into_iter().collect(),
- ..Self::default()
- }
- }
-}
-
-impl DirstateMap {
- pub fn new() -> Self {
- Self::default()
- }
-
- pub fn clear(&mut self) {
- self.state_map = StateMap::default();
- self.copy_map.clear();
- }
-
- pub fn set_entry(&mut self, filename: &HgPath, entry: DirstateEntry) {
- self.state_map.insert(filename.to_owned(), entry);
- }
-
- /// Add a tracked file to the dirstate
- pub fn add_file(
- &mut self,
- filename: &HgPath,
- entry: DirstateEntry,
- ) -> Result<(), DirstateError> {
- let old_state = self.get(filename).map(|e| e.state());
- if old_state.is_none() || old_state == Some(EntryState::Removed) {
- if let Some(ref mut dirs) = self.dirs {
- dirs.add_path(filename)?;
- }
- }
- if old_state.is_none() {
- if let Some(ref mut all_dirs) = self.all_dirs {
- all_dirs.add_path(filename)?;
- }
- }
- self.state_map.insert(filename.to_owned(), entry.to_owned());
- Ok(())
- }
-
- /// Mark a file as removed in the dirstate.
- ///
- /// The `size` parameter is used to store sentinel values that indicate
- /// the file's previous state. In the future, we should refactor this
- /// to be more explicit about what that state is.
- pub fn remove_file(
- &mut self,
- filename: &HgPath,
- in_merge: bool,
- ) -> Result<(), DirstateError> {
- let old_entry_opt = self.get(filename);
- let old_state = old_entry_opt.map(|e| e.state());
- let mut size = 0;
- if in_merge {
- // XXX we should not be able to have 'm' state and 'FROM_P2' if not
- // during a merge. So I (marmoute) am not sure we need the
- // conditionnal at all. Adding double checking this with assert
- // would be nice.
- if let Some(old_entry) = old_entry_opt {
- // backup the previous state
- if old_entry.state() == EntryState::Merged {
- size = SIZE_NON_NORMAL;
- } else if old_entry.state() == EntryState::Normal
- && old_entry.size() == SIZE_FROM_OTHER_PARENT
- {
- // other parent
- size = SIZE_FROM_OTHER_PARENT;
- }
- }
- }
- if old_state.is_some() && old_state != Some(EntryState::Removed) {
- if let Some(ref mut dirs) = self.dirs {
- dirs.delete_path(filename)?;
- }
- }
- if old_state.is_none() {
- if let Some(ref mut all_dirs) = self.all_dirs {
- all_dirs.add_path(filename)?;
- }
- }
- if size == 0 {
- self.copy_map.remove(filename);
- }
-
- self.state_map
- .insert(filename.to_owned(), DirstateEntry::new_removed(size));
- Ok(())
- }
-
- /// Remove a file from the dirstate.
- /// Returns `true` if the file was previously recorded.
- pub fn drop_entry_and_copy_source(
- &mut self,
- filename: &HgPath,
- ) -> Result<(), DirstateError> {
- let old_state = self.get(filename).map(|e| e.state());
- let exists = self.state_map.remove(filename).is_some();
-
- if exists {
- if old_state != Some(EntryState::Removed) {
- if let Some(ref mut dirs) = self.dirs {
- dirs.delete_path(filename)?;
- }
- }
- if let Some(ref mut all_dirs) = self.all_dirs {
- all_dirs.delete_path(filename)?;
- }
- }
- self.copy_map.remove(filename);
-
- Ok(())
- }
-
- /// Both of these setters and their uses appear to be the simplest way to
- /// emulate a Python lazy property, but it is ugly and unidiomatic.
- /// TODO One day, rewriting this struct using the typestate might be a
- /// good idea.
- pub fn set_all_dirs(&mut self) -> Result<(), DirstateError> {
- if self.all_dirs.is_none() {
- self.all_dirs = Some(DirsMultiset::from_dirstate(
- self.state_map.iter().map(|(k, v)| Ok((k, *v))),
- false,
- )?);
- }
- Ok(())
- }
-
- pub fn set_dirs(&mut self) -> Result<(), DirstateError> {
- if self.dirs.is_none() {
- self.dirs = Some(DirsMultiset::from_dirstate(
- self.state_map.iter().map(|(k, v)| Ok((k, *v))),
- true,
- )?);
- }
- Ok(())
- }
-
- pub fn has_tracked_dir(
- &mut self,
- directory: &HgPath,
- ) -> Result<bool, DirstateError> {
- self.set_dirs()?;
- Ok(self.dirs.as_ref().unwrap().contains(directory))
- }
-
- pub fn has_dir(
- &mut self,
- directory: &HgPath,
- ) -> Result<bool, DirstateError> {
- self.set_all_dirs()?;
- Ok(self.all_dirs.as_ref().unwrap().contains(directory))
- }
-
- #[timed]
- pub fn read(
- &mut self,
- file_contents: &[u8],
- ) -> Result<Option<DirstateParents>, DirstateError> {
- if file_contents.is_empty() {
- return Ok(None);
- }
-
- let (parents, entries, copies) = parse_dirstate(file_contents)?;
- self.state_map.extend(
- entries
- .into_iter()
- .map(|(path, entry)| (path.to_owned(), entry)),
- );
- self.copy_map.extend(
- copies
- .into_iter()
- .map(|(path, copy)| (path.to_owned(), copy.to_owned())),
- );
- Ok(Some(parents.clone()))
- }
-
- pub fn pack(
- &mut self,
- parents: DirstateParents,
- now: Timestamp,
- ) -> Result<Vec<u8>, HgError> {
- pack_dirstate(&mut self.state_map, &self.copy_map, parents, now)
- }
-}
-
-#[cfg(test)]
-mod tests {
- use super::*;
-
- #[test]
- fn test_dirs_multiset() {
- let mut map = DirstateMap::new();
- assert!(map.dirs.is_none());
- assert!(map.all_dirs.is_none());
-
- assert_eq!(map.has_dir(HgPath::new(b"nope")).unwrap(), false);
- assert!(map.all_dirs.is_some());
- assert!(map.dirs.is_none());
-
- assert_eq!(map.has_tracked_dir(HgPath::new(b"nope")).unwrap(), false);
- assert!(map.dirs.is_some());
- }
-
- #[test]
- fn test_add_file() {
- let mut map = DirstateMap::new();
-
- assert_eq!(0, map.len());
-
- map.add_file(
- HgPath::new(b"meh"),
- DirstateEntry::from_v1_data(EntryState::Normal, 1337, 1337, 1337),
- )
- .unwrap();
-
- assert_eq!(1, map.len());
- }
-}
--- a/rust/hg-core/src/dirstate/parsers.rs Tue Sep 28 20:00:19 2021 +0200
+++ b/rust/hg-core/src/dirstate/parsers.rs Mon Sep 27 12:09:15 2021 +0200
@@ -5,14 +5,11 @@
use crate::errors::HgError;
use crate::utils::hg_path::HgPath;
-use crate::{
- dirstate::{CopyMap, EntryState, StateMap},
- DirstateEntry, DirstateParents,
-};
+use crate::{dirstate::EntryState, DirstateEntry, DirstateParents};
use byteorder::{BigEndian, WriteBytesExt};
use bytes_cast::{unaligned, BytesCast};
use micro_timer::timed;
-use std::convert::{TryFrom, TryInto};
+use std::convert::TryFrom;
/// Parents are stored in the dirstate as byte hashes.
pub const PARENT_SIZE: usize = 20;
@@ -141,328 +138,3 @@
/// Seconds since the Unix epoch
pub struct Timestamp(pub i64);
-
-pub fn pack_dirstate(
- state_map: &mut StateMap,
- copy_map: &CopyMap,
- parents: DirstateParents,
- now: Timestamp,
-) -> Result<Vec<u8>, HgError> {
- // TODO move away from i32 before 2038.
- let now: i32 = now.0.try_into().expect("time overflow");
-
- let expected_size: usize = state_map
- .iter()
- .map(|(filename, _)| {
- packed_entry_size(filename, copy_map.get(filename).map(|p| &**p))
- })
- .sum();
- let expected_size = expected_size + PARENT_SIZE * 2;
-
- let mut packed = Vec::with_capacity(expected_size);
-
- packed.extend(parents.p1.as_bytes());
- packed.extend(parents.p2.as_bytes());
-
- for (filename, entry) in state_map.iter_mut() {
- entry.clear_ambiguous_mtime(now);
- pack_entry(
- filename,
- entry,
- copy_map.get(filename).map(|p| &**p),
- &mut packed,
- )
- }
-
- if packed.len() != expected_size {
- return Err(HgError::CorruptedRepository(format!(
- "bad dirstate size: {} != {}",
- expected_size,
- packed.len()
- )));
- }
-
- Ok(packed)
-}
-
-#[cfg(test)]
-mod tests {
- use super::*;
- use crate::{utils::hg_path::HgPathBuf, FastHashMap};
- use pretty_assertions::assert_eq;
-
- #[test]
- fn test_pack_dirstate_empty() {
- let mut state_map = StateMap::default();
- let copymap = FastHashMap::default();
- let parents = DirstateParents {
- p1: b"12345678910111213141".into(),
- p2: b"00000000000000000000".into(),
- };
- let now = Timestamp(15000000);
- let expected = b"1234567891011121314100000000000000000000".to_vec();
-
- assert_eq!(
- expected,
- pack_dirstate(&mut state_map, ©map, parents, now).unwrap()
- );
-
- assert!(state_map.is_empty())
- }
- #[test]
- fn test_pack_dirstate_one_entry() {
- let expected_state_map: StateMap = [(
- HgPathBuf::from_bytes(b"f1"),
- DirstateEntry::from_v1_data(
- EntryState::Normal,
- 0o644,
- 0,
- 791231220,
- ),
- )]
- .iter()
- .cloned()
- .collect();
- let mut state_map = expected_state_map.clone();
-
- let copymap = FastHashMap::default();
- let parents = DirstateParents {
- p1: b"12345678910111213141".into(),
- p2: b"00000000000000000000".into(),
- };
- let now = Timestamp(15000000);
- let expected = [
- 49, 50, 51, 52, 53, 54, 55, 56, 57, 49, 48, 49, 49, 49, 50, 49,
- 51, 49, 52, 49, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48,
- 48, 48, 48, 48, 48, 48, 48, 48, 110, 0, 0, 1, 164, 0, 0, 0, 0, 47,
- 41, 58, 244, 0, 0, 0, 2, 102, 49,
- ]
- .to_vec();
-
- assert_eq!(
- expected,
- pack_dirstate(&mut state_map, ©map, parents, now).unwrap()
- );
-
- assert_eq!(expected_state_map, state_map);
- }
- #[test]
- fn test_pack_dirstate_one_entry_with_copy() {
- let expected_state_map: StateMap = [(
- HgPathBuf::from_bytes(b"f1"),
- DirstateEntry::from_v1_data(
- EntryState::Normal,
- 0o644,
- 0,
- 791231220,
- ),
- )]
- .iter()
- .cloned()
- .collect();
- let mut state_map = expected_state_map.clone();
- let mut copymap = FastHashMap::default();
- copymap.insert(
- HgPathBuf::from_bytes(b"f1"),
- HgPathBuf::from_bytes(b"copyname"),
- );
- let parents = DirstateParents {
- p1: b"12345678910111213141".into(),
- p2: b"00000000000000000000".into(),
- };
- let now = Timestamp(15000000);
- let expected = [
- 49, 50, 51, 52, 53, 54, 55, 56, 57, 49, 48, 49, 49, 49, 50, 49,
- 51, 49, 52, 49, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48,
- 48, 48, 48, 48, 48, 48, 48, 48, 110, 0, 0, 1, 164, 0, 0, 0, 0, 47,
- 41, 58, 244, 0, 0, 0, 11, 102, 49, 0, 99, 111, 112, 121, 110, 97,
- 109, 101,
- ]
- .to_vec();
-
- assert_eq!(
- expected,
- pack_dirstate(&mut state_map, ©map, parents, now).unwrap()
- );
- assert_eq!(expected_state_map, state_map);
- }
-
- #[test]
- fn test_parse_pack_one_entry_with_copy() {
- let mut state_map: StateMap = [(
- HgPathBuf::from_bytes(b"f1"),
- DirstateEntry::from_v1_data(
- EntryState::Normal,
- 0o644,
- 0,
- 791231220,
- ),
- )]
- .iter()
- .cloned()
- .collect();
- let mut copymap = FastHashMap::default();
- copymap.insert(
- HgPathBuf::from_bytes(b"f1"),
- HgPathBuf::from_bytes(b"copyname"),
- );
- let parents = DirstateParents {
- p1: b"12345678910111213141".into(),
- p2: b"00000000000000000000".into(),
- };
- let now = Timestamp(15000000);
- let result =
- pack_dirstate(&mut state_map, ©map, parents.clone(), now)
- .unwrap();
-
- let (new_parents, entries, copies) =
- parse_dirstate(result.as_slice()).unwrap();
- let new_state_map: StateMap = entries
- .into_iter()
- .map(|(path, entry)| (path.to_owned(), entry))
- .collect();
- let new_copy_map: CopyMap = copies
- .into_iter()
- .map(|(path, copy)| (path.to_owned(), copy.to_owned()))
- .collect();
-
- assert_eq!(
- (&parents, state_map, copymap),
- (new_parents, new_state_map, new_copy_map)
- )
- }
-
- #[test]
- fn test_parse_pack_multiple_entries_with_copy() {
- let mut state_map: StateMap = [
- (
- HgPathBuf::from_bytes(b"f1"),
- DirstateEntry::from_v1_data(
- EntryState::Normal,
- 0o644,
- 0,
- 791231220,
- ),
- ),
- (
- HgPathBuf::from_bytes(b"f2"),
- DirstateEntry::from_v1_data(
- EntryState::Merged,
- 0o777,
- 1000,
- 791231220,
- ),
- ),
- (
- HgPathBuf::from_bytes(b"f3"),
- DirstateEntry::from_v1_data(
- EntryState::Removed,
- 0o644,
- 234553,
- 791231220,
- ),
- ),
- (
- HgPathBuf::from_bytes(b"f4\xF6"),
- DirstateEntry::from_v1_data(EntryState::Added, 0o644, -1, -1),
- ),
- ]
- .iter()
- .cloned()
- .collect();
- let mut copymap = FastHashMap::default();
- copymap.insert(
- HgPathBuf::from_bytes(b"f1"),
- HgPathBuf::from_bytes(b"copyname"),
- );
- copymap.insert(
- HgPathBuf::from_bytes(b"f4\xF6"),
- HgPathBuf::from_bytes(b"copyname2"),
- );
- let parents = DirstateParents {
- p1: b"12345678910111213141".into(),
- p2: b"00000000000000000000".into(),
- };
- let now = Timestamp(15000000);
- let result =
- pack_dirstate(&mut state_map, ©map, parents.clone(), now)
- .unwrap();
-
- let (new_parents, entries, copies) =
- parse_dirstate(result.as_slice()).unwrap();
- let new_state_map: StateMap = entries
- .into_iter()
- .map(|(path, entry)| (path.to_owned(), entry))
- .collect();
- let new_copy_map: CopyMap = copies
- .into_iter()
- .map(|(path, copy)| (path.to_owned(), copy.to_owned()))
- .collect();
-
- assert_eq!(
- (&parents, state_map, copymap),
- (new_parents, new_state_map, new_copy_map)
- )
- }
-
- #[test]
- /// https://www.mercurial-scm.org/repo/hg/rev/af3f26b6bba4
- fn test_parse_pack_one_entry_with_copy_and_time_conflict() {
- let mut state_map: StateMap = [(
- HgPathBuf::from_bytes(b"f1"),
- DirstateEntry::from_v1_data(
- EntryState::Normal,
- 0o644,
- 0,
- 15000000,
- ),
- )]
- .iter()
- .cloned()
- .collect();
- let mut copymap = FastHashMap::default();
- copymap.insert(
- HgPathBuf::from_bytes(b"f1"),
- HgPathBuf::from_bytes(b"copyname"),
- );
- let parents = DirstateParents {
- p1: b"12345678910111213141".into(),
- p2: b"00000000000000000000".into(),
- };
- let now = Timestamp(15000000);
- let result =
- pack_dirstate(&mut state_map, ©map, parents.clone(), now)
- .unwrap();
-
- let (new_parents, entries, copies) =
- parse_dirstate(result.as_slice()).unwrap();
- let new_state_map: StateMap = entries
- .into_iter()
- .map(|(path, entry)| (path.to_owned(), entry))
- .collect();
- let new_copy_map: CopyMap = copies
- .into_iter()
- .map(|(path, copy)| (path.to_owned(), copy.to_owned()))
- .collect();
-
- assert_eq!(
- (
- &parents,
- [(
- HgPathBuf::from_bytes(b"f1"),
- DirstateEntry::from_v1_data(
- EntryState::Normal,
- 0o644,
- 0,
- -1
- )
- )]
- .iter()
- .cloned()
- .collect::<StateMap>(),
- copymap,
- ),
- (new_parents, new_state_map, new_copy_map)
- )
- }
-}
--- a/rust/hg-core/src/dirstate/status.rs Tue Sep 28 20:00:19 2021 +0200
+++ b/rust/hg-core/src/dirstate/status.rs Mon Sep 27 12:09:15 2021 +0200
@@ -10,33 +10,13 @@
//! and will only be triggered in narrow cases.
use crate::dirstate_tree::on_disk::DirstateV2ParseError;
-use crate::utils::path_auditor::PathAuditor;
+
use crate::{
- dirstate::SIZE_FROM_OTHER_PARENT,
- filepatterns::PatternFileWarning,
- matchers::{get_ignore_function, Matcher, VisitChildrenSet},
- utils::{
- files::{find_dirs, HgMetadata},
- hg_path::{
- hg_path_to_path_buf, os_string_to_hg_path_buf, HgPath, HgPathBuf,
- HgPathError,
- },
- },
- CopyMap, DirstateEntry, DirstateMap, EntryState, FastHashMap,
+ utils::hg_path::{HgPath, HgPathError},
PatternError,
};
-use lazy_static::lazy_static;
-use micro_timer::timed;
-use rayon::prelude::*;
-use std::{
- borrow::Cow,
- collections::HashSet,
- fmt,
- fs::{read_dir, DirEntry},
- io::ErrorKind,
- ops::Deref,
- path::{Path, PathBuf},
-};
+
+use std::{borrow::Cow, fmt};
/// Wrong type of file from a `BadMatch`
/// Note: a lot of those don't exist on all platforms.
@@ -70,32 +50,6 @@
BadType(BadType),
}
-/// Enum used to dispatch new status entries into the right collections.
-/// Is similar to `crate::EntryState`, but represents the transient state of
-/// entries during the lifetime of a command.
-#[derive(Debug, Copy, Clone)]
-pub enum Dispatch {
- Unsure,
- Modified,
- Added,
- Removed,
- Deleted,
- Clean,
- Unknown,
- Ignored,
- /// Empty dispatch, the file is not worth listing
- None,
- /// Was explicitly matched but cannot be found/accessed
- Bad(BadMatch),
- Directory {
- /// True if the directory used to be a file in the dmap so we can say
- /// that it's been removed.
- was_file: bool,
- },
-}
-
-type IoResult<T> = std::io::Result<T>;
-
/// `Box<dyn Trait>` is syntactic sugar for `Box<dyn Trait + 'static>`, so add
/// an explicit lifetime here to not fight `'static` bounds "out of nowhere".
pub type IgnoreFnType<'a> =
@@ -105,135 +59,6 @@
/// the dirstate/explicit) paths, this comes up a lot.
pub type HgPathCow<'a> = Cow<'a, HgPath>;
-/// A path with its computed ``Dispatch`` information
-type DispatchedPath<'a> = (HgPathCow<'a>, Dispatch);
-
-/// The conversion from `HgPath` to a real fs path failed.
-/// `22` is the error code for "Invalid argument"
-const INVALID_PATH_DISPATCH: Dispatch = Dispatch::Bad(BadMatch::OsError(22));
-
-/// Dates and times that are outside the 31-bit signed range are compared
-/// modulo 2^31. This should prevent hg from behaving badly with very large
-/// files or corrupt dates while still having a high probability of detecting
-/// changes. (issue2608)
-/// TODO I haven't found a way of having `b` be `Into<i32>`, since `From<u64>`
-/// is not defined for `i32`, and there is no `As` trait. This forces the
-/// caller to cast `b` as `i32`.
-fn mod_compare(a: i32, b: i32) -> bool {
- a & i32::max_value() != b & i32::max_value()
-}
-
-/// Return a sorted list containing information about the entries
-/// in the directory.
-///
-/// * `skip_dot_hg` - Return an empty vec if `path` contains a `.hg` directory
-fn list_directory(
- path: impl AsRef<Path>,
- skip_dot_hg: bool,
-) -> std::io::Result<Vec<(HgPathBuf, DirEntry)>> {
- let mut results = vec![];
- let entries = read_dir(path.as_ref())?;
-
- for entry in entries {
- let entry = entry?;
- let filename = os_string_to_hg_path_buf(entry.file_name())?;
- let file_type = entry.file_type()?;
- if skip_dot_hg && filename.as_bytes() == b".hg" && file_type.is_dir() {
- return Ok(vec![]);
- } else {
- results.push((filename, entry))
- }
- }
-
- results.sort_unstable_by_key(|e| e.0.clone());
- Ok(results)
-}
-
-/// The file corresponding to the dirstate entry was found on the filesystem.
-fn dispatch_found(
- filename: impl AsRef<HgPath>,
- entry: DirstateEntry,
- metadata: HgMetadata,
- copy_map: &CopyMap,
- options: StatusOptions,
-) -> Dispatch {
- match entry.state() {
- EntryState::Normal => {
- let mode = entry.mode();
- let size = entry.size();
- let mtime = entry.mtime();
-
- let HgMetadata {
- st_mode,
- st_size,
- st_mtime,
- ..
- } = metadata;
-
- let size_changed = mod_compare(size, st_size as i32);
- let mode_changed =
- (mode ^ st_mode as i32) & 0o100 != 0o000 && options.check_exec;
- let metadata_changed = size >= 0 && (size_changed || mode_changed);
- let other_parent = size == SIZE_FROM_OTHER_PARENT;
-
- if metadata_changed
- || other_parent
- || copy_map.contains_key(filename.as_ref())
- {
- if metadata.is_symlink() && size_changed {
- // issue6456: Size returned may be longer due to encryption
- // on EXT-4 fscrypt. TODO maybe only do it on EXT4?
- Dispatch::Unsure
- } else {
- Dispatch::Modified
- }
- } else if mod_compare(mtime, st_mtime as i32)
- || st_mtime == options.last_normal_time
- {
- // the file may have just been marked as normal and
- // it may have changed in the same second without
- // changing its size. This can happen if we quickly
- // do multiple commits. Force lookup, so we don't
- // miss such a racy file change.
- Dispatch::Unsure
- } else if options.list_clean {
- Dispatch::Clean
- } else {
- Dispatch::None
- }
- }
- EntryState::Merged => Dispatch::Modified,
- EntryState::Added => Dispatch::Added,
- EntryState::Removed => Dispatch::Removed,
- }
-}
-
-/// The file corresponding to this Dirstate entry is missing.
-fn dispatch_missing(state: EntryState) -> Dispatch {
- match state {
- // File was removed from the filesystem during commands
- EntryState::Normal | EntryState::Merged | EntryState::Added => {
- Dispatch::Deleted
- }
- // File was removed, everything is normal
- EntryState::Removed => Dispatch::Removed,
- }
-}
-
-fn dispatch_os_error(e: &std::io::Error) -> Dispatch {
- Dispatch::Bad(BadMatch::OsError(
- e.raw_os_error().expect("expected real OS error"),
- ))
-}
-
-lazy_static! {
- static ref DEFAULT_WORK: HashSet<&'static HgPath> = {
- let mut h = HashSet::new();
- h.insert(HgPath::new(b""));
- h
- };
-}
-
#[derive(Debug, Copy, Clone)]
pub struct StatusOptions {
/// Remember the most recent modification timeslot for status, to make
@@ -319,626 +144,3 @@
}
}
}
-
-/// Gives information about which files are changed in the working directory
-/// and how, compared to the revision we're based on
-pub struct Status<'a, M: ?Sized + Matcher + Sync> {
- dmap: &'a DirstateMap,
- pub(crate) matcher: &'a M,
- root_dir: PathBuf,
- pub(crate) options: StatusOptions,
- ignore_fn: IgnoreFnType<'a>,
-}
-
-impl<'a, M> Status<'a, M>
-where
- M: ?Sized + Matcher + Sync,
-{
- pub fn new(
- dmap: &'a DirstateMap,
- matcher: &'a M,
- root_dir: PathBuf,
- ignore_files: Vec<PathBuf>,
- options: StatusOptions,
- ) -> StatusResult<(Self, Vec<PatternFileWarning>)> {
- // Needs to outlive `dir_ignore_fn` since it's captured.
-
- let (ignore_fn, warnings): (IgnoreFnType, _) =
- if options.list_ignored || options.list_unknown {
- get_ignore_function(ignore_files, &root_dir, &mut |_| {})?
- } else {
- (Box::new(|&_| true), vec![])
- };
-
- Ok((
- Self {
- dmap,
- matcher,
- root_dir,
- options,
- ignore_fn,
- },
- warnings,
- ))
- }
-
- /// Is the path ignored?
- pub fn is_ignored(&self, path: impl AsRef<HgPath>) -> bool {
- (self.ignore_fn)(path.as_ref())
- }
-
- /// Is the path or one of its ancestors ignored?
- pub fn dir_ignore(&self, dir: impl AsRef<HgPath>) -> bool {
- // Only involve ignore mechanism if we're listing unknowns or ignored.
- if self.options.list_ignored || self.options.list_unknown {
- if self.is_ignored(&dir) {
- true
- } else {
- for p in find_dirs(dir.as_ref()) {
- if self.is_ignored(p) {
- return true;
- }
- }
- false
- }
- } else {
- true
- }
- }
-
- /// Get stat data about the files explicitly specified by the matcher.
- /// Returns a tuple of the directories that need to be traversed and the
- /// files with their corresponding `Dispatch`.
- /// TODO subrepos
- #[timed]
- pub fn walk_explicit(
- &self,
- traversed_sender: crossbeam_channel::Sender<HgPathBuf>,
- ) -> (Vec<DispatchedPath<'a>>, Vec<DispatchedPath<'a>>) {
- self.matcher
- .file_set()
- .unwrap_or(&DEFAULT_WORK)
- .par_iter()
- .flat_map(|&filename| -> Option<_> {
- // TODO normalization
- let normalized = filename;
-
- let buf = match hg_path_to_path_buf(normalized) {
- Ok(x) => x,
- Err(_) => {
- return Some((
- Cow::Borrowed(normalized),
- INVALID_PATH_DISPATCH,
- ))
- }
- };
- let target = self.root_dir.join(buf);
- let st = target.symlink_metadata();
- let in_dmap = self.dmap.get(normalized);
- match st {
- Ok(meta) => {
- let file_type = meta.file_type();
- return if file_type.is_file() || file_type.is_symlink()
- {
- if let Some(entry) = in_dmap {
- return Some((
- Cow::Borrowed(normalized),
- dispatch_found(
- &normalized,
- *entry,
- HgMetadata::from_metadata(meta),
- &self.dmap.copy_map,
- self.options,
- ),
- ));
- }
- Some((
- Cow::Borrowed(normalized),
- Dispatch::Unknown,
- ))
- } else if file_type.is_dir() {
- if self.options.collect_traversed_dirs {
- traversed_sender
- .send(normalized.to_owned())
- .expect("receiver should outlive sender");
- }
- Some((
- Cow::Borrowed(normalized),
- Dispatch::Directory {
- was_file: in_dmap.is_some(),
- },
- ))
- } else {
- Some((
- Cow::Borrowed(normalized),
- Dispatch::Bad(BadMatch::BadType(
- // TODO do more than unknown
- // Support for all `BadType` variant
- // varies greatly between platforms.
- // So far, no tests check the type and
- // this should be good enough for most
- // users.
- BadType::Unknown,
- )),
- ))
- };
- }
- Err(_) => {
- if let Some(entry) = in_dmap {
- return Some((
- Cow::Borrowed(normalized),
- dispatch_missing(entry.state()),
- ));
- }
- }
- };
- None
- })
- .partition(|(_, dispatch)| match dispatch {
- Dispatch::Directory { .. } => true,
- _ => false,
- })
- }
-
- /// Walk the working directory recursively to look for changes compared to
- /// the current `DirstateMap`.
- ///
- /// This takes a mutable reference to the results to account for the
- /// `extend` in timings
- #[timed]
- pub fn traverse(
- &self,
- path: impl AsRef<HgPath>,
- old_results: &FastHashMap<HgPathCow<'a>, Dispatch>,
- results: &mut Vec<DispatchedPath<'a>>,
- traversed_sender: crossbeam_channel::Sender<HgPathBuf>,
- ) {
- // The traversal is done in parallel, so use a channel to gather
- // entries. `crossbeam_channel::Sender` is `Sync`, while `mpsc::Sender`
- // is not.
- let (files_transmitter, files_receiver) =
- crossbeam_channel::unbounded();
-
- self.traverse_dir(
- &files_transmitter,
- path,
- &old_results,
- traversed_sender,
- );
-
- // Disconnect the channel so the receiver stops waiting
- drop(files_transmitter);
-
- let new_results = files_receiver
- .into_iter()
- .par_bridge()
- .map(|(f, d)| (Cow::Owned(f), d));
-
- results.par_extend(new_results);
- }
-
- /// Dispatch a single entry (file, folder, symlink...) found during
- /// `traverse`. If the entry is a folder that needs to be traversed, it
- /// will be handled in a separate thread.
- fn handle_traversed_entry<'b>(
- &'a self,
- scope: &rayon::Scope<'b>,
- files_sender: &'b crossbeam_channel::Sender<(HgPathBuf, Dispatch)>,
- old_results: &'a FastHashMap<Cow<HgPath>, Dispatch>,
- filename: HgPathBuf,
- dir_entry: DirEntry,
- traversed_sender: crossbeam_channel::Sender<HgPathBuf>,
- ) -> IoResult<()>
- where
- 'a: 'b,
- {
- let file_type = dir_entry.file_type()?;
- let entry_option = self.dmap.get(&filename);
-
- if filename.as_bytes() == b".hg" {
- // Could be a directory or a symlink
- return Ok(());
- }
-
- if file_type.is_dir() {
- self.handle_traversed_dir(
- scope,
- files_sender,
- old_results,
- entry_option,
- filename,
- traversed_sender,
- );
- } else if file_type.is_file() || file_type.is_symlink() {
- if let Some(entry) = entry_option {
- if self.matcher.matches_everything()
- || self.matcher.matches(&filename)
- {
- let metadata = dir_entry.metadata()?;
- files_sender
- .send((
- filename.to_owned(),
- dispatch_found(
- &filename,
- *entry,
- HgMetadata::from_metadata(metadata),
- &self.dmap.copy_map,
- self.options,
- ),
- ))
- .unwrap();
- }
- } else if (self.matcher.matches_everything()
- || self.matcher.matches(&filename))
- && !self.is_ignored(&filename)
- {
- if (self.options.list_ignored
- || self.matcher.exact_match(&filename))
- && self.dir_ignore(&filename)
- {
- if self.options.list_ignored {
- files_sender
- .send((filename.to_owned(), Dispatch::Ignored))
- .unwrap();
- }
- } else if self.options.list_unknown {
- files_sender
- .send((filename.to_owned(), Dispatch::Unknown))
- .unwrap();
- }
- } else if self.is_ignored(&filename) && self.options.list_ignored {
- if self.matcher.matches(&filename) {
- files_sender
- .send((filename.to_owned(), Dispatch::Ignored))
- .unwrap();
- }
- }
- } else if let Some(entry) = entry_option {
- // Used to be a file or a folder, now something else.
- if self.matcher.matches_everything()
- || self.matcher.matches(&filename)
- {
- files_sender
- .send((
- filename.to_owned(),
- dispatch_missing(entry.state()),
- ))
- .unwrap();
- }
- }
-
- Ok(())
- }
-
- /// A directory was found in the filesystem and needs to be traversed
- fn handle_traversed_dir<'b>(
- &'a self,
- scope: &rayon::Scope<'b>,
- files_sender: &'b crossbeam_channel::Sender<(HgPathBuf, Dispatch)>,
- old_results: &'a FastHashMap<Cow<HgPath>, Dispatch>,
- entry_option: Option<&'a DirstateEntry>,
- directory: HgPathBuf,
- traversed_sender: crossbeam_channel::Sender<HgPathBuf>,
- ) where
- 'a: 'b,
- {
- scope.spawn(move |_| {
- // Nested `if` until `rust-lang/rust#53668` is stable
- if let Some(entry) = entry_option {
- // Used to be a file, is now a folder
- if self.matcher.matches_everything()
- || self.matcher.matches(&directory)
- {
- files_sender
- .send((
- directory.to_owned(),
- dispatch_missing(entry.state()),
- ))
- .unwrap();
- }
- }
- // Do we need to traverse it?
- if !self.is_ignored(&directory) || self.options.list_ignored {
- self.traverse_dir(
- files_sender,
- directory,
- &old_results,
- traversed_sender,
- )
- }
- });
- }
-
- /// Decides whether the directory needs to be listed, and if so handles the
- /// entries in a separate thread.
- fn traverse_dir(
- &self,
- files_sender: &crossbeam_channel::Sender<(HgPathBuf, Dispatch)>,
- directory: impl AsRef<HgPath>,
- old_results: &FastHashMap<Cow<HgPath>, Dispatch>,
- traversed_sender: crossbeam_channel::Sender<HgPathBuf>,
- ) {
- let directory = directory.as_ref();
-
- if self.options.collect_traversed_dirs {
- traversed_sender
- .send(directory.to_owned())
- .expect("receiver should outlive sender");
- }
-
- let visit_entries = match self.matcher.visit_children_set(directory) {
- VisitChildrenSet::Empty => return,
- VisitChildrenSet::This | VisitChildrenSet::Recursive => None,
- VisitChildrenSet::Set(set) => Some(set),
- };
- let buf = match hg_path_to_path_buf(directory) {
- Ok(b) => b,
- Err(_) => {
- files_sender
- .send((directory.to_owned(), INVALID_PATH_DISPATCH))
- .expect("receiver should outlive sender");
- return;
- }
- };
- let dir_path = self.root_dir.join(buf);
-
- let skip_dot_hg = !directory.as_bytes().is_empty();
- let entries = match list_directory(dir_path, skip_dot_hg) {
- Err(e) => {
- files_sender
- .send((directory.to_owned(), dispatch_os_error(&e)))
- .expect("receiver should outlive sender");
- return;
- }
- Ok(entries) => entries,
- };
-
- rayon::scope(|scope| {
- for (filename, dir_entry) in entries {
- if let Some(ref set) = visit_entries {
- if !set.contains(filename.deref()) {
- continue;
- }
- }
- // TODO normalize
- let filename = if directory.is_empty() {
- filename.to_owned()
- } else {
- directory.join(&filename)
- };
-
- if !old_results.contains_key(filename.deref()) {
- match self.handle_traversed_entry(
- scope,
- files_sender,
- old_results,
- filename,
- dir_entry,
- traversed_sender.clone(),
- ) {
- Err(e) => {
- files_sender
- .send((
- directory.to_owned(),
- dispatch_os_error(&e),
- ))
- .expect("receiver should outlive sender");
- }
- Ok(_) => {}
- }
- }
- }
- })
- }
-
- /// Add the files in the dirstate to the results.
- ///
- /// This takes a mutable reference to the results to account for the
- /// `extend` in timings
- #[timed]
- pub fn extend_from_dmap(&self, results: &mut Vec<DispatchedPath<'a>>) {
- results.par_extend(
- self.dmap
- .par_iter()
- .filter(|(path, _)| self.matcher.matches(path))
- .map(move |(filename, entry)| {
- let filename: &HgPath = filename;
- let filename_as_path = match hg_path_to_path_buf(filename)
- {
- Ok(f) => f,
- Err(_) => {
- return (
- Cow::Borrowed(filename),
- INVALID_PATH_DISPATCH,
- )
- }
- };
- let meta = self
- .root_dir
- .join(filename_as_path)
- .symlink_metadata();
- match meta {
- Ok(m)
- if !(m.file_type().is_file()
- || m.file_type().is_symlink()) =>
- {
- (
- Cow::Borrowed(filename),
- dispatch_missing(entry.state()),
- )
- }
- Ok(m) => (
- Cow::Borrowed(filename),
- dispatch_found(
- filename,
- *entry,
- HgMetadata::from_metadata(m),
- &self.dmap.copy_map,
- self.options,
- ),
- ),
- Err(e)
- if e.kind() == ErrorKind::NotFound
- || e.raw_os_error() == Some(20) =>
- {
- // Rust does not yet have an `ErrorKind` for
- // `NotADirectory` (errno 20)
- // It happens if the dirstate contains `foo/bar`
- // and foo is not a
- // directory
- (
- Cow::Borrowed(filename),
- dispatch_missing(entry.state()),
- )
- }
- Err(e) => {
- (Cow::Borrowed(filename), dispatch_os_error(&e))
- }
- }
- }),
- );
- }
-
- /// Checks all files that are in the dirstate but were not found during the
- /// working directory traversal. This means that the rest must
- /// be either ignored, under a symlink or under a new nested repo.
- ///
- /// This takes a mutable reference to the results to account for the
- /// `extend` in timings
- #[timed]
- pub fn handle_unknowns(&self, results: &mut Vec<DispatchedPath<'a>>) {
- let to_visit: Vec<(&HgPath, &DirstateEntry)> =
- if results.is_empty() && self.matcher.matches_everything() {
- self.dmap.iter().map(|(f, e)| (f.deref(), e)).collect()
- } else {
- // Only convert to a hashmap if needed.
- let old_results: FastHashMap<_, _> =
- results.iter().cloned().collect();
- self.dmap
- .iter()
- .filter_map(move |(f, e)| {
- if !old_results.contains_key(f.deref())
- && self.matcher.matches(f)
- {
- Some((f.deref(), e))
- } else {
- None
- }
- })
- .collect()
- };
-
- let path_auditor = PathAuditor::new(&self.root_dir);
-
- let new_results = to_visit.into_par_iter().filter_map(
- |(filename, entry)| -> Option<_> {
- // Report ignored items in the dmap as long as they are not
- // under a symlink directory.
- if path_auditor.check(filename) {
- // TODO normalize for case-insensitive filesystems
- let buf = match hg_path_to_path_buf(filename) {
- Ok(x) => x,
- Err(_) => {
- return Some((
- Cow::Owned(filename.to_owned()),
- INVALID_PATH_DISPATCH,
- ));
- }
- };
- Some((
- Cow::Owned(filename.to_owned()),
- match self.root_dir.join(&buf).symlink_metadata() {
- // File was just ignored, no links, and exists
- Ok(meta) => {
- let metadata = HgMetadata::from_metadata(meta);
- dispatch_found(
- filename,
- *entry,
- metadata,
- &self.dmap.copy_map,
- self.options,
- )
- }
- // File doesn't exist
- Err(_) => dispatch_missing(entry.state()),
- },
- ))
- } else {
- // It's either missing or under a symlink directory which
- // we, in this case, report as missing.
- Some((
- Cow::Owned(filename.to_owned()),
- dispatch_missing(entry.state()),
- ))
- }
- },
- );
-
- results.par_extend(new_results);
- }
-}
-
-#[timed]
-pub fn build_response<'a>(
- results: impl IntoIterator<Item = DispatchedPath<'a>>,
- traversed: Vec<HgPathCow<'a>>,
-) -> DirstateStatus<'a> {
- let mut unsure = vec![];
- let mut modified = vec![];
- let mut added = vec![];
- let mut removed = vec![];
- let mut deleted = vec![];
- let mut clean = vec![];
- let mut ignored = vec![];
- let mut unknown = vec![];
- let mut bad = vec![];
-
- for (filename, dispatch) in results.into_iter() {
- match dispatch {
- Dispatch::Unknown => unknown.push(filename),
- Dispatch::Unsure => unsure.push(filename),
- Dispatch::Modified => modified.push(filename),
- Dispatch::Added => added.push(filename),
- Dispatch::Removed => removed.push(filename),
- Dispatch::Deleted => deleted.push(filename),
- Dispatch::Clean => clean.push(filename),
- Dispatch::Ignored => ignored.push(filename),
- Dispatch::None => {}
- Dispatch::Bad(reason) => bad.push((filename, reason)),
- Dispatch::Directory { .. } => {}
- }
- }
-
- DirstateStatus {
- modified,
- added,
- removed,
- deleted,
- clean,
- ignored,
- unknown,
- bad,
- unsure,
- traversed,
- dirty: false,
- }
-}
-
-/// Get the status of files in the working directory.
-///
-/// This is the current entry-point for `hg-core` and is realistically unusable
-/// outside of a Python context because its arguments need to provide a lot of
-/// information that will not be necessary in the future.
-#[timed]
-pub fn status<'a>(
- dmap: &'a DirstateMap,
- matcher: &'a (dyn Matcher + Sync),
- root_dir: PathBuf,
- ignore_files: Vec<PathBuf>,
- options: StatusOptions,
-) -> StatusResult<(DirstateStatus<'a>, Vec<PatternFileWarning>)> {
- let (status, warnings) =
- Status::new(dmap, matcher, root_dir, ignore_files, options)?;
-
- Ok((status.run()?, warnings))
-}
--- a/rust/hg-core/src/dirstate_tree/dirstate_map.rs Tue Sep 28 20:00:19 2021 +0200
+++ b/rust/hg-core/src/dirstate_tree/dirstate_map.rs Mon Sep 27 12:09:15 2021 +0200
@@ -11,11 +11,12 @@
use crate::dirstate::parsers::packed_entry_size;
use crate::dirstate::parsers::parse_dirstate_entries;
use crate::dirstate::parsers::Timestamp;
+use crate::dirstate::CopyMapIter;
+use crate::dirstate::StateMapIter;
use crate::dirstate::SIZE_FROM_OTHER_PARENT;
use crate::dirstate::SIZE_NON_NORMAL;
use crate::matchers::Matcher;
use crate::utils::hg_path::{HgPath, HgPathBuf};
-use crate::CopyMapIter;
use crate::DirstateEntry;
use crate::DirstateError;
use crate::DirstateParents;
@@ -23,7 +24,6 @@
use crate::EntryState;
use crate::FastHashMap;
use crate::PatternFileWarning;
-use crate::StateMapIter;
use crate::StatusError;
use crate::StatusOptions;
--- a/rust/hg-core/src/dirstate_tree/dispatch.rs Tue Sep 28 20:00:19 2021 +0200
+++ b/rust/hg-core/src/dirstate_tree/dispatch.rs Mon Sep 27 12:09:15 2021 +0200
@@ -1,17 +1,16 @@
use std::path::PathBuf;
use crate::dirstate::parsers::Timestamp;
+use crate::dirstate::CopyMapIter;
+use crate::dirstate::StateMapIter;
use crate::dirstate_tree::on_disk::DirstateV2ParseError;
use crate::matchers::Matcher;
use crate::utils::hg_path::{HgPath, HgPathBuf};
-use crate::CopyMapIter;
use crate::DirstateEntry;
use crate::DirstateError;
-use crate::DirstateMap;
use crate::DirstateParents;
use crate::DirstateStatus;
use crate::PatternFileWarning;
-use crate::StateMapIter;
use crate::StatusError;
use crate::StatusOptions;
@@ -212,190 +211,3 @@
+ '_,
>;
}
-
-impl DirstateMapMethods for DirstateMap {
- fn clear(&mut self) {
- self.clear()
- }
-
- /// Used to set a value directory.
- ///
- /// XXX Is temporary during a refactor of V1 dirstate and will disappear
- /// shortly.
- fn set_entry(
- &mut self,
- filename: &HgPath,
- entry: DirstateEntry,
- ) -> Result<(), DirstateV2ParseError> {
- self.set_entry(&filename, entry);
- Ok(())
- }
-
- fn add_file(
- &mut self,
- filename: &HgPath,
- entry: DirstateEntry,
- ) -> Result<(), DirstateError> {
- self.add_file(filename, entry)
- }
-
- fn remove_file(
- &mut self,
- filename: &HgPath,
- in_merge: bool,
- ) -> Result<(), DirstateError> {
- self.remove_file(filename, in_merge)
- }
-
- fn drop_entry_and_copy_source(
- &mut self,
- filename: &HgPath,
- ) -> Result<(), DirstateError> {
- self.drop_entry_and_copy_source(filename)
- }
-
- fn has_tracked_dir(
- &mut self,
- directory: &HgPath,
- ) -> Result<bool, DirstateError> {
- self.has_tracked_dir(directory)
- }
-
- fn has_dir(&mut self, directory: &HgPath) -> Result<bool, DirstateError> {
- self.has_dir(directory)
- }
-
- fn pack_v1(
- &mut self,
- parents: DirstateParents,
- now: Timestamp,
- ) -> Result<Vec<u8>, DirstateError> {
- Ok(self.pack(parents, now)?)
- }
-
- fn pack_v2(
- &mut self,
- _now: Timestamp,
- _can_append: bool,
- ) -> Result<(Vec<u8>, Vec<u8>, bool), DirstateError> {
- panic!(
- "should have used dirstate_tree::DirstateMap to use the v2 format"
- )
- }
-
- fn status<'a>(
- &'a mut self,
- matcher: &'a (dyn Matcher + Sync),
- root_dir: PathBuf,
- ignore_files: Vec<PathBuf>,
- options: StatusOptions,
- ) -> Result<(DirstateStatus<'a>, Vec<PatternFileWarning>), StatusError>
- {
- crate::status(self, matcher, root_dir, ignore_files, options)
- }
-
- fn copy_map_len(&self) -> usize {
- self.copy_map.len()
- }
-
- fn copy_map_iter(&self) -> CopyMapIter<'_> {
- Box::new(
- self.copy_map
- .iter()
- .map(|(key, value)| Ok((&**key, &**value))),
- )
- }
-
- fn copy_map_contains_key(
- &self,
- key: &HgPath,
- ) -> Result<bool, DirstateV2ParseError> {
- Ok(self.copy_map.contains_key(key))
- }
-
- fn copy_map_get(
- &self,
- key: &HgPath,
- ) -> Result<Option<&HgPath>, DirstateV2ParseError> {
- Ok(self.copy_map.get(key).map(|p| &**p))
- }
-
- fn copy_map_remove(
- &mut self,
- key: &HgPath,
- ) -> Result<Option<HgPathBuf>, DirstateV2ParseError> {
- Ok(self.copy_map.remove(key))
- }
-
- fn copy_map_insert(
- &mut self,
- key: HgPathBuf,
- value: HgPathBuf,
- ) -> Result<Option<HgPathBuf>, DirstateV2ParseError> {
- Ok(self.copy_map.insert(key, value))
- }
-
- fn len(&self) -> usize {
- (&**self).len()
- }
-
- fn contains_key(
- &self,
- key: &HgPath,
- ) -> Result<bool, DirstateV2ParseError> {
- Ok((&**self).contains_key(key))
- }
-
- fn get(
- &self,
- key: &HgPath,
- ) -> Result<Option<DirstateEntry>, DirstateV2ParseError> {
- Ok((&**self).get(key).cloned())
- }
-
- fn iter(&self) -> StateMapIter<'_> {
- Box::new((&**self).iter().map(|(key, value)| Ok((&**key, *value))))
- }
-
- fn iter_tracked_dirs(
- &mut self,
- ) -> Result<
- Box<
- dyn Iterator<Item = Result<&HgPath, DirstateV2ParseError>>
- + Send
- + '_,
- >,
- DirstateError,
- > {
- self.set_all_dirs()?;
- Ok(Box::new(
- self.all_dirs
- .as_ref()
- .unwrap()
- .iter()
- .map(|path| Ok(&**path)),
- ))
- }
-
- fn debug_iter(
- &self,
- all: bool,
- ) -> Box<
- dyn Iterator<
- Item = Result<
- (&HgPath, (u8, i32, i32, i32)),
- DirstateV2ParseError,
- >,
- > + Send
- + '_,
- > {
- // Not used for the flat (not tree-based) DirstateMap
- let _ = all;
-
- Box::new(
- (&**self)
- .iter()
- .map(|(path, entry)| Ok((&**path, entry.debug_tuple()))),
- )
- }
-}
--- a/rust/hg-core/src/dirstate_tree/owning_dispatch.rs Tue Sep 28 20:00:19 2021 +0200
+++ b/rust/hg-core/src/dirstate_tree/owning_dispatch.rs Mon Sep 27 12:09:15 2021 +0200
@@ -1,16 +1,16 @@
use crate::dirstate::parsers::Timestamp;
+use crate::dirstate::CopyMapIter;
+use crate::dirstate::StateMapIter;
use crate::dirstate_tree::dispatch::DirstateMapMethods;
use crate::dirstate_tree::on_disk::DirstateV2ParseError;
use crate::dirstate_tree::owning::OwningDirstateMap;
use crate::matchers::Matcher;
use crate::utils::hg_path::{HgPath, HgPathBuf};
-use crate::CopyMapIter;
use crate::DirstateEntry;
use crate::DirstateError;
use crate::DirstateParents;
use crate::DirstateStatus;
use crate::PatternFileWarning;
-use crate::StateMapIter;
use crate::StatusError;
use crate::StatusOptions;
use std::path::PathBuf;
--- a/rust/hg-core/src/lib.rs Tue Sep 28 20:00:19 2021 +0200
+++ b/rust/hg-core/src/lib.rs Mon Sep 27 12:09:15 2021 +0200
@@ -16,14 +16,11 @@
pub mod testing; // unconditionally built, for use from integration tests
pub use dirstate::{
dirs_multiset::{DirsMultiset, DirsMultisetIter},
- dirstate_map::DirstateMap,
- parsers::{pack_dirstate, parse_dirstate, PARENT_SIZE},
status::{
- status, BadMatch, BadType, DirstateStatus, HgPathCow, StatusError,
+ BadMatch, BadType, DirstateStatus, HgPathCow, StatusError,
StatusOptions,
},
- CopyMap, CopyMapIter, DirstateEntry, DirstateParents, EntryState,
- StateMap, StateMapIter,
+ DirstateEntry, DirstateParents, EntryState,
};
pub mod copy_tracing;
mod filepatterns;
--- a/rust/hg-core/src/operations/dirstate_status.rs Tue Sep 28 20:00:19 2021 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,71 +0,0 @@
-// dirstate_status.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.
-
-use crate::dirstate::status::{build_response, Dispatch, Status};
-use crate::matchers::Matcher;
-use crate::{DirstateStatus, StatusError};
-
-impl<'a, M: ?Sized + Matcher + Sync> Status<'a, M> {
- pub(crate) fn run(&self) -> Result<DirstateStatus<'a>, StatusError> {
- let (traversed_sender, traversed_receiver) =
- crossbeam_channel::unbounded();
-
- // Step 1: check the files explicitly mentioned by the user
- let (work, mut results) = self.walk_explicit(traversed_sender.clone());
-
- if !work.is_empty() {
- // Hashmaps are quite a bit slower to build than vecs, so only
- // build it if needed.
- let old_results = results.iter().cloned().collect();
-
- // Step 2: recursively check the working directory for changes if
- // needed
- for (dir, dispatch) in work {
- match dispatch {
- Dispatch::Directory { was_file } => {
- if was_file {
- results.push((dir.to_owned(), Dispatch::Removed));
- }
- if self.options.list_ignored
- || self.options.list_unknown
- && !self.dir_ignore(&dir)
- {
- self.traverse(
- &dir,
- &old_results,
- &mut results,
- traversed_sender.clone(),
- );
- }
- }
- _ => {
- unreachable!("There can only be directories in `work`")
- }
- }
- }
- }
-
- if !self.matcher.is_exact() {
- if self.options.list_unknown {
- self.handle_unknowns(&mut results);
- } else {
- // TODO this is incorrect, see issue6335
- // This requires a fix in both Python and Rust that can happen
- // with other pending changes to `status`.
- self.extend_from_dmap(&mut results);
- }
- }
-
- drop(traversed_sender);
- let traversed = traversed_receiver
- .into_iter()
- .map(std::borrow::Cow::Owned)
- .collect();
-
- Ok(build_response(results, traversed))
- }
-}
--- a/rust/hg-core/src/operations/mod.rs Tue Sep 28 20:00:19 2021 +0200
+++ b/rust/hg-core/src/operations/mod.rs Mon Sep 27 12:09:15 2021 +0200
@@ -4,7 +4,6 @@
mod cat;
mod debugdata;
-mod dirstate_status;
mod list_tracked_files;
pub use cat::{cat, CatOutput};
pub use debugdata::{debug_data, DebugDataKind};
--- a/rust/hg-cpython/src/dirstate/copymap.rs Tue Sep 28 20:00:19 2021 +0200
+++ b/rust/hg-cpython/src/dirstate/copymap.rs Mon Sep 27 12:09:15 2021 +0200
@@ -15,9 +15,9 @@
use crate::dirstate::dirstate_map::v2_error;
use crate::dirstate::dirstate_map::DirstateMap;
+use hg::dirstate::CopyMapIter;
use hg::dirstate_tree::on_disk::DirstateV2ParseError;
use hg::utils::hg_path::HgPath;
-use hg::CopyMapIter;
py_class!(pub class CopyMap |py| {
data dirstate_map: DirstateMap;
--- a/rust/hg-cpython/src/dirstate/dirstate_map.rs Tue Sep 28 20:00:19 2021 +0200
+++ b/rust/hg-cpython/src/dirstate/dirstate_map.rs Mon Sep 27 12:09:15 2021 +0200
@@ -23,6 +23,7 @@
};
use hg::{
dirstate::parsers::Timestamp,
+ dirstate::StateMapIter,
dirstate_tree::dirstate_map::DirstateMap as TreeDirstateMap,
dirstate_tree::dispatch::DirstateMapMethods,
dirstate_tree::on_disk::DirstateV2ParseError,
@@ -30,8 +31,7 @@
revlog::Node,
utils::files::normalize_case,
utils::hg_path::{HgPath, HgPathBuf},
- DirstateEntry, DirstateError, DirstateMap as RustDirstateMap,
- DirstateParents, EntryState, StateMapIter,
+ DirstateEntry, DirstateError, DirstateParents, EntryState,
};
// TODO
@@ -52,25 +52,16 @@
/// Returns a `(dirstate_map, parents)` tuple
@staticmethod
def new_v1(
- use_dirstate_tree: bool,
on_disk: PyBytes,
) -> PyResult<PyObject> {
- let (inner, parents) = if use_dirstate_tree {
- 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 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)
- .map_err(|e| dirstate_error(py, e))?;
- *map_placeholder = actual_map;
- (Box::new(map) as _, parents)
- } else {
- let bytes = on_disk.data(py);
- let mut map = RustDirstateMap::default();
- let parents = map.read(bytes).map_err(|e| dirstate_error(py, e))?;
- (Box::new(map) as _, parents)
- };
- let map = Self::create_instance(py, inner)?;
+ let (actual_map, parents) = TreeDirstateMap::new_v1(on_disk)
+ .map_err(|e| dirstate_error(py, e))?;
+ *map_placeholder = actual_map;
+ let map = Self::create_instance(py, Box::new(map))?;
let parents = parents.map(|p| {
let p1 = PyBytes::new(py, p.p1.as_bytes());
let p2 = PyBytes::new(py, p.p2.as_bytes());
--- a/tests/test-dirstate-race.t Tue Sep 28 20:00:19 2021 +0200
+++ b/tests/test-dirstate-race.t Mon Sep 27 12:09:15 2021 +0200
@@ -1,10 +1,4 @@
-#testcases dirstate-v1 dirstate-v1-tree dirstate-v2
-
-#if dirstate-v1-tree
-#require rust
- $ echo '[experimental]' >> $HGRCPATH
- $ echo 'dirstate-tree.in-memory=1' >> $HGRCPATH
-#endif
+#testcases dirstate-v1 dirstate-v2
#if dirstate-v2
#require rust
--- a/tests/test-dirstate-race2.t Tue Sep 28 20:00:19 2021 +0200
+++ b/tests/test-dirstate-race2.t Mon Sep 27 12:09:15 2021 +0200
@@ -1,10 +1,4 @@
-#testcases dirstate-v1 dirstate-v1-tree dirstate-v2
-
-#if dirstate-v1-tree
-#require rust
- $ echo '[experimental]' >> $HGRCPATH
- $ echo 'dirstate-tree.in-memory=1' >> $HGRCPATH
-#endif
+#testcases dirstate-v1 dirstate-v2
#if dirstate-v2
#require rust
--- a/tests/test-dirstate.t Tue Sep 28 20:00:19 2021 +0200
+++ b/tests/test-dirstate.t Mon Sep 27 12:09:15 2021 +0200
@@ -1,10 +1,4 @@
-#testcases dirstate-v1 dirstate-v1-tree dirstate-v2
-
-#if dirstate-v1-tree
-#require rust
- $ echo '[experimental]' >> $HGRCPATH
- $ echo 'dirstate-tree.in-memory=1' >> $HGRCPATH
-#endif
+#testcases dirstate-v1 dirstate-v2
#if dirstate-v2
#require rust
--- a/tests/test-hgignore.t Tue Sep 28 20:00:19 2021 +0200
+++ b/tests/test-hgignore.t Mon Sep 27 12:09:15 2021 +0200
@@ -1,10 +1,4 @@
-#testcases dirstate-v1 dirstate-v1-tree dirstate-v2
-
-#if dirstate-v1-tree
-#require rust
- $ echo '[experimental]' >> $HGRCPATH
- $ echo 'dirstate-tree.in-memory=1' >> $HGRCPATH
-#endif
+#testcases dirstate-v1 dirstate-v2
#if dirstate-v2
#require rust
--- a/tests/test-permissions.t Tue Sep 28 20:00:19 2021 +0200
+++ b/tests/test-permissions.t Mon Sep 27 12:09:15 2021 +0200
@@ -1,12 +1,6 @@
#require unix-permissions no-root reporevlogstore
-#testcases dirstate-v1 dirstate-v1-tree dirstate-v2
-
-#if dirstate-v1-tree
-#require rust
- $ echo '[experimental]' >> $HGRCPATH
- $ echo 'dirstate-tree.in-memory=1' >> $HGRCPATH
-#endif
+#testcases dirstate-v1 dirstate-v2
#if dirstate-v2
#require rust
--- a/tests/test-purge.t Tue Sep 28 20:00:19 2021 +0200
+++ b/tests/test-purge.t Mon Sep 27 12:09:15 2021 +0200
@@ -1,10 +1,4 @@
-#testcases dirstate-v1 dirstate-v1-tree dirstate-v2
-
-#if dirstate-v1-tree
-#require rust
- $ echo '[experimental]' >> $HGRCPATH
- $ echo 'dirstate-tree.in-memory=1' >> $HGRCPATH
-#endif
+#testcases dirstate-v1 dirstate-v2
#if dirstate-v2
#require rust
--- a/tests/test-status.t Tue Sep 28 20:00:19 2021 +0200
+++ b/tests/test-status.t Mon Sep 27 12:09:15 2021 +0200
@@ -1,4 +1,4 @@
-#testcases dirstate-v1 dirstate-v1-tree dirstate-v2
+#testcases dirstate-v1 dirstate-v2
#if no-rust
$ hg init repo0 --config format.exp-dirstate-v2=1
@@ -6,12 +6,6 @@
[255]
#endif
-#if dirstate-v1-tree
-#require rust
- $ echo '[experimental]' >> $HGRCPATH
- $ echo 'dirstate-tree.in-memory=1' >> $HGRCPATH
-#endif
-
#if dirstate-v2
#require rust
$ echo '[format]' >> $HGRCPATH
--- a/tests/test-symlinks.t Tue Sep 28 20:00:19 2021 +0200
+++ b/tests/test-symlinks.t Mon Sep 27 12:09:15 2021 +0200
@@ -1,12 +1,6 @@
#require symlink
-#testcases dirstate-v1 dirstate-v1-tree dirstate-v2
-
-#if dirstate-v1-tree
-#require rust
- $ echo '[experimental]' >> $HGRCPATH
- $ echo 'dirstate-tree.in-memory=1' >> $HGRCPATH
-#endif
+#testcases dirstate-v1 dirstate-v2
#if dirstate-v2
#require rust