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 |
7 |
8 from revlog import * |
8 from revlog import * |
9 from demandload import * |
9 from demandload import * |
10 demandload(globals(), "bdiff os") |
10 demandload(globals(), "os") |
11 |
11 |
12 class filelog(revlog): |
12 class filelog(revlog): |
13 def __init__(self, opener, path, defversion=REVLOG_DEFAULT_VERSION): |
13 def __init__(self, opener, path, defversion=REVLOG_DEFAULT_VERSION): |
14 revlog.__init__(self, opener, |
14 revlog.__init__(self, opener, |
15 os.path.join("data", self.encodedir(path + ".i")), |
15 os.path.join("data", self.encodedir(path + ".i")), |
82 if self.renamed(node): |
82 if self.renamed(node): |
83 t2 = self.read(node) |
83 t2 = self.read(node) |
84 return t2 != text |
84 return t2 != text |
85 |
85 |
86 return revlog.cmp(self, node, text) |
86 return revlog.cmp(self, node, text) |
87 |
|
88 def annotate(self, node): |
|
89 |
|
90 def decorate(text, rev): |
|
91 return ([rev] * len(text.splitlines()), text) |
|
92 |
|
93 def pair(parent, child): |
|
94 for a1, a2, b1, b2 in bdiff.blocks(parent[1], child[1]): |
|
95 child[0][b1:b2] = parent[0][a1:a2] |
|
96 return child |
|
97 |
|
98 # find all ancestors |
|
99 needed = {(self, node):1} |
|
100 files = [self] |
|
101 visit = [(self, node)] |
|
102 while visit: |
|
103 f, n = visit.pop(0) |
|
104 rn = f.renamed(n) |
|
105 if rn: |
|
106 f, n = rn |
|
107 f = filelog(self.opener, f, self.defversion) |
|
108 files.insert(0, f) |
|
109 if (f, n) not in needed: |
|
110 needed[(f, n)] = 1 |
|
111 else: |
|
112 needed[(f, n)] += 1 |
|
113 for p in f.parents(n): |
|
114 if p == nullid: |
|
115 continue |
|
116 if (f, p) not in needed: |
|
117 needed[(f, p)] = 1 |
|
118 visit.append((f, p)) |
|
119 else: |
|
120 # count how many times we'll use this |
|
121 needed[(f, p)] += 1 |
|
122 |
|
123 # sort by revision (per file) which is a topological order |
|
124 visit = [] |
|
125 for f in files: |
|
126 fn = [(f.rev(n[1]), f, n[1]) for n in needed.keys() if n[0] == f] |
|
127 fn.sort() |
|
128 visit.extend(fn) |
|
129 hist = {} |
|
130 |
|
131 for i in range(len(visit)): |
|
132 r, f, n = visit[i] |
|
133 curr = decorate(f.read(n), f.linkrev(n)) |
|
134 if r == -1: |
|
135 continue |
|
136 parents = f.parents(n) |
|
137 # follow parents across renames |
|
138 if r < 1 and i > 0: |
|
139 j = i |
|
140 while j > 0 and visit[j][1] == f: |
|
141 j -= 1 |
|
142 parents = (visit[j][2],) |
|
143 f = visit[j][1] |
|
144 else: |
|
145 parents = f.parents(n) |
|
146 for p in parents: |
|
147 if p != nullid: |
|
148 curr = pair(hist[p], curr) |
|
149 # trim the history of unneeded revs |
|
150 needed[(f, p)] -= 1 |
|
151 if not needed[(f, p)]: |
|
152 del hist[p] |
|
153 hist[n] = curr |
|
154 |
|
155 return zip(hist[n][0], hist[n][1].splitlines(1)) |
|