Mercurial > hg > mercurial-crew-with-dirclash
comparison mercurial/util.py @ 4195:b5d1eaade333
Merge a bunch of matcher and locate fixes.
author | Alexis S. L. Carvalho <alexis@cecm.usp.br> |
---|---|
date | Sat, 10 Mar 2007 23:21:33 -0300 |
parents | 9dc64c8414ca ec932167c3a7 |
children | 0d51eb296fb9 |
comparison
equal
deleted
inserted
replaced
4177:ba51a8225a60 | 4195:b5d1eaade333 |
---|---|
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 |