mercurial/context.py
changeset 3165 5c93dd0ae413
parent 3154 15d585dcdd1c
child 3203 14792adabf80
child 3207 0790dce2f3a8
equal deleted inserted replaced
3164:706277866251 3165:5c93dd0ae413
     2 #
     2 #
     3 # Copyright 2006 Matt Mackall <mpm@selenic.com>
     3 # Copyright 2006 Matt Mackall <mpm@selenic.com>
     4 #
     4 #
     5 # This software may be used and distributed according to the terms
     5 # This software may be used and distributed according to the terms
     6 # of the GNU General Public License, incorporated herein by reference.
     6 # of the GNU General Public License, incorporated herein by reference.
       
     7 
       
     8 from demandload import *
       
     9 from node import *
       
    10 demandload(globals(), 'bdiff')
     7 
    11 
     8 from node import *
    12 from node import *
     9 from demandload import demandload
    13 from demandload import demandload
    10 demandload(globals(), "ancestor util")
    14 demandload(globals(), "ancestor util")
    11 
    15 
   163         # hard for renames
   167         # hard for renames
   164         c = self._filelog.children(self._filenode)
   168         c = self._filelog.children(self._filenode)
   165         return [ filectx(self._repo, self._path, fileid=x,
   169         return [ filectx(self._repo, self._path, fileid=x,
   166                          filelog=self._filelog) for x in c ]
   170                          filelog=self._filelog) for x in c ]
   167 
   171 
   168     def annotate(self):
   172     def annotate(self, follow=False):
   169         getctx = util.cachefunc(lambda x: filectx(self._repo, self._path,
   173         '''returns a list of tuples of (ctx, line) for each line
   170                                                   changeid=x,
   174         in the file, where ctx is the filectx of the node where
   171                                                   filelog=self._filelog))
   175         that line was last changed'''
   172         hist = self._filelog.annotate(self._filenode)
   176 
   173 
   177         def decorate(text, rev):
   174         return [(getctx(rev), line) for rev, line in hist]
   178             return ([rev] * len(text.splitlines()), text)
       
   179 
       
   180         def pair(parent, child):
       
   181             for a1, a2, b1, b2 in bdiff.blocks(parent[1], child[1]):
       
   182                 child[0][b1:b2] = parent[0][a1:a2]
       
   183             return child
       
   184 
       
   185         getlog = util.cachefunc(lambda x: self._repo.file(x))
       
   186         def getctx(path, fileid):
       
   187             log = path == self._path and self._filelog or getlog(path)
       
   188             return filectx(self._repo, path, fileid=fileid, filelog=log)
       
   189         getctx = util.cachefunc(getctx)
       
   190 
       
   191         def parents(f):
       
   192             # we want to reuse filectx objects as much as possible
       
   193             p = f._path
       
   194             pl = [ (p, f._filelog.rev(n)) for n in f._filelog.parents(f._filenode) ]
       
   195 
       
   196             if follow:
       
   197                 r = f.renamed()
       
   198                 if r:
       
   199                     pl[0] = (r[0], getlog(r[0]).rev(r[1]))
       
   200 
       
   201             return [ getctx(p, n) for p, n in pl if n != -1 ]
       
   202                 
       
   203         # find all ancestors
       
   204         needed = {self: 1}
       
   205         visit = [self]
       
   206         files = [self._path]
       
   207         while visit:
       
   208             f = visit.pop(0)
       
   209             for p in parents(f):
       
   210                 if p not in needed:
       
   211                     needed[p] = 1
       
   212                     visit.append(p)
       
   213                     if p._path not in files:
       
   214                         files.append(p._path)
       
   215                 else:
       
   216                     # count how many times we'll use this
       
   217                     needed[p] += 1
       
   218 
       
   219         # sort by revision (per file) which is a topological order
       
   220         visit = []
       
   221         files.reverse()
       
   222         for f in files:
       
   223             fn = [(n._filerev, n) for n in needed.keys() if n._path == f]
       
   224             fn.sort()
       
   225             visit.extend(fn)
       
   226         hist = {}
       
   227 
       
   228         for r, f in visit:
       
   229             curr = decorate(f.data(), f)
       
   230             for p in parents(f):
       
   231                 if p != nullid:
       
   232                     curr = pair(hist[p], curr)
       
   233                     # trim the history of unneeded revs
       
   234                     needed[p] -= 1
       
   235                     if not needed[p]:
       
   236                         del hist[p]
       
   237             hist[f] = curr
       
   238 
       
   239         return zip(hist[f][0], hist[f][1].splitlines(1))
   175 
   240 
   176     def ancestor(self, fc2):
   241     def ancestor(self, fc2):
   177         """
   242         """
   178         find the common ancestor file context, if any, of self, and fc2
   243         find the common ancestor file context, if any, of self, and fc2
   179         """
   244         """