Show More
@@ -34,21 +34,21 b' use std::path::{Path, PathBuf};' | |||||
34 | use micro_timer::timed; |
|
34 | use micro_timer::timed; | |
35 |
|
35 | |||
36 | #[derive(Debug, PartialEq)] |
|
36 | #[derive(Debug, PartialEq)] | |
37 |
pub enum VisitChildrenSet |
|
37 | pub enum VisitChildrenSet { | |
38 | /// Don't visit anything |
|
38 | /// Don't visit anything | |
39 | Empty, |
|
39 | Empty, | |
40 | /// Only visit this directory |
|
40 | /// Only visit this directory | |
41 | This, |
|
41 | This, | |
42 | /// Visit this directory and these subdirectories |
|
42 | /// Visit this directory and these subdirectories | |
43 | /// TODO Should we implement a `NonEmptyHashSet`? |
|
43 | /// TODO Should we implement a `NonEmptyHashSet`? | |
44 |
Set(HashSet< |
|
44 | Set(HashSet<HgPathBuf>), | |
45 | /// Visit this directory and all subdirectories |
|
45 | /// Visit this directory and all subdirectories | |
46 | Recursive, |
|
46 | Recursive, | |
47 | } |
|
47 | } | |
48 |
|
48 | |||
49 | pub trait Matcher { |
|
49 | pub trait Matcher { | |
50 | /// Explicitly listed files |
|
50 | /// Explicitly listed files | |
51 |
fn file_set(&self) -> Option<&HashSet< |
|
51 | fn file_set(&self) -> Option<&HashSet<HgPathBuf>>; | |
52 | /// Returns whether `filename` is in `file_set` |
|
52 | /// Returns whether `filename` is in `file_set` | |
53 | fn exact_match(&self, filename: &HgPath) -> bool; |
|
53 | fn exact_match(&self, filename: &HgPath) -> bool; | |
54 | /// Returns whether `filename` is matched by this matcher |
|
54 | /// Returns whether `filename` is matched by this matcher | |
@@ -114,7 +114,7 b' pub trait Matcher {' | |||||
114 | pub struct AlwaysMatcher; |
|
114 | pub struct AlwaysMatcher; | |
115 |
|
115 | |||
116 | impl Matcher for AlwaysMatcher { |
|
116 | impl Matcher for AlwaysMatcher { | |
117 |
fn file_set(&self) -> Option<&HashSet< |
|
117 | fn file_set(&self) -> Option<&HashSet<HgPathBuf>> { | |
118 | None |
|
118 | None | |
119 | } |
|
119 | } | |
120 | fn exact_match(&self, _filename: &HgPath) -> bool { |
|
120 | fn exact_match(&self, _filename: &HgPath) -> bool { | |
@@ -140,8 +140,8 b' impl Matcher for AlwaysMatcher {' | |||||
140 | ///``` |
|
140 | ///``` | |
141 | /// use hg::{ matchers::{Matcher, FileMatcher}, utils::hg_path::{HgPath, HgPathBuf} }; |
|
141 | /// use hg::{ matchers::{Matcher, FileMatcher}, utils::hg_path::{HgPath, HgPathBuf} }; | |
142 | /// |
|
142 | /// | |
143 | /// let files = [HgPathBuf::from_bytes(b"a.txt"), HgPathBuf::from_bytes(br"re:.*\.c$")]; |
|
143 | /// let files = vec![HgPathBuf::from_bytes(b"a.txt"), HgPathBuf::from_bytes(br"re:.*\.c$")]; | |
144 |
/// let matcher = FileMatcher::new( |
|
144 | /// let matcher = FileMatcher::new(files).unwrap(); | |
145 | /// |
|
145 | /// | |
146 | /// assert_eq!(matcher.matches(HgPath::new(b"a.txt")), true); |
|
146 | /// assert_eq!(matcher.matches(HgPath::new(b"a.txt")), true); | |
147 | /// assert_eq!(matcher.matches(HgPath::new(b"b.txt")), false); |
|
147 | /// assert_eq!(matcher.matches(HgPath::new(b"b.txt")), false); | |
@@ -149,16 +149,17 b' impl Matcher for AlwaysMatcher {' | |||||
149 | /// assert_eq!(matcher.matches(HgPath::new(br"re:.*\.c$")), true); |
|
149 | /// assert_eq!(matcher.matches(HgPath::new(br"re:.*\.c$")), true); | |
150 | /// ``` |
|
150 | /// ``` | |
151 | #[derive(Debug)] |
|
151 | #[derive(Debug)] | |
152 |
pub struct FileMatcher |
|
152 | pub struct FileMatcher { | |
153 |
files: HashSet< |
|
153 | files: HashSet<HgPathBuf>, | |
154 | dirs: DirsMultiset, |
|
154 | dirs: DirsMultiset, | |
155 | } |
|
155 | } | |
156 |
|
156 | |||
157 |
impl |
|
157 | impl FileMatcher { | |
158 |
pub fn new(files: |
|
158 | pub fn new(files: Vec<HgPathBuf>) -> Result<Self, DirstateMapError> { | |
|
159 | let dirs = DirsMultiset::from_manifest(&files)?; | |||
159 | Ok(Self { |
|
160 | Ok(Self { | |
160 |
files: HashSet::from_iter(files.iter( |
|
161 | files: HashSet::from_iter(files.into_iter()), | |
161 | dirs: DirsMultiset::from_manifest(files)?, |
|
162 | dirs, | |
162 | }) |
|
163 | }) | |
163 | } |
|
164 | } | |
164 | fn inner_matches(&self, filename: &HgPath) -> bool { |
|
165 | fn inner_matches(&self, filename: &HgPath) -> bool { | |
@@ -166,8 +167,8 b" impl<'a> FileMatcher<'a> {" | |||||
166 | } |
|
167 | } | |
167 | } |
|
168 | } | |
168 |
|
169 | |||
169 |
impl |
|
170 | impl Matcher for FileMatcher { | |
170 |
fn file_set(&self) -> Option<&HashSet< |
|
171 | fn file_set(&self) -> Option<&HashSet<HgPathBuf>> { | |
171 | Some(&self.files) |
|
172 | Some(&self.files) | |
172 | } |
|
173 | } | |
173 | fn exact_match(&self, filename: &HgPath) -> bool { |
|
174 | fn exact_match(&self, filename: &HgPath) -> bool { | |
@@ -180,10 +181,10 b" impl<'a> Matcher for FileMatcher<'a> {" | |||||
180 | if self.files.is_empty() || !self.dirs.contains(&directory) { |
|
181 | if self.files.is_empty() || !self.dirs.contains(&directory) { | |
181 | return VisitChildrenSet::Empty; |
|
182 | return VisitChildrenSet::Empty; | |
182 | } |
|
183 | } | |
183 | let dirs_as_set = self.dirs.iter().map(Deref::deref).collect(); |
|
184 | let mut candidates: HashSet<HgPathBuf> = | |
|
185 | self.dirs.iter().cloned().collect(); | |||
184 |
|
186 | |||
185 | let mut candidates: HashSet<&HgPath> = |
|
187 | candidates.extend(self.files.iter().cloned()); | |
186 | self.files.union(&dirs_as_set).cloned().collect(); |
|
|||
187 | candidates.remove(HgPath::new(b"")); |
|
188 | candidates.remove(HgPath::new(b"")); | |
188 |
|
189 | |||
189 | if !directory.as_ref().is_empty() { |
|
190 | if !directory.as_ref().is_empty() { | |
@@ -192,7 +193,9 b" impl<'a> Matcher for FileMatcher<'a> {" | |||||
192 | .iter() |
|
193 | .iter() | |
193 | .filter_map(|c| { |
|
194 | .filter_map(|c| { | |
194 | if c.as_bytes().starts_with(&directory) { |
|
195 | if c.as_bytes().starts_with(&directory) { | |
195 |
Some(HgPath:: |
|
196 | Some(HgPathBuf::from_bytes( | |
|
197 | &c.as_bytes()[directory.len()..], | |||
|
198 | )) | |||
196 | } else { |
|
199 | } else { | |
197 | None |
|
200 | None | |
198 | } |
|
201 | } | |
@@ -207,10 +210,10 b" impl<'a> Matcher for FileMatcher<'a> {" | |||||
207 | // subdir will be in there without a slash. |
|
210 | // subdir will be in there without a slash. | |
208 | VisitChildrenSet::Set( |
|
211 | VisitChildrenSet::Set( | |
209 | candidates |
|
212 | candidates | |
210 | .iter() |
|
213 | .into_iter() | |
211 | .filter_map(|c| { |
|
214 | .filter_map(|c| { | |
212 | if c.bytes().all(|b| *b != b'/') { |
|
215 | if c.bytes().all(|b| *b != b'/') { | |
213 |
Some( |
|
216 | Some(c) | |
214 | } else { |
|
217 | } else { | |
215 | None |
|
218 | None | |
216 | } |
|
219 | } | |
@@ -256,7 +259,7 b" pub struct IncludeMatcher<'a> {" | |||||
256 | } |
|
259 | } | |
257 |
|
260 | |||
258 | impl<'a> Matcher for IncludeMatcher<'a> { |
|
261 | impl<'a> Matcher for IncludeMatcher<'a> { | |
259 |
fn file_set(&self) -> Option<&HashSet< |
|
262 | fn file_set(&self) -> Option<&HashSet<HgPathBuf>> { | |
260 | None |
|
263 | None | |
261 | } |
|
264 | } | |
262 |
|
265 | |||
@@ -284,7 +287,9 b" impl<'a> Matcher for IncludeMatcher<'a> " | |||||
284 | if self.parents.contains(directory.as_ref()) { |
|
287 | if self.parents.contains(directory.as_ref()) { | |
285 | let multiset = self.get_all_parents_children(); |
|
288 | let multiset = self.get_all_parents_children(); | |
286 | if let Some(children) = multiset.get(dir) { |
|
289 | if let Some(children) = multiset.get(dir) { | |
287 |
return VisitChildrenSet::Set( |
|
290 | return VisitChildrenSet::Set( | |
|
291 | children.into_iter().map(HgPathBuf::from).collect(), | |||
|
292 | ); | |||
288 | } |
|
293 | } | |
289 | } |
|
294 | } | |
290 | VisitChildrenSet::Empty |
|
295 | VisitChildrenSet::Empty | |
@@ -721,24 +726,24 b' mod tests {' | |||||
721 | fn test_filematcher_visit_children_set() { |
|
726 | fn test_filematcher_visit_children_set() { | |
722 | // Visitchildrenset |
|
727 | // Visitchildrenset | |
723 | let files = vec![HgPathBuf::from_bytes(b"dir/subdir/foo.txt")]; |
|
728 | let files = vec![HgPathBuf::from_bytes(b"dir/subdir/foo.txt")]; | |
724 |
let matcher = FileMatcher::new( |
|
729 | let matcher = FileMatcher::new(files).unwrap(); | |
725 |
|
730 | |||
726 | let mut set = HashSet::new(); |
|
731 | let mut set = HashSet::new(); | |
727 |
set.insert(HgPath:: |
|
732 | set.insert(HgPathBuf::from_bytes(b"dir")); | |
728 | assert_eq!( |
|
733 | assert_eq!( | |
729 | matcher.visit_children_set(HgPath::new(b"")), |
|
734 | matcher.visit_children_set(HgPath::new(b"")), | |
730 | VisitChildrenSet::Set(set) |
|
735 | VisitChildrenSet::Set(set) | |
731 | ); |
|
736 | ); | |
732 |
|
737 | |||
733 | let mut set = HashSet::new(); |
|
738 | let mut set = HashSet::new(); | |
734 |
set.insert(HgPath:: |
|
739 | set.insert(HgPathBuf::from_bytes(b"subdir")); | |
735 | assert_eq!( |
|
740 | assert_eq!( | |
736 | matcher.visit_children_set(HgPath::new(b"dir")), |
|
741 | matcher.visit_children_set(HgPath::new(b"dir")), | |
737 | VisitChildrenSet::Set(set) |
|
742 | VisitChildrenSet::Set(set) | |
738 | ); |
|
743 | ); | |
739 |
|
744 | |||
740 | let mut set = HashSet::new(); |
|
745 | let mut set = HashSet::new(); | |
741 |
set.insert(HgPath:: |
|
746 | set.insert(HgPathBuf::from_bytes(b"foo.txt")); | |
742 | assert_eq!( |
|
747 | assert_eq!( | |
743 | matcher.visit_children_set(HgPath::new(b"dir/subdir")), |
|
748 | matcher.visit_children_set(HgPath::new(b"dir/subdir")), | |
744 | VisitChildrenSet::Set(set) |
|
749 | VisitChildrenSet::Set(set) | |
@@ -767,40 +772,40 b' mod tests {' | |||||
767 | // No file in a/b/c |
|
772 | // No file in a/b/c | |
768 | HgPathBuf::from_bytes(b"a/b/c/d/file4.txt"), |
|
773 | HgPathBuf::from_bytes(b"a/b/c/d/file4.txt"), | |
769 | ]; |
|
774 | ]; | |
770 |
let matcher = FileMatcher::new( |
|
775 | let matcher = FileMatcher::new(files).unwrap(); | |
771 |
|
776 | |||
772 | let mut set = HashSet::new(); |
|
777 | let mut set = HashSet::new(); | |
773 |
set.insert(HgPath:: |
|
778 | set.insert(HgPathBuf::from_bytes(b"a")); | |
774 |
set.insert(HgPath:: |
|
779 | set.insert(HgPathBuf::from_bytes(b"rootfile.txt")); | |
775 | assert_eq!( |
|
780 | assert_eq!( | |
776 | matcher.visit_children_set(HgPath::new(b"")), |
|
781 | matcher.visit_children_set(HgPath::new(b"")), | |
777 | VisitChildrenSet::Set(set) |
|
782 | VisitChildrenSet::Set(set) | |
778 | ); |
|
783 | ); | |
779 |
|
784 | |||
780 | let mut set = HashSet::new(); |
|
785 | let mut set = HashSet::new(); | |
781 |
set.insert(HgPath:: |
|
786 | set.insert(HgPathBuf::from_bytes(b"b")); | |
782 |
set.insert(HgPath:: |
|
787 | set.insert(HgPathBuf::from_bytes(b"file1.txt")); | |
783 | assert_eq!( |
|
788 | assert_eq!( | |
784 | matcher.visit_children_set(HgPath::new(b"a")), |
|
789 | matcher.visit_children_set(HgPath::new(b"a")), | |
785 | VisitChildrenSet::Set(set) |
|
790 | VisitChildrenSet::Set(set) | |
786 | ); |
|
791 | ); | |
787 |
|
792 | |||
788 | let mut set = HashSet::new(); |
|
793 | let mut set = HashSet::new(); | |
789 |
set.insert(HgPath:: |
|
794 | set.insert(HgPathBuf::from_bytes(b"c")); | |
790 |
set.insert(HgPath:: |
|
795 | set.insert(HgPathBuf::from_bytes(b"file2.txt")); | |
791 | assert_eq!( |
|
796 | assert_eq!( | |
792 | matcher.visit_children_set(HgPath::new(b"a/b")), |
|
797 | matcher.visit_children_set(HgPath::new(b"a/b")), | |
793 | VisitChildrenSet::Set(set) |
|
798 | VisitChildrenSet::Set(set) | |
794 | ); |
|
799 | ); | |
795 |
|
800 | |||
796 | let mut set = HashSet::new(); |
|
801 | let mut set = HashSet::new(); | |
797 |
set.insert(HgPath:: |
|
802 | set.insert(HgPathBuf::from_bytes(b"d")); | |
798 | assert_eq!( |
|
803 | assert_eq!( | |
799 | matcher.visit_children_set(HgPath::new(b"a/b/c")), |
|
804 | matcher.visit_children_set(HgPath::new(b"a/b/c")), | |
800 | VisitChildrenSet::Set(set) |
|
805 | VisitChildrenSet::Set(set) | |
801 | ); |
|
806 | ); | |
802 | let mut set = HashSet::new(); |
|
807 | let mut set = HashSet::new(); | |
803 |
set.insert(HgPath:: |
|
808 | set.insert(HgPathBuf::from_bytes(b"file4.txt")); | |
804 | assert_eq!( |
|
809 | assert_eq!( | |
805 | matcher.visit_children_set(HgPath::new(b"a/b/c/d")), |
|
810 | matcher.visit_children_set(HgPath::new(b"a/b/c/d")), | |
806 | VisitChildrenSet::Set(set) |
|
811 | VisitChildrenSet::Set(set) | |
@@ -827,14 +832,14 b' mod tests {' | |||||
827 | .unwrap(); |
|
832 | .unwrap(); | |
828 |
|
833 | |||
829 | let mut set = HashSet::new(); |
|
834 | let mut set = HashSet::new(); | |
830 |
set.insert(HgPath:: |
|
835 | set.insert(HgPathBuf::from_bytes(b"dir")); | |
831 | assert_eq!( |
|
836 | assert_eq!( | |
832 | matcher.visit_children_set(HgPath::new(b"")), |
|
837 | matcher.visit_children_set(HgPath::new(b"")), | |
833 | VisitChildrenSet::Set(set) |
|
838 | VisitChildrenSet::Set(set) | |
834 | ); |
|
839 | ); | |
835 |
|
840 | |||
836 | let mut set = HashSet::new(); |
|
841 | let mut set = HashSet::new(); | |
837 |
set.insert(HgPath:: |
|
842 | set.insert(HgPathBuf::from_bytes(b"subdir")); | |
838 | assert_eq!( |
|
843 | assert_eq!( | |
839 | matcher.visit_children_set(HgPath::new(b"dir")), |
|
844 | matcher.visit_children_set(HgPath::new(b"dir")), | |
840 | VisitChildrenSet::Set(set) |
|
845 | VisitChildrenSet::Set(set) | |
@@ -862,14 +867,14 b' mod tests {' | |||||
862 | .unwrap(); |
|
867 | .unwrap(); | |
863 |
|
868 | |||
864 | let mut set = HashSet::new(); |
|
869 | let mut set = HashSet::new(); | |
865 |
set.insert(HgPath:: |
|
870 | set.insert(HgPathBuf::from_bytes(b"dir")); | |
866 | assert_eq!( |
|
871 | assert_eq!( | |
867 | matcher.visit_children_set(HgPath::new(b"")), |
|
872 | matcher.visit_children_set(HgPath::new(b"")), | |
868 | VisitChildrenSet::Set(set) |
|
873 | VisitChildrenSet::Set(set) | |
869 | ); |
|
874 | ); | |
870 |
|
875 | |||
871 | let mut set = HashSet::new(); |
|
876 | let mut set = HashSet::new(); | |
872 |
set.insert(HgPath:: |
|
877 | set.insert(HgPathBuf::from_bytes(b"subdir")); | |
873 | assert_eq!( |
|
878 | assert_eq!( | |
874 | matcher.visit_children_set(HgPath::new(b"dir")), |
|
879 | matcher.visit_children_set(HgPath::new(b"dir")), | |
875 | VisitChildrenSet::Set(set) |
|
880 | VisitChildrenSet::Set(set) | |
@@ -897,7 +902,7 b' mod tests {' | |||||
897 | .unwrap(); |
|
902 | .unwrap(); | |
898 |
|
903 | |||
899 | let mut set = HashSet::new(); |
|
904 | let mut set = HashSet::new(); | |
900 |
set.insert(HgPath:: |
|
905 | set.insert(HgPathBuf::from_bytes(b"dir")); | |
901 | assert_eq!( |
|
906 | assert_eq!( | |
902 | matcher.visit_children_set(HgPath::new(b"")), |
|
907 | matcher.visit_children_set(HgPath::new(b"")), | |
903 | VisitChildrenSet::Set(set) |
|
908 | VisitChildrenSet::Set(set) |
@@ -169,7 +169,7 b' pub fn status_wrapper(' | |||||
169 | .collect(); |
|
169 | .collect(); | |
170 |
|
170 | |||
171 | let files = files?; |
|
171 | let files = files?; | |
172 |
let matcher = FileMatcher::new(files |
|
172 | let matcher = FileMatcher::new(files) | |
173 | .map_err(|e| PyErr::new::<ValueError, _>(py, e.to_string()))?; |
|
173 | .map_err(|e| PyErr::new::<ValueError, _>(py, e.to_string()))?; | |
174 | dmap.with_status( |
|
174 | dmap.with_status( | |
175 | &matcher, |
|
175 | &matcher, |
General Comments 0
You need to be logged in to leave comments.
Login now