mercurial/commands.py
changeset 1031 503aaf19a040
parent 1030 28e2f13ca7c4
child 1034 8dbbea5bc844
equal deleted inserted replaced
1030:28e2f13ca7c4 1031:503aaf19a040
    33     return util.matcher(repo, cwd, pats or ['.'], opts.get('include'),
    33     return util.matcher(repo, cwd, pats or ['.'], opts.get('include'),
    34                         opts.get('exclude'), head)
    34                         opts.get('exclude'), head)
    35 
    35 
    36 def makewalk(repo, pats, opts, head = ''):
    36 def makewalk(repo, pats, opts, head = ''):
    37     cwd = repo.getcwd()
    37     cwd = repo.getcwd()
    38     files, matchfn = matchpats(repo, cwd, pats, opts, head)
    38     files, matchfn, anypats = matchpats(repo, cwd, pats, opts, head)
    39     exact = dict(zip(files, files))
    39     exact = dict(zip(files, files))
    40     def walk():
    40     def walk():
    41         for src, fn in repo.walk(files = files, match = matchfn):
    41         for src, fn in repo.walk(files = files, match = matchfn):
    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()
    84                 end -= 1
    84                 end -= 1
    85                 step = -1
    85                 step = -1
    86             for rev in xrange(start, end, step):
    86             for rev in xrange(start, end, step):
    87                 yield str(rev)
    87                 yield str(rev)
    88         else:
    88         else:
    89             yield spec
    89             yield str(fix(spec, None))
    90 
    90 
    91 def make_filename(repo, r, pat, node=None,
    91 def make_filename(repo, r, pat, node=None,
    92                   total=None, seqno=None, revwidth=None):
    92                   total=None, seqno=None, revwidth=None):
    93     node_expander = {
    93     node_expander = {
    94         'H': lambda: hg.hex(node),
    94         'H': lambda: hg.hex(node),
   191     for f in d:
   191     for f in d:
   192         to = repo.file(f).read(mmap[f])
   192         to = repo.file(f).read(mmap[f])
   193         tn = None
   193         tn = None
   194         fp.write(mdiff.unidiff(to, date1, tn, date2, f, r, text=text))
   194         fp.write(mdiff.unidiff(to, date1, tn, date2, f, r, text=text))
   195 
   195 
   196 def show_changeset(ui, repo, rev=0, changenode=None, filelog=None, brinfo=None):
   196 def show_changeset(ui, repo, rev=0, changenode=None, brinfo=None):
   197     """show a single changeset or file revision"""
   197     """show a single changeset or file revision"""
   198     changelog = repo.changelog
   198     log = repo.changelog
   199     if filelog:
   199     if changenode is None:
   200         log = filelog
   200         changenode = log.node(rev)
   201         filerev = rev
   201     elif not rev:
   202         node = filenode = filelog.node(filerev)
   202         rev = log.rev(changenode)
   203         changerev = filelog.linkrev(filenode)
       
   204         changenode = changenode or changelog.node(changerev)
       
   205     else:
       
   206         log = changelog
       
   207         changerev = rev
       
   208         if changenode is None:
       
   209             changenode = changelog.node(changerev)
       
   210         elif not changerev:
       
   211             rev = changerev = changelog.rev(changenode)
       
   212         node = changenode
       
   213 
   203 
   214     if ui.quiet:
   204     if ui.quiet:
   215         ui.write("%d:%s\n" % (rev, hg.short(node)))
   205         ui.write("%d:%s\n" % (rev, hg.short(changenode)))
   216         return
   206         return
   217 
   207 
   218     changes = changelog.read(changenode)
   208     changes = log.read(changenode)
   219 
   209 
   220     t, tz = changes[2].split(' ')
   210     t, tz = changes[2].split(' ')
   221     # a conversion tool was sticking non-integer offsets into repos
   211     # a conversion tool was sticking non-integer offsets into repos
   222     try:
   212     try:
   223         tz = int(tz)
   213         tz = int(tz)
   224     except ValueError:
   214     except ValueError:
   225         tz = 0
   215         tz = 0
   226     date = time.asctime(time.localtime(float(t))) + " %+05d" % (int(tz)/-36)
   216     date = time.asctime(time.localtime(float(t))) + " %+05d" % (int(tz)/-36)
   227 
   217 
   228     parents = [(log.rev(p), ui.verbose and hg.hex(p) or hg.short(p))
   218     parents = [(log.rev(p), ui.verbose and hg.hex(p) or hg.short(p))
   229                for p in log.parents(node)
   219                for p in log.parents(changenode)
   230                if ui.debugflag or p != hg.nullid]
   220                if ui.debugflag or p != hg.nullid]
   231     if not ui.debugflag and len(parents) == 1 and parents[0][0] == rev-1:
   221     if not ui.debugflag and len(parents) == 1 and parents[0][0] == rev-1:
   232         parents = []
   222         parents = []
   233 
   223 
   234     if ui.verbose:
   224     if ui.verbose:
   235         ui.write("changeset:   %d:%s\n" % (changerev, hg.hex(changenode)))
   225         ui.write("changeset:   %d:%s\n" % (rev, hg.hex(changenode)))
   236     else:
   226     else:
   237         ui.write("changeset:   %d:%s\n" % (changerev, hg.short(changenode)))
   227         ui.write("changeset:   %d:%s\n" % (rev, hg.short(changenode)))
   238 
   228 
   239     for tag in repo.nodetags(changenode):
   229     for tag in repo.nodetags(changenode):
   240         ui.status("tag:         %s\n" % tag)
   230         ui.status("tag:         %s\n" % tag)
   241     for parent in parents:
   231     for parent in parents:
   242         ui.write("parent:      %d:%s\n" % parent)
   232         ui.write("parent:      %d:%s\n" % parent)
   243     if filelog:
       
   244         ui.debug("file rev:    %d:%s\n" % (filerev, hg.hex(filenode)))
       
   245 
   233 
   246     if brinfo and changenode in brinfo:
   234     if brinfo and changenode in brinfo:
   247         br = brinfo[changenode]
   235         br = brinfo[changenode]
   248         ui.write("branch:      %s\n" % " ".join(br))
   236         ui.write("branch:      %s\n" % " ".join(br))
   249 
   237 
   251                                       hg.hex(changes[0])))
   239                                       hg.hex(changes[0])))
   252     ui.status("user:        %s\n" % changes[1])
   240     ui.status("user:        %s\n" % changes[1])
   253     ui.status("date:        %s\n" % date)
   241     ui.status("date:        %s\n" % date)
   254 
   242 
   255     if ui.debugflag:
   243     if ui.debugflag:
   256         files = repo.changes(changelog.parents(changenode)[0], changenode)
   244         files = repo.changes(log.parents(changenode)[0], changenode)
   257         for key, value in zip(["files:", "files+:", "files-:"], files):
   245         for key, value in zip(["files:", "files+:", "files-:"], files):
   258             if value:
   246             if value:
   259                 ui.note("%-12s %s\n" % (key, " ".join(value)))
   247                 ui.note("%-12s %s\n" % (key, " ".join(value)))
   260     else:
   248     else:
   261         ui.note("files:       %s\n" % " ".join(changes[3]))
   249         ui.note("files:       %s\n" % " ".join(changes[3]))
   558         addremove(ui, repo, *pats, **opts)
   546         addremove(ui, repo, *pats, **opts)
   559     cwd = repo.getcwd()
   547     cwd = repo.getcwd()
   560     if not pats and cwd:
   548     if not pats and cwd:
   561         opts['include'] = [os.path.join(cwd, i) for i in opts['include']]
   549         opts['include'] = [os.path.join(cwd, i) for i in opts['include']]
   562         opts['exclude'] = [os.path.join(cwd, x) for x in opts['exclude']]
   550         opts['exclude'] = [os.path.join(cwd, x) for x in opts['exclude']]
   563     fns, match = matchpats(repo, (pats and repo.getcwd()) or '', pats, opts)
   551     fns, match, anypats = matchpats(repo, (pats and repo.getcwd()) or '',
       
   552                                     pats, opts)
   564     if pats:
   553     if pats:
   565         c, a, d, u = repo.changes(files = fns, match = match)
   554         c, a, d, u = repo.changes(files = fns, match = match)
   566         files = c + a + [fn for fn in d if repo.dirstate.state(fn) == 'r']
   555         files = c + a + [fn for fn in d if repo.dirstate.state(fn) == 'r']
   567     else:
   556     else:
   568         files = []
   557         files = []
   847         if opts['fullpath']:
   836         if opts['fullpath']:
   848             ui.write(os.path.join(repo.root, abs), end)
   837             ui.write(os.path.join(repo.root, abs), end)
   849         else:
   838         else:
   850             ui.write(rel, end)
   839             ui.write(rel, end)
   851 
   840 
   852 def log(ui, repo, f=None, **opts):
   841 def log(ui, repo, *pats, **opts):
   853     """show the revision history of the repository or a single file"""
   842     """show revision history of entire repository or files"""
   854     if f:
   843     # This code most commonly needs to iterate backwards over the
   855         files = relpath(repo, [f])
   844     # history it is interested in.  This has awful (quadratic-looking)
   856         filelog = repo.file(files[0])
   845     # performance, so we use iterators that walk forwards through
   857         log = filelog
   846     # windows of revisions, yielding revisions in reverse order, while
   858         lookup = filelog.lookup
   847     # walking the windows backwards.
   859     else:
   848     files, matchfn, anypats = matchpats(repo, repo.getcwd(), pats, opts)
   860         files = None
   849     revs = map(int, revrange(ui, repo, opts['rev'] or ['tip:0']))
   861         filelog = None
   850     wanted = {}
   862         log = repo.changelog
   851     slowpath = anypats
   863         lookup = repo.lookup
   852     window = 300
   864     revlist = []
   853     if not slowpath and not files:
   865     revs = [log.rev(lookup(rev)) for rev in opts['rev']]
   854         # No files, no patterns.  Display all revs.
   866     while revs:
   855         wanted = dict(zip(revs, revs))
   867         if len(revs) == 1:
   856     if not slowpath:
   868             revlist.append(revs.pop(0))
   857         # Only files, no patterns.  Check the history of each file.
   869         else:
   858         def filerevgen(filelog):
   870             a = revs.pop(0)
   859             for i in xrange(filelog.count() - 1, 0, -window):
   871             b = revs.pop(0)
   860                 revs = []
   872             off = a > b and -1 or 1
   861                 for j in xrange(max(0, i - window), i):
   873             revlist.extend(range(a, b + off, off))
   862                     revs.append(filelog.linkrev(filelog.node(j)))
   874 
   863                 revs.reverse()
   875     for i in revlist or range(log.count() - 1, -1, -1):
   864                 for rev in revs:
   876         show_changeset(ui, repo, filelog=filelog, rev=i)
   865                     yield rev
       
   866 
       
   867         minrev, maxrev = min(revs), max(revs)
       
   868         for filelog in map(repo.file, files):
       
   869             # A zero count may be a directory or deleted file, so
       
   870             # try to find matching entries on the slow path.
       
   871             if filelog.count() == 0:
       
   872                 slowpath = True
       
   873                 break
       
   874             for rev in filerevgen(filelog):
       
   875                 if rev <= maxrev:
       
   876                     if rev < minrev: break
       
   877                     wanted[rev] = 1
       
   878     if slowpath:
       
   879         # The slow path checks files modified in every changeset.
       
   880         def mfrevgen():
       
   881             for i in xrange(repo.changelog.count() - 1, 0, -window):
       
   882                 for j in xrange(max(0, i - window), i):
       
   883                     yield j, repo.changelog.read(repo.lookup(str(j)))[3]
       
   884 
       
   885         for rev, mf in mfrevgen():
       
   886             if filter(matchfn, mf):
       
   887                 wanted[rev] = 1
       
   888 
       
   889     def changerevgen():
       
   890         class dui:
       
   891             # Implement and delegate some ui protocol.  Save hunks of
       
   892             # output for later display in the desired order.
       
   893             def __init__(self, ui):
       
   894                 self.ui = ui
       
   895                 self.hunk = {}
       
   896             def bump(self, rev):
       
   897                 self.rev = rev
       
   898                 self.hunk[rev] = []
       
   899             def status(self, *args):
       
   900                 if not self.quiet: self.write(*args)
       
   901             def write(self, *args):
       
   902                 self.hunk[self.rev].append(args)
       
   903             def __getattr__(self, key):
       
   904                 return getattr(self.ui, key)
       
   905         for i in xrange(0, len(revs), window):
       
   906             nrevs = [rev for rev in revs[i : min(i + window, len(revs))]
       
   907                      if rev in wanted]
       
   908             srevs = list(nrevs)
       
   909             srevs.sort()
       
   910             du = dui(ui)
       
   911             for rev in srevs:
       
   912                 du.bump(rev)
       
   913                 yield rev, du
       
   914             for rev in nrevs:
       
   915                 for args in du.hunk[rev]:
       
   916                     ui.write(*args)
       
   917 
       
   918     for rev, dui in changerevgen():
       
   919         show_changeset(dui, repo, rev)
   877         if opts['patch']:
   920         if opts['patch']:
   878             if filelog:
   921             changenode = repo.changelog.node(rev)
   879                 filenode = filelog.node(i)
       
   880                 i = filelog.linkrev(filenode)
       
   881             changenode = repo.changelog.node(i)
       
   882             prev, other = repo.changelog.parents(changenode)
   922             prev, other = repo.changelog.parents(changenode)
   883             dodiff(sys.stdout, ui, repo, prev, changenode, files)
   923             dodiff(dui, dui, repo, prev, changenode, files)
   884             ui.write("\n\n")
   924             du.write("\n\n")
   885 
   925 
   886 def manifest(ui, repo, rev=None):
   926 def manifest(ui, repo, rev=None):
   887     """output the latest or given revision of the project manifest"""
   927     """output the latest or given revision of the project manifest"""
   888     if rev:
   928     if rev:
   889         try:
   929         try:
  1160     R = removed
  1200     R = removed
  1161     ? = not tracked
  1201     ? = not tracked
  1162     '''
  1202     '''
  1163 
  1203 
  1164     cwd = repo.getcwd()
  1204     cwd = repo.getcwd()
  1165     files, matchfn = matchpats(repo, cwd, pats, opts)
  1205     files, matchfn, anypats = matchpats(repo, cwd, pats, opts)
  1166     (c, a, d, u) = [[util.pathto(cwd, x) for x in n]
  1206     (c, a, d, u) = [[util.pathto(cwd, x) for x in n]
  1167                     for n in repo.changes(files=files, match=matchfn)]
  1207                     for n in repo.changes(files=files, match=matchfn)]
  1168 
  1208 
  1169     changetypes = [('modified', 'M', c),
  1209     changetypes = [('modified', 'M', c),
  1170                    ('added', 'A', a),
  1210                    ('added', 'A', a),
  1376           ('I', 'include', [], 'include path in search'),
  1416           ('I', 'include', [], 'include path in search'),
  1377           ('X', 'exclude', [], 'exclude path from search')],
  1417           ('X', 'exclude', [], 'exclude path from search')],
  1378          'hg locate [OPTION]... [PATTERN]...'),
  1418          'hg locate [OPTION]... [PATTERN]...'),
  1379     "^log|history":
  1419     "^log|history":
  1380         (log,
  1420         (log,
  1381          [('r', 'rev', [], 'revision'),
  1421          [('I', 'include', [], 'include path in search'),
       
  1422           ('X', 'exclude', [], 'exclude path from search'),
       
  1423           ('r', 'rev', [], 'revision'),
  1382           ('p', 'patch', None, 'show patch')],
  1424           ('p', 'patch', None, 'show patch')],
  1383          'hg log [-r REV1 [-r REV2]] [-p] [FILE]'),
  1425          'hg log [-r REV1 [-r REV2]] [-p] [FILE]'),
  1384     "manifest": (manifest, [], 'hg manifest [REV]'),
  1426     "manifest": (manifest, [], 'hg manifest [REV]'),
  1385     "outgoing|out": (outgoing, [], 'hg outgoing [DEST]'),
  1427     "outgoing|out": (outgoing, [], 'hg outgoing [DEST]'),
  1386     "parents": (parents, [], 'hg parents [REV]'),
  1428     "parents": (parents, [], 'hg parents [REV]'),