387 break |
387 break |
388 name = dirname |
388 name = dirname |
389 |
389 |
390 raise Abort('%s not under root' % myname) |
390 raise Abort('%s not under root' % myname) |
391 |
391 |
392 def matcher(canonroot, cwd='', names=['.'], inc=[], exc=[], head='', src=None): |
392 def matcher(canonroot, cwd='', names=[], inc=[], exc=[], src=None): |
393 return _matcher(canonroot, cwd, names, inc, exc, head, 'glob', src) |
393 return _matcher(canonroot, cwd, names, inc, exc, 'glob', src) |
394 |
394 |
395 def cmdmatcher(canonroot, cwd='', names=['.'], inc=[], exc=[], head='', |
395 def cmdmatcher(canonroot, cwd='', names=[], inc=[], exc=[], src=None, |
396 src=None, globbed=False): |
396 globbed=False, default=None): |
397 if not globbed: |
397 default = default or 'relpath' |
|
398 if default == 'relpath' and not globbed: |
398 names = expand_glob(names) |
399 names = expand_glob(names) |
399 return _matcher(canonroot, cwd, names, inc, exc, head, 'relpath', src) |
400 return _matcher(canonroot, cwd, names, inc, exc, default, src) |
400 |
401 |
401 def _matcher(canonroot, cwd, names, inc, exc, head, dflt_pat, src): |
402 def _matcher(canonroot, cwd, names, inc, exc, dflt_pat, src): |
402 """build a function to match a set of file patterns |
403 """build a function to match a set of file patterns |
403 |
404 |
404 arguments: |
405 arguments: |
405 canonroot - the canonical root of the tree you're matching against |
406 canonroot - the canonical root of the tree you're matching against |
406 cwd - the current working directory, if relevant |
407 cwd - the current working directory, if relevant |
407 names - patterns to find |
408 names - patterns to find |
408 inc - patterns to include |
409 inc - patterns to include |
409 exc - patterns to exclude |
410 exc - patterns to exclude |
410 head - a regex to prepend to patterns to control whether a match is rooted |
411 dflt_pat - if a pattern in names has no explicit type, assume this one |
|
412 src - where these patterns came from (e.g. .hgignore) |
411 |
413 |
412 a pattern is one of: |
414 a pattern is one of: |
413 'glob:<rooted glob>' |
415 'glob:<glob>' - a glob relative to cwd |
414 're:<rooted regexp>' |
416 're:<regexp>' - a regular expression |
415 'path:<rooted path>' |
417 'path:<path>' - a path relative to canonroot |
416 'relglob:<relative glob>' |
418 'relglob:<glob>' - an unrooted glob (*.c matches C files in all dirs) |
417 'relpath:<relative path>' |
419 'relpath:<path>' - a path relative to cwd |
418 'relre:<relative regexp>' |
420 'relre:<regexp>' - a regexp that doesn't have to match the start of a name |
419 '<rooted path or regexp>' |
421 '<something>' - one of the cases above, selected by the dflt_pat argument |
420 |
422 |
421 returns: |
423 returns: |
422 a 3-tuple containing |
424 a 3-tuple containing |
423 - list of explicit non-pattern names passed in |
425 - list of roots (places where one should start a recursive walk of the fs); |
|
426 this often matches the explicit non-pattern names passed in, but also |
|
427 includes the initial part of glob: patterns that has no glob characters |
424 - a bool match(filename) function |
428 - a bool match(filename) function |
425 - a bool indicating if any patterns were passed in |
429 - a bool indicating if any patterns were passed in |
426 |
|
427 todo: |
|
428 make head regex a rooted bool |
|
429 """ |
430 """ |
|
431 |
|
432 # a common case: no patterns at all |
|
433 if not names and not inc and not exc: |
|
434 return [], always, False |
430 |
435 |
431 def contains_glob(name): |
436 def contains_glob(name): |
432 for c in name: |
437 for c in name: |
433 if c in _globchars: return True |
438 if c in _globchars: return True |
434 return False |
439 return False |
435 |
440 |
436 def regex(kind, name, tail): |
441 def regex(kind, name, tail): |
437 '''convert a pattern into a regular expression''' |
442 '''convert a pattern into a regular expression''' |
|
443 if not name: |
|
444 return '' |
438 if kind == 're': |
445 if kind == 're': |
439 return name |
446 return name |
440 elif kind == 'path': |
447 elif kind == 'path': |
441 return '^' + re.escape(name) + '(?:/|$)' |
448 return '^' + re.escape(name) + '(?:/|$)' |
442 elif kind == 'relglob': |
449 elif kind == 'relglob': |
443 return head + globre(name, '(?:|.*/)', tail) |
450 return globre(name, '(?:|.*/)', '(?:/|$)') |
444 elif kind == 'relpath': |
451 elif kind == 'relpath': |
445 return head + re.escape(name) + tail |
452 return re.escape(name) + '(?:/|$)' |
446 elif kind == 'relre': |
453 elif kind == 'relre': |
447 if name.startswith('^'): |
454 if name.startswith('^'): |
448 return name |
455 return name |
449 return '.*' + name |
456 return '.*' + name |
450 return head + globre(name, '', tail) |
457 return globre(name, '', tail) |
451 |
458 |
452 def matchfn(pats, tail): |
459 def matchfn(pats, tail): |
453 """build a matching function from a set of patterns""" |
460 """build a matching function from a set of patterns""" |
454 if not pats: |
461 if not pats: |
455 return |
462 return |
471 return buildfn |
478 return buildfn |
472 |
479 |
473 def globprefix(pat): |
480 def globprefix(pat): |
474 '''return the non-glob prefix of a path, e.g. foo/* -> foo''' |
481 '''return the non-glob prefix of a path, e.g. foo/* -> foo''' |
475 root = [] |
482 root = [] |
476 for p in pat.split(os.sep): |
483 for p in pat.split('/'): |
477 if contains_glob(p): break |
484 if contains_glob(p): break |
478 root.append(p) |
485 root.append(p) |
479 return '/'.join(root) |
486 return '/'.join(root) or '.' |
480 |
487 |
481 pats = [] |
488 def normalizepats(names, default): |
482 files = [] |
489 pats = [] |
483 roots = [] |
490 files = [] |
484 for kind, name in [patkind(p, dflt_pat) for p in names]: |
491 roots = [] |
485 if kind in ('glob', 'relpath'): |
492 anypats = False |
486 name = canonpath(canonroot, cwd, name) |
493 for kind, name in [patkind(p, default) for p in names]: |
487 if name == '': |
494 if kind in ('glob', 'relpath'): |
488 kind, name = 'glob', '**' |
495 name = canonpath(canonroot, cwd, name) |
489 if kind in ('glob', 'path', 're'): |
496 elif kind in ('relglob', 'path'): |
490 pats.append((kind, name)) |
497 name = normpath(name) |
491 if kind == 'glob': |
498 if kind in ('glob', 're', 'relglob', 'relre'): |
492 root = globprefix(name) |
499 pats.append((kind, name)) |
493 if root: roots.append(root) |
500 anypats = True |
494 elif kind == 'relpath': |
501 if kind == 'glob': |
495 files.append((kind, name)) |
502 root = globprefix(name) |
496 roots.append(name) |
503 roots.append(root) |
|
504 elif kind in ('relpath', 'path'): |
|
505 files.append((kind, name)) |
|
506 roots.append(name) |
|
507 elif kind == 'relglob': |
|
508 roots.append('.') |
|
509 return roots, pats + files, anypats |
|
510 |
|
511 roots, pats, anypats = normalizepats(names, dflt_pat) |
497 |
512 |
498 patmatch = matchfn(pats, '$') or always |
513 patmatch = matchfn(pats, '$') or always |
499 filematch = matchfn(files, '(?:/|$)') or always |
|
500 incmatch = always |
514 incmatch = always |
501 if inc: |
515 if inc: |
502 inckinds = [patkind(canonpath(canonroot, cwd, i)) for i in inc] |
516 dummy, inckinds, dummy = normalizepats(inc, 'glob') |
503 incmatch = matchfn(inckinds, '(?:/|$)') |
517 incmatch = matchfn(inckinds, '(?:/|$)') |
504 excmatch = lambda fn: False |
518 excmatch = lambda fn: False |
505 if exc: |
519 if exc: |
506 exckinds = [patkind(canonpath(canonroot, cwd, x)) for x in exc] |
520 dummy, exckinds, dummy = normalizepats(exc, 'glob') |
507 excmatch = matchfn(exckinds, '(?:/|$)') |
521 excmatch = matchfn(exckinds, '(?:/|$)') |
508 |
522 |
509 return (roots, |
523 if not names and inc and not exc: |
510 lambda fn: (incmatch(fn) and not excmatch(fn) and |
524 # common case: hgignore patterns |
511 (fn.endswith('/') or |
525 match = incmatch |
512 (not pats and not files) or |
526 else: |
513 (pats and patmatch(fn)) or |
527 match = lambda fn: incmatch(fn) and not excmatch(fn) and patmatch(fn) |
514 (files and filematch(fn)))), |
528 |
515 (inc or exc or (pats and pats != [('glob', '**')])) and True) |
529 return (roots, match, (inc or exc or anypats) and True) |
516 |
530 |
517 def system(cmd, environ={}, cwd=None, onerr=None, errprefix=None): |
531 def system(cmd, environ={}, cwd=None, onerr=None, errprefix=None): |
518 '''enhanced shell command execution. |
532 '''enhanced shell command execution. |
519 run with environment maybe modified, maybe in different dir. |
533 run with environment maybe modified, maybe in different dir. |
520 |
534 |