##// END OF EJS Templates
wix: tell ComponentSearch that it is finding a directory (not a file)...
wix: tell ComponentSearch that it is finding a directory (not a file) This is to fix an issue we've noticed where fresh installations start at `C:\Program Files\Mercurial`, and then upgrades "walk up" the tree and end up in `C:\Program Files` and finally `C:\` (where they stay). ComponentSearch defaults to finding files, which I think means "it produces a string like `C:\Program Files\Mercurial`", whereas with the type being explicitly a directory, it would return `C:\Program Files\Mercurial\` (note the final trailing backslash). Presumably, a latter step then tries to turn that file name into a proper directory, by removing everything after the last `\`. This could likely also be fixed by actually searching for the component for hg.exe itself. That seemed a lot more complicated, as the GUID for hg.exe isn't known in this file (it's one of the "auto-derived" ones). We could also consider adding a Condition that I think could check the Property and ensure it's either empty or ends in a trailing slash, but that would be an installer runtime check and I'm not convinced it'd actually be useful. This will *not* cause existing installations that are in one of the bad directories to fix themselves. Doing that would require a fair amount more understanding of wix and windows installer than I have, and it *probably* wouldn't be possible to be 100% correct about it either (there's nothing preventing a user from intentionally installing it in C:\, though I don't know why they would do so). If someone wants to tackle fixing existing installations, I think that the first installation is actually the only one that shows up in "Add or Remove Programs", and that its registry keys still exist. You might be able to find something under HKEY_USERS that lists both the "good" and the "bad" InstallDirs. Mine was under `HKEY_USERS\S-1-5-18\Software\Mercurial\InstallDir` (C:\), and `HKEY_USERS\S-1-5-21-..numbers..\Software\Mercurial\InstallDir` (C:\Program Files\Mercurial). If you find exactly two, with one being the default path, and the other being a prefix of it, the user almost certainly hit this bug :D We had originally thought that this bug might be due to unattended installations/upgrades, but I no longer think that's the case. We were able to reproduce the issue by uninstalling all copies of Mercurial I could find, installing one version (it chose the correct location), and then starting the installer for a different version (higher or lower didn't matter). I did not need to deal with an unattended or headless installation/upgrade to trigger the issue, but it's possible that my system was "primed" for this bug to happen because of a previous unattended installation/upgrade. Differential Revision: https://phab.mercurial-scm.org/D9891

File last commit:

r46844:5bae4bc9 default
r47159:8deab876 stable
Show More
dirstate_map.rs
546 lines | 16.4 KiB | application/rls-services+xml | RustLexer
Raphaël Gomès
rust-dirstate: rust implementation of dirstatemap...
r42998 // 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.
Antoine Cezar
hg-core: check data integrity in `Revlog`...
r46102 use crate::revlog::node::NULL_NODE_ID;
Raphaël Gomès
rust-dirstate: rust implementation of dirstatemap...
r42998 use crate::{
Raphaël Gomès
rust: introduce SIZE_FROM_OTHER_PARENT constant...
r44003 dirstate::{parsers::PARENT_SIZE, EntryState, SIZE_FROM_OTHER_PARENT},
Raphaël Gomès
rust-utils: add normalize_case util to mirror Python one...
r43108 pack_dirstate, parse_dirstate,
Raphaël Gomès
rust: introduce SIZE_FROM_OTHER_PARENT constant...
r44003 utils::{
files::normalize_case,
hg_path::{HgPath, HgPathBuf},
},
Raphaël Gomès
rust: format with rustfmt...
r46162 CopyMap, DirsMultiset, DirstateEntry, DirstateError, DirstateMapError,
DirstateParents, DirstateParseError, FastHashMap, StateMap,
Raphaël Gomès
rust-dirstate: rust implementation of dirstatemap...
r42998 };
Raphaël Gomès
rust-dirstatemap: add #[timed] to dirstatemap read for comparison...
r46135 use micro_timer::timed;
Raphaël Gomès
rust-performance: introduce FastHashMap type alias for HashMap...
r44278 use std::collections::HashSet;
Yuya Nishihara
rust: simply use TryInto to convert slice to array...
r43067 use std::convert::TryInto;
Raphaël Gomès
rust-dirstate: rust implementation of dirstatemap...
r42998 use std::iter::FromIterator;
use std::ops::Deref;
use std::time::Duration;
Raphaël Gomès
rust-performance: introduce FastHashMap type alias for HashMap...
r44278 pub type FileFoldMap = FastHashMap<HgPathBuf, HgPathBuf>;
Raphaël Gomès
rust-dirstate: rust implementation of dirstatemap...
r42998
const MTIME_UNSET: i32 = -1;
#[derive(Default)]
pub struct DirstateMap {
state_map: StateMap,
pub copy_map: CopyMap,
file_fold_map: Option<FileFoldMap>,
pub dirs: Option<DirsMultiset>,
pub all_dirs: Option<DirsMultiset>,
Raphaël Gomès
rust-dirstatemap: cache non normal and other parent set...
r44775 non_normal_set: Option<HashSet<HgPathBuf>>,
other_parent_set: Option<HashSet<HgPathBuf>>,
Raphaël Gomès
rust-dirstate: rust implementation of dirstatemap...
r42998 parents: Option<DirstateParents>,
dirty_parents: bool,
}
/// 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
}
}
Raphaël Gomès
rust-hgpath: replace all paths and filenames with HgPath/HgPathBuf...
r43227 impl FromIterator<(HgPathBuf, DirstateEntry)> for DirstateMap {
Raphaël Gomès
rust: format with rustfmt...
r46162 fn from_iter<I: IntoIterator<Item = (HgPathBuf, DirstateEntry)>>(
iter: I,
) -> Self {
Raphaël Gomès
rust-dirstate: rust implementation of dirstatemap...
r42998 Self {
state_map: iter.into_iter().collect(),
..Self::default()
}
}
}
impl DirstateMap {
pub fn new() -> Self {
Self::default()
}
pub fn clear(&mut self) {
Raphaël Gomès
rust: start plugging the dirstate tree behind a feature gate...
r46185 self.state_map = StateMap::default();
Raphaël Gomès
rust-dirstate: rust implementation of dirstatemap...
r42998 self.copy_map.clear();
self.file_fold_map = None;
Raphaël Gomès
rust-dirstatemap: cache non normal and other parent set...
r44775 self.non_normal_set = None;
self.other_parent_set = None;
Yuya Nishihara
rust-dirstate: remove excessive clone() of parameter and return value...
r43069 self.set_parents(&DirstateParents {
Antoine Cezar
hg-core: check data integrity in `Revlog`...
r46102 p1: NULL_NODE_ID,
p2: NULL_NODE_ID,
Raphaël Gomès
rust-dirstate: rust implementation of dirstatemap...
r42998 })
}
/// Add a tracked file to the dirstate
pub fn add_file(
&mut self,
Raphaël Gomès
rust-hgpath: replace all paths and filenames with HgPath/HgPathBuf...
r43227 filename: &HgPath,
Raphaël Gomès
rust-dirstate: rust implementation of dirstatemap...
r42998 old_state: EntryState,
entry: DirstateEntry,
Raphaël Gomès
rust-dirs: address failing tests for `dirs` impl with a temporary fix...
r44227 ) -> Result<(), DirstateMapError> {
Raphaël Gomès
rust: format with rustfmt...
r46162 if old_state == EntryState::Unknown || old_state == EntryState::Removed
{
Raphaël Gomès
rust-dirstate: rust implementation of dirstatemap...
r42998 if let Some(ref mut dirs) = self.dirs {
Raphaël Gomès
rust-dirs: address failing tests for `dirs` impl with a temporary fix...
r44227 dirs.add_path(filename)?;
Raphaël Gomès
rust-dirstate: rust implementation of dirstatemap...
r42998 }
}
if old_state == EntryState::Unknown {
if let Some(ref mut all_dirs) = self.all_dirs {
Raphaël Gomès
rust-dirs: address failing tests for `dirs` impl with a temporary fix...
r44227 all_dirs.add_path(filename)?;
Raphaël Gomès
rust-dirstate: rust implementation of dirstatemap...
r42998 }
}
self.state_map.insert(filename.to_owned(), entry.to_owned());
if entry.state != EntryState::Normal || entry.mtime == MTIME_UNSET {
Raphaël Gomès
rust-dirstatemap: cache non normal and other parent set...
r44775 self.get_non_normal_other_parent_entries()
.0
.insert(filename.to_owned());
Raphaël Gomès
rust-dirstate: rust implementation of dirstatemap...
r42998 }
Raphaël Gomès
rust: introduce SIZE_FROM_OTHER_PARENT constant...
r44003 if entry.size == SIZE_FROM_OTHER_PARENT {
Raphaël Gomès
rust-dirstatemap: cache non normal and other parent set...
r44775 self.get_non_normal_other_parent_entries()
.1
.insert(filename.to_owned());
Raphaël Gomès
rust-dirstate: rust implementation of dirstatemap...
r42998 }
Raphaël Gomès
rust-dirs: address failing tests for `dirs` impl with a temporary fix...
r44227 Ok(())
Raphaël Gomès
rust-dirstate: rust implementation of dirstatemap...
r42998 }
/// 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,
Raphaël Gomès
rust-hgpath: replace all paths and filenames with HgPath/HgPathBuf...
r43227 filename: &HgPath,
Raphaël Gomès
rust-dirstate: rust implementation of dirstatemap...
r42998 old_state: EntryState,
size: i32,
) -> Result<(), DirstateMapError> {
Raphaël Gomès
rust: format with rustfmt...
r46162 if old_state != EntryState::Unknown && old_state != EntryState::Removed
{
Raphaël Gomès
rust-dirstate: rust implementation of dirstatemap...
r42998 if let Some(ref mut dirs) = self.dirs {
dirs.delete_path(filename)?;
}
}
if old_state == EntryState::Unknown {
if let Some(ref mut all_dirs) = self.all_dirs {
Raphaël Gomès
rust-dirs: handle forgotten `Result`s...
r44315 all_dirs.add_path(filename)?;
Raphaël Gomès
rust-dirstate: rust implementation of dirstatemap...
r42998 }
}
if let Some(ref mut file_fold_map) = self.file_fold_map {
Raphaël Gomès
rust-utils: add normalize_case util to mirror Python one...
r43108 file_fold_map.remove(&normalize_case(filename));
Raphaël Gomès
rust-dirstate: rust implementation of dirstatemap...
r42998 }
self.state_map.insert(
filename.to_owned(),
DirstateEntry {
state: EntryState::Removed,
mode: 0,
size,
mtime: 0,
},
);
Raphaël Gomès
rust-dirstatemap: cache non normal and other parent set...
r44775 self.get_non_normal_other_parent_entries()
.0
.insert(filename.to_owned());
Raphaël Gomès
rust-dirstate: rust implementation of dirstatemap...
r42998 Ok(())
}
/// Remove a file from the dirstate.
/// Returns `true` if the file was previously recorded.
pub fn drop_file(
&mut self,
Raphaël Gomès
rust-hgpath: replace all paths and filenames with HgPath/HgPathBuf...
r43227 filename: &HgPath,
Raphaël Gomès
rust-dirstate: rust implementation of dirstatemap...
r42998 old_state: EntryState,
) -> Result<bool, DirstateMapError> {
Yuya Nishihara
rust-dirstate: remove too abstracted way of getting &[u8]
r43063 let exists = self.state_map.remove(filename).is_some();
Raphaël Gomès
rust-dirstate: rust implementation of dirstatemap...
r42998
if exists {
if old_state != 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)?;
}
}
if let Some(ref mut file_fold_map) = self.file_fold_map {
Raphaël Gomès
rust-utils: add normalize_case util to mirror Python one...
r43108 file_fold_map.remove(&normalize_case(filename));
Raphaël Gomès
rust-dirstate: rust implementation of dirstatemap...
r42998 }
Raphaël Gomès
rust-dirstatemap: cache non normal and other parent set...
r44775 self.get_non_normal_other_parent_entries()
.0
.remove(filename);
Raphaël Gomès
rust-dirstate: rust implementation of dirstatemap...
r42998
Ok(exists)
}
Raphaël Gomès
rust: format with rustfmt...
r46162 pub fn clear_ambiguous_times(
&mut self,
filenames: Vec<HgPathBuf>,
now: i32,
) {
Raphaël Gomès
rust-dirstate: rust implementation of dirstatemap...
r42998 for filename in filenames {
let mut changed = false;
Raphaël Gomès
rust: start plugging the dirstate tree behind a feature gate...
r46185 if let Some(entry) = self.state_map.get_mut(&filename) {
if entry.state == EntryState::Normal && entry.mtime == now {
changed = true;
*entry = DirstateEntry {
mtime: MTIME_UNSET,
..*entry
};
}
}
Raphaël Gomès
rust-dirstate: rust implementation of dirstatemap...
r42998 if changed {
Raphaël Gomès
rust-dirstatemap: cache non normal and other parent set...
r44775 self.get_non_normal_other_parent_entries()
.0
.insert(filename.to_owned());
Raphaël Gomès
rust-dirstate: rust implementation of dirstatemap...
r42998 }
}
}
Raphaël Gomès
rust: format with rustfmt...
r46162 pub fn non_normal_entries_remove(
&mut self,
key: impl AsRef<HgPath>,
) -> bool {
Raphaël Gomès
rust-dirstatemap: cache non normal and other parent set...
r44775 self.get_non_normal_other_parent_entries()
.0
.remove(key.as_ref())
}
Raphaël Gomès
rust: format with rustfmt...
r46162 pub fn non_normal_entries_union(
&mut self,
other: HashSet<HgPathBuf>,
) -> Vec<HgPathBuf> {
Raphaël Gomès
rust-dirstatemap: cache non normal and other parent set...
r44775 self.get_non_normal_other_parent_entries()
.0
.union(&other)
Raphaël Gomès
rust: do a clippy pass...
r45500 .map(ToOwned::to_owned)
Raphaël Gomès
rust-dirstatemap: cache non normal and other parent set...
r44775 .collect()
}
pub fn get_non_normal_other_parent_entries(
&mut self,
Raphaël Gomès
rust-dirstatemap: directly return `non_normal` and `other_entries`...
r44842 ) -> (&mut HashSet<HgPathBuf>, &mut HashSet<HgPathBuf>) {
Raphaël Gomès
rust-dirstatemap: cache non normal and other parent set...
r44775 self.set_non_normal_other_parent_entries(false);
Raphaël Gomès
rust-dirstatemap: directly return `non_normal` and `other_entries`...
r44842 (
self.non_normal_set.as_mut().unwrap(),
self.other_parent_set.as_mut().unwrap(),
)
Raphaël Gomès
rust-dirstatemap: cache non normal and other parent set...
r44775 }
Raphaël Gomès
rust-cpython: make `NonNormalEntires` iterable to fix `fsmonitor` (issue6276)...
r44903 /// Useful to get immutable references to those sets in contexts where
/// you only have an immutable reference to the `DirstateMap`, like when
/// sharing references with Python.
///
/// TODO, get rid of this along with the other "setter/getter" stuff when
/// a nice typestate plan is defined.
///
/// # Panics
///
/// Will panic if either set is `None`.
pub fn get_non_normal_other_parent_entries_panic(
&self,
) -> (&HashSet<HgPathBuf>, &HashSet<HgPathBuf>) {
(
self.non_normal_set.as_ref().unwrap(),
self.other_parent_set.as_ref().unwrap(),
)
}
Raphaël Gomès
rust: start plugging the dirstate tree behind a feature gate...
r46185 #[cfg(not(feature = "dirstate-tree"))]
Raphaël Gomès
rust-dirstatemap: cache non normal and other parent set...
r44775 pub fn set_non_normal_other_parent_entries(&mut self, force: bool) {
Raphaël Gomès
rust: format with rustfmt...
r46162 if !force
&& self.non_normal_set.is_some()
&& self.other_parent_set.is_some()
{
Raphaël Gomès
rust-dirstatemap: cache non normal and other parent set...
r44775 return;
}
Raphaël Gomès
rust-dirstate: rust implementation of dirstatemap...
r42998 let mut non_normal = HashSet::new();
let mut other_parent = HashSet::new();
for (
filename,
DirstateEntry {
state, size, mtime, ..
},
) in self.state_map.iter()
{
if *state != EntryState::Normal || *mtime == MTIME_UNSET {
non_normal.insert(filename.to_owned());
}
Raphaël Gomès
rust: format with rustfmt...
r46162 if *state == EntryState::Normal && *size == SIZE_FROM_OTHER_PARENT
{
Raphaël Gomès
rust-dirstate: rust implementation of dirstatemap...
r42998 other_parent.insert(filename.to_owned());
}
}
Raphaël Gomès
rust-dirstatemap: cache non normal and other parent set...
r44775 self.non_normal_set = Some(non_normal);
self.other_parent_set = Some(other_parent);
Raphaël Gomès
rust-dirstate: rust implementation of dirstatemap...
r42998 }
Raphaël Gomès
rust: start plugging the dirstate tree behind a feature gate...
r46185 #[cfg(feature = "dirstate-tree")]
pub fn set_non_normal_other_parent_entries(&mut self, force: bool) {
if !force
&& self.non_normal_set.is_some()
&& self.other_parent_set.is_some()
{
return;
}
let mut non_normal = HashSet::new();
let mut other_parent = HashSet::new();
for (
filename,
DirstateEntry {
state, size, mtime, ..
},
) in self.state_map.iter()
{
if state != EntryState::Normal || mtime == MTIME_UNSET {
non_normal.insert(filename.to_owned());
}
if state == EntryState::Normal && size == SIZE_FROM_OTHER_PARENT {
other_parent.insert(filename.to_owned());
}
}
self.non_normal_set = Some(non_normal);
self.other_parent_set = Some(other_parent);
}
Raphaël Gomès
rust-dirstate: rust implementation of dirstatemap...
r42998
/// 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.
Raphaël Gomès
rust-dirs: handle forgotten `Result`s...
r44315 pub fn set_all_dirs(&mut self) -> Result<(), DirstateMapError> {
Raphaël Gomès
rust-dirstate: rust implementation of dirstatemap...
r42998 if self.all_dirs.is_none() {
Raphaël Gomès
rust: format with rustfmt...
r46162 self.all_dirs =
Some(DirsMultiset::from_dirstate(&self.state_map, None)?);
Raphaël Gomès
rust-dirstate: rust implementation of dirstatemap...
r42998 }
Raphaël Gomès
rust-dirs: handle forgotten `Result`s...
r44315 Ok(())
Raphaël Gomès
rust-dirstate: rust implementation of dirstatemap...
r42998 }
Raphaël Gomès
rust-dirs: handle forgotten `Result`s...
r44315 pub fn set_dirs(&mut self) -> Result<(), DirstateMapError> {
Raphaël Gomès
rust-dirstate: rust implementation of dirstatemap...
r42998 if self.dirs.is_none() {
Yuya Nishihara
rust-dirstate: split DirsMultiset constructor per input type...
r43070 self.dirs = Some(DirsMultiset::from_dirstate(
&self.state_map,
Raphaël Gomès
rust-dirstate: rust implementation of dirstatemap...
r42998 Some(EntryState::Removed),
Raphaël Gomès
rust-dirs: handle forgotten `Result`s...
r44315 )?);
Raphaël Gomès
rust-dirstate: rust implementation of dirstatemap...
r42998 }
Raphaël Gomès
rust-dirs: handle forgotten `Result`s...
r44315 Ok(())
Raphaël Gomès
rust-dirstate: rust implementation of dirstatemap...
r42998 }
Raphaël Gomès
rust: format with rustfmt...
r46162 pub fn has_tracked_dir(
&mut self,
directory: &HgPath,
) -> Result<bool, DirstateMapError> {
Raphaël Gomès
rust-dirs: handle forgotten `Result`s...
r44315 self.set_dirs()?;
Ok(self.dirs.as_ref().unwrap().contains(directory))
Raphaël Gomès
rust-dirstate: rust implementation of dirstatemap...
r42998 }
Raphaël Gomès
rust: format with rustfmt...
r46162 pub fn has_dir(
&mut self,
directory: &HgPath,
) -> Result<bool, DirstateMapError> {
Raphaël Gomès
rust-dirs: handle forgotten `Result`s...
r44315 self.set_all_dirs()?;
Ok(self.all_dirs.as_ref().unwrap().contains(directory))
Raphaël Gomès
rust-dirstate: rust implementation of dirstatemap...
r42998 }
Raphaël Gomès
rust: format with rustfmt...
r46162 pub fn parents(
&mut self,
file_contents: &[u8],
) -> Result<&DirstateParents, DirstateError> {
Raphaël Gomès
rust-dirstate: rust implementation of dirstatemap...
r42998 if let Some(ref parents) = self.parents {
Yuya Nishihara
rust-dirstate: remove excessive clone() of parameter and return value...
r43069 return Ok(parents);
Raphaël Gomès
rust-dirstate: rust implementation of dirstatemap...
r42998 }
let parents;
Yuya Nishihara
rust-dirstate: use PARENT_SIZE constant where appropriate
r43066 if file_contents.len() == PARENT_SIZE * 2 {
Raphaël Gomès
rust-dirstate: rust implementation of dirstatemap...
r42998 parents = DirstateParents {
Yuya Nishihara
rust: simply use TryInto to convert slice to array...
r43067 p1: file_contents[..PARENT_SIZE].try_into().unwrap(),
p2: file_contents[PARENT_SIZE..PARENT_SIZE * 2]
.try_into()
.unwrap(),
Raphaël Gomès
rust-dirstate: rust implementation of dirstatemap...
r42998 };
} else if file_contents.is_empty() {
parents = DirstateParents {
Antoine Cezar
hg-core: check data integrity in `Revlog`...
r46102 p1: NULL_NODE_ID,
p2: NULL_NODE_ID,
Raphaël Gomès
rust-dirstate: rust implementation of dirstatemap...
r42998 };
} else {
return Err(DirstateError::Parse(DirstateParseError::Damaged));
}
Yuya Nishihara
rust-dirstate: remove excessive clone() of parameter and return value...
r43069 self.parents = Some(parents);
Ok(self.parents.as_ref().unwrap())
Raphaël Gomès
rust-dirstate: rust implementation of dirstatemap...
r42998 }
Yuya Nishihara
rust-dirstate: remove excessive clone() of parameter and return value...
r43069 pub fn set_parents(&mut self, parents: &DirstateParents) {
Raphaël Gomès
rust-dirstate: rust implementation of dirstatemap...
r42998 self.parents = Some(parents.clone());
self.dirty_parents = true;
}
Raphaël Gomès
rust-dirstatemap: add #[timed] to dirstatemap read for comparison...
r46135 #[timed]
Raphaël Gomès
rust: format with rustfmt...
r46162 pub fn read(
&mut self,
file_contents: &[u8],
) -> Result<Option<DirstateParents>, DirstateError> {
Raphaël Gomès
rust-dirstate: rust implementation of dirstatemap...
r42998 if file_contents.is_empty() {
return Ok(None);
}
Antoine Cezar
hg-core: make parse_dirstate return references rather than update hashmaps...
r45916 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())),
);
Raphaël Gomès
rust-dirstate: rust implementation of dirstatemap...
r42998
if !self.dirty_parents {
Yuya Nishihara
rust-dirstate: remove excessive clone() of parameter and return value...
r43069 self.set_parents(&parents);
Raphaël Gomès
rust-dirstate: rust implementation of dirstatemap...
r42998 }
Ok(Some(parents))
}
pub fn pack(
&mut self,
parents: DirstateParents,
now: Duration,
) -> Result<Vec<u8>, DirstateError> {
Raphaël Gomès
rust: format with rustfmt...
r46162 let packed =
pack_dirstate(&mut self.state_map, &self.copy_map, parents, now)?;
Raphaël Gomès
rust-dirstate: rust implementation of dirstatemap...
r42998
self.dirty_parents = false;
Raphaël Gomès
rust-dirstatemap: cache non normal and other parent set...
r44775 self.set_non_normal_other_parent_entries(true);
Raphaël Gomès
rust-dirstate: rust implementation of dirstatemap...
r42998 Ok(packed)
}
Raphaël Gomès
rust: start plugging the dirstate tree behind a feature gate...
r46185 #[cfg(not(feature = "dirstate-tree"))]
Yuya Nishihara
rust-dirstate: remove excessive clone() of parameter and return value...
r43069 pub fn build_file_fold_map(&mut self) -> &FileFoldMap {
Raphaël Gomès
rust-dirstate: rust implementation of dirstatemap...
r42998 if let Some(ref file_fold_map) = self.file_fold_map {
Yuya Nishihara
rust-dirstate: remove excessive clone() of parameter and return value...
r43069 return file_fold_map;
Raphaël Gomès
rust-dirstate: rust implementation of dirstatemap...
r42998 }
Raphaël Gomès
rust-performance: introduce FastHashMap type alias for HashMap...
r44278 let mut new_file_fold_map = FileFoldMap::default();
Raphaël Gomès
rust: start plugging the dirstate tree behind a feature gate...
r46185
for (filename, DirstateEntry { state, .. }) in self.state_map.iter() {
Dan Villiom Podlaski Christiansen
rust: fix file folding map...
r46844 if *state != EntryState::Removed {
Raphaël Gomès
rust: format with rustfmt...
r46162 new_file_fold_map
Raphaël Gomès
rust: start plugging the dirstate tree behind a feature gate...
r46185 .insert(normalize_case(&filename), filename.to_owned());
}
}
self.file_fold_map = Some(new_file_fold_map);
self.file_fold_map.as_ref().unwrap()
}
#[cfg(feature = "dirstate-tree")]
pub fn build_file_fold_map(&mut self) -> &FileFoldMap {
if let Some(ref file_fold_map) = self.file_fold_map {
return file_fold_map;
}
let mut new_file_fold_map = FileFoldMap::default();
for (filename, DirstateEntry { state, .. }) in self.state_map.iter() {
Dan Villiom Podlaski Christiansen
rust: fix file folding map...
r46844 if state != EntryState::Removed {
Raphaël Gomès
rust: start plugging the dirstate tree behind a feature gate...
r46185 new_file_fold_map
.insert(normalize_case(&filename), filename.to_owned());
Raphaël Gomès
rust-dirstate: rust implementation of dirstatemap...
r42998 }
}
self.file_fold_map = Some(new_file_fold_map);
Yuya Nishihara
rust-dirstate: remove excessive clone() of parameter and return value...
r43069 self.file_fold_map.as_ref().unwrap()
Raphaël Gomès
rust-dirstate: rust implementation of dirstatemap...
r42998 }
}
#[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());
Raphaël Gomès
rust-dirs: handle forgotten `Result`s...
r44315 assert_eq!(map.has_dir(HgPath::new(b"nope")).unwrap(), false);
Raphaël Gomès
rust-dirstate: rust implementation of dirstatemap...
r42998 assert!(map.all_dirs.is_some());
assert!(map.dirs.is_none());
Raphaël Gomès
rust-dirs: handle forgotten `Result`s...
r44315 assert_eq!(map.has_tracked_dir(HgPath::new(b"nope")).unwrap(), false);
Raphaël Gomès
rust-dirstate: rust implementation of dirstatemap...
r42998 assert!(map.dirs.is_some());
}
#[test]
fn test_add_file() {
let mut map = DirstateMap::new();
assert_eq!(0, map.len());
map.add_file(
Raphaël Gomès
rust-hgpath: replace all paths and filenames with HgPath/HgPathBuf...
r43227 HgPath::new(b"meh"),
Raphaël Gomès
rust-dirstate: rust implementation of dirstatemap...
r42998 EntryState::Normal,
DirstateEntry {
state: EntryState::Normal,
mode: 1337,
mtime: 1337,
size: 1337,
},
Raphaël Gomès
rust-warnings: fix warnings in tests...
r44342 )
.unwrap();
Raphaël Gomès
rust-dirstate: rust implementation of dirstatemap...
r42998
assert_eq!(1, map.len());
Raphaël Gomès
rust-dirstatemap: directly return `non_normal` and `other_entries`...
r44842 assert_eq!(0, map.get_non_normal_other_parent_entries().0.len());
assert_eq!(0, map.get_non_normal_other_parent_entries().1.len());
Raphaël Gomès
rust-dirstate: rust implementation of dirstatemap...
r42998 }
#[test]
fn test_non_normal_other_parent_entries() {
Raphaël Gomès
rust-dirstatemap: cache non normal and other parent set...
r44775 let mut map: DirstateMap = [
Raphaël Gomès
rust-dirstate: rust implementation of dirstatemap...
r42998 (b"f1", (EntryState::Removed, 1337, 1337, 1337)),
(b"f2", (EntryState::Normal, 1337, 1337, -1)),
(b"f3", (EntryState::Normal, 1337, 1337, 1337)),
(b"f4", (EntryState::Normal, 1337, -2, 1337)),
(b"f5", (EntryState::Added, 1337, 1337, 1337)),
(b"f6", (EntryState::Added, 1337, 1337, -1)),
(b"f7", (EntryState::Merged, 1337, 1337, -1)),
(b"f8", (EntryState::Merged, 1337, 1337, 1337)),
(b"f9", (EntryState::Merged, 1337, -2, 1337)),
(b"fa", (EntryState::Added, 1337, -2, 1337)),
(b"fb", (EntryState::Removed, 1337, -2, 1337)),
]
.iter()
.map(|(fname, (state, mode, size, mtime))| {
(
Raphaël Gomès
rust-hgpath: replace all paths and filenames with HgPath/HgPathBuf...
r43227 HgPathBuf::from_bytes(fname.as_ref()),
Raphaël Gomès
rust-dirstate: rust implementation of dirstatemap...
r42998 DirstateEntry {
state: *state,
mode: *mode,
size: *size,
mtime: *mtime,
},
)
})
.collect();
Raphaël Gomès
rust-dirstatemap: directly return `non_normal` and `other_entries`...
r44842 let mut non_normal = [
Raphaël Gomès
rust-dirstate: rust implementation of dirstatemap...
r42998 b"f1", b"f2", b"f5", b"f6", b"f7", b"f8", b"f9", b"fa", b"fb",
]
.iter()
Raphaël Gomès
rust-hgpath: replace all paths and filenames with HgPath/HgPathBuf...
r43227 .map(|x| HgPathBuf::from_bytes(x.as_ref()))
Raphaël Gomès
rust-dirstate: rust implementation of dirstatemap...
r42998 .collect();
let mut other_parent = HashSet::new();
Raphaël Gomès
rust-hgpath: replace all paths and filenames with HgPath/HgPathBuf...
r43227 other_parent.insert(HgPathBuf::from_bytes(b"f4"));
Raphaël Gomès
rust-dirstatemap: cache non normal and other parent set...
r44775 let entries = map.get_non_normal_other_parent_entries();
Raphaël Gomès
rust-dirstate: rust implementation of dirstatemap...
r42998
Raphaël Gomès
rust: format with rustfmt...
r46162 assert_eq!(
(&mut non_normal, &mut other_parent),
(entries.0, entries.1)
);
Raphaël Gomès
rust-dirstate: rust implementation of dirstatemap...
r42998 }
}