D7923: rust-matchers: add functions to get roots, dirs and parents from patterns
Alphare created this revision. Herald added subscribers: mercurial-devel, kevincox, durin42. Herald added a reviewer: hg-reviewers. REVISION SUMMARY These functions will be used to help build the upcoming `IncludeMatcher`. REPOSITORY rHG Mercurial BRANCH default REVISION DETAIL https://phab.mercurial-scm.org/D7923 AFFECTED FILES rust/hg-core/src/matchers.rs CHANGE DETAILS diff --git a/rust/hg-core/src/matchers.rs b/rust/hg-core/src/matchers.rs --- a/rust/hg-core/src/matchers.rs +++ b/rust/hg-core/src/matchers.rs @@ -10,8 +10,10 @@ #[cfg(feature = "with-re2")] use crate::re2::Re2; use crate::{ -filepatterns::PatternResult, utils::hg_path::HgPath, DirsMultiset, -DirstateMapError, PatternError, +filepatterns::PatternResult, +utils::hg_path::{HgPath, HgPathBuf}, +DirsMultiset, DirstateMapError, IgnorePattern, PatternError, +PatternSyntax, }; use std::collections::HashSet; use std::iter::FromIterator; @@ -242,10 +244,147 @@ Err(PatternError::Re2NotInstalled) } +/// Returns roots and directories corresponding to each pattern. +/// +/// This calculates the roots and directories exactly matching the patterns and +/// returns a tuple of (roots, dirs) for each. It does not return other +/// directories which may also need to be considered, like the parent +/// directories. +fn roots_and_dirs( +ignore_patterns: &[IgnorePattern], +) -> (Vec, Vec) { +let mut roots = Vec::new(); +let mut dirs = Vec::new(); + +for ignore_pattern in ignore_patterns { +let IgnorePattern { +syntax, pattern, .. +} = ignore_pattern; +match syntax { +PatternSyntax::RootGlob | PatternSyntax::Glob => { +let mut root = vec![]; + +for p in pattern.split(|c| *c == b'/') { +if p.iter().any(|c| match *c { +b'[' | b'{' | b'*' | b'?' => true, +_ => false, +}) { +break; +} +root.push(HgPathBuf::from_bytes(p)); +} +let buf = +root.iter().fold(HgPathBuf::new(), |acc, r| acc.join(r)); +roots.push(buf); +} +PatternSyntax::Path | PatternSyntax::RelPath => { +let pat = HgPath::new(if pattern == b"." { +&[] as &[u8] +} else { +pattern +}); +roots.push(pat.to_owned()); +} +PatternSyntax::RootFiles => { +let pat = if pattern == b"." { +&[] as &[u8] +} else { +pattern +}; +dirs.push(HgPathBuf::from_bytes(pat)); +} +_ => { +roots.push(HgPathBuf::new()); +} +} +} +(roots, dirs) +} + +/// Returns roots and exact directories from patterns. +/// +/// `roots` are directories to match recursively, `dirs` should +/// be matched non-recursively, and `parents` are the implicitly required +/// directories to walk to items in either roots or dirs. +fn roots_dirs_and_parents( +ignore_patterns: &[IgnorePattern], +) -> PatternResult<(HashSet, HashSet, HashSet)> +{ +let (roots, dirs) = roots_and_dirs(ignore_patterns); + +let mut parents = HashSet::new(); + +parents.extend( +DirsMultiset::from_manifest(&dirs) +.map_err(|e| match e { +DirstateMapError::InvalidPath(e) => e, +_ => unreachable!(), +})? +.iter() +.map(|k| k.to_owned()), +); +parents.extend( +DirsMultiset::from_manifest(&roots) +.map_err(|e| match e { +DirstateMapError::InvalidPath(e) => e, +_ => unreachable!(), +})? +.iter() +.map(|k| k.to_owned()), +); + +Ok((HashSet::from_iter(roots), HashSet::from_iter(dirs), parents)) +} + #[cfg(test)] mod tests { use super::*; use pretty_assertions::assert_eq; +use std::path::Path; + +#[test] +fn test_roots_and_dirs() { +let pats = vec![ +IgnorePattern::new(PatternSyntax::Glob, b"g/h/*", Path::new("")), +IgnorePattern::new(PatternSyntax::Glob, b"g/h", Path::new("")), +IgnorePattern::new(PatternSyntax::Glob, b"g*", Path::new("")), +]; +let (roots, dirs) = roots_and_dirs(&pats); + +assert_eq!( +roots, +vec!( +HgPathBuf::from_bytes(b"g/h"), +HgPathBuf::from_bytes(b"g/h"), +HgPathBuf::new() +), +); +assert_eq!(dirs, vec!()); +} + +#[test] +fn test_roots_dirs_and_parents() { +let pats = vec![ +IgnorePattern::new(PatternSyntax::Glob, b"g/h/*", Path::new("")), +IgnoreP
D7923: rust-matchers: add functions to get roots, dirs and parents from patterns
This revision now requires changes to proceed. kevincox added inline comments. kevincox requested changes to this revision. INLINE COMMENTS > matchers.rs:250 > +/// This calculates the roots and directories exactly matching the patterns > and > +/// returns a tuple of (roots, dirs) for each. It does not return other > +/// directories which may also need to be considered, like the parent I'm confused by the "for each" since this only returns one tuple. > matchers.rs:311 > +ignore_patterns: &[IgnorePattern], > +) -> PatternResult<(HashSet, HashSet, > HashSet)> > +{ Please describe the return value. REPOSITORY rHG Mercurial CHANGES SINCE LAST ACTION https://phab.mercurial-scm.org/D7923/new/ REVISION DETAIL https://phab.mercurial-scm.org/D7923 To: Alphare, #hg-reviewers, kevincox Cc: durin42, kevincox, mercurial-devel ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
D7923: rust-matchers: add functions to get roots, dirs and parents from patterns
Alphare updated this revision to Diff 19418. REPOSITORY rHG Mercurial CHANGES SINCE LAST UPDATE https://phab.mercurial-scm.org/D7923?vs=19402&id=19418 BRANCH default CHANGES SINCE LAST ACTION https://phab.mercurial-scm.org/D7923/new/ REVISION DETAIL https://phab.mercurial-scm.org/D7923 AFFECTED FILES rust/hg-core/src/matchers.rs CHANGE DETAILS diff --git a/rust/hg-core/src/matchers.rs b/rust/hg-core/src/matchers.rs --- a/rust/hg-core/src/matchers.rs +++ b/rust/hg-core/src/matchers.rs @@ -10,8 +10,10 @@ #[cfg(feature = "with-re2")] use crate::re2::Re2; use crate::{ -filepatterns::PatternResult, utils::hg_path::HgPath, DirsMultiset, -DirstateMapError, PatternError, +filepatterns::PatternResult, +utils::hg_path::{HgPath, HgPathBuf}, +DirsMultiset, DirstateMapError, IgnorePattern, PatternError, +PatternSyntax, }; use std::collections::HashSet; use std::iter::FromIterator; @@ -242,10 +244,155 @@ Err(PatternError::Re2NotInstalled) } +/// Returns roots and directories corresponding to each pattern. +/// +/// This calculates the roots and directories exactly matching the patterns and +/// returns a tuple of (roots, dirs). It does not return other directories +/// which may also need to be considered, like the parent directories. +fn roots_and_dirs( +ignore_patterns: &[IgnorePattern], +) -> (Vec, Vec) { +let mut roots = Vec::new(); +let mut dirs = Vec::new(); + +for ignore_pattern in ignore_patterns { +let IgnorePattern { +syntax, pattern, .. +} = ignore_pattern; +match syntax { +PatternSyntax::RootGlob | PatternSyntax::Glob => { +let mut root = vec![]; + +for p in pattern.split(|c| *c == b'/') { +if p.iter().any(|c| match *c { +b'[' | b'{' | b'*' | b'?' => true, +_ => false, +}) { +break; +} +root.push(HgPathBuf::from_bytes(p)); +} +let buf = +root.iter().fold(HgPathBuf::new(), |acc, r| acc.join(r)); +roots.push(buf); +} +PatternSyntax::Path | PatternSyntax::RelPath => { +let pat = HgPath::new(if pattern == b"." { +&[] as &[u8] +} else { +pattern +}); +roots.push(pat.to_owned()); +} +PatternSyntax::RootFiles => { +let pat = if pattern == b"." { +&[] as &[u8] +} else { +pattern +}; +dirs.push(HgPathBuf::from_bytes(pat)); +} +_ => { +roots.push(HgPathBuf::new()); +} +} +} +(roots, dirs) +} + +/// Paths extracted from patterns +struct RootsDirsAndParents { +/// Directories to match recursively +pub roots: HashSet, +/// Directories to match non-recursively +pub dirs: HashSet, +/// Implicitly required directories to go to items in either roots or dirs +pub parents: HashSet, +} + +/// Extract roots, dirs and parents from patterns. +fn roots_dirs_and_parents( +ignore_patterns: &[IgnorePattern], +) -> PatternResult { +let (roots, dirs) = roots_and_dirs(ignore_patterns); + +let mut parents = HashSet::new(); + +parents.extend( +DirsMultiset::from_manifest(&dirs) +.map_err(|e| match e { +DirstateMapError::InvalidPath(e) => e, +_ => unreachable!(), +})? +.iter() +.map(|k| k.to_owned()), +); +parents.extend( +DirsMultiset::from_manifest(&roots) +.map_err(|e| match e { +DirstateMapError::InvalidPath(e) => e, +_ => unreachable!(), +})? +.iter() +.map(|k| k.to_owned()), +); + +Ok(RootsDirsAndParents { +roots: HashSet::from_iter(roots), +dirs: HashSet::from_iter(dirs), +parents, +}) +} + #[cfg(test)] mod tests { use super::*; use pretty_assertions::assert_eq; +use std::path::Path; + +#[test] +fn test_roots_and_dirs() { +let pats = vec![ +IgnorePattern::new(PatternSyntax::Glob, b"g/h/*", Path::new("")), +IgnorePattern::new(PatternSyntax::Glob, b"g/h", Path::new("")), +IgnorePattern::new(PatternSyntax::Glob, b"g*", Path::new("")), +]; +let (roots, dirs) = roots_and_dirs(&pats); + +assert_eq!( +roots, +vec!( +HgPathBuf::from_bytes(b"g/h"), +HgPathBuf::from_bytes(b"g/h"), +HgPathBuf::new() +), +); +assert_eq!(dirs, vec!()); +} + +#[test] +fn test_roots_dirs_and_parents() { +let pats = ve
D7923: rust-matchers: add functions to get roots, dirs and parents from patterns
Alphare updated this revision to Diff 19939. REPOSITORY rHG Mercurial CHANGES SINCE LAST UPDATE https://phab.mercurial-scm.org/D7923?vs=19418&id=19939 BRANCH default CHANGES SINCE LAST ACTION https://phab.mercurial-scm.org/D7923/new/ REVISION DETAIL https://phab.mercurial-scm.org/D7923 AFFECTED FILES rust/hg-core/src/matchers.rs CHANGE DETAILS diff --git a/rust/hg-core/src/matchers.rs b/rust/hg-core/src/matchers.rs --- a/rust/hg-core/src/matchers.rs +++ b/rust/hg-core/src/matchers.rs @@ -10,8 +10,10 @@ #[cfg(feature = "with-re2")] use crate::re2::Re2; use crate::{ -filepatterns::PatternResult, utils::hg_path::HgPath, DirsMultiset, -DirstateMapError, PatternError, +filepatterns::PatternResult, +utils::hg_path::{HgPath, HgPathBuf}, +DirsMultiset, DirstateMapError, IgnorePattern, PatternError, +PatternSyntax, }; use std::collections::HashSet; use std::iter::FromIterator; @@ -242,10 +244,156 @@ Err(PatternError::Re2NotInstalled) } +/// Returns roots and directories corresponding to each pattern. +/// +/// This calculates the roots and directories exactly matching the patterns and +/// returns a tuple of (roots, dirs). It does not return other directories +/// which may also need to be considered, like the parent directories. +fn roots_and_dirs( +ignore_patterns: &[IgnorePattern], +) -> (Vec, Vec) { +let mut roots = Vec::new(); +let mut dirs = Vec::new(); + +for ignore_pattern in ignore_patterns { +let IgnorePattern { +syntax, pattern, .. +} = ignore_pattern; +match syntax { +PatternSyntax::RootGlob | PatternSyntax::Glob => { +let mut root = vec![]; + +for p in pattern.split(|c| *c == b'/') { +if p.iter().any(|c| match *c { +b'[' | b'{' | b'*' | b'?' => true, +_ => false, +}) { +break; +} +root.push(HgPathBuf::from_bytes(p)); +} +let buf = +root.iter().fold(HgPathBuf::new(), |acc, r| acc.join(r)); +roots.push(buf); +} +PatternSyntax::Path | PatternSyntax::RelPath => { +let pat = HgPath::new(if pattern == b"." { +&[] as &[u8] +} else { +pattern +}); +roots.push(pat.to_owned()); +} +PatternSyntax::RootFiles => { +let pat = if pattern == b"." { +&[] as &[u8] +} else { +pattern +}; +dirs.push(HgPathBuf::from_bytes(pat)); +} +_ => { +roots.push(HgPathBuf::new()); +} +} +} +(roots, dirs) +} + +/// Paths extracted from patterns +#[derive(Debug, PartialEq)] +struct RootsDirsAndParents { +/// Directories to match recursively +pub roots: HashSet, +/// Directories to match non-recursively +pub dirs: HashSet, +/// Implicitly required directories to go to items in either roots or dirs +pub parents: HashSet, +} + +/// Extract roots, dirs and parents from patterns. +fn roots_dirs_and_parents( +ignore_patterns: &[IgnorePattern], +) -> PatternResult { +let (roots, dirs) = roots_and_dirs(ignore_patterns); + +let mut parents = HashSet::new(); + +parents.extend( +DirsMultiset::from_manifest(&dirs) +.map_err(|e| match e { +DirstateMapError::InvalidPath(e) => e, +_ => unreachable!(), +})? +.iter() +.map(|k| k.to_owned()), +); +parents.extend( +DirsMultiset::from_manifest(&roots) +.map_err(|e| match e { +DirstateMapError::InvalidPath(e) => e, +_ => unreachable!(), +})? +.iter() +.map(|k| k.to_owned()), +); + +Ok(RootsDirsAndParents { +roots: HashSet::from_iter(roots), +dirs: HashSet::from_iter(dirs), +parents, +}) +} + #[cfg(test)] mod tests { use super::*; use pretty_assertions::assert_eq; +use std::path::Path; + +#[test] +fn test_roots_and_dirs() { +let pats = vec![ +IgnorePattern::new(PatternSyntax::Glob, b"g/h/*", Path::new("")), +IgnorePattern::new(PatternSyntax::Glob, b"g/h", Path::new("")), +IgnorePattern::new(PatternSyntax::Glob, b"g*", Path::new("")), +]; +let (roots, dirs) = roots_and_dirs(&pats); + +assert_eq!( +roots, +vec!( +HgPathBuf::from_bytes(b"g/h"), +HgPathBuf::from_bytes(b"g/h"), +HgPathBuf::new() +), +); +assert_eq!(dirs, vec!()); +} + +#[test] +fn test_roots_dirs_and_paren
D7923: rust-matchers: add functions to get roots, dirs and parents from patterns
Alphare added a comment. @kevincox I am currently fighting a nasty rebase and will be re-sending a lot of these patches (in less than 30 minutes hopefully). Just so you don't have to re-check another time. :) REPOSITORY rHG Mercurial CHANGES SINCE LAST ACTION https://phab.mercurial-scm.org/D7923/new/ REVISION DETAIL https://phab.mercurial-scm.org/D7923 To: Alphare, #hg-reviewers, kevincox Cc: durin42, kevincox, mercurial-devel ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
D7923: rust-matchers: add functions to get roots, dirs and parents from patterns
kevincox added a comment. Thanks for the heads up. I'll try to dedup them. REPOSITORY rHG Mercurial CHANGES SINCE LAST ACTION https://phab.mercurial-scm.org/D7923/new/ REVISION DETAIL https://phab.mercurial-scm.org/D7923 To: Alphare, #hg-reviewers, kevincox Cc: durin42, kevincox, mercurial-devel ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
D7923: rust-matchers: add functions to get roots, dirs and parents from patterns
Alphare updated this revision to Diff 20161. REPOSITORY rHG Mercurial CHANGES SINCE LAST UPDATE https://phab.mercurial-scm.org/D7923?vs=19939&id=20161 BRANCH default CHANGES SINCE LAST ACTION https://phab.mercurial-scm.org/D7923/new/ REVISION DETAIL https://phab.mercurial-scm.org/D7923 AFFECTED FILES rust/hg-core/src/matchers.rs CHANGE DETAILS diff --git a/rust/hg-core/src/matchers.rs b/rust/hg-core/src/matchers.rs --- a/rust/hg-core/src/matchers.rs +++ b/rust/hg-core/src/matchers.rs @@ -10,8 +10,10 @@ #[cfg(feature = "with-re2")] use crate::re2::Re2; use crate::{ -filepatterns::PatternResult, utils::hg_path::HgPath, DirsMultiset, -DirstateMapError, PatternError, +filepatterns::PatternResult, +utils::hg_path::{HgPath, HgPathBuf}, +DirsMultiset, DirstateMapError, IgnorePattern, PatternError, +PatternSyntax, }; use std::collections::HashSet; use std::iter::FromIterator; @@ -240,10 +242,156 @@ Err(PatternError::Re2NotInstalled) } +/// Returns roots and directories corresponding to each pattern. +/// +/// This calculates the roots and directories exactly matching the patterns and +/// returns a tuple of (roots, dirs). It does not return other directories +/// which may also need to be considered, like the parent directories. +fn roots_and_dirs( +ignore_patterns: &[IgnorePattern], +) -> (Vec, Vec) { +let mut roots = Vec::new(); +let mut dirs = Vec::new(); + +for ignore_pattern in ignore_patterns { +let IgnorePattern { +syntax, pattern, .. +} = ignore_pattern; +match syntax { +PatternSyntax::RootGlob | PatternSyntax::Glob => { +let mut root = vec![]; + +for p in pattern.split(|c| *c == b'/') { +if p.iter().any(|c| match *c { +b'[' | b'{' | b'*' | b'?' => true, +_ => false, +}) { +break; +} +root.push(HgPathBuf::from_bytes(p)); +} +let buf = +root.iter().fold(HgPathBuf::new(), |acc, r| acc.join(r)); +roots.push(buf); +} +PatternSyntax::Path | PatternSyntax::RelPath => { +let pat = HgPath::new(if pattern == b"." { +&[] as &[u8] +} else { +pattern +}); +roots.push(pat.to_owned()); +} +PatternSyntax::RootFiles => { +let pat = if pattern == b"." { +&[] as &[u8] +} else { +pattern +}; +dirs.push(HgPathBuf::from_bytes(pat)); +} +_ => { +roots.push(HgPathBuf::new()); +} +} +} +(roots, dirs) +} + +/// Paths extracted from patterns +#[derive(Debug, PartialEq)] +struct RootsDirsAndParents { +/// Directories to match recursively +pub roots: HashSet, +/// Directories to match non-recursively +pub dirs: HashSet, +/// Implicitly required directories to go to items in either roots or dirs +pub parents: HashSet, +} + +/// Extract roots, dirs and parents from patterns. +fn roots_dirs_and_parents( +ignore_patterns: &[IgnorePattern], +) -> PatternResult { +let (roots, dirs) = roots_and_dirs(ignore_patterns); + +let mut parents = HashSet::new(); + +parents.extend( +DirsMultiset::from_manifest(&dirs) +.map_err(|e| match e { +DirstateMapError::InvalidPath(e) => e, +_ => unreachable!(), +})? +.iter() +.map(|k| k.to_owned()), +); +parents.extend( +DirsMultiset::from_manifest(&roots) +.map_err(|e| match e { +DirstateMapError::InvalidPath(e) => e, +_ => unreachable!(), +})? +.iter() +.map(|k| k.to_owned()), +); + +Ok(RootsDirsAndParents { +roots: HashSet::from_iter(roots), +dirs: HashSet::from_iter(dirs), +parents, +}) +} + #[cfg(test)] mod tests { use super::*; use pretty_assertions::assert_eq; +use std::path::Path; + +#[test] +fn test_roots_and_dirs() { +let pats = vec![ +IgnorePattern::new(PatternSyntax::Glob, b"g/h/*", Path::new("")), +IgnorePattern::new(PatternSyntax::Glob, b"g/h", Path::new("")), +IgnorePattern::new(PatternSyntax::Glob, b"g*", Path::new("")), +]; +let (roots, dirs) = roots_and_dirs(&pats); + +assert_eq!( +roots, +vec!( +HgPathBuf::from_bytes(b"g/h"), +HgPathBuf::from_bytes(b"g/h"), +HgPathBuf::new() +), +); +assert_eq!(dirs, vec!()); +} + +#[test] +fn test_roots_dirs_and_paren
D7923: rust-matchers: add functions to get roots, dirs and parents from patterns
Closed by commit rHGd4e8cfcde012: rust-matchers: add functions to get roots, dirs and parents from patterns (authored by Alphare). This revision was automatically updated to reflect the committed changes. REPOSITORY rHG Mercurial CHANGES SINCE LAST UPDATE https://phab.mercurial-scm.org/D7923?vs=20161&id=20713 CHANGES SINCE LAST ACTION https://phab.mercurial-scm.org/D7923/new/ REVISION DETAIL https://phab.mercurial-scm.org/D7923 AFFECTED FILES rust/hg-core/src/matchers.rs CHANGE DETAILS diff --git a/rust/hg-core/src/matchers.rs b/rust/hg-core/src/matchers.rs --- a/rust/hg-core/src/matchers.rs +++ b/rust/hg-core/src/matchers.rs @@ -10,8 +10,10 @@ #[cfg(feature = "with-re2")] use crate::re2::Re2; use crate::{ -filepatterns::PatternResult, utils::hg_path::HgPath, DirsMultiset, -DirstateMapError, PatternError, +filepatterns::PatternResult, +utils::hg_path::{HgPath, HgPathBuf}, +DirsMultiset, DirstateMapError, IgnorePattern, PatternError, +PatternSyntax, }; use std::collections::HashSet; use std::iter::FromIterator; @@ -240,10 +242,156 @@ Err(PatternError::Re2NotInstalled) } +/// Returns roots and directories corresponding to each pattern. +/// +/// This calculates the roots and directories exactly matching the patterns and +/// returns a tuple of (roots, dirs). It does not return other directories +/// which may also need to be considered, like the parent directories. +fn roots_and_dirs( +ignore_patterns: &[IgnorePattern], +) -> (Vec, Vec) { +let mut roots = Vec::new(); +let mut dirs = Vec::new(); + +for ignore_pattern in ignore_patterns { +let IgnorePattern { +syntax, pattern, .. +} = ignore_pattern; +match syntax { +PatternSyntax::RootGlob | PatternSyntax::Glob => { +let mut root = vec![]; + +for p in pattern.split(|c| *c == b'/') { +if p.iter().any(|c| match *c { +b'[' | b'{' | b'*' | b'?' => true, +_ => false, +}) { +break; +} +root.push(HgPathBuf::from_bytes(p)); +} +let buf = +root.iter().fold(HgPathBuf::new(), |acc, r| acc.join(r)); +roots.push(buf); +} +PatternSyntax::Path | PatternSyntax::RelPath => { +let pat = HgPath::new(if pattern == b"." { +&[] as &[u8] +} else { +pattern +}); +roots.push(pat.to_owned()); +} +PatternSyntax::RootFiles => { +let pat = if pattern == b"." { +&[] as &[u8] +} else { +pattern +}; +dirs.push(HgPathBuf::from_bytes(pat)); +} +_ => { +roots.push(HgPathBuf::new()); +} +} +} +(roots, dirs) +} + +/// Paths extracted from patterns +#[derive(Debug, PartialEq)] +struct RootsDirsAndParents { +/// Directories to match recursively +pub roots: HashSet, +/// Directories to match non-recursively +pub dirs: HashSet, +/// Implicitly required directories to go to items in either roots or dirs +pub parents: HashSet, +} + +/// Extract roots, dirs and parents from patterns. +fn roots_dirs_and_parents( +ignore_patterns: &[IgnorePattern], +) -> PatternResult { +let (roots, dirs) = roots_and_dirs(ignore_patterns); + +let mut parents = HashSet::new(); + +parents.extend( +DirsMultiset::from_manifest(&dirs) +.map_err(|e| match e { +DirstateMapError::InvalidPath(e) => e, +_ => unreachable!(), +})? +.iter() +.map(|k| k.to_owned()), +); +parents.extend( +DirsMultiset::from_manifest(&roots) +.map_err(|e| match e { +DirstateMapError::InvalidPath(e) => e, +_ => unreachable!(), +})? +.iter() +.map(|k| k.to_owned()), +); + +Ok(RootsDirsAndParents { +roots: HashSet::from_iter(roots), +dirs: HashSet::from_iter(dirs), +parents, +}) +} + #[cfg(test)] mod tests { use super::*; use pretty_assertions::assert_eq; +use std::path::Path; + +#[test] +fn test_roots_and_dirs() { +let pats = vec![ +IgnorePattern::new(PatternSyntax::Glob, b"g/h/*", Path::new("")), +IgnorePattern::new(PatternSyntax::Glob, b"g/h", Path::new("")), +IgnorePattern::new(PatternSyntax::Glob, b"g*", Path::new("")), +]; +let (roots, dirs) = roots_and_dirs(&pats); + +assert_eq!( +roots, +vec!( +HgPathBuf::from_bytes(b"g/h"), +HgPathBuf::from_bytes(b"g/h"), +