##// END OF EJS Templates
branching: merge stable into default
Raphaël Gomès -
r52493:ee1b648e merge default
parent child Browse files
Show More
@@ -179,6 +179,9 b' bundle_spec_param_processing = {'
179 b"obsolescence": param_bool,
179 b"obsolescence": param_bool,
180 b"obsolescence-mandatory": param_bool,
180 b"obsolescence-mandatory": param_bool,
181 b"phases": param_bool,
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 params[b'obsolescence-mandatory'] = b'no'
158 params[b'obsolescence-mandatory'] = b'no'
159
159
160 if not version:
160 if not version:
161 raise error.Abort(
161 params[b'changegroup'] = b'no'
162 _(b'could not identify changegroup version in bundle')
162 version = b'v2'
163 )
164 spec = b'%s-%s' % (comp, version)
163 spec = b'%s-%s' % (comp, version)
165 if params:
164 if params:
166 spec += b';'
165 spec += b';'
@@ -638,7 +638,10 b' class patternmatcher(basematcher):'
638 super(patternmatcher, self).__init__(badfn)
638 super(patternmatcher, self).__init__(badfn)
639 kindpats.sort()
639 kindpats.sort()
640
640
641 roots, dirs, parents = _rootsdirsandparents(kindpats)
641 self._files = _explicitfiles(kindpats)
642 self._files = _explicitfiles(kindpats)
643 self._dirs_explicit = set(dirs)
644 self._dirs = parents
642 self._prefix = _prefix(kindpats)
645 self._prefix = _prefix(kindpats)
643 self._pats, self._matchfn = _buildmatch(kindpats, b'$', root)
646 self._pats, self._matchfn = _buildmatch(kindpats, b'$', root)
644
647
@@ -647,14 +650,14 b' class patternmatcher(basematcher):'
647 return True
650 return True
648 return self._matchfn(fn)
651 return self._matchfn(fn)
649
652
650 @propertycache
651 def _dirs(self):
652 return set(pathutil.dirs(self._fileset))
653
654 def visitdir(self, dir):
653 def visitdir(self, dir):
655 if self._prefix and dir in self._fileset:
654 if self._prefix and dir in self._fileset:
656 return b'all'
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 def visitchildrenset(self, dir):
662 def visitchildrenset(self, dir):
660 ret = self.visitdir(dir)
663 ret = self.visitdir(dir)
@@ -1461,7 +1464,7 b' def _buildregexmatch(kindpats, globsuffi'
1461 allgroups = []
1464 allgroups = []
1462 regexps = []
1465 regexps = []
1463 exact = set()
1466 exact = set()
1464 for (kind, pattern, _source) in kindpats:
1467 for kind, pattern, _source in kindpats:
1465 if kind == b'filepath':
1468 if kind == b'filepath':
1466 exact.add(pattern)
1469 exact.add(pattern)
1467 continue
1470 continue
@@ -527,24 +527,34 b' class sshserver:'
527 def __init__(self, ui, repo, logfh=None, accesshidden=False):
527 def __init__(self, ui, repo, logfh=None, accesshidden=False):
528 self._ui = ui
528 self._ui = ui
529 self._repo = repo
529 self._repo = repo
530 self._fin, self._fout = ui.protectfinout()
531 self._accesshidden = accesshidden
530 self._accesshidden = accesshidden
532
531 self._logfh = logfh
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 )
541
532
542 def serve_forever(self):
533 def serve_forever(self):
543 self.serveuntil(threading.Event())
534 self.serveuntil(threading.Event())
544 self._ui.restorefinout(self._fin, self._fout)
545
535
546 def serveuntil(self, ev):
536 def serveuntil(self, ev):
547 """Serve until a threading.Event is set."""
537 """Serve until a threading.Event is set."""
548 _runsshserver(
538 with self._ui.protectedfinout() as (fin, fout):
549 self._ui, self._repo, self._fin, self._fout, ev, self._accesshidden
539 if self._logfh:
550 )
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 impl<'a> DirsChildrenMultiset<'a> {
160 impl<'a> DirsChildrenMultiset<'a> {
161 pub fn new(
161 pub fn new<I: Iterator<Item = &'a HgPathBuf>>(
162 paths: impl Iterator<Item = &'a HgPathBuf>,
162 paths: impl Iterator<Item = &'a HgPathBuf>,
163 only_include: Option<&'a HashSet<impl AsRef<HgPath> + 'a>>,
163 only_include: Option<I>,
164 ) -> Self {
164 ) -> Self {
165 let mut new = Self {
165 let mut new = Self {
166 inner: HashMap::default(),
166 inner: HashMap::default(),
167 only_include: only_include
167 only_include: only_include.map(|s| s.map(AsRef::as_ref).collect()),
168 .map(|s| s.iter().map(AsRef::as_ref).collect()),
169 };
168 };
170
169
171 for path in paths {
170 for path in paths {
@@ -57,7 +57,7 b' pub enum PatternSyntax {'
57 RelRegexp,
57 RelRegexp,
58 /// A path relative to repository root, which is matched non-recursively
58 /// A path relative to repository root, which is matched non-recursively
59 /// (will not match subdirectories)
59 /// (will not match subdirectories)
60 RootFiles,
60 RootFilesIn,
61 /// A file of patterns to read and include
61 /// A file of patterns to read and include
62 Include,
62 Include,
63 /// A file of patterns to match against files under the same directory
63 /// A file of patterns to match against files under the same directory
@@ -158,7 +158,7 b' pub fn parse_pattern_syntax('
158 b"path:" => Ok(PatternSyntax::Path),
158 b"path:" => Ok(PatternSyntax::Path),
159 b"filepath:" => Ok(PatternSyntax::FilePath),
159 b"filepath:" => Ok(PatternSyntax::FilePath),
160 b"relpath:" => Ok(PatternSyntax::RelPath),
160 b"relpath:" => Ok(PatternSyntax::RelPath),
161 b"rootfilesin:" => Ok(PatternSyntax::RootFiles),
161 b"rootfilesin:" => Ok(PatternSyntax::RootFilesIn),
162 b"relglob:" => Ok(PatternSyntax::RelGlob),
162 b"relglob:" => Ok(PatternSyntax::RelGlob),
163 b"relre:" => Ok(PatternSyntax::RelRegexp),
163 b"relre:" => Ok(PatternSyntax::RelRegexp),
164 b"glob:" => Ok(PatternSyntax::Glob),
164 b"glob:" => Ok(PatternSyntax::Glob),
@@ -227,7 +227,7 b' fn _build_single_regex(entry: &IgnorePat'
227 }
227 }
228 [escape_pattern(pattern).as_slice(), b"(?:/|$)"].concat()
228 [escape_pattern(pattern).as_slice(), b"(?:/|$)"].concat()
229 }
229 }
230 PatternSyntax::RootFiles => {
230 PatternSyntax::RootFilesIn => {
231 let mut res = if pattern == b"." {
231 let mut res = if pattern == b"." {
232 vec![]
232 vec![]
233 } else {
233 } else {
@@ -316,7 +316,7 b' pub fn build_single_regex('
316 | PatternSyntax::Path
316 | PatternSyntax::Path
317 | PatternSyntax::RelGlob
317 | PatternSyntax::RelGlob
318 | PatternSyntax::RelPath
318 | PatternSyntax::RelPath
319 | PatternSyntax::RootFiles => normalize_path_bytes(pattern),
319 | PatternSyntax::RootFilesIn => normalize_path_bytes(pattern),
320 PatternSyntax::Include | PatternSyntax::SubInclude => {
320 PatternSyntax::Include | PatternSyntax::SubInclude => {
321 return Err(PatternError::NonRegexPattern(entry.clone()))
321 return Err(PatternError::NonRegexPattern(entry.clone()))
322 }
322 }
@@ -342,7 +342,7 b' lazy_static! {'
342 m.insert(b"path:".as_ref(), PatternSyntax::Path);
342 m.insert(b"path:".as_ref(), PatternSyntax::Path);
343 m.insert(b"filepath:".as_ref(), PatternSyntax::FilePath);
343 m.insert(b"filepath:".as_ref(), PatternSyntax::FilePath);
344 m.insert(b"relpath:".as_ref(), PatternSyntax::RelPath);
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 m.insert(b"relglob:".as_ref(), PatternSyntax::RelGlob);
346 m.insert(b"relglob:".as_ref(), PatternSyntax::RelGlob);
347 m.insert(b"relre:".as_ref(), PatternSyntax::RelRegexp);
347 m.insert(b"relre:".as_ref(), PatternSyntax::RelRegexp);
348 m.insert(b"glob:".as_ref(), PatternSyntax::Glob);
348 m.insert(b"glob:".as_ref(), PatternSyntax::Glob);
@@ -385,7 +385,7 b' pub fn parse_one_pattern('
385 | PatternSyntax::Glob
385 | PatternSyntax::Glob
386 | PatternSyntax::RelGlob
386 | PatternSyntax::RelGlob
387 | PatternSyntax::RelPath
387 | PatternSyntax::RelPath
388 | PatternSyntax::RootFiles
388 | PatternSyntax::RootFilesIn
389 if normalize =>
389 if normalize =>
390 {
390 {
391 normalize_path_bytes(pattern_bytes)
391 normalize_path_bytes(pattern_bytes)
@@ -17,7 +17,7 b' use crate::{'
17 PatternFileWarning, PatternResult,
17 PatternFileWarning, PatternResult,
18 },
18 },
19 utils::{
19 utils::{
20 files::find_dirs,
20 files::{dir_ancestors, find_dirs},
21 hg_path::{HgPath, HgPathBuf, HgPathError},
21 hg_path::{HgPath, HgPathBuf, HgPathError},
22 Escaped,
22 Escaped,
23 },
23 },
@@ -35,12 +35,14 b' use std::{borrow::ToOwned, collections::'
35 pub enum VisitChildrenSet {
35 pub enum VisitChildrenSet {
36 /// Don't visit anything
36 /// Don't visit anything
37 Empty,
37 Empty,
38 /// Only visit this directory
38 /// Visit this directory and probably its children
39 This,
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 /// TODO Should we implement a `NonEmptyHashSet`?
42 /// TODO Should we implement a `NonEmptyHashSet`?
42 Set(HashSet<HgPathBuf>),
43 Set(HashSet<HgPathBuf>),
43 /// Visit this directory and all subdirectories
44 /// Visit this directory and all subdirectories
45 /// (you can stop asking about the children set)
44 Recursive,
46 Recursive,
45 }
47 }
46
48
@@ -297,6 +299,7 b" pub struct PatternMatcher<'a> {"
297 /// Whether all the patterns match a prefix (i.e. recursively)
299 /// Whether all the patterns match a prefix (i.e. recursively)
298 prefix: bool,
300 prefix: bool,
299 files: HashSet<HgPathBuf>,
301 files: HashSet<HgPathBuf>,
302 dirs_explicit: HashSet<HgPathBuf>,
300 dirs: DirsMultiset,
303 dirs: DirsMultiset,
301 }
304 }
302
305
@@ -313,8 +316,13 b' impl core::fmt::Debug for PatternMatcher'
313
316
314 impl<'a> PatternMatcher<'a> {
317 impl<'a> PatternMatcher<'a> {
315 pub fn new(ignore_patterns: Vec<IgnorePattern>) -> PatternResult<Self> {
318 pub fn new(ignore_patterns: Vec<IgnorePattern>) -> PatternResult<Self> {
316 let (files, _) = roots_and_dirs(&ignore_patterns);
319 let RootsDirsAndParents {
317 let dirs = DirsMultiset::from_manifest(&files)?;
320 roots,
321 dirs: dirs_explicit,
322 parents,
323 } = roots_dirs_and_parents(&ignore_patterns)?;
324 let files = roots;
325 let dirs = parents;
318 let files: HashSet<HgPathBuf> = HashSet::from_iter(files);
326 let files: HashSet<HgPathBuf> = HashSet::from_iter(files);
319
327
320 let prefix = ignore_patterns.iter().all(|k| {
328 let prefix = ignore_patterns.iter().all(|k| {
@@ -328,6 +336,7 b" impl<'a> PatternMatcher<'a> {"
328 prefix,
336 prefix,
329 files,
337 files,
330 dirs,
338 dirs,
339 dirs_explicit,
331 })
340 })
332 }
341 }
333 }
342 }
@@ -352,9 +361,13 b" impl<'a> Matcher for PatternMatcher<'a> "
352 if self.prefix && self.files.contains(directory) {
361 if self.prefix && self.files.contains(directory) {
353 return VisitChildrenSet::Recursive;
362 return VisitChildrenSet::Recursive;
354 }
363 }
355 let path_or_parents_in_set = find_dirs(directory)
364 if self.dirs.contains(directory) {
356 .any(|parent_dir| self.files.contains(parent_dir));
365 return VisitChildrenSet::This;
357 if self.dirs.contains(directory) || path_or_parents_in_set {
366 }
367 if dir_ancestors(directory).any(|parent_dir| {
368 self.files.contains(parent_dir)
369 || self.dirs_explicit.contains(parent_dir)
370 }) {
358 VisitChildrenSet::This
371 VisitChildrenSet::This
359 } else {
372 } else {
360 VisitChildrenSet::Empty
373 VisitChildrenSet::Empty
@@ -390,7 +403,7 b" impl<'a> Matcher for PatternMatcher<'a> "
390 /// assert_eq!(matcher.matches(HgPath::new(b"but not this")), false);
403 /// assert_eq!(matcher.matches(HgPath::new(b"but not this")), false);
391 /// ///
404 /// ///
392 /// let ignore_patterns =
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 /// let matcher = IncludeMatcher::new(ignore_patterns).unwrap();
407 /// let matcher = IncludeMatcher::new(ignore_patterns).unwrap();
395 /// ///
408 /// ///
396 /// assert!(!matcher.matches(HgPath::new(b"file")));
409 /// assert!(!matcher.matches(HgPath::new(b"file")));
@@ -405,7 +418,7 b" pub struct IncludeMatcher<'a> {"
405 prefix: bool,
418 prefix: bool,
406 roots: HashSet<HgPathBuf>,
419 roots: HashSet<HgPathBuf>,
407 dirs: HashSet<HgPathBuf>,
420 dirs: HashSet<HgPathBuf>,
408 parents: HashSet<HgPathBuf>,
421 parents: DirsMultiset,
409 }
422 }
410
423
411 impl core::fmt::Debug for IncludeMatcher<'_> {
424 impl core::fmt::Debug for IncludeMatcher<'_> {
@@ -861,7 +874,7 b' fn roots_and_dirs('
861 });
874 });
862 roots.push(pat.to_owned());
875 roots.push(pat.to_owned());
863 }
876 }
864 PatternSyntax::RootFiles => {
877 PatternSyntax::RootFilesIn => {
865 let pat = if pattern == b"." {
878 let pat = if pattern == b"." {
866 &[] as &[u8]
879 &[] as &[u8]
867 } else {
880 } else {
@@ -885,7 +898,7 b' struct RootsDirsAndParents {'
885 /// Directories to match non-recursively
898 /// Directories to match non-recursively
886 pub dirs: HashSet<HgPathBuf>,
899 pub dirs: HashSet<HgPathBuf>,
887 /// Implicitly required directories to go to items in either roots or dirs
900 /// Implicitly required directories to go to items in either roots or dirs
888 pub parents: HashSet<HgPathBuf>,
901 pub parents: DirsMultiset,
889 }
902 }
890
903
891 /// Extract roots, dirs and parents from patterns.
904 /// Extract roots, dirs and parents from patterns.
@@ -894,18 +907,11 b' fn roots_dirs_and_parents('
894 ) -> PatternResult<RootsDirsAndParents> {
907 ) -> PatternResult<RootsDirsAndParents> {
895 let (roots, dirs) = roots_and_dirs(ignore_patterns);
908 let (roots, dirs) = roots_and_dirs(ignore_patterns);
896
909
897 let mut parents = HashSet::new();
910 let mut parents = DirsMultiset::from_manifest(&dirs)?;
898
911
899 parents.extend(
912 for path in &roots {
900 DirsMultiset::from_manifest(&dirs)?
913 parents.add_path(path)?
901 .iter()
914 }
902 .map(ToOwned::to_owned),
903 );
904 parents.extend(
905 DirsMultiset::from_manifest(&roots)?
906 .iter()
907 .map(ToOwned::to_owned),
908 );
909
915
910 Ok(RootsDirsAndParents {
916 Ok(RootsDirsAndParents {
911 roots: HashSet::from_iter(roots),
917 roots: HashSet::from_iter(roots),
@@ -958,7 +964,7 b" fn build_match<'a>("
958 // with a regex.
964 // with a regex.
959 if ignore_patterns
965 if ignore_patterns
960 .iter()
966 .iter()
961 .all(|k| k.syntax == PatternSyntax::RootFiles)
967 .all(|k| k.syntax == PatternSyntax::RootFilesIn)
962 {
968 {
963 let dirs: HashSet<_> = ignore_patterns
969 let dirs: HashSet<_> = ignore_patterns
964 .iter()
970 .iter()
@@ -1077,7 +1083,7 b" impl<'a> IncludeMatcher<'a> {"
1077 .iter()
1083 .iter()
1078 .chain(self.roots.iter())
1084 .chain(self.roots.iter())
1079 .chain(self.parents.iter());
1085 .chain(self.parents.iter());
1080 DirsChildrenMultiset::new(thing, Some(&self.parents))
1086 DirsChildrenMultiset::new(thing, Some(self.parents.iter()))
1081 }
1087 }
1082
1088
1083 pub fn debug_get_patterns(&self) -> &[u8] {
1089 pub fn debug_get_patterns(&self) -> &[u8] {
@@ -1105,6 +1111,9 b" impl<'a> Display for IncludeMatcher<'a> "
1105 mod tests {
1111 mod tests {
1106 use super::*;
1112 use super::*;
1107 use pretty_assertions::assert_eq;
1113 use pretty_assertions::assert_eq;
1114 use std::collections::BTreeMap;
1115 use std::collections::BTreeSet;
1116 use std::fmt::Debug;
1108 use std::path::Path;
1117 use std::path::Path;
1109
1118
1110 #[test]
1119 #[test]
@@ -1141,9 +1150,12 b' mod tests {'
1141
1150
1142 let dirs = HashSet::new();
1151 let dirs = HashSet::new();
1143
1152
1144 let mut parents = HashSet::new();
1153 let parents = DirsMultiset::from_manifest(&[
1145 parents.insert(HgPathBuf::new());
1154 HgPathBuf::from_bytes(b"x"),
1146 parents.insert(HgPathBuf::from_bytes(b"g"));
1155 HgPathBuf::from_bytes(b"g/x"),
1156 HgPathBuf::from_bytes(b"g/y"),
1157 ])
1158 .unwrap();
1147
1159
1148 assert_eq!(
1160 assert_eq!(
1149 roots_dirs_and_parents(&pats).unwrap(),
1161 roots_dirs_and_parents(&pats).unwrap(),
@@ -1316,61 +1328,60 b' mod tests {'
1316
1328
1317 // VisitdirRootfilesin
1329 // VisitdirRootfilesin
1318 let m = PatternMatcher::new(vec![IgnorePattern::new(
1330 let m = PatternMatcher::new(vec![IgnorePattern::new(
1319 PatternSyntax::RootFiles,
1331 PatternSyntax::RootFilesIn,
1320 b"dir/subdir",
1332 b"dir/subdir",
1321 Path::new(""),
1333 Path::new(""),
1322 )])
1334 )])
1323 .unwrap();
1335 .unwrap();
1324 assert_eq!(
1336 assert_eq!(
1325 m.visit_children_set(HgPath::new(b"dir/subdir/x")),
1337 m.visit_children_set(HgPath::new(b"dir/subdir/x")),
1326 VisitChildrenSet::Empty
1338 VisitChildrenSet::This
1327 );
1339 );
1328 assert_eq!(
1340 assert_eq!(
1329 m.visit_children_set(HgPath::new(b"folder")),
1341 m.visit_children_set(HgPath::new(b"folder")),
1330 VisitChildrenSet::Empty
1342 VisitChildrenSet::Empty
1331 );
1343 );
1332 // FIXME: These should probably be This.
1333 assert_eq!(
1344 assert_eq!(
1334 m.visit_children_set(HgPath::new(b"")),
1345 m.visit_children_set(HgPath::new(b"")),
1335 VisitChildrenSet::Empty
1346 VisitChildrenSet::This
1336 );
1347 );
1337 assert_eq!(
1348 assert_eq!(
1338 m.visit_children_set(HgPath::new(b"dir")),
1349 m.visit_children_set(HgPath::new(b"dir")),
1339 VisitChildrenSet::Empty
1350 VisitChildrenSet::This
1340 );
1351 );
1341 assert_eq!(
1352 assert_eq!(
1342 m.visit_children_set(HgPath::new(b"dir/subdir")),
1353 m.visit_children_set(HgPath::new(b"dir/subdir")),
1343 VisitChildrenSet::Empty
1354 VisitChildrenSet::This
1344 );
1355 );
1345
1356
1346 // VisitchildrensetRootfilesin
1357 // VisitchildrensetRootfilesin
1347 let m = PatternMatcher::new(vec![IgnorePattern::new(
1358 let m = PatternMatcher::new(vec![IgnorePattern::new(
1348 PatternSyntax::RootFiles,
1359 PatternSyntax::RootFilesIn,
1349 b"dir/subdir",
1360 b"dir/subdir",
1350 Path::new(""),
1361 Path::new(""),
1351 )])
1362 )])
1352 .unwrap();
1363 .unwrap();
1353 assert_eq!(
1364 assert_eq!(
1354 m.visit_children_set(HgPath::new(b"dir/subdir/x")),
1365 m.visit_children_set(HgPath::new(b"dir/subdir/x")),
1355 VisitChildrenSet::Empty
1366 VisitChildrenSet::This
1356 );
1367 );
1357 assert_eq!(
1368 assert_eq!(
1358 m.visit_children_set(HgPath::new(b"folder")),
1369 m.visit_children_set(HgPath::new(b"folder")),
1359 VisitChildrenSet::Empty
1370 VisitChildrenSet::Empty
1360 );
1371 );
1361 // FIXME: These should probably be {'dir'}, {'subdir'} and This,
1372 // FIXME: These should probably be {'dir'}, {'subdir'} and This,
1362 // respectively, or at least This for all three.
1373 // respectively
1363 assert_eq!(
1374 assert_eq!(
1364 m.visit_children_set(HgPath::new(b"")),
1375 m.visit_children_set(HgPath::new(b"")),
1365 VisitChildrenSet::Empty
1376 VisitChildrenSet::This
1366 );
1377 );
1367 assert_eq!(
1378 assert_eq!(
1368 m.visit_children_set(HgPath::new(b"dir")),
1379 m.visit_children_set(HgPath::new(b"dir")),
1369 VisitChildrenSet::Empty
1380 VisitChildrenSet::This
1370 );
1381 );
1371 assert_eq!(
1382 assert_eq!(
1372 m.visit_children_set(HgPath::new(b"dir/subdir")),
1383 m.visit_children_set(HgPath::new(b"dir/subdir")),
1373 VisitChildrenSet::Empty
1384 VisitChildrenSet::This
1374 );
1385 );
1375
1386
1376 // VisitdirGlob
1387 // VisitdirGlob
@@ -1384,10 +1395,9 b' mod tests {'
1384 m.visit_children_set(HgPath::new(b"")),
1395 m.visit_children_set(HgPath::new(b"")),
1385 VisitChildrenSet::This
1396 VisitChildrenSet::This
1386 );
1397 );
1387 // FIXME: This probably should be This
1388 assert_eq!(
1398 assert_eq!(
1389 m.visit_children_set(HgPath::new(b"dir")),
1399 m.visit_children_set(HgPath::new(b"dir")),
1390 VisitChildrenSet::Empty
1400 VisitChildrenSet::This
1391 );
1401 );
1392 assert_eq!(
1402 assert_eq!(
1393 m.visit_children_set(HgPath::new(b"folder")),
1403 m.visit_children_set(HgPath::new(b"folder")),
@@ -1418,10 +1428,9 b' mod tests {'
1418 m.visit_children_set(HgPath::new(b"folder")),
1428 m.visit_children_set(HgPath::new(b"folder")),
1419 VisitChildrenSet::Empty
1429 VisitChildrenSet::Empty
1420 );
1430 );
1421 // FIXME: This probably should be This
1422 assert_eq!(
1431 assert_eq!(
1423 m.visit_children_set(HgPath::new(b"dir")),
1432 m.visit_children_set(HgPath::new(b"dir")),
1424 VisitChildrenSet::Empty
1433 VisitChildrenSet::This
1425 );
1434 );
1426 // OPT: these should probably be Empty
1435 // OPT: these should probably be Empty
1427 assert_eq!(
1436 assert_eq!(
@@ -1529,7 +1538,7 b' mod tests {'
1529
1538
1530 // VisitchildrensetRootfilesin
1539 // VisitchildrensetRootfilesin
1531 let matcher = IncludeMatcher::new(vec![IgnorePattern::new(
1540 let matcher = IncludeMatcher::new(vec![IgnorePattern::new(
1532 PatternSyntax::RootFiles,
1541 PatternSyntax::RootFilesIn,
1533 b"dir/subdir",
1542 b"dir/subdir",
1534 Path::new(""),
1543 Path::new(""),
1535 )])
1544 )])
@@ -1664,7 +1673,7 b' mod tests {'
1664 )])
1673 )])
1665 .unwrap();
1674 .unwrap();
1666 let m2 = IncludeMatcher::new(vec![IgnorePattern::new(
1675 let m2 = IncludeMatcher::new(vec![IgnorePattern::new(
1667 PatternSyntax::RootFiles,
1676 PatternSyntax::RootFilesIn,
1668 b"dir",
1677 b"dir",
1669 Path::new(""),
1678 Path::new(""),
1670 )])
1679 )])
@@ -1825,7 +1834,7 b' mod tests {'
1825 );
1834 );
1826 let m2 = Box::new(
1835 let m2 = Box::new(
1827 IncludeMatcher::new(vec![IgnorePattern::new(
1836 IncludeMatcher::new(vec![IgnorePattern::new(
1828 PatternSyntax::RootFiles,
1837 PatternSyntax::RootFilesIn,
1829 b"dir",
1838 b"dir",
1830 Path::new(""),
1839 Path::new(""),
1831 )])
1840 )])
@@ -2076,7 +2085,7 b' mod tests {'
2076 );
2085 );
2077 let m2 = Box::new(
2086 let m2 = Box::new(
2078 IncludeMatcher::new(vec![IgnorePattern::new(
2087 IncludeMatcher::new(vec![IgnorePattern::new(
2079 PatternSyntax::RootFiles,
2088 PatternSyntax::RootFilesIn,
2080 b"dir",
2089 b"dir",
2081 Path::new("/repo"),
2090 Path::new("/repo"),
2082 )])
2091 )])
@@ -2119,4 +2128,323 b' mod tests {'
2119 VisitChildrenSet::This
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 &not_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 dirs
120 dirs
121 }
121 }
122
122
123 pub fn dir_ancestors(path: &HgPath) -> Ancestors {
124 Ancestors { next: Some(path) }
125 }
126
123 /// Returns an iterator yielding ancestor directories of the given repository
127 /// Returns an iterator yielding ancestor directories of the given repository
124 /// path.
128 /// path.
125 ///
129 ///
@@ -232,6 +232,10 b' class hgcommand:'
232 print("stderr from '%s':" % (' '.join(cmd)), file=sys.stderr)
232 print("stderr from '%s':" % (' '.join(cmd)), file=sys.stderr)
233 print(err, file=sys.stderr)
233 print(err, file=sys.stderr)
234 if returncode != 0:
234 if returncode != 0:
235 print(
236 "non zero-return '%s': %d" % (' '.join(cmd), returncode),
237 file=sys.stderr,
238 )
235 return b''
239 return b''
236 return out
240 return out
237
241
@@ -30,7 +30,7 b' class bannerserver(wireprotoserver.sshse'
30
30
31 def serve_forever(self):
31 def serve_forever(self):
32 for i in range(10):
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 super(bannerserver, self).serve_forever()
35 super(bannerserver, self).serve_forever()
36
36
@@ -45,17 +45,16 b' class prehelloserver(wireprotoserver.ssh'
45 """
45 """
46
46
47 def serve_forever(self):
47 def serve_forever(self):
48 l = self._fin.readline()
48 ui = self._ui
49 l = ui.fin.readline()
49 assert l == b'hello\n'
50 assert l == b'hello\n'
50 # Respond to unknown commands with an empty reply.
51 # Respond to unknown commands with an empty reply.
51 wireprotoserver._sshv1respondbytes(self._fout, b'')
52 wireprotoserver._sshv1respondbytes(ui.fout, b'')
52 l = self._fin.readline()
53 l = ui.fin.readline()
53 assert l == b'between\n'
54 assert l == b'between\n'
54 proto = wireprotoserver.sshv1protocolhandler(
55 proto = wireprotoserver.sshv1protocolhandler(ui, ui.fin, ui.fout)
55 self._ui, self._fin, self._fout
56 )
57 rsp = wireprotov1server.dispatch(self._repo, proto, b'between')
56 rsp = wireprotov1server.dispatch(self._repo, proto, b'between')
58 wireprotoserver._sshv1respondbytes(self._fout, rsp.data)
57 wireprotoserver._sshv1respondbytes(ui.fout, rsp.data)
59
58
60 super(prehelloserver, self).serve_forever()
59 super(prehelloserver, self).serve_forever()
61
60
@@ -620,3 +620,93 b' Test controlling the changegroup version'
620 b9f5f740a8cd76700020e3903ee55ecff78bd3e5
620 b9f5f740a8cd76700020e3903ee55ecff78bd3e5
621 $ hg debugbundle ./v2-cg-03.hg --spec
621 $ hg debugbundle ./v2-cg-03.hg --spec
622 bzip2-v2;cg.version=03
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 patterns=[b'rootfilesin:dir/subdir'],
94 patterns=[b'rootfilesin:dir/subdir'],
95 )
95 )
96 assert isinstance(m, matchmod.patternmatcher)
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 self.assertFalse(m.visitdir(b'folder'))
101 self.assertFalse(m.visitdir(b'folder'))
99 # FIXME: These should probably be True.
102 self.assertTrue(m.visitdir(b''))
100 self.assertFalse(m.visitdir(b''))
103 self.assertTrue(m.visitdir(b'dir'))
101 self.assertFalse(m.visitdir(b'dir'))
104 self.assertTrue(m.visitdir(b'dir/subdir'))
102 self.assertFalse(m.visitdir(b'dir/subdir'))
103
105
104 def testVisitchildrensetRootfilesin(self):
106 def testVisitchildrensetRootfilesin(self):
105 m = matchmod.match(
107 m = matchmod.match(
@@ -108,13 +110,13 b' class PatternMatcherTests(unittest.TestC'
108 patterns=[b'rootfilesin:dir/subdir'],
110 patterns=[b'rootfilesin:dir/subdir'],
109 )
111 )
110 assert isinstance(m, matchmod.patternmatcher)
112 assert isinstance(m, matchmod.patternmatcher)
111 self.assertEqual(m.visitchildrenset(b'dir/subdir/x'), set())
113 self.assertEqual(m.visitchildrenset(b'dir/subdir/x'), b'this')
112 self.assertEqual(m.visitchildrenset(b'folder'), set())
114 self.assertEqual(m.visitchildrenset(b'folder'), set())
113 # FIXME: These should probably be {'dir'}, {'subdir'} and 'this',
115 # OPT: These should probably be {'dir'}, {'subdir'} and 'this',
114 # respectively, or at least 'this' for all three.
116 # respectively
115 self.assertEqual(m.visitchildrenset(b''), set())
117 self.assertEqual(m.visitchildrenset(b''), b'this')
116 self.assertEqual(m.visitchildrenset(b'dir'), set())
118 self.assertEqual(m.visitchildrenset(b'dir'), b'this')
117 self.assertEqual(m.visitchildrenset(b'dir/subdir'), set())
119 self.assertEqual(m.visitchildrenset(b'dir/subdir'), b'this')
118
120
119 def testVisitdirGlob(self):
121 def testVisitdirGlob(self):
120 m = matchmod.match(
122 m = matchmod.match(
@@ -25,9 +25,8 b' class SSHServerGetArgsTests(unittest.Tes'
25
25
26 def assertparse(self, cmd, input, expected):
26 def assertparse(self, cmd, input, expected):
27 server = mockserver(input)
27 server = mockserver(input)
28 proto = wireprotoserver.sshv1protocolhandler(
28 ui = server._ui
29 server._ui, server._fin, server._fout
29 proto = wireprotoserver.sshv1protocolhandler(ui, ui.fin, ui.fout)
30 )
31 _func, spec = wireprotov1server.commands[cmd]
30 _func, spec = wireprotov1server.commands[cmd]
32 self.assertEqual(proto.getargs(spec), expected)
31 self.assertEqual(proto.getargs(spec), expected)
33
32
@@ -35,6 +34,9 b' class SSHServerGetArgsTests(unittest.Tes'
35 def mockserver(inbytes):
34 def mockserver(inbytes):
36 ui = mockui(inbytes)
35 ui = mockui(inbytes)
37 repo = mockrepo(ui)
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 return wireprotoserver.sshserver(ui, repo)
40 return wireprotoserver.sshserver(ui, repo)
39
41
40
42
@@ -842,6 +842,26 b' Check the output'
842 C clean
842 C clean
843 C subdir/clean
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 Note: `hg status some-name` creates a patternmatcher which is not supported
865 Note: `hg status some-name` creates a patternmatcher which is not supported
846 yet by the Rust implementation of status, but includematcher is supported.
866 yet by the Rust implementation of status, but includematcher is supported.
847 --include is used below for that reason
867 --include is used below for that reason
General Comments 0
You need to be logged in to leave comments. Login now