42 yield src, fn, util.pathto(cwd, fn), fn in exact |
42 yield src, fn, util.pathto(cwd, fn), fn in exact |
43 return files, matchfn, walk() |
43 return files, matchfn, walk() |
44 |
44 |
45 def walk(repo, pats, opts, head=''): |
45 def walk(repo, pats, opts, head=''): |
46 files, matchfn, results = makewalk(repo, pats, opts, head) |
46 files, matchfn, results = makewalk(repo, pats, opts, head) |
47 for r in results: yield r |
47 for r in results: |
|
48 yield r |
48 |
49 |
49 def walkchangerevs(ui, repo, cwd, pats, opts): |
50 def walkchangerevs(ui, repo, cwd, pats, opts): |
50 # This code most commonly needs to iterate backwards over the |
51 # This code most commonly needs to iterate backwards over the |
51 # history it is interested in. Doing so has awful |
52 # history it is interested in. Doing so has awful |
52 # (quadratic-looking) performance, so we use iterators in a |
53 # (quadratic-looking) performance, so we use iterators in a |
203 inst.args[0]) |
205 inst.args[0]) |
204 |
206 |
205 def make_file(repo, r, pat, node=None, |
207 def make_file(repo, r, pat, node=None, |
206 total=None, seqno=None, revwidth=None, mode='wb'): |
208 total=None, seqno=None, revwidth=None, mode='wb'): |
207 if not pat or pat == '-': |
209 if not pat or pat == '-': |
208 if 'w' in mode: return sys.stdout |
210 return 'w' in mode and sys.stdout or sys.stdin |
209 else: return sys.stdin |
|
210 if hasattr(pat, 'write') and 'w' in mode: |
211 if hasattr(pat, 'write') and 'w' in mode: |
211 return pat |
212 return pat |
212 if hasattr(pat, 'read') and 'r' in mode: |
213 if hasattr(pat, 'read') and 'r' in mode: |
213 return pat |
214 return pat |
214 return open(make_filename(repo, r, pat, node, total, seqno, revwidth), |
215 return open(make_filename(repo, r, pat, node, total, seqno, revwidth), |
453 """add all new files, delete all missing files""" |
454 """add all new files, delete all missing files""" |
454 add, remove = [], [] |
455 add, remove = [], [] |
455 for src, abs, rel, exact in walk(repo, pats, opts): |
456 for src, abs, rel, exact in walk(repo, pats, opts): |
456 if src == 'f' and repo.dirstate.state(abs) == '?': |
457 if src == 'f' and repo.dirstate.state(abs) == '?': |
457 add.append(abs) |
458 add.append(abs) |
458 if not exact: ui.status('adding ', rel, '\n') |
459 if not exact: |
|
460 ui.status('adding ', rel, '\n') |
459 if repo.dirstate.state(abs) != 'r' and not os.path.exists(rel): |
461 if repo.dirstate.state(abs) != 'r' and not os.path.exists(rel): |
460 remove.append(abs) |
462 remove.append(abs) |
461 if not exact: ui.status('removing ', rel, '\n') |
463 if not exact: |
|
464 ui.status('removing ', rel, '\n') |
462 repo.add(add) |
465 repo.add(add) |
463 repo.remove(remove) |
466 repo.remove(remove) |
464 |
467 |
465 def annotate(ui, repo, *pats, **opts): |
468 def annotate(ui, repo, *pats, **opts): |
466 """show changeset information per file line""" |
469 """show changeset information per file line""" |
716 ui.write("}\n") |
720 ui.write("}\n") |
717 |
721 |
718 def debugwalk(ui, repo, *pats, **opts): |
722 def debugwalk(ui, repo, *pats, **opts): |
719 """show how files match on given patterns""" |
723 """show how files match on given patterns""" |
720 items = list(walk(repo, pats, opts)) |
724 items = list(walk(repo, pats, opts)) |
721 if not items: return |
725 if not items: |
|
726 return |
722 fmt = '%%s %%-%ds %%-%ds %%s\n' % ( |
727 fmt = '%%s %%-%ds %%-%ds %%s\n' % ( |
723 max([len(abs) for (src, abs, rel, exact) in items]), |
728 max([len(abs) for (src, abs, rel, exact) in items]), |
724 max([len(rel) for (src, abs, rel, exact) in items])) |
729 max([len(rel) for (src, abs, rel, exact) in items])) |
725 exactly = {True: 'exact', False: ''} |
|
726 for src, abs, rel, exact in items: |
730 for src, abs, rel, exact in items: |
727 ui.write(fmt % (src, abs, rel, exactly[exact])) |
731 ui.write(fmt % (src, abs, rel, exact and 'exact' or '')) |
728 |
732 |
729 def diff(ui, repo, *pats, **opts): |
733 def diff(ui, repo, *pats, **opts): |
730 """diff working directory (or selected files)""" |
734 """diff working directory (or selected files)""" |
731 node1, node2 = None, None |
735 node1, node2 = None, None |
732 revs = [repo.lookup(x) for x in opts['rev']] |
736 revs = [repo.lookup(x) for x in opts['rev']] |
767 fp.write("# Parent %s\n" % hg.hex(other)) |
771 fp.write("# Parent %s\n" % hg.hex(other)) |
768 fp.write(change[4].rstrip()) |
772 fp.write(change[4].rstrip()) |
769 fp.write("\n\n") |
773 fp.write("\n\n") |
770 |
774 |
771 dodiff(fp, ui, repo, prev, node, text=opts['text']) |
775 dodiff(fp, ui, repo, prev, node, text=opts['text']) |
772 if fp != sys.stdout: fp.close() |
776 if fp != sys.stdout: |
|
777 fp.close() |
773 |
778 |
774 def export(ui, repo, *changesets, **opts): |
779 def export(ui, repo, *changesets, **opts): |
775 """dump the header and diffs for one or more changesets""" |
780 """dump the header and diffs for one or more changesets""" |
776 if not changesets: |
781 if not changesets: |
777 raise util.Abort("export requires at least one changeset") |
782 raise util.Abort("export requires at least one changeset") |
788 """don't add the specified files on the next commit""" |
793 """don't add the specified files on the next commit""" |
789 forget = [] |
794 forget = [] |
790 for src, abs, rel, exact in walk(repo, pats, opts): |
795 for src, abs, rel, exact in walk(repo, pats, opts): |
791 if repo.dirstate.state(abs) == 'a': |
796 if repo.dirstate.state(abs) == 'a': |
792 forget.append(abs) |
797 forget.append(abs) |
793 if not exact: ui.status('forgetting ', rel, '\n') |
798 if not exact: |
|
799 ui.status('forgetting ', rel, '\n') |
794 repo.forget(forget) |
800 repo.forget(forget) |
795 |
801 |
796 def grep(ui, repo, pattern=None, *pats, **opts): |
802 def grep(ui, repo, pattern=None, *pats, **opts): |
797 """search for a pattern in specified files and revisions""" |
803 """search for a pattern in specified files and revisions""" |
798 if pattern is None: pattern = opts['regexp'] |
804 if pattern is None: |
799 if not pattern: raise util.Abort('no pattern to search for') |
805 pattern = opts['regexp'] |
|
806 if not pattern: |
|
807 raise util.Abort('no pattern to search for') |
800 reflags = 0 |
808 reflags = 0 |
801 if opts['ignore_case']: reflags |= re.I |
809 if opts['ignore_case']: |
|
810 reflags |= re.I |
802 regexp = re.compile(pattern, reflags) |
811 regexp = re.compile(pattern, reflags) |
803 sep, end = ':', '\n' |
812 sep, end = ':', '\n' |
804 if opts['null'] or opts['print0']: sep = end = '\0' |
813 if opts['null'] or opts['print0']: |
|
814 sep = end = '\0' |
805 |
815 |
806 fcache = {} |
816 fcache = {} |
807 def getfile(fn): |
817 def getfile(fn): |
808 if fn not in fcache: |
818 if fn not in fcache: |
809 fcache[fn] = repo.file(fn) |
819 fcache[fn] = repo.file(fn) |
812 def matchlines(body): |
822 def matchlines(body): |
813 begin = 0 |
823 begin = 0 |
814 linenum = 0 |
824 linenum = 0 |
815 while True: |
825 while True: |
816 match = regexp.search(body, begin) |
826 match = regexp.search(body, begin) |
817 if not match: break |
827 if not match: |
|
828 break |
818 mstart, mend = match.span() |
829 mstart, mend = match.span() |
819 linenum += body.count('\n', begin, mstart) + 1 |
830 linenum += body.count('\n', begin, mstart) + 1 |
820 lstart = body.rfind('\n', begin, mstart) + 1 or begin |
831 lstart = body.rfind('\n', begin, mstart) + 1 or begin |
821 lend = body.find('\n', mend) |
832 lend = body.find('\n', mend) |
822 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend] |
833 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend] |
826 def __init__(self, line, linenum, colstart, colend): |
837 def __init__(self, line, linenum, colstart, colend): |
827 self.line = line |
838 self.line = line |
828 self.linenum = linenum |
839 self.linenum = linenum |
829 self.colstart = colstart |
840 self.colstart = colstart |
830 self.colend = colend |
841 self.colend = colend |
831 def __eq__(self, other): return self.line == other.line |
842 def __eq__(self, other): |
832 def __hash__(self): return hash(self.line) |
843 return self.line == other.line |
|
844 def __hash__(self): |
|
845 return hash(self.line) |
833 |
846 |
834 matches = {} |
847 matches = {} |
835 def grepbody(fn, rev, body): |
848 def grepbody(fn, rev, body): |
836 matches[rev].setdefault(fn, {}) |
849 matches[rev].setdefault(fn, {}) |
837 m = matches[rev][fn] |
850 m = matches[rev][fn] |
997 os.mkdir(dest) |
1010 os.mkdir(dest) |
998 hg.repository(ui, dest, create=1) |
1011 hg.repository(ui, dest, create=1) |
999 |
1012 |
1000 def locate(ui, repo, *pats, **opts): |
1013 def locate(ui, repo, *pats, **opts): |
1001 """locate files matching specific patterns""" |
1014 """locate files matching specific patterns""" |
1002 end = '\n' |
1015 end = opts['print0'] and '\0' or '\n' |
1003 if opts['print0']: end = '\0' |
|
1004 |
1016 |
1005 for src, abs, rel, exact in walk(repo, pats, opts, '(?:.*/|)'): |
1017 for src, abs, rel, exact in walk(repo, pats, opts, '(?:.*/|)'): |
1006 if repo.dirstate.state(abs) == '?': continue |
1018 if repo.dirstate.state(abs) == '?': |
|
1019 continue |
1007 if opts['fullpath']: |
1020 if opts['fullpath']: |
1008 ui.write(os.path.join(repo.root, abs), end) |
1021 ui.write(os.path.join(repo.root, abs), end) |
1009 else: |
1022 else: |
1010 ui.write(rel, end) |
1023 ui.write(rel, end) |
1011 |
1024 |
1518 "forget": |
1533 "forget": |
1519 (forget, |
1534 (forget, |
1520 [('I', 'include', [], 'include path in search'), |
1535 [('I', 'include', [], 'include path in search'), |
1521 ('X', 'exclude', [], 'exclude path from search')], |
1536 ('X', 'exclude', [], 'exclude path from search')], |
1522 "hg forget [OPTION]... FILE..."), |
1537 "hg forget [OPTION]... FILE..."), |
1523 "grep": (grep, |
1538 "grep": |
1524 [('0', 'print0', None, 'terminate file names with NUL'), |
1539 (grep, |
1525 ('I', 'include', [], 'include path in search'), |
1540 [('0', 'print0', None, 'terminate file names with NUL'), |
1526 ('X', 'exclude', [], 'include path in search'), |
1541 ('I', 'include', [], 'include path in search'), |
1527 ('Z', 'null', None, 'terminate file names with NUL'), |
1542 ('X', 'exclude', [], 'include path in search'), |
1528 ('a', 'all-revs', '', 'search all revs'), |
1543 ('Z', 'null', None, 'terminate file names with NUL'), |
1529 ('e', 'regexp', '', 'pattern to search for'), |
1544 ('a', 'all-revs', '', 'search all revs'), |
1530 ('f', 'full-path', None, 'print complete paths'), |
1545 ('e', 'regexp', '', 'pattern to search for'), |
1531 ('i', 'ignore-case', None, 'ignore case when matching'), |
1546 ('f', 'full-path', None, 'print complete paths'), |
1532 ('l', 'files-with-matches', None, 'print names of files with matches'), |
1547 ('i', 'ignore-case', None, 'ignore case when matching'), |
1533 ('n', 'line-number', '', 'print line numbers'), |
1548 ('l', 'files-with-matches', None, 'print names of files with matches'), |
1534 ('r', 'rev', [], 'search in revision rev'), |
1549 ('n', 'line-number', '', 'print line numbers'), |
1535 ('s', 'no-messages', None, 'do not print error messages'), |
1550 ('r', 'rev', [], 'search in revision rev'), |
1536 ('v', 'invert-match', None, 'select non-matching lines')], |
1551 ('s', 'no-messages', None, 'do not print error messages'), |
1537 "hg grep [options] [pat] [files]"), |
1552 ('v', 'invert-match', None, 'select non-matching lines')], |
|
1553 "hg grep [options] [pat] [files]"), |
1538 "heads": |
1554 "heads": |
1539 (heads, |
1555 (heads, |
1540 [('b', 'branches', None, 'find branch info')], |
1556 [('b', 'branches', None, 'find branch info')], |
1541 'hg heads [-b]'), |
1557 'hg heads [-b]'), |
1542 "help": (help_, [], 'hg help [COMMAND]'), |
1558 "help": (help_, [], 'hg help [COMMAND]'), |
1652 ('', 'profile', None, 'profile'), |
1668 ('', 'profile', None, 'profile'), |
1653 ('', 'version', None, 'output version information and exit'), |
1669 ('', 'version', None, 'output version information and exit'), |
1654 ('h', 'help', None, 'display help and exit'), |
1670 ('h', 'help', None, 'display help and exit'), |
1655 ] |
1671 ] |
1656 |
1672 |
1657 norepo = "clone init version help debugconfig debugdata" + \ |
1673 norepo = ("clone init version help debugconfig debugdata" |
1658 " debugindex debugindexdot paths" |
1674 " debugindex debugindexdot paths") |
1659 |
1675 |
1660 def find(cmd): |
1676 def find(cmd): |
1661 for e in table.keys(): |
1677 for e in table.keys(): |
1662 if re.match("(%s)$" % e, cmd): |
1678 if re.match("(%s)$" % e, cmd): |
1663 return e, table[e] |
1679 return e, table[e] |
1810 if hasattr(inst, "code"): |
1826 if hasattr(inst, "code"): |
1811 u.warn("abort: %s\n" % inst) |
1827 u.warn("abort: %s\n" % inst) |
1812 elif hasattr(inst, "reason"): |
1828 elif hasattr(inst, "reason"): |
1813 u.warn("abort: error: %s\n" % inst.reason[1]) |
1829 u.warn("abort: error: %s\n" % inst.reason[1]) |
1814 elif hasattr(inst, "args") and inst[0] == errno.EPIPE: |
1830 elif hasattr(inst, "args") and inst[0] == errno.EPIPE: |
1815 if u.debugflag: u.warn("broken pipe\n") |
1831 if u.debugflag: |
|
1832 u.warn("broken pipe\n") |
1816 else: |
1833 else: |
1817 raise |
1834 raise |
1818 except OSError, inst: |
1835 except OSError, inst: |
1819 if hasattr(inst, "filename"): |
1836 if hasattr(inst, "filename"): |
1820 u.warn("abort: %s: %s\n" % (inst.strerror, inst.filename)) |
1837 u.warn("abort: %s: %s\n" % (inst.strerror, inst.filename)) |