mercurial/commands.py
changeset 3558 45620faafa28
parent 3557 68341c06bc61
child 3561 cd2216599c99
equal deleted inserted replaced
3557:68341c06bc61 3558:45620faafa28
    48         except IOError, inst:
    48         except IOError, inst:
    49             raise util.Abort(_("can't read commit message '%s': %s") %
    49             raise util.Abort(_("can't read commit message '%s': %s") %
    50                              (logfile, inst.strerror))
    50                              (logfile, inst.strerror))
    51     return message
    51     return message
    52 
    52 
    53 def walkchangerevs(ui, repo, pats, opts):
    53 def walkchangerevs(ui, repo, pats, change, opts):
    54     '''Iterate over files and the revs they changed in.
    54     '''Iterate over files and the revs they changed in.
    55 
    55 
    56     Callers most commonly need to iterate backwards over the history
    56     Callers most commonly need to iterate backwards over the history
    57     it is interested in.  Doing so has awful (quadratic-looking)
    57     it is interested in.  Doing so has awful (quadratic-looking)
    58     performance, so we use iterators in a "windowed" way.
    58     performance, so we use iterators in a "windowed" way.
    59 
    59 
    60     We walk a window of revisions in the desired order.  Within the
    60     We walk a window of revisions in the desired order.  Within the
    61     window, we first walk forwards to gather data, then in the desired
    61     window, we first walk forwards to gather data, then in the desired
    62     order (usually backwards) to display it.
    62     order (usually backwards) to display it.
    63 
    63 
    64     This function returns an (iterator, getchange, matchfn) tuple.  The
    64     This function returns an (iterator, matchfn) tuple. The iterator
    65     getchange function returns the changelog entry for a numeric
    65     yields 3-tuples. They will be of one of the following forms:
    66     revision.  The iterator yields 3-tuples.  They will be of one of
       
    67     the following forms:
       
    68 
    66 
    69     "window", incrementing, lastrev: stepping through a window,
    67     "window", incrementing, lastrev: stepping through a window,
    70     positive if walking forwards through revs, last rev in the
    68     positive if walking forwards through revs, last rev in the
    71     sequence iterated over - use to reset state for the current window
    69     sequence iterated over - use to reset state for the current window
    72 
    70 
    89                 yield start, min(windowsize, start-end-1)
    87                 yield start, min(windowsize, start-end-1)
    90                 start -= windowsize
    88                 start -= windowsize
    91                 if windowsize < sizelimit:
    89                 if windowsize < sizelimit:
    92                     windowsize *= 2
    90                     windowsize *= 2
    93 
    91 
    94 
       
    95     files, matchfn, anypats = cmdutil.matchpats(repo, pats, opts)
    92     files, matchfn, anypats = cmdutil.matchpats(repo, pats, opts)
    96     follow = opts.get('follow') or opts.get('follow_first')
    93     follow = opts.get('follow') or opts.get('follow_first')
    97 
    94 
    98     if repo.changelog.count() == 0:
    95     if repo.changelog.count() == 0:
    99         return [], False, matchfn
    96         return [], matchfn
   100 
    97 
   101     if follow:
    98     if follow:
   102         defrange = '%s:0' % repo.changectx().rev()
    99         defrange = '%s:0' % repo.changectx().rev()
   103     else:
   100     else:
   104         defrange = 'tip:0'
   101         defrange = 'tip:0'
   105     revs = cmdutil.revrange(ui, repo, opts['rev'] or [defrange])
   102     revs = cmdutil.revrange(ui, repo, opts['rev'] or [defrange])
   106     wanted = {}
   103     wanted = {}
   107     slowpath = anypats
   104     slowpath = anypats
   108     fncache = {}
   105     fncache = {}
   109 
       
   110     chcache = {}
       
   111     def getchange(rev):
       
   112         ch = chcache.get(rev)
       
   113         if ch is None:
       
   114             chcache[rev] = ch = repo.changelog.read(repo.lookup(str(rev)))
       
   115         return ch
       
   116 
   106 
   117     if not slowpath and not files:
   107     if not slowpath and not files:
   118         # No files, no patterns.  Display all revs.
   108         # No files, no patterns.  Display all revs.
   119         wanted = dict(zip(revs, revs))
   109         wanted = dict(zip(revs, revs))
   120     copies = []
   110     copies = []
   167 
   157 
   168         # The slow path checks files modified in every changeset.
   158         # The slow path checks files modified in every changeset.
   169         def changerevgen():
   159         def changerevgen():
   170             for i, window in increasing_windows(repo.changelog.count()-1, -1):
   160             for i, window in increasing_windows(repo.changelog.count()-1, -1):
   171                 for j in xrange(i - window, i + 1):
   161                 for j in xrange(i - window, i + 1):
   172                     yield j, getchange(j)[3]
   162                     yield j, change(j)[3]
   173 
   163 
   174         for rev, changefiles in changerevgen():
   164         for rev, changefiles in changerevgen():
   175             matches = filter(matchfn, changefiles)
   165             matches = filter(matchfn, changefiles)
   176             if matches:
   166             if matches:
   177                 fncache[rev] = matches
   167                 fncache[rev] = matches
   238             yield 'window', revs[0] < revs[-1], revs[-1]
   228             yield 'window', revs[0] < revs[-1], revs[-1]
   239             nrevs = [rev for rev in revs[i:i+window] if want(rev)]
   229             nrevs = [rev for rev in revs[i:i+window] if want(rev)]
   240             srevs = list(nrevs)
   230             srevs = list(nrevs)
   241             srevs.sort()
   231             srevs.sort()
   242             for rev in srevs:
   232             for rev in srevs:
   243                 fns = fncache.get(rev) or filter(matchfn, getchange(rev)[3])
   233                 fns = fncache.get(rev) or filter(matchfn, change(rev)[3])
   244                 yield 'add', rev, fns
   234                 yield 'add', rev, fns
   245             for rev in nrevs:
   235             for rev in nrevs:
   246                 yield 'iter', rev, None
   236                 yield 'iter', rev, None
   247     return iterate(), getchange, matchfn
   237     return iterate(), matchfn
   248 
   238 
   249 def write_bundle(cg, filename=None, compress=True):
   239 def write_bundle(cg, filename=None, compress=True):
   250     """Write a bundle file and return its filename.
   240     """Write a bundle file and return its filename.
   251 
   241 
   252     Existing files will not be overwritten.
   242     Existing files will not be overwritten.
  1489             counts[change] += 1
  1479             counts[change] += 1
  1490         return counts['+'], counts['-']
  1480         return counts['+'], counts['-']
  1491 
  1481 
  1492     fstate = {}
  1482     fstate = {}
  1493     skip = {}
  1483     skip = {}
  1494     changeiter, getchange, matchfn = walkchangerevs(ui, repo, pats, opts)
  1484     getchange = util.cachefunc(lambda r:repo.changectx(r).changeset())
       
  1485     changeiter, matchfn = walkchangerevs(ui, repo, pats, getchange, opts)
  1495     count = 0
  1486     count = 0
  1496     incrementing = False
  1487     incrementing = False
  1497     follow = opts.get('follow')
  1488     follow = opts.get('follow')
  1498     for st, rev, fns in changeiter:
  1489     for st, rev, fns in changeiter:
  1499         if st == 'window':
  1490         if st == 'window':
  1822             if self.debugflag:
  1813             if self.debugflag:
  1823                 self.write(*args)
  1814                 self.write(*args)
  1824         def __getattr__(self, key):
  1815         def __getattr__(self, key):
  1825             return getattr(self.ui, key)
  1816             return getattr(self.ui, key)
  1826 
  1817 
  1827     changeiter, getchange, matchfn = walkchangerevs(ui, repo, pats, opts)
  1818     getchange = util.cachefunc(lambda r:repo.changectx(r).changeset())
       
  1819     changeiter, matchfn = walkchangerevs(ui, repo, pats, getchange, opts)
  1828 
  1820 
  1829     if opts['branches']:
  1821     if opts['branches']:
  1830         ui.warn(_("the --branches option is deprecated, "
  1822         ui.warn(_("the --branches option is deprecated, "
  1831                   "please use 'hg branches' instead\n"))
  1823                   "please use 'hg branches' instead\n"))
  1832 
  1824