161 fn matches(&self, filename: impl AsRef<HgPath>) -> bool { |
163 fn matches(&self, filename: impl AsRef<HgPath>) -> bool { |
162 self.inner_matches(filename) |
164 self.inner_matches(filename) |
163 } |
165 } |
164 fn visit_children_set( |
166 fn visit_children_set( |
165 &self, |
167 &self, |
166 _directory: impl AsRef<HgPath>, |
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 |
175 } |
213 } |
176 fn is_exact(&self) -> bool { |
214 fn is_exact(&self) -> bool { |
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 } |