mercurial/cmdutil.py
changeset 9667 8743f2e1bc54
parent 9666 71e081b88f3e
parent 9665 1de5ebfa5585
child 9668 2c24471d478c
equal deleted inserted replaced
9666:71e081b88f3e 9667:8743f2e1bc54
  1020     if tmpl: t.use_template(tmpl)
  1020     if tmpl: t.use_template(tmpl)
  1021     return t
  1021     return t
  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 
  1025     df = util.matchdate(date)
  1026     df = util.matchdate(date)
  1026     m = matchall(repo)
  1027     m = matchall(repo)
  1027     results = {}
  1028     results = {}
  1028     for st, ctx, fns in walkchangerevs(ui, repo, m, {'rev': None}):
  1029 
       
  1030     def prep(ctx, fns):
       
  1031         d = ctx.date()
       
  1032         if df(d[0]):
       
  1033             results[rev] = d
       
  1034 
       
  1035     for ctx in walkchangerevs(repo, m, {'rev': None}, prep):
  1029         rev = ctx.rev()
  1036         rev = ctx.rev()
  1030         if st == 'add':
  1037         if rev in results:
  1031             d = ctx.date()
  1038             ui.status(_("Found revision %s from %s\n") %
  1032             if df(d[0]):
  1039                       (rev, util.datestr(results[rev])))
  1033                 results[rev] = d
  1040             return str(rev)
  1034         elif st == 'iter':
       
  1035             if rev in results:
       
  1036                 ui.status(_("Found revision %s from %s\n") %
       
  1037                           (rev, util.datestr(results[rev])))
       
  1038                 return str(rev)
       
  1039 
  1041 
  1040     raise util.Abort(_("revision matching date not found"))
  1042     raise util.Abort(_("revision matching date not found"))
  1041 
  1043 
  1042 def walkchangerevs(ui, repo, match, opts):
  1044 def walkchangerevs(repo, match, opts, prepare):
  1043     '''Iterate over files and the revs in which they changed.
  1045     '''Iterate over files and the revs in which they changed.
  1044 
  1046 
  1045     Callers most commonly need to iterate backwards over the history
  1047     Callers most commonly need to iterate backwards over the history
  1046     in which they are interested. Doing so has awful (quadratic-looking)
  1048     in which they are interested. Doing so has awful (quadratic-looking)
  1047     performance, so we use iterators in a "windowed" way.
  1049     performance, so we use iterators in a "windowed" way.
  1048 
  1050 
  1049     We walk a window of revisions in the desired order.  Within the
  1051     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
  1052     window, we first walk forwards to gather data, then in the desired
  1051     order (usually backwards) to display it.
  1053     order (usually backwards) to display it.
  1052 
  1054 
  1053     This function returns an iterator. The iterator yields 3-tuples.
  1055     This function returns an iterator yielding contexts. Before
  1054     They will be of one of the following forms:
  1056     yielding each context, the iterator will first call the prepare
  1055 
  1057     function on each context in the window in forward order.'''
  1056     "add", rev, fns: out-of-order traversal of the given filenames
       
  1057     fns, which changed during revision rev - use to gather data for
       
  1058     possible display
       
  1059 
       
  1060     "iter", rev, None: in-order traversal of the revs earlier iterated
       
  1061     over with "add" - use to display data'''
       
  1062 
  1058 
  1063     def increasing_windows(start, end, windowsize=8, sizelimit=512):
  1059     def increasing_windows(start, end, windowsize=8, sizelimit=512):
  1064         if start < end:
  1060         if start < end:
  1065             while start < end:
  1061             while start < end:
  1066                 yield start, min(windowsize, end-start)
  1062                 yield start, min(windowsize, end-start)
  1091 
  1087 
  1092     if not slowpath and not match.files():
  1088     if not slowpath and not match.files():
  1093         # No files, no patterns.  Display all revs.
  1089         # No files, no patterns.  Display all revs.
  1094         wanted = set(revs)
  1090         wanted = set(revs)
  1095     copies = []
  1091     copies = []
       
  1092 
  1096     if not slowpath:
  1093     if not slowpath:
  1097         # Only files, no patterns.  Check the history of each file.
  1094         # Only files, no patterns.  Check the history of each file.
  1098         def filerevgen(filelog, node):
  1095         def filerevgen(filelog, node):
  1099             cl_count = len(repo)
  1096             cl_count = len(repo)
  1100             if node is None:
  1097             if node is None:
  1127                     if follow:
  1124                     if follow:
  1128                         raise util.Abort(_('cannot follow nonexistent file: "%s"') % file_)
  1125                         raise util.Abort(_('cannot follow nonexistent file: "%s"') % file_)
  1129                     slowpath = True
  1126                     slowpath = True
  1130                     break
  1127                     break
  1131                 else:
  1128                 else:
  1132                     ui.warn(_('%s:%s copy source revision cannot be found!\n')
       
  1133                             % (file_, short(node)))
       
  1134                     continue
  1129                     continue
  1135             for rev, copied in filerevgen(filelog, node):
  1130             for rev, copied in filerevgen(filelog, node):
  1136                 if rev <= maxrev:
  1131                 if rev <= maxrev:
  1137                     if rev < minrev:
  1132                     if rev < minrev:
  1138                         break
  1133                         break
  1213         else:
  1208         else:
  1214             def want(rev):
  1209             def want(rev):
  1215                 return rev in wanted
  1210                 return rev in wanted
  1216 
  1211 
  1217         for i, window in increasing_windows(0, len(revs)):
  1212         for i, window in increasing_windows(0, len(revs)):
       
  1213             change = util.cachefunc(repo.changectx)
  1218             nrevs = [rev for rev in revs[i:i+window] if want(rev)]
  1214             nrevs = [rev for rev in revs[i:i+window] if want(rev)]
  1219             for rev in sorted(nrevs):
  1215             for rev in sorted(nrevs):
  1220                 fns = fncache.get(rev)
  1216                 fns = fncache.get(rev)
  1221                 ctx = change(rev)
  1217                 ctx = change(rev)
  1222                 if not fns:
  1218                 if not fns:
  1223                     def fns_generator():
  1219                     def fns_generator():
  1224                         for f in ctx.files():
  1220                         for f in ctx.files():
  1225                             if match(f):
  1221                             if match(f):
  1226                                 yield f
  1222                                 yield f
  1227                     fns = fns_generator()
  1223                     fns = fns_generator()
  1228                 yield 'add', ctx, fns
  1224                 prepare(ctx, fns)
  1229             for rev in nrevs:
  1225             for rev in nrevs:
  1230                 yield 'iter', change(rev), None
  1226                 yield change(rev)
  1231     return iterate()
  1227     return iterate()
  1232 
  1228 
  1233 def commit(ui, repo, commitfunc, pats, opts):
  1229 def commit(ui, repo, commitfunc, pats, opts):
  1234     '''commit the specified files or all outstanding changes'''
  1230     '''commit the specified files or all outstanding changes'''
  1235     date = opts.get('date')
  1231     date = opts.get('date')