Show More
@@ -179,6 +179,9 b' bundle_spec_param_processing = {' | |||
|
179 | 179 | b"obsolescence": param_bool, |
|
180 | 180 | b"obsolescence-mandatory": param_bool, |
|
181 | 181 | b"phases": param_bool, |
|
182 | b"changegroup": param_bool, | |
|
183 | b"tagsfnodescache": param_bool, | |
|
184 | b"revbranchcache": param_bool, | |
|
182 | 185 | } |
|
183 | 186 | |
|
184 | 187 |
@@ -158,9 +158,8 b' def getbundlespec(ui, fh):' | |||
|
158 | 158 | params[b'obsolescence-mandatory'] = b'no' |
|
159 | 159 | |
|
160 | 160 | if not version: |
|
161 | raise error.Abort( | |
|
162 | _(b'could not identify changegroup version in bundle') | |
|
163 | ) | |
|
161 | params[b'changegroup'] = b'no' | |
|
162 | version = b'v2' | |
|
164 | 163 | spec = b'%s-%s' % (comp, version) |
|
165 | 164 | if params: |
|
166 | 165 | spec += b';' |
@@ -638,7 +638,10 b' class patternmatcher(basematcher):' | |||
|
638 | 638 | super(patternmatcher, self).__init__(badfn) |
|
639 | 639 | kindpats.sort() |
|
640 | 640 | |
|
641 | roots, dirs, parents = _rootsdirsandparents(kindpats) | |
|
641 | 642 | self._files = _explicitfiles(kindpats) |
|
643 | self._dirs_explicit = set(dirs) | |
|
644 | self._dirs = parents | |
|
642 | 645 | self._prefix = _prefix(kindpats) |
|
643 | 646 | self._pats, self._matchfn = _buildmatch(kindpats, b'$', root) |
|
644 | 647 | |
@@ -647,14 +650,14 b' class patternmatcher(basematcher):' | |||
|
647 | 650 | return True |
|
648 | 651 | return self._matchfn(fn) |
|
649 | 652 | |
|
650 | @propertycache | |
|
651 | def _dirs(self): | |
|
652 | return set(pathutil.dirs(self._fileset)) | |
|
653 | ||
|
654 | 653 | def visitdir(self, dir): |
|
655 | 654 | if self._prefix and dir in self._fileset: |
|
656 | 655 | return b'all' |
|
657 | return dir in self._dirs or path_or_parents_in_set(dir, self._fileset) | |
|
656 | return ( | |
|
657 | dir in self._dirs | |
|
658 | or path_or_parents_in_set(dir, self._fileset) | |
|
659 | or path_or_parents_in_set(dir, self._dirs_explicit) | |
|
660 | ) | |
|
658 | 661 | |
|
659 | 662 | def visitchildrenset(self, dir): |
|
660 | 663 | ret = self.visitdir(dir) |
@@ -1461,7 +1464,7 b' def _buildregexmatch(kindpats, globsuffi' | |||
|
1461 | 1464 | allgroups = [] |
|
1462 | 1465 | regexps = [] |
|
1463 | 1466 | exact = set() |
|
1464 |
for |
|
|
1467 | for kind, pattern, _source in kindpats: | |
|
1465 | 1468 | if kind == b'filepath': |
|
1466 | 1469 | exact.add(pattern) |
|
1467 | 1470 | continue |
@@ -527,24 +527,34 b' class sshserver:' | |||
|
527 | 527 | def __init__(self, ui, repo, logfh=None, accesshidden=False): |
|
528 | 528 | self._ui = ui |
|
529 | 529 | self._repo = repo |
|
530 | self._fin, self._fout = ui.protectfinout() | |
|
531 | 530 | self._accesshidden = accesshidden |
|
532 | ||
|
533 | # Log write I/O to stdout and stderr if configured. | |
|
534 | if logfh: | |
|
535 | self._fout = util.makeloggingfileobject( | |
|
536 | logfh, self._fout, b'o', logdata=True | |
|
537 | ) | |
|
538 | ui.ferr = util.makeloggingfileobject( | |
|
539 | logfh, ui.ferr, b'e', logdata=True | |
|
540 | ) | |
|
531 | self._logfh = logfh | |
|
541 | 532 | |
|
542 | 533 | def serve_forever(self): |
|
543 | 534 | self.serveuntil(threading.Event()) |
|
544 | self._ui.restorefinout(self._fin, self._fout) | |
|
545 | 535 | |
|
546 | 536 | def serveuntil(self, ev): |
|
547 | 537 | """Serve until a threading.Event is set.""" |
|
548 | _runsshserver( | |
|
549 | self._ui, self._repo, self._fin, self._fout, ev, self._accesshidden | |
|
550 | ) | |
|
538 | with self._ui.protectedfinout() as (fin, fout): | |
|
539 | if self._logfh: | |
|
540 | # Log write I/O to stdout and stderr if configured. | |
|
541 | fout = util.makeloggingfileobject( | |
|
542 | self._logfh, | |
|
543 | fout, | |
|
544 | b'o', | |
|
545 | logdata=True, | |
|
546 | ) | |
|
547 | self._ui.ferr = util.makeloggingfileobject( | |
|
548 | self._logfh, | |
|
549 | self._ui.ferr, | |
|
550 | b'e', | |
|
551 | logdata=True, | |
|
552 | ) | |
|
553 | _runsshserver( | |
|
554 | self._ui, | |
|
555 | self._repo, | |
|
556 | fin, | |
|
557 | fout, | |
|
558 | ev, | |
|
559 | self._accesshidden, | |
|
560 | ) |
@@ -158,14 +158,13 b" pub struct DirsChildrenMultiset<'a> {" | |||
|
158 | 158 | } |
|
159 | 159 | |
|
160 | 160 | impl<'a> DirsChildrenMultiset<'a> { |
|
161 | pub fn new( | |
|
161 | pub fn new<I: Iterator<Item = &'a HgPathBuf>>( | |
|
162 | 162 | paths: impl Iterator<Item = &'a HgPathBuf>, |
|
163 |
only_include: Option< |
|
|
163 | only_include: Option<I>, | |
|
164 | 164 | ) -> Self { |
|
165 | 165 | let mut new = Self { |
|
166 | 166 | inner: HashMap::default(), |
|
167 | only_include: only_include | |
|
168 | .map(|s| s.iter().map(AsRef::as_ref).collect()), | |
|
167 | only_include: only_include.map(|s| s.map(AsRef::as_ref).collect()), | |
|
169 | 168 | }; |
|
170 | 169 | |
|
171 | 170 | for path in paths { |
@@ -57,7 +57,7 b' pub enum PatternSyntax {' | |||
|
57 | 57 | RelRegexp, |
|
58 | 58 | /// A path relative to repository root, which is matched non-recursively |
|
59 | 59 | /// (will not match subdirectories) |
|
60 | RootFiles, | |
|
60 | RootFilesIn, | |
|
61 | 61 | /// A file of patterns to read and include |
|
62 | 62 | Include, |
|
63 | 63 | /// A file of patterns to match against files under the same directory |
@@ -158,7 +158,7 b' pub fn parse_pattern_syntax(' | |||
|
158 | 158 | b"path:" => Ok(PatternSyntax::Path), |
|
159 | 159 | b"filepath:" => Ok(PatternSyntax::FilePath), |
|
160 | 160 | b"relpath:" => Ok(PatternSyntax::RelPath), |
|
161 | b"rootfilesin:" => Ok(PatternSyntax::RootFiles), | |
|
161 | b"rootfilesin:" => Ok(PatternSyntax::RootFilesIn), | |
|
162 | 162 | b"relglob:" => Ok(PatternSyntax::RelGlob), |
|
163 | 163 | b"relre:" => Ok(PatternSyntax::RelRegexp), |
|
164 | 164 | b"glob:" => Ok(PatternSyntax::Glob), |
@@ -227,7 +227,7 b' fn _build_single_regex(entry: &IgnorePat' | |||
|
227 | 227 | } |
|
228 | 228 | [escape_pattern(pattern).as_slice(), b"(?:/|$)"].concat() |
|
229 | 229 | } |
|
230 | PatternSyntax::RootFiles => { | |
|
230 | PatternSyntax::RootFilesIn => { | |
|
231 | 231 | let mut res = if pattern == b"." { |
|
232 | 232 | vec![] |
|
233 | 233 | } else { |
@@ -316,7 +316,7 b' pub fn build_single_regex(' | |||
|
316 | 316 | | PatternSyntax::Path |
|
317 | 317 | | PatternSyntax::RelGlob |
|
318 | 318 | | PatternSyntax::RelPath |
|
319 | | PatternSyntax::RootFiles => normalize_path_bytes(pattern), | |
|
319 | | PatternSyntax::RootFilesIn => normalize_path_bytes(pattern), | |
|
320 | 320 | PatternSyntax::Include | PatternSyntax::SubInclude => { |
|
321 | 321 | return Err(PatternError::NonRegexPattern(entry.clone())) |
|
322 | 322 | } |
@@ -342,7 +342,7 b' lazy_static! {' | |||
|
342 | 342 | m.insert(b"path:".as_ref(), PatternSyntax::Path); |
|
343 | 343 | m.insert(b"filepath:".as_ref(), PatternSyntax::FilePath); |
|
344 | 344 | m.insert(b"relpath:".as_ref(), PatternSyntax::RelPath); |
|
345 | m.insert(b"rootfilesin:".as_ref(), PatternSyntax::RootFiles); | |
|
345 | m.insert(b"rootfilesin:".as_ref(), PatternSyntax::RootFilesIn); | |
|
346 | 346 | m.insert(b"relglob:".as_ref(), PatternSyntax::RelGlob); |
|
347 | 347 | m.insert(b"relre:".as_ref(), PatternSyntax::RelRegexp); |
|
348 | 348 | m.insert(b"glob:".as_ref(), PatternSyntax::Glob); |
@@ -385,7 +385,7 b' pub fn parse_one_pattern(' | |||
|
385 | 385 | | PatternSyntax::Glob |
|
386 | 386 | | PatternSyntax::RelGlob |
|
387 | 387 | | PatternSyntax::RelPath |
|
388 | | PatternSyntax::RootFiles | |
|
388 | | PatternSyntax::RootFilesIn | |
|
389 | 389 | if normalize => |
|
390 | 390 | { |
|
391 | 391 | normalize_path_bytes(pattern_bytes) |
@@ -17,7 +17,7 b' use crate::{' | |||
|
17 | 17 | PatternFileWarning, PatternResult, |
|
18 | 18 | }, |
|
19 | 19 | utils::{ |
|
20 | files::find_dirs, | |
|
20 | files::{dir_ancestors, find_dirs}, | |
|
21 | 21 | hg_path::{HgPath, HgPathBuf, HgPathError}, |
|
22 | 22 | Escaped, |
|
23 | 23 | }, |
@@ -35,12 +35,14 b' use std::{borrow::ToOwned, collections::' | |||
|
35 | 35 | pub enum VisitChildrenSet { |
|
36 | 36 | /// Don't visit anything |
|
37 | 37 | Empty, |
|
38 |
/// |
|
|
38 | /// Visit this directory and probably its children | |
|
39 | 39 | This, |
|
40 | /// Visit this directory and these subdirectories | |
|
40 | /// Only visit the children (both files and directories) if they | |
|
41 | /// are mentioned in this set. (empty set corresponds to [Empty]) | |
|
41 | 42 | /// TODO Should we implement a `NonEmptyHashSet`? |
|
42 | 43 | Set(HashSet<HgPathBuf>), |
|
43 | 44 | /// Visit this directory and all subdirectories |
|
45 | /// (you can stop asking about the children set) | |
|
44 | 46 | Recursive, |
|
45 | 47 | } |
|
46 | 48 | |
@@ -297,6 +299,7 b" pub struct PatternMatcher<'a> {" | |||
|
297 | 299 | /// Whether all the patterns match a prefix (i.e. recursively) |
|
298 | 300 | prefix: bool, |
|
299 | 301 | files: HashSet<HgPathBuf>, |
|
302 | dirs_explicit: HashSet<HgPathBuf>, | |
|
300 | 303 | dirs: DirsMultiset, |
|
301 | 304 | } |
|
302 | 305 | |
@@ -313,8 +316,13 b' impl core::fmt::Debug for PatternMatcher' | |||
|
313 | 316 | |
|
314 | 317 | impl<'a> PatternMatcher<'a> { |
|
315 | 318 | pub fn new(ignore_patterns: Vec<IgnorePattern>) -> PatternResult<Self> { |
|
316 | let (files, _) = roots_and_dirs(&ignore_patterns); | |
|
317 | let dirs = DirsMultiset::from_manifest(&files)?; | |
|
319 | let RootsDirsAndParents { | |
|
320 | roots, | |
|
321 | dirs: dirs_explicit, | |
|
322 | parents, | |
|
323 | } = roots_dirs_and_parents(&ignore_patterns)?; | |
|
324 | let files = roots; | |
|
325 | let dirs = parents; | |
|
318 | 326 | let files: HashSet<HgPathBuf> = HashSet::from_iter(files); |
|
319 | 327 | |
|
320 | 328 | let prefix = ignore_patterns.iter().all(|k| { |
@@ -328,6 +336,7 b" impl<'a> PatternMatcher<'a> {" | |||
|
328 | 336 | prefix, |
|
329 | 337 | files, |
|
330 | 338 | dirs, |
|
339 | dirs_explicit, | |
|
331 | 340 | }) |
|
332 | 341 | } |
|
333 | 342 | } |
@@ -352,9 +361,13 b" impl<'a> Matcher for PatternMatcher<'a> " | |||
|
352 | 361 | if self.prefix && self.files.contains(directory) { |
|
353 | 362 | return VisitChildrenSet::Recursive; |
|
354 | 363 | } |
|
355 | let path_or_parents_in_set = find_dirs(directory) | |
|
356 | .any(|parent_dir| self.files.contains(parent_dir)); | |
|
357 | if self.dirs.contains(directory) || path_or_parents_in_set { | |
|
364 | if self.dirs.contains(directory) { | |
|
365 | return VisitChildrenSet::This; | |
|
366 | } | |
|
367 | if dir_ancestors(directory).any(|parent_dir| { | |
|
368 | self.files.contains(parent_dir) | |
|
369 | || self.dirs_explicit.contains(parent_dir) | |
|
370 | }) { | |
|
358 | 371 | VisitChildrenSet::This |
|
359 | 372 | } else { |
|
360 | 373 | VisitChildrenSet::Empty |
@@ -390,7 +403,7 b" impl<'a> Matcher for PatternMatcher<'a> " | |||
|
390 | 403 | /// assert_eq!(matcher.matches(HgPath::new(b"but not this")), false); |
|
391 | 404 | /// /// |
|
392 | 405 | /// let ignore_patterns = |
|
393 | /// vec![IgnorePattern::new(PatternSyntax::RootFiles, b"dir/subdir", Path::new(""))]; | |
|
406 | /// vec![IgnorePattern::new(PatternSyntax::RootFilesIn, b"dir/subdir", Path::new(""))]; | |
|
394 | 407 | /// let matcher = IncludeMatcher::new(ignore_patterns).unwrap(); |
|
395 | 408 | /// /// |
|
396 | 409 | /// assert!(!matcher.matches(HgPath::new(b"file"))); |
@@ -405,7 +418,7 b" pub struct IncludeMatcher<'a> {" | |||
|
405 | 418 | prefix: bool, |
|
406 | 419 | roots: HashSet<HgPathBuf>, |
|
407 | 420 | dirs: HashSet<HgPathBuf>, |
|
408 | parents: HashSet<HgPathBuf>, | |
|
421 | parents: DirsMultiset, | |
|
409 | 422 | } |
|
410 | 423 | |
|
411 | 424 | impl core::fmt::Debug for IncludeMatcher<'_> { |
@@ -861,7 +874,7 b' fn roots_and_dirs(' | |||
|
861 | 874 | }); |
|
862 | 875 | roots.push(pat.to_owned()); |
|
863 | 876 | } |
|
864 | PatternSyntax::RootFiles => { | |
|
877 | PatternSyntax::RootFilesIn => { | |
|
865 | 878 | let pat = if pattern == b"." { |
|
866 | 879 | &[] as &[u8] |
|
867 | 880 | } else { |
@@ -885,7 +898,7 b' struct RootsDirsAndParents {' | |||
|
885 | 898 | /// Directories to match non-recursively |
|
886 | 899 | pub dirs: HashSet<HgPathBuf>, |
|
887 | 900 | /// Implicitly required directories to go to items in either roots or dirs |
|
888 |
pub parents: |
|
|
901 | pub parents: DirsMultiset, | |
|
889 | 902 | } |
|
890 | 903 | |
|
891 | 904 | /// Extract roots, dirs and parents from patterns. |
@@ -894,18 +907,11 b' fn roots_dirs_and_parents(' | |||
|
894 | 907 | ) -> PatternResult<RootsDirsAndParents> { |
|
895 | 908 | let (roots, dirs) = roots_and_dirs(ignore_patterns); |
|
896 | 909 | |
|
897 |
let mut parents = |
|
|
910 | let mut parents = DirsMultiset::from_manifest(&dirs)?; | |
|
898 | 911 | |
|
899 | parents.extend( | |
|
900 | DirsMultiset::from_manifest(&dirs)? | |
|
901 | .iter() | |
|
902 | .map(ToOwned::to_owned), | |
|
903 | ); | |
|
904 | parents.extend( | |
|
905 | DirsMultiset::from_manifest(&roots)? | |
|
906 | .iter() | |
|
907 | .map(ToOwned::to_owned), | |
|
908 | ); | |
|
912 | for path in &roots { | |
|
913 | parents.add_path(path)? | |
|
914 | } | |
|
909 | 915 | |
|
910 | 916 | Ok(RootsDirsAndParents { |
|
911 | 917 | roots: HashSet::from_iter(roots), |
@@ -958,7 +964,7 b" fn build_match<'a>(" | |||
|
958 | 964 | // with a regex. |
|
959 | 965 | if ignore_patterns |
|
960 | 966 | .iter() |
|
961 | .all(|k| k.syntax == PatternSyntax::RootFiles) | |
|
967 | .all(|k| k.syntax == PatternSyntax::RootFilesIn) | |
|
962 | 968 | { |
|
963 | 969 | let dirs: HashSet<_> = ignore_patterns |
|
964 | 970 | .iter() |
@@ -1077,7 +1083,7 b" impl<'a> IncludeMatcher<'a> {" | |||
|
1077 | 1083 | .iter() |
|
1078 | 1084 | .chain(self.roots.iter()) |
|
1079 | 1085 | .chain(self.parents.iter()); |
|
1080 |
DirsChildrenMultiset::new(thing, Some( |
|
|
1086 | DirsChildrenMultiset::new(thing, Some(self.parents.iter())) | |
|
1081 | 1087 | } |
|
1082 | 1088 | |
|
1083 | 1089 | pub fn debug_get_patterns(&self) -> &[u8] { |
@@ -1105,6 +1111,9 b" impl<'a> Display for IncludeMatcher<'a> " | |||
|
1105 | 1111 | mod tests { |
|
1106 | 1112 | use super::*; |
|
1107 | 1113 | use pretty_assertions::assert_eq; |
|
1114 | use std::collections::BTreeMap; | |
|
1115 | use std::collections::BTreeSet; | |
|
1116 | use std::fmt::Debug; | |
|
1108 | 1117 | use std::path::Path; |
|
1109 | 1118 | |
|
1110 | 1119 | #[test] |
@@ -1141,9 +1150,12 b' mod tests {' | |||
|
1141 | 1150 | |
|
1142 | 1151 | let dirs = HashSet::new(); |
|
1143 | 1152 | |
|
1144 |
let |
|
|
1145 | parents.insert(HgPathBuf::new()); | |
|
1146 |
|
|
|
1153 | let parents = DirsMultiset::from_manifest(&[ | |
|
1154 | HgPathBuf::from_bytes(b"x"), | |
|
1155 | HgPathBuf::from_bytes(b"g/x"), | |
|
1156 | HgPathBuf::from_bytes(b"g/y"), | |
|
1157 | ]) | |
|
1158 | .unwrap(); | |
|
1147 | 1159 | |
|
1148 | 1160 | assert_eq!( |
|
1149 | 1161 | roots_dirs_and_parents(&pats).unwrap(), |
@@ -1316,61 +1328,60 b' mod tests {' | |||
|
1316 | 1328 | |
|
1317 | 1329 | // VisitdirRootfilesin |
|
1318 | 1330 | let m = PatternMatcher::new(vec![IgnorePattern::new( |
|
1319 | PatternSyntax::RootFiles, | |
|
1331 | PatternSyntax::RootFilesIn, | |
|
1320 | 1332 | b"dir/subdir", |
|
1321 | 1333 | Path::new(""), |
|
1322 | 1334 | )]) |
|
1323 | 1335 | .unwrap(); |
|
1324 | 1336 | assert_eq!( |
|
1325 | 1337 | m.visit_children_set(HgPath::new(b"dir/subdir/x")), |
|
1326 |
VisitChildrenSet:: |
|
|
1338 | VisitChildrenSet::This | |
|
1327 | 1339 | ); |
|
1328 | 1340 | assert_eq!( |
|
1329 | 1341 | m.visit_children_set(HgPath::new(b"folder")), |
|
1330 | 1342 | VisitChildrenSet::Empty |
|
1331 | 1343 | ); |
|
1332 | // FIXME: These should probably be This. | |
|
1333 | 1344 | assert_eq!( |
|
1334 | 1345 | m.visit_children_set(HgPath::new(b"")), |
|
1335 |
VisitChildrenSet:: |
|
|
1346 | VisitChildrenSet::This | |
|
1336 | 1347 | ); |
|
1337 | 1348 | assert_eq!( |
|
1338 | 1349 | m.visit_children_set(HgPath::new(b"dir")), |
|
1339 |
VisitChildrenSet:: |
|
|
1350 | VisitChildrenSet::This | |
|
1340 | 1351 | ); |
|
1341 | 1352 | assert_eq!( |
|
1342 | 1353 | m.visit_children_set(HgPath::new(b"dir/subdir")), |
|
1343 |
VisitChildrenSet:: |
|
|
1354 | VisitChildrenSet::This | |
|
1344 | 1355 | ); |
|
1345 | 1356 | |
|
1346 | 1357 | // VisitchildrensetRootfilesin |
|
1347 | 1358 | let m = PatternMatcher::new(vec![IgnorePattern::new( |
|
1348 | PatternSyntax::RootFiles, | |
|
1359 | PatternSyntax::RootFilesIn, | |
|
1349 | 1360 | b"dir/subdir", |
|
1350 | 1361 | Path::new(""), |
|
1351 | 1362 | )]) |
|
1352 | 1363 | .unwrap(); |
|
1353 | 1364 | assert_eq!( |
|
1354 | 1365 | m.visit_children_set(HgPath::new(b"dir/subdir/x")), |
|
1355 |
VisitChildrenSet:: |
|
|
1366 | VisitChildrenSet::This | |
|
1356 | 1367 | ); |
|
1357 | 1368 | assert_eq!( |
|
1358 | 1369 | m.visit_children_set(HgPath::new(b"folder")), |
|
1359 | 1370 | VisitChildrenSet::Empty |
|
1360 | 1371 | ); |
|
1361 | 1372 | // FIXME: These should probably be {'dir'}, {'subdir'} and This, |
|
1362 | // respectively, or at least This for all three. | |
|
1373 | // respectively | |
|
1363 | 1374 | assert_eq!( |
|
1364 | 1375 | m.visit_children_set(HgPath::new(b"")), |
|
1365 |
VisitChildrenSet:: |
|
|
1376 | VisitChildrenSet::This | |
|
1366 | 1377 | ); |
|
1367 | 1378 | assert_eq!( |
|
1368 | 1379 | m.visit_children_set(HgPath::new(b"dir")), |
|
1369 |
VisitChildrenSet:: |
|
|
1380 | VisitChildrenSet::This | |
|
1370 | 1381 | ); |
|
1371 | 1382 | assert_eq!( |
|
1372 | 1383 | m.visit_children_set(HgPath::new(b"dir/subdir")), |
|
1373 |
VisitChildrenSet:: |
|
|
1384 | VisitChildrenSet::This | |
|
1374 | 1385 | ); |
|
1375 | 1386 | |
|
1376 | 1387 | // VisitdirGlob |
@@ -1384,10 +1395,9 b' mod tests {' | |||
|
1384 | 1395 | m.visit_children_set(HgPath::new(b"")), |
|
1385 | 1396 | VisitChildrenSet::This |
|
1386 | 1397 | ); |
|
1387 | // FIXME: This probably should be This | |
|
1388 | 1398 | assert_eq!( |
|
1389 | 1399 | m.visit_children_set(HgPath::new(b"dir")), |
|
1390 |
VisitChildrenSet:: |
|
|
1400 | VisitChildrenSet::This | |
|
1391 | 1401 | ); |
|
1392 | 1402 | assert_eq!( |
|
1393 | 1403 | m.visit_children_set(HgPath::new(b"folder")), |
@@ -1418,10 +1428,9 b' mod tests {' | |||
|
1418 | 1428 | m.visit_children_set(HgPath::new(b"folder")), |
|
1419 | 1429 | VisitChildrenSet::Empty |
|
1420 | 1430 | ); |
|
1421 | // FIXME: This probably should be This | |
|
1422 | 1431 | assert_eq!( |
|
1423 | 1432 | m.visit_children_set(HgPath::new(b"dir")), |
|
1424 |
VisitChildrenSet:: |
|
|
1433 | VisitChildrenSet::This | |
|
1425 | 1434 | ); |
|
1426 | 1435 | // OPT: these should probably be Empty |
|
1427 | 1436 | assert_eq!( |
@@ -1529,7 +1538,7 b' mod tests {' | |||
|
1529 | 1538 | |
|
1530 | 1539 | // VisitchildrensetRootfilesin |
|
1531 | 1540 | let matcher = IncludeMatcher::new(vec![IgnorePattern::new( |
|
1532 | PatternSyntax::RootFiles, | |
|
1541 | PatternSyntax::RootFilesIn, | |
|
1533 | 1542 | b"dir/subdir", |
|
1534 | 1543 | Path::new(""), |
|
1535 | 1544 | )]) |
@@ -1664,7 +1673,7 b' mod tests {' | |||
|
1664 | 1673 | )]) |
|
1665 | 1674 | .unwrap(); |
|
1666 | 1675 | let m2 = IncludeMatcher::new(vec![IgnorePattern::new( |
|
1667 | PatternSyntax::RootFiles, | |
|
1676 | PatternSyntax::RootFilesIn, | |
|
1668 | 1677 | b"dir", |
|
1669 | 1678 | Path::new(""), |
|
1670 | 1679 | )]) |
@@ -1825,7 +1834,7 b' mod tests {' | |||
|
1825 | 1834 | ); |
|
1826 | 1835 | let m2 = Box::new( |
|
1827 | 1836 | IncludeMatcher::new(vec![IgnorePattern::new( |
|
1828 | PatternSyntax::RootFiles, | |
|
1837 | PatternSyntax::RootFilesIn, | |
|
1829 | 1838 | b"dir", |
|
1830 | 1839 | Path::new(""), |
|
1831 | 1840 | )]) |
@@ -2076,7 +2085,7 b' mod tests {' | |||
|
2076 | 2085 | ); |
|
2077 | 2086 | let m2 = Box::new( |
|
2078 | 2087 | IncludeMatcher::new(vec![IgnorePattern::new( |
|
2079 | PatternSyntax::RootFiles, | |
|
2088 | PatternSyntax::RootFilesIn, | |
|
2080 | 2089 | b"dir", |
|
2081 | 2090 | Path::new("/repo"), |
|
2082 | 2091 | )]) |
@@ -2119,4 +2128,323 b' mod tests {' | |||
|
2119 | 2128 | VisitChildrenSet::This |
|
2120 | 2129 | ); |
|
2121 | 2130 | } |
|
2131 | ||
|
2132 | mod invariants { | |
|
2133 | pub mod visit_children_set { | |
|
2134 | ||
|
2135 | use crate::{ | |
|
2136 | matchers::{tests::Tree, Matcher, VisitChildrenSet}, | |
|
2137 | utils::hg_path::HgPath, | |
|
2138 | }; | |
|
2139 | ||
|
2140 | #[allow(dead_code)] | |
|
2141 | #[derive(Debug)] | |
|
2142 | struct Error<'a, M> { | |
|
2143 | matcher: &'a M, | |
|
2144 | path: &'a HgPath, | |
|
2145 | matching: &'a Tree, | |
|
2146 | visit_children_set: &'a VisitChildrenSet, | |
|
2147 | } | |
|
2148 | ||
|
2149 | fn holds( | |
|
2150 | matching: &Tree, | |
|
2151 | not_matching: &Tree, | |
|
2152 | vcs: &VisitChildrenSet, | |
|
2153 | ) -> bool { | |
|
2154 | match vcs { | |
|
2155 | VisitChildrenSet::Empty => matching.is_empty(), | |
|
2156 | VisitChildrenSet::This => { | |
|
2157 | // `This` does not come with any obligations. | |
|
2158 | true | |
|
2159 | } | |
|
2160 | VisitChildrenSet::Recursive => { | |
|
2161 | // `Recursive` requires that *everything* in the | |
|
2162 | // subtree matches. This | |
|
2163 | // requirement is relied on for example in | |
|
2164 | // DifferenceMatcher implementation. | |
|
2165 | not_matching.is_empty() | |
|
2166 | } | |
|
2167 | VisitChildrenSet::Set(allowed_children) => { | |
|
2168 | // `allowed_children` does not distinguish between | |
|
2169 | // files and directories: if it's not included, it | |
|
2170 | // must not be matched. | |
|
2171 | for k in matching.dirs.keys() { | |
|
2172 | if !(allowed_children.contains(k)) { | |
|
2173 | return false; | |
|
2174 | } | |
|
2175 | } | |
|
2176 | for k in matching.files.iter() { | |
|
2177 | if !(allowed_children.contains(k)) { | |
|
2178 | return false; | |
|
2179 | } | |
|
2180 | } | |
|
2181 | true | |
|
2182 | } | |
|
2183 | } | |
|
2184 | } | |
|
2185 | ||
|
2186 | pub fn check<M: Matcher + std::fmt::Debug>( | |
|
2187 | matcher: &M, | |
|
2188 | path: &HgPath, | |
|
2189 | matching: &Tree, | |
|
2190 | not_matching: &Tree, | |
|
2191 | visit_children_set: &VisitChildrenSet, | |
|
2192 | ) { | |
|
2193 | if !holds(matching, not_matching, visit_children_set) { | |
|
2194 | panic!( | |
|
2195 | "{:#?}", | |
|
2196 | Error { | |
|
2197 | matcher, | |
|
2198 | path, | |
|
2199 | visit_children_set, | |
|
2200 | matching | |
|
2201 | } | |
|
2202 | ) | |
|
2203 | } | |
|
2204 | } | |
|
2205 | } | |
|
2206 | } | |
|
2207 | ||
|
2208 | #[derive(Debug, Clone)] | |
|
2209 | pub struct Tree { | |
|
2210 | files: BTreeSet<HgPathBuf>, | |
|
2211 | dirs: BTreeMap<HgPathBuf, Tree>, | |
|
2212 | } | |
|
2213 | ||
|
2214 | impl Tree { | |
|
2215 | fn len(&self) -> usize { | |
|
2216 | let mut n = 0; | |
|
2217 | n += self.files.len(); | |
|
2218 | for d in self.dirs.values() { | |
|
2219 | n += d.len(); | |
|
2220 | } | |
|
2221 | n | |
|
2222 | } | |
|
2223 | ||
|
2224 | fn is_empty(&self) -> bool { | |
|
2225 | self.files.is_empty() && self.dirs.is_empty() | |
|
2226 | } | |
|
2227 | ||
|
2228 | fn make( | |
|
2229 | files: BTreeSet<HgPathBuf>, | |
|
2230 | dirs: BTreeMap<HgPathBuf, Tree>, | |
|
2231 | ) -> Self { | |
|
2232 | Self { | |
|
2233 | files, | |
|
2234 | dirs: dirs | |
|
2235 | .into_iter() | |
|
2236 | .filter(|(_k, v)| (!(v.is_empty()))) | |
|
2237 | .collect(), | |
|
2238 | } | |
|
2239 | } | |
|
2240 | ||
|
2241 | fn filter_and_check<M: Matcher + Debug>( | |
|
2242 | &self, | |
|
2243 | m: &M, | |
|
2244 | path: &HgPath, | |
|
2245 | ) -> (Self, Self) { | |
|
2246 | let (files1, files2): (BTreeSet<HgPathBuf>, BTreeSet<HgPathBuf>) = | |
|
2247 | self.files | |
|
2248 | .iter() | |
|
2249 | .map(|v| v.to_owned()) | |
|
2250 | .partition(|v| m.matches(&path.join(v))); | |
|
2251 | let (dirs1, dirs2): ( | |
|
2252 | BTreeMap<HgPathBuf, Tree>, | |
|
2253 | BTreeMap<HgPathBuf, Tree>, | |
|
2254 | ) = self | |
|
2255 | .dirs | |
|
2256 | .iter() | |
|
2257 | .map(|(k, v)| { | |
|
2258 | let path = path.join(k); | |
|
2259 | let (t1, t2) = v.filter_and_check(m, &path); | |
|
2260 | ((k.clone(), t1), (k.clone(), t2)) | |
|
2261 | }) | |
|
2262 | .unzip(); | |
|
2263 | let matching = Self::make(files1, dirs1); | |
|
2264 | let not_matching = Self::make(files2, dirs2); | |
|
2265 | let vcs = m.visit_children_set(path); | |
|
2266 | invariants::visit_children_set::check( | |
|
2267 | m, | |
|
2268 | path, | |
|
2269 | &matching, | |
|
2270 | ¬_matching, | |
|
2271 | &vcs, | |
|
2272 | ); | |
|
2273 | (matching, not_matching) | |
|
2274 | } | |
|
2275 | ||
|
2276 | fn check_matcher<M: Matcher + Debug>( | |
|
2277 | &self, | |
|
2278 | m: &M, | |
|
2279 | expect_count: usize, | |
|
2280 | ) { | |
|
2281 | let res = self.filter_and_check(m, &HgPathBuf::new()); | |
|
2282 | if expect_count != res.0.len() { | |
|
2283 | eprintln!( | |
|
2284 | "warning: expected {} matches, got {} for {:#?}", | |
|
2285 | expect_count, | |
|
2286 | res.0.len(), | |
|
2287 | m | |
|
2288 | ); | |
|
2289 | } | |
|
2290 | } | |
|
2291 | } | |
|
2292 | ||
|
2293 | fn mkdir(children: &[(&[u8], &Tree)]) -> Tree { | |
|
2294 | let p = HgPathBuf::from_bytes; | |
|
2295 | let names = [ | |
|
2296 | p(b"a"), | |
|
2297 | p(b"b.txt"), | |
|
2298 | p(b"file.txt"), | |
|
2299 | p(b"c.c"), | |
|
2300 | p(b"c.h"), | |
|
2301 | p(b"dir1"), | |
|
2302 | p(b"dir2"), | |
|
2303 | p(b"subdir"), | |
|
2304 | ]; | |
|
2305 | let files: BTreeSet<HgPathBuf> = BTreeSet::from(names); | |
|
2306 | let dirs = children | |
|
2307 | .iter() | |
|
2308 | .map(|(name, t)| (p(name), (*t).clone())) | |
|
2309 | .collect(); | |
|
2310 | Tree { files, dirs } | |
|
2311 | } | |
|
2312 | ||
|
2313 | fn make_example_tree() -> Tree { | |
|
2314 | let leaf = mkdir(&[]); | |
|
2315 | let abc = mkdir(&[(b"d", &leaf)]); | |
|
2316 | let ab = mkdir(&[(b"c", &abc)]); | |
|
2317 | let a = mkdir(&[(b"b", &ab)]); | |
|
2318 | let dir = mkdir(&[(b"subdir", &leaf), (b"subdir.c", &leaf)]); | |
|
2319 | mkdir(&[(b"dir", &dir), (b"dir1", &dir), (b"dir2", &dir), (b"a", &a)]) | |
|
2320 | } | |
|
2321 | ||
|
2322 | #[test] | |
|
2323 | fn test_pattern_matcher_visit_children_set() { | |
|
2324 | let tree = make_example_tree(); | |
|
2325 | let pattern_dir1_glob_c = | |
|
2326 | PatternMatcher::new(vec![IgnorePattern::new( | |
|
2327 | PatternSyntax::Glob, | |
|
2328 | b"dir1/*.c", | |
|
2329 | Path::new(""), | |
|
2330 | )]) | |
|
2331 | .unwrap(); | |
|
2332 | let pattern_dir1 = || { | |
|
2333 | PatternMatcher::new(vec![IgnorePattern::new( | |
|
2334 | PatternSyntax::Path, | |
|
2335 | b"dir1", | |
|
2336 | Path::new(""), | |
|
2337 | )]) | |
|
2338 | .unwrap() | |
|
2339 | }; | |
|
2340 | let pattern_dir1_a = PatternMatcher::new(vec![IgnorePattern::new( | |
|
2341 | PatternSyntax::Glob, | |
|
2342 | b"dir1/a", | |
|
2343 | Path::new(""), | |
|
2344 | )]) | |
|
2345 | .unwrap(); | |
|
2346 | let pattern_relglob_c = || { | |
|
2347 | PatternMatcher::new(vec![IgnorePattern::new( | |
|
2348 | PatternSyntax::RelGlob, | |
|
2349 | b"*.c", | |
|
2350 | Path::new(""), | |
|
2351 | )]) | |
|
2352 | .unwrap() | |
|
2353 | }; | |
|
2354 | let files = vec![HgPathBuf::from_bytes(b"dir/subdir/b.txt")]; | |
|
2355 | let file_dir_subdir_b = FileMatcher::new(files).unwrap(); | |
|
2356 | ||
|
2357 | let files = vec![ | |
|
2358 | HgPathBuf::from_bytes(b"file.txt"), | |
|
2359 | HgPathBuf::from_bytes(b"a/file.txt"), | |
|
2360 | HgPathBuf::from_bytes(b"a/b/file.txt"), | |
|
2361 | // No file in a/b/c | |
|
2362 | HgPathBuf::from_bytes(b"a/b/c/d/file.txt"), | |
|
2363 | ]; | |
|
2364 | let file_abcdfile = FileMatcher::new(files).unwrap(); | |
|
2365 | let rootfilesin_dir = PatternMatcher::new(vec![IgnorePattern::new( | |
|
2366 | PatternSyntax::RootFilesIn, | |
|
2367 | b"dir", | |
|
2368 | Path::new(""), | |
|
2369 | )]) | |
|
2370 | .unwrap(); | |
|
2371 | ||
|
2372 | let pattern_filepath_dir_subdir = | |
|
2373 | PatternMatcher::new(vec![IgnorePattern::new( | |
|
2374 | PatternSyntax::FilePath, | |
|
2375 | b"dir/subdir", | |
|
2376 | Path::new(""), | |
|
2377 | )]) | |
|
2378 | .unwrap(); | |
|
2379 | ||
|
2380 | let include_dir_subdir = | |
|
2381 | IncludeMatcher::new(vec![IgnorePattern::new( | |
|
2382 | PatternSyntax::RelPath, | |
|
2383 | b"dir/subdir", | |
|
2384 | Path::new(""), | |
|
2385 | )]) | |
|
2386 | .unwrap(); | |
|
2387 | ||
|
2388 | let more_includematchers = [ | |
|
2389 | IncludeMatcher::new(vec![IgnorePattern::new( | |
|
2390 | PatternSyntax::Glob, | |
|
2391 | b"dir/s*", | |
|
2392 | Path::new(""), | |
|
2393 | )]) | |
|
2394 | .unwrap(), | |
|
2395 | // Test multiple patterns | |
|
2396 | IncludeMatcher::new(vec![ | |
|
2397 | IgnorePattern::new( | |
|
2398 | PatternSyntax::RelPath, | |
|
2399 | b"dir", | |
|
2400 | Path::new(""), | |
|
2401 | ), | |
|
2402 | IgnorePattern::new(PatternSyntax::Glob, b"s*", Path::new("")), | |
|
2403 | ]) | |
|
2404 | .unwrap(), | |
|
2405 | // Test multiple patterns | |
|
2406 | IncludeMatcher::new(vec![IgnorePattern::new( | |
|
2407 | PatternSyntax::Glob, | |
|
2408 | b"**/*.c", | |
|
2409 | Path::new(""), | |
|
2410 | )]) | |
|
2411 | .unwrap(), | |
|
2412 | ]; | |
|
2413 | ||
|
2414 | tree.check_matcher(&pattern_dir1(), 25); | |
|
2415 | tree.check_matcher(&pattern_dir1_a, 1); | |
|
2416 | tree.check_matcher(&pattern_dir1_glob_c, 2); | |
|
2417 | tree.check_matcher(&pattern_relglob_c(), 14); | |
|
2418 | tree.check_matcher(&AlwaysMatcher, 112); | |
|
2419 | tree.check_matcher(&NeverMatcher, 0); | |
|
2420 | tree.check_matcher( | |
|
2421 | &IntersectionMatcher::new( | |
|
2422 | Box::new(pattern_relglob_c()), | |
|
2423 | Box::new(pattern_dir1()), | |
|
2424 | ), | |
|
2425 | 3, | |
|
2426 | ); | |
|
2427 | tree.check_matcher( | |
|
2428 | &UnionMatcher::new(vec![ | |
|
2429 | Box::new(pattern_relglob_c()), | |
|
2430 | Box::new(pattern_dir1()), | |
|
2431 | ]), | |
|
2432 | 36, | |
|
2433 | ); | |
|
2434 | tree.check_matcher( | |
|
2435 | &DifferenceMatcher::new( | |
|
2436 | Box::new(pattern_relglob_c()), | |
|
2437 | Box::new(pattern_dir1()), | |
|
2438 | ), | |
|
2439 | 11, | |
|
2440 | ); | |
|
2441 | tree.check_matcher(&file_dir_subdir_b, 1); | |
|
2442 | tree.check_matcher(&file_abcdfile, 4); | |
|
2443 | tree.check_matcher(&rootfilesin_dir, 8); | |
|
2444 | tree.check_matcher(&pattern_filepath_dir_subdir, 1); | |
|
2445 | tree.check_matcher(&include_dir_subdir, 9); | |
|
2446 | tree.check_matcher(&more_includematchers[0], 17); | |
|
2447 | tree.check_matcher(&more_includematchers[1], 25); | |
|
2448 | tree.check_matcher(&more_includematchers[2], 35); | |
|
2449 | } | |
|
2122 | 2450 | } |
@@ -120,6 +120,10 b' pub fn find_dirs(path: &HgPath) -> Ances' | |||
|
120 | 120 | dirs |
|
121 | 121 | } |
|
122 | 122 | |
|
123 | pub fn dir_ancestors(path: &HgPath) -> Ancestors { | |
|
124 | Ancestors { next: Some(path) } | |
|
125 | } | |
|
126 | ||
|
123 | 127 | /// Returns an iterator yielding ancestor directories of the given repository |
|
124 | 128 | /// path. |
|
125 | 129 | /// |
@@ -232,6 +232,10 b' class hgcommand:' | |||
|
232 | 232 | print("stderr from '%s':" % (' '.join(cmd)), file=sys.stderr) |
|
233 | 233 | print(err, file=sys.stderr) |
|
234 | 234 | if returncode != 0: |
|
235 | print( | |
|
236 | "non zero-return '%s': %d" % (' '.join(cmd), returncode), | |
|
237 | file=sys.stderr, | |
|
238 | ) | |
|
235 | 239 | return b'' |
|
236 | 240 | return out |
|
237 | 241 |
@@ -30,7 +30,7 b' class bannerserver(wireprotoserver.sshse' | |||
|
30 | 30 | |
|
31 | 31 | def serve_forever(self): |
|
32 | 32 | for i in range(10): |
|
33 | self._fout.write(b'banner: line %d\n' % i) | |
|
33 | self._ui.fout.write(b'banner: line %d\n' % i) | |
|
34 | 34 | |
|
35 | 35 | super(bannerserver, self).serve_forever() |
|
36 | 36 | |
@@ -45,17 +45,16 b' class prehelloserver(wireprotoserver.ssh' | |||
|
45 | 45 | """ |
|
46 | 46 | |
|
47 | 47 | def serve_forever(self): |
|
48 |
|
|
|
48 | ui = self._ui | |
|
49 | l = ui.fin.readline() | |
|
49 | 50 | assert l == b'hello\n' |
|
50 | 51 | # Respond to unknown commands with an empty reply. |
|
51 |
wireprotoserver._sshv1respondbytes( |
|
|
52 |
l = |
|
|
52 | wireprotoserver._sshv1respondbytes(ui.fout, b'') | |
|
53 | l = ui.fin.readline() | |
|
53 | 54 | assert l == b'between\n' |
|
54 | proto = wireprotoserver.sshv1protocolhandler( | |
|
55 | self._ui, self._fin, self._fout | |
|
56 | ) | |
|
55 | proto = wireprotoserver.sshv1protocolhandler(ui, ui.fin, ui.fout) | |
|
57 | 56 | rsp = wireprotov1server.dispatch(self._repo, proto, b'between') |
|
58 |
wireprotoserver._sshv1respondbytes( |
|
|
57 | wireprotoserver._sshv1respondbytes(ui.fout, rsp.data) | |
|
59 | 58 | |
|
60 | 59 | super(prehelloserver, self).serve_forever() |
|
61 | 60 |
@@ -620,3 +620,93 b' Test controlling the changegroup version' | |||
|
620 | 620 | b9f5f740a8cd76700020e3903ee55ecff78bd3e5 |
|
621 | 621 | $ hg debugbundle ./v2-cg-03.hg --spec |
|
622 | 622 | bzip2-v2;cg.version=03 |
|
623 | ||
|
624 | tests controlling bundle contents | |
|
625 | ================================= | |
|
626 | ||
|
627 | $ hg debugupdatecache -R t1 | |
|
628 | ||
|
629 | default content | |
|
630 | --------------- | |
|
631 | ||
|
632 | $ hg -R t1 bundle --all --quiet --type 'v2' ./v2.hg | |
|
633 | $ hg debugbundle ./v2.hg --spec | |
|
634 | bzip2-v2 | |
|
635 | $ hg debugbundle ./v2.hg --quiet | |
|
636 | Stream params: {Compression: BZ} | |
|
637 | changegroup -- {nbchanges: 7, version: 02} (mandatory: True) | |
|
638 | hgtagsfnodes -- {} (mandatory: False) | |
|
639 | cache:rev-branch-cache -- {} (mandatory: False) | |
|
640 | ||
|
641 | $ hg -R t1 bundle --all --quiet --type 'v3' ./v3.hg | |
|
642 | $ hg debugbundle ./v3.hg --spec | |
|
643 | bzip2-v2;cg.version=03 | |
|
644 | $ hg debugbundle ./v3.hg --quiet | |
|
645 | Stream params: {Compression: BZ} | |
|
646 | changegroup -- {nbchanges: 7, targetphase: 2, version: 03} (mandatory: True) | |
|
647 | hgtagsfnodes -- {} (mandatory: False) | |
|
648 | cache:rev-branch-cache -- {} (mandatory: False) | |
|
649 | phase-heads -- {} (mandatory: True) | |
|
650 | ||
|
651 | adding extra parts | |
|
652 | ------------------ | |
|
653 | ||
|
654 | We should have a "phase-heads" part here that we did not had in the default content | |
|
655 | ||
|
656 | $ hg -R t1 bundle --all --quiet --type 'v2;phases=1' ./v2-phases.hg | |
|
657 | $ hg debugbundle ./v2-phases.hg --spec | |
|
658 | bzip2-v2 | |
|
659 | $ hg debugbundle ./v2-phases.hg --quiet | |
|
660 | Stream params: {Compression: BZ} | |
|
661 | changegroup -- {nbchanges: 7, targetphase: 2, version: 02} (mandatory: True) | |
|
662 | hgtagsfnodes -- {} (mandatory: False) | |
|
663 | cache:rev-branch-cache -- {} (mandatory: False) | |
|
664 | phase-heads -- {} (mandatory: True) | |
|
665 | ||
|
666 | skipping default inclusion | |
|
667 | -------------------------- | |
|
668 | ||
|
669 | $ hg -R t1 bundle --all --quiet --type 'v2;tagsfnodescache=false' ./v2-no-tfc.hg | |
|
670 | $ hg debugbundle ./v2-no-tfc.hg --spec | |
|
671 | bzip2-v2 | |
|
672 | $ hg debugbundle ./v2-no-tfc.hg --quiet | |
|
673 | Stream params: {Compression: BZ} | |
|
674 | changegroup -- {nbchanges: 7, version: 02} (mandatory: True) | |
|
675 | cache:rev-branch-cache -- {} (mandatory: False) | |
|
676 | ||
|
677 | $ hg -R t1 bundle --all --quiet --type 'v3;phases=0' ./v3-no-phases.hg | |
|
678 | $ hg debugbundle ./v3-no-phases.hg --spec | |
|
679 | bzip2-v2;cg.version=03 | |
|
680 | $ hg debugbundle ./v3-no-phases.hg --quiet | |
|
681 | Stream params: {Compression: BZ} | |
|
682 | changegroup -- {nbchanges: 7, version: 03} (mandatory: True) | |
|
683 | hgtagsfnodes -- {} (mandatory: False) | |
|
684 | cache:rev-branch-cache -- {} (mandatory: False) | |
|
685 | ||
|
686 | $ hg -R t1 bundle --all --quiet --type 'v3;phases=no;tagsfnodescache=0' ./v3-multi-no.hg | |
|
687 | $ hg debugbundle ./v3-multi-no.hg --spec | |
|
688 | bzip2-v2;cg.version=03 | |
|
689 | $ hg debugbundle ./v3-multi-no.hg --quiet | |
|
690 | Stream params: {Compression: BZ} | |
|
691 | changegroup -- {nbchanges: 7, version: 03} (mandatory: True) | |
|
692 | cache:rev-branch-cache -- {} (mandatory: False) | |
|
693 | ||
|
694 | skipping changegroup | |
|
695 | -------------------- | |
|
696 | ||
|
697 | $ hg -R t1 bundle --all --quiet --type 'v2;changegroup=no' ./v2-no-cg.hg | |
|
698 | $ hg debugbundle ./v2-no-cg.hg --spec | |
|
699 | bzip2-v2;changegroup=no | |
|
700 | $ hg debugbundle ./v2-no-cg.hg --quiet | |
|
701 | Stream params: {Compression: BZ} | |
|
702 | hgtagsfnodes -- {} (mandatory: False) | |
|
703 | cache:rev-branch-cache -- {} (mandatory: False) | |
|
704 | ||
|
705 | $ hg -R t1 bundle --all --quiet --type 'v3;changegroup=0' ./v3-no-cg.hg | |
|
706 | $ hg debugbundle ./v3-no-cg.hg --spec | |
|
707 | bzip2-v2;changegroup=no | |
|
708 | $ hg debugbundle ./v3-no-cg.hg --quiet | |
|
709 | Stream params: {Compression: BZ} | |
|
710 | hgtagsfnodes -- {} (mandatory: False) | |
|
711 | cache:rev-branch-cache -- {} (mandatory: False) | |
|
712 | phase-heads -- {} (mandatory: True) |
@@ -94,12 +94,14 b' class PatternMatcherTests(unittest.TestC' | |||
|
94 | 94 | patterns=[b'rootfilesin:dir/subdir'], |
|
95 | 95 | ) |
|
96 | 96 | assert isinstance(m, matchmod.patternmatcher) |
|
97 | self.assertFalse(m.visitdir(b'dir/subdir/x')) | |
|
97 | # OPT: we shouldn't visit [x] as a directory, | |
|
98 | # but we should still visit it as a file. | |
|
99 | # Unfortunately, `visitdir` is used for both. | |
|
100 | self.assertTrue(m.visitdir(b'dir/subdir/x')) | |
|
98 | 101 | self.assertFalse(m.visitdir(b'folder')) |
|
99 | # FIXME: These should probably be True. | |
|
100 |
self.assert |
|
|
101 |
self.assert |
|
|
102 | self.assertFalse(m.visitdir(b'dir/subdir')) | |
|
102 | self.assertTrue(m.visitdir(b'')) | |
|
103 | self.assertTrue(m.visitdir(b'dir')) | |
|
104 | self.assertTrue(m.visitdir(b'dir/subdir')) | |
|
103 | 105 | |
|
104 | 106 | def testVisitchildrensetRootfilesin(self): |
|
105 | 107 | m = matchmod.match( |
@@ -108,13 +110,13 b' class PatternMatcherTests(unittest.TestC' | |||
|
108 | 110 | patterns=[b'rootfilesin:dir/subdir'], |
|
109 | 111 | ) |
|
110 | 112 | assert isinstance(m, matchmod.patternmatcher) |
|
111 |
self.assertEqual(m.visitchildrenset(b'dir/subdir/x'), |
|
|
113 | self.assertEqual(m.visitchildrenset(b'dir/subdir/x'), b'this') | |
|
112 | 114 | self.assertEqual(m.visitchildrenset(b'folder'), set()) |
|
113 |
# |
|
|
114 | # respectively, or at least 'this' for all three. | |
|
115 |
self.assertEqual(m.visitchildrenset(b''), |
|
|
116 |
self.assertEqual(m.visitchildrenset(b'dir'), |
|
|
117 |
self.assertEqual(m.visitchildrenset(b'dir/subdir'), |
|
|
115 | # OPT: These should probably be {'dir'}, {'subdir'} and 'this', | |
|
116 | # respectively | |
|
117 | self.assertEqual(m.visitchildrenset(b''), b'this') | |
|
118 | self.assertEqual(m.visitchildrenset(b'dir'), b'this') | |
|
119 | self.assertEqual(m.visitchildrenset(b'dir/subdir'), b'this') | |
|
118 | 120 | |
|
119 | 121 | def testVisitdirGlob(self): |
|
120 | 122 | m = matchmod.match( |
@@ -25,9 +25,8 b' class SSHServerGetArgsTests(unittest.Tes' | |||
|
25 | 25 | |
|
26 | 26 | def assertparse(self, cmd, input, expected): |
|
27 | 27 | server = mockserver(input) |
|
28 | proto = wireprotoserver.sshv1protocolhandler( | |
|
29 | server._ui, server._fin, server._fout | |
|
30 | ) | |
|
28 | ui = server._ui | |
|
29 | proto = wireprotoserver.sshv1protocolhandler(ui, ui.fin, ui.fout) | |
|
31 | 30 | _func, spec = wireprotov1server.commands[cmd] |
|
32 | 31 | self.assertEqual(proto.getargs(spec), expected) |
|
33 | 32 | |
@@ -35,6 +34,9 b' class SSHServerGetArgsTests(unittest.Tes' | |||
|
35 | 34 | def mockserver(inbytes): |
|
36 | 35 | ui = mockui(inbytes) |
|
37 | 36 | repo = mockrepo(ui) |
|
37 | # note: this test unfortunately doesn't really test anything about | |
|
38 | # `sshserver` class anymore: the entirety of logic of that class lives | |
|
39 | # in `serveuntil`, and that function is not even called by this test. | |
|
38 | 40 | return wireprotoserver.sshserver(ui, repo) |
|
39 | 41 | |
|
40 | 42 |
@@ -842,6 +842,26 b' Check the output' | |||
|
842 | 842 | C clean |
|
843 | 843 | C subdir/clean |
|
844 | 844 | |
|
845 | Test various matchers interatction with dirstate code: | |
|
846 | ||
|
847 | $ hg status path:subdir | |
|
848 | M subdir/modified | |
|
849 | R subdir/removed | |
|
850 | ! subdir/deleted | |
|
851 | ? subdir/unknown | |
|
852 | ||
|
853 | $ hg status 'glob:subdir/*' | |
|
854 | M subdir/modified | |
|
855 | R subdir/removed | |
|
856 | ! subdir/deleted | |
|
857 | ? subdir/unknown | |
|
858 | ||
|
859 | $ hg status rootfilesin:subdir | |
|
860 | M subdir/modified | |
|
861 | R subdir/removed | |
|
862 | ! subdir/deleted | |
|
863 | ? subdir/unknown | |
|
864 | ||
|
845 | 865 | Note: `hg status some-name` creates a patternmatcher which is not supported |
|
846 | 866 | yet by the Rust implementation of status, but includematcher is supported. |
|
847 | 867 | --include is used below for that reason |
General Comments 0
You need to be logged in to leave comments.
Login now