mercurial/cmdutil.py
changeset 9652 2cb0cab10d2e
parent 9547 f57640bf10d4
child 9653 e4de75343743
equal deleted inserted replaced
9632:16698d87ad20 9652:2cb0cab10d2e
  1022 
  1022 
  1023 def finddate(ui, repo, date):
  1023 def finddate(ui, repo, date):
  1024     """Find the tipmost changeset that matches the given date spec"""
  1024     """Find the tipmost changeset that matches the given date spec"""
  1025     df = util.matchdate(date)
  1025     df = util.matchdate(date)
  1026     get = util.cachefunc(lambda r: repo[r])
  1026     get = util.cachefunc(lambda r: repo[r])
  1027     changeiter, matchfn = walkchangerevs(ui, repo, [], get, {'rev':None})
  1027     m = matchall(repo)
  1028     results = {}
  1028     results = {}
  1029     for st, rev, fns in changeiter:
  1029     for st, rev, fns in walkchangerevs(ui, repo, m, get, {'rev':None}):
  1030         if st == 'add':
  1030         if st == 'add':
  1031             d = get(rev).date()
  1031             d = get(rev).date()
  1032             if df(d[0]):
  1032             if df(d[0]):
  1033                 results[rev] = d
  1033                 results[rev] = d
  1034         elif st == 'iter':
  1034         elif st == 'iter':
  1037                           (rev, util.datestr(results[rev])))
  1037                           (rev, util.datestr(results[rev])))
  1038                 return str(rev)
  1038                 return str(rev)
  1039 
  1039 
  1040     raise util.Abort(_("revision matching date not found"))
  1040     raise util.Abort(_("revision matching date not found"))
  1041 
  1041 
  1042 def walkchangerevs(ui, repo, pats, change, opts):
  1042 def walkchangerevs(ui, repo, match, change, opts):
  1043     '''Iterate over files and the revs in which they changed.
  1043     '''Iterate over files and the revs in which they changed.
  1044 
  1044 
  1045     Callers most commonly need to iterate backwards over the history
  1045     Callers most commonly need to iterate backwards over the history
  1046     in which they are interested. Doing so has awful (quadratic-looking)
  1046     in which they are interested. Doing so has awful (quadratic-looking)
  1047     performance, so we use iterators in a "windowed" way.
  1047     performance, so we use iterators in a "windowed" way.
  1048 
  1048 
  1049     We walk a window of revisions in the desired order.  Within the
  1049     We walk a window of revisions in the desired order.  Within the
  1050     window, we first walk forwards to gather data, then in the desired
  1050     window, we first walk forwards to gather data, then in the desired
  1051     order (usually backwards) to display it.
  1051     order (usually backwards) to display it.
  1052 
  1052 
  1053     This function returns an (iterator, matchfn) tuple. The iterator
  1053     This function returns an iterator. The iterator yields 3-tuples.
  1054     yields 3-tuples. They will be of one of the following forms:
  1054     They will be of one of the following forms:
  1055 
  1055 
  1056     "window", incrementing, lastrev: stepping through a window,
  1056     "window", incrementing, lastrev: stepping through a window,
  1057     positive if walking forwards through revs, last rev in the
  1057     positive if walking forwards through revs, last rev in the
  1058     sequence iterated over - use to reset state for the current window
  1058     sequence iterated over - use to reset state for the current window
  1059 
  1059 
  1076                 yield start, min(windowsize, start-end-1)
  1076                 yield start, min(windowsize, start-end-1)
  1077                 start -= windowsize
  1077                 start -= windowsize
  1078                 if windowsize < sizelimit:
  1078                 if windowsize < sizelimit:
  1079                     windowsize *= 2
  1079                     windowsize *= 2
  1080 
  1080 
  1081     m = match(repo, pats, opts)
       
  1082     follow = opts.get('follow') or opts.get('follow_first')
  1081     follow = opts.get('follow') or opts.get('follow_first')
  1083 
  1082 
  1084     if not len(repo):
  1083     if not len(repo):
  1085         return [], m
  1084         return []
  1086 
  1085 
  1087     if follow:
  1086     if follow:
  1088         defrange = '%s:0' % repo['.'].rev()
  1087         defrange = '%s:0' % repo['.'].rev()
  1089     else:
  1088     else:
  1090         defrange = '-1:0'
  1089         defrange = '-1:0'
  1091     revs = revrange(repo, opts['rev'] or [defrange])
  1090     revs = revrange(repo, opts['rev'] or [defrange])
  1092     wanted = set()
  1091     wanted = set()
  1093     slowpath = m.anypats() or (m.files() and opts.get('removed'))
  1092     slowpath = match.anypats() or (match.files() and opts.get('removed'))
  1094     fncache = {}
  1093     fncache = {}
  1095 
  1094 
  1096     if not slowpath and not m.files():
  1095     if not slowpath and not match.files():
  1097         # No files, no patterns.  Display all revs.
  1096         # No files, no patterns.  Display all revs.
  1098         wanted = set(revs)
  1097         wanted = set(revs)
  1099     copies = []
  1098     copies = []
  1100     if not slowpath:
  1099     if not slowpath:
  1101         # Only files, no patterns.  Check the history of each file.
  1100         # Only files, no patterns.  Check the history of each file.
  1115                     # only yield rev for which we have the changelog, it can
  1114                     # only yield rev for which we have the changelog, it can
  1116                     # happen while doing "hg log" during a pull or commit
  1115                     # happen while doing "hg log" during a pull or commit
  1117                     if rev[0] < cl_count:
  1116                     if rev[0] < cl_count:
  1118                         yield rev
  1117                         yield rev
  1119         def iterfiles():
  1118         def iterfiles():
  1120             for filename in m.files():
  1119             for filename in match.files():
  1121                 yield filename, None
  1120                 yield filename, None
  1122             for filename_node in copies:
  1121             for filename_node in copies:
  1123                 yield filename_node
  1122                 yield filename_node
  1124         minrev, maxrev = min(revs), max(revs)
  1123         minrev, maxrev = min(revs), max(revs)
  1125         for file_, node in iterfiles():
  1124         for file_, node in iterfiles():
  1155             for i, window in increasing_windows(len(repo) - 1, nullrev):
  1154             for i, window in increasing_windows(len(repo) - 1, nullrev):
  1156                 for j in xrange(i - window, i + 1):
  1155                 for j in xrange(i - window, i + 1):
  1157                     yield change(j)
  1156                     yield change(j)
  1158 
  1157 
  1159         for ctx in changerevgen():
  1158         for ctx in changerevgen():
  1160             matches = filter(m, ctx.files())
  1159             matches = filter(match, ctx.files())
  1161             if matches:
  1160             if matches:
  1162                 fncache[ctx.rev()] = matches
  1161                 fncache[ctx.rev()] = matches
  1163                 wanted.add(ctx.rev())
  1162                 wanted.add(ctx.rev())
  1164 
  1163 
  1165     class followfilter(object):
  1164     class followfilter(object):
  1208         for x in xrange(rev, stop-1, -1):
  1207         for x in xrange(rev, stop-1, -1):
  1209             if ff.match(x):
  1208             if ff.match(x):
  1210                 wanted.discard(x)
  1209                 wanted.discard(x)
  1211 
  1210 
  1212     def iterate():
  1211     def iterate():
  1213         if follow and not m.files():
  1212         if follow and not match.files():
  1214             ff = followfilter(onlyfirst=opts.get('follow_first'))
  1213             ff = followfilter(onlyfirst=opts.get('follow_first'))
  1215             def want(rev):
  1214             def want(rev):
  1216                 return ff.match(rev) and rev in wanted
  1215                 return ff.match(rev) and rev in wanted
  1217         else:
  1216         else:
  1218             def want(rev):
  1217             def want(rev):
  1224             for rev in sorted(nrevs):
  1223             for rev in sorted(nrevs):
  1225                 fns = fncache.get(rev)
  1224                 fns = fncache.get(rev)
  1226                 if not fns:
  1225                 if not fns:
  1227                     def fns_generator():
  1226                     def fns_generator():
  1228                         for f in change(rev).files():
  1227                         for f in change(rev).files():
  1229                             if m(f):
  1228                             if match(f):
  1230                                 yield f
  1229                                 yield f
  1231                     fns = fns_generator()
  1230                     fns = fns_generator()
  1232                 yield 'add', rev, fns
  1231                 yield 'add', rev, fns
  1233             for rev in nrevs:
  1232             for rev in nrevs:
  1234                 yield 'iter', rev, None
  1233                 yield 'iter', rev, None
  1235     return iterate(), m
  1234     return iterate()
  1236 
  1235 
  1237 def commit(ui, repo, commitfunc, pats, opts):
  1236 def commit(ui, repo, commitfunc, pats, opts):
  1238     '''commit the specified files or all outstanding changes'''
  1237     '''commit the specified files or all outstanding changes'''
  1239     date = opts.get('date')
  1238     date = opts.get('date')
  1240     if date:
  1239     if date: