Show More
@@ -10,7 +10,9 b'' | |||||
10 | use crate::{utils::hg_path::HgPath, DirsMultiset, DirstateMapError}; |
|
10 | use crate::{utils::hg_path::HgPath, DirsMultiset, DirstateMapError}; | |
11 | use std::collections::HashSet; |
|
11 | use std::collections::HashSet; | |
12 | use std::iter::FromIterator; |
|
12 | use std::iter::FromIterator; | |
|
13 | use std::ops::Deref; | |||
13 |
|
14 | |||
|
15 | #[derive(Debug, PartialEq)] | |||
14 | pub enum VisitChildrenSet<'a> { |
|
16 | pub enum VisitChildrenSet<'a> { | |
15 | /// Don't visit anything |
|
17 | /// Don't visit anything | |
16 | Empty, |
|
18 | Empty, | |
@@ -163,12 +165,48 b" impl<'a> Matcher for FileMatcher<'a> {" | |||||
163 | } |
|
165 | } | |
164 | fn visit_children_set( |
|
166 | fn visit_children_set( | |
165 | &self, |
|
167 | &self, | |
166 |
|
|
168 | directory: impl AsRef<HgPath>, | |
167 | ) -> VisitChildrenSet { |
|
169 | ) -> VisitChildrenSet { | |
168 | // TODO implement once we have `status.traverse` |
|
170 | if self.files.is_empty() || !self.dirs.contains(&directory) { | |
169 | // This is useless until unknown files are taken into account |
|
171 | return VisitChildrenSet::Empty; | |
170 | // Which will not need to happen before the `IncludeMatcher`. |
|
172 | } | |
171 | unimplemented!() |
|
173 | let dirs_as_set = self.dirs.iter().map(|k| k.deref()).collect(); | |
|
174 | ||||
|
175 | let mut candidates: HashSet<&HgPath> = | |||
|
176 | self.files.union(&dirs_as_set).map(|k| *k).collect(); | |||
|
177 | candidates.remove(HgPath::new(b"")); | |||
|
178 | ||||
|
179 | if !directory.as_ref().is_empty() { | |||
|
180 | let directory = [directory.as_ref().as_bytes(), b"/"].concat(); | |||
|
181 | candidates = candidates | |||
|
182 | .iter() | |||
|
183 | .filter_map(|c| { | |||
|
184 | if c.as_bytes().starts_with(&directory) { | |||
|
185 | Some(HgPath::new(&c.as_bytes()[directory.len()..])) | |||
|
186 | } else { | |||
|
187 | None | |||
|
188 | } | |||
|
189 | }) | |||
|
190 | .collect(); | |||
|
191 | } | |||
|
192 | ||||
|
193 | // `self.dirs` includes all of the directories, recursively, so if | |||
|
194 | // we're attempting to match 'foo/bar/baz.txt', it'll have '', 'foo', | |||
|
195 | // 'foo/bar' in it. Thus we can safely ignore a candidate that has a | |||
|
196 | // '/' in it, indicating it's for a subdir-of-a-subdir; the immediate | |||
|
197 | // subdir will be in there without a slash. | |||
|
198 | VisitChildrenSet::Set( | |||
|
199 | candidates | |||
|
200 | .iter() | |||
|
201 | .filter_map(|c| { | |||
|
202 | if c.bytes().all(|b| *b != b'/') { | |||
|
203 | Some(*c) | |||
|
204 | } else { | |||
|
205 | None | |||
|
206 | } | |||
|
207 | }) | |||
|
208 | .collect(), | |||
|
209 | ) | |||
172 | } |
|
210 | } | |
173 | fn matches_everything(&self) -> bool { |
|
211 | fn matches_everything(&self) -> bool { | |
174 | false |
|
212 | false | |
@@ -177,3 +215,107 b" impl<'a> Matcher for FileMatcher<'a> {" | |||||
177 | true |
|
215 | true | |
178 | } |
|
216 | } | |
179 | } |
|
217 | } | |
|
218 | #[cfg(test)] | |||
|
219 | mod tests { | |||
|
220 | use super::*; | |||
|
221 | use pretty_assertions::assert_eq; | |||
|
222 | ||||
|
223 | #[test] | |||
|
224 | fn test_filematcher_visit_children_set() { | |||
|
225 | // Visitchildrenset | |||
|
226 | let files = vec![HgPath::new(b"dir/subdir/foo.txt")]; | |||
|
227 | let matcher = FileMatcher::new(&files).unwrap(); | |||
|
228 | ||||
|
229 | let mut set = HashSet::new(); | |||
|
230 | set.insert(HgPath::new(b"dir")); | |||
|
231 | assert_eq!( | |||
|
232 | matcher.visit_children_set(HgPath::new(b"")), | |||
|
233 | VisitChildrenSet::Set(set) | |||
|
234 | ); | |||
|
235 | ||||
|
236 | let mut set = HashSet::new(); | |||
|
237 | set.insert(HgPath::new(b"subdir")); | |||
|
238 | assert_eq!( | |||
|
239 | matcher.visit_children_set(HgPath::new(b"dir")), | |||
|
240 | VisitChildrenSet::Set(set) | |||
|
241 | ); | |||
|
242 | ||||
|
243 | let mut set = HashSet::new(); | |||
|
244 | set.insert(HgPath::new(b"foo.txt")); | |||
|
245 | assert_eq!( | |||
|
246 | matcher.visit_children_set(HgPath::new(b"dir/subdir")), | |||
|
247 | VisitChildrenSet::Set(set) | |||
|
248 | ); | |||
|
249 | ||||
|
250 | assert_eq!( | |||
|
251 | matcher.visit_children_set(HgPath::new(b"dir/subdir/x")), | |||
|
252 | VisitChildrenSet::Empty | |||
|
253 | ); | |||
|
254 | assert_eq!( | |||
|
255 | matcher.visit_children_set(HgPath::new(b"dir/subdir/foo.txt")), | |||
|
256 | VisitChildrenSet::Empty | |||
|
257 | ); | |||
|
258 | assert_eq!( | |||
|
259 | matcher.visit_children_set(HgPath::new(b"folder")), | |||
|
260 | VisitChildrenSet::Empty | |||
|
261 | ); | |||
|
262 | } | |||
|
263 | ||||
|
264 | #[test] | |||
|
265 | fn test_filematcher_visit_children_set_files_and_dirs() { | |||
|
266 | let files = vec![ | |||
|
267 | HgPath::new(b"rootfile.txt"), | |||
|
268 | HgPath::new(b"a/file1.txt"), | |||
|
269 | HgPath::new(b"a/b/file2.txt"), | |||
|
270 | // No file in a/b/c | |||
|
271 | HgPath::new(b"a/b/c/d/file4.txt"), | |||
|
272 | ]; | |||
|
273 | let matcher = FileMatcher::new(&files).unwrap(); | |||
|
274 | ||||
|
275 | let mut set = HashSet::new(); | |||
|
276 | set.insert(HgPath::new(b"a")); | |||
|
277 | set.insert(HgPath::new(b"rootfile.txt")); | |||
|
278 | assert_eq!( | |||
|
279 | matcher.visit_children_set(HgPath::new(b"")), | |||
|
280 | VisitChildrenSet::Set(set) | |||
|
281 | ); | |||
|
282 | ||||
|
283 | let mut set = HashSet::new(); | |||
|
284 | set.insert(HgPath::new(b"b")); | |||
|
285 | set.insert(HgPath::new(b"file1.txt")); | |||
|
286 | assert_eq!( | |||
|
287 | matcher.visit_children_set(HgPath::new(b"a")), | |||
|
288 | VisitChildrenSet::Set(set) | |||
|
289 | ); | |||
|
290 | ||||
|
291 | let mut set = HashSet::new(); | |||
|
292 | set.insert(HgPath::new(b"c")); | |||
|
293 | set.insert(HgPath::new(b"file2.txt")); | |||
|
294 | assert_eq!( | |||
|
295 | matcher.visit_children_set(HgPath::new(b"a/b")), | |||
|
296 | VisitChildrenSet::Set(set) | |||
|
297 | ); | |||
|
298 | ||||
|
299 | let mut set = HashSet::new(); | |||
|
300 | set.insert(HgPath::new(b"d")); | |||
|
301 | assert_eq!( | |||
|
302 | matcher.visit_children_set(HgPath::new(b"a/b/c")), | |||
|
303 | VisitChildrenSet::Set(set) | |||
|
304 | ); | |||
|
305 | let mut set = HashSet::new(); | |||
|
306 | set.insert(HgPath::new(b"file4.txt")); | |||
|
307 | assert_eq!( | |||
|
308 | matcher.visit_children_set(HgPath::new(b"a/b/c/d")), | |||
|
309 | VisitChildrenSet::Set(set) | |||
|
310 | ); | |||
|
311 | ||||
|
312 | assert_eq!( | |||
|
313 | matcher.visit_children_set(HgPath::new(b"a/b/c/d/e")), | |||
|
314 | VisitChildrenSet::Empty | |||
|
315 | ); | |||
|
316 | assert_eq!( | |||
|
317 | matcher.visit_children_set(HgPath::new(b"folder")), | |||
|
318 | VisitChildrenSet::Empty | |||
|
319 | ); | |||
|
320 | } | |||
|
321 | } |
General Comments 0
You need to be logged in to leave comments.
Login now