##// END OF EJS Templates
filelog: record what's using attributes...
Gregory Szorc -
r39819:76f92d20 default
parent child Browse files
Show More
@@ -1,262 +1,278 b''
1 # filelog.py - file history class for mercurial
1 # filelog.py - file history class for mercurial
2 #
2 #
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 from __future__ import absolute_import
8 from __future__ import absolute_import
9
9
10 from . import (
10 from . import (
11 error,
11 error,
12 repository,
12 repository,
13 revlog,
13 revlog,
14 )
14 )
15 from .utils import (
15 from .utils import (
16 interfaceutil,
16 interfaceutil,
17 )
17 )
18
18
19 @interfaceutil.implementer(repository.ifilestorage)
19 @interfaceutil.implementer(repository.ifilestorage)
20 class filelog(object):
20 class filelog(object):
21 def __init__(self, opener, path):
21 def __init__(self, opener, path):
22 self._revlog = revlog.revlog(opener,
22 self._revlog = revlog.revlog(opener,
23 '/'.join(('data', path + '.i')),
23 '/'.join(('data', path + '.i')),
24 censorable=True)
24 censorable=True)
25 # full name of the user visible file, relative to the repository root
25 # Full name of the user visible file, relative to the repository root.
26 # Used by LFS.
26 self.filename = path
27 self.filename = path
28 # Used by repo upgrade.
27 self.index = self._revlog.index
29 self.index = self._revlog.index
30 # Used by verify.
28 self.version = self._revlog.version
31 self.version = self._revlog.version
32 # Used by changegroup generation.
29 self._generaldelta = self._revlog._generaldelta
33 self._generaldelta = self._revlog._generaldelta
30
34
31 def __len__(self):
35 def __len__(self):
32 return len(self._revlog)
36 return len(self._revlog)
33
37
34 def __iter__(self):
38 def __iter__(self):
35 return self._revlog.__iter__()
39 return self._revlog.__iter__()
36
40
37 def revs(self, start=0, stop=None):
41 def revs(self, start=0, stop=None):
38 return self._revlog.revs(start=start, stop=stop)
42 return self._revlog.revs(start=start, stop=stop)
39
43
40 def parents(self, node):
44 def parents(self, node):
41 return self._revlog.parents(node)
45 return self._revlog.parents(node)
42
46
43 def parentrevs(self, rev):
47 def parentrevs(self, rev):
44 return self._revlog.parentrevs(rev)
48 return self._revlog.parentrevs(rev)
45
49
46 def rev(self, node):
50 def rev(self, node):
47 return self._revlog.rev(node)
51 return self._revlog.rev(node)
48
52
49 def node(self, rev):
53 def node(self, rev):
50 return self._revlog.node(rev)
54 return self._revlog.node(rev)
51
55
52 def lookup(self, node):
56 def lookup(self, node):
53 return self._revlog.lookup(node)
57 return self._revlog.lookup(node)
54
58
55 def linkrev(self, rev):
59 def linkrev(self, rev):
56 return self._revlog.linkrev(rev)
60 return self._revlog.linkrev(rev)
57
61
62 # Used by LFS, verify.
58 def flags(self, rev):
63 def flags(self, rev):
59 return self._revlog.flags(rev)
64 return self._revlog.flags(rev)
60
65
61 def commonancestorsheads(self, node1, node2):
66 def commonancestorsheads(self, node1, node2):
62 return self._revlog.commonancestorsheads(node1, node2)
67 return self._revlog.commonancestorsheads(node1, node2)
63
68
69 # Used by dagop.blockdescendants().
64 def descendants(self, revs):
70 def descendants(self, revs):
65 return self._revlog.descendants(revs)
71 return self._revlog.descendants(revs)
66
72
73 # Used by hgweb.
67 def headrevs(self):
74 def headrevs(self):
68 return self._revlog.headrevs()
75 return self._revlog.headrevs()
69
76
70 def heads(self, start=None, stop=None):
77 def heads(self, start=None, stop=None):
71 return self._revlog.heads(start, stop)
78 return self._revlog.heads(start, stop)
72
79
80 # Used by hgweb, children extension.
73 def children(self, node):
81 def children(self, node):
74 return self._revlog.children(node)
82 return self._revlog.children(node)
75
83
76 def deltaparent(self, rev):
84 def deltaparent(self, rev):
77 return self._revlog.deltaparent(rev)
85 return self._revlog.deltaparent(rev)
78
86
79 def iscensored(self, rev):
87 def iscensored(self, rev):
80 return self._revlog.iscensored(rev)
88 return self._revlog.iscensored(rev)
81
89
90 # Used by verify.
82 def rawsize(self, rev):
91 def rawsize(self, rev):
83 return self._revlog.rawsize(rev)
92 return self._revlog.rawsize(rev)
84
93
94 # Might be unused.
85 def checkhash(self, text, node, p1=None, p2=None, rev=None):
95 def checkhash(self, text, node, p1=None, p2=None, rev=None):
86 return self._revlog.checkhash(text, node, p1=p1, p2=p2, rev=rev)
96 return self._revlog.checkhash(text, node, p1=p1, p2=p2, rev=rev)
87
97
88 def revision(self, node, _df=None, raw=False):
98 def revision(self, node, _df=None, raw=False):
89 return self._revlog.revision(node, _df=_df, raw=raw)
99 return self._revlog.revision(node, _df=_df, raw=raw)
90
100
91 def revdiff(self, rev1, rev2):
101 def revdiff(self, rev1, rev2):
92 return self._revlog.revdiff(rev1, rev2)
102 return self._revlog.revdiff(rev1, rev2)
93
103
94 def emitrevisiondeltas(self, requests):
104 def emitrevisiondeltas(self, requests):
95 return self._revlog.emitrevisiondeltas(requests)
105 return self._revlog.emitrevisiondeltas(requests)
96
106
97 def addrevision(self, revisiondata, transaction, linkrev, p1, p2,
107 def addrevision(self, revisiondata, transaction, linkrev, p1, p2,
98 node=None, flags=revlog.REVIDX_DEFAULT_FLAGS,
108 node=None, flags=revlog.REVIDX_DEFAULT_FLAGS,
99 cachedelta=None):
109 cachedelta=None):
100 return self._revlog.addrevision(revisiondata, transaction, linkrev,
110 return self._revlog.addrevision(revisiondata, transaction, linkrev,
101 p1, p2, node=node, flags=flags,
111 p1, p2, node=node, flags=flags,
102 cachedelta=cachedelta)
112 cachedelta=cachedelta)
103
113
104 def addgroup(self, deltas, linkmapper, transaction, addrevisioncb=None):
114 def addgroup(self, deltas, linkmapper, transaction, addrevisioncb=None):
105 return self._revlog.addgroup(deltas, linkmapper, transaction,
115 return self._revlog.addgroup(deltas, linkmapper, transaction,
106 addrevisioncb=addrevisioncb)
116 addrevisioncb=addrevisioncb)
107
117
108 def getstrippoint(self, minlink):
118 def getstrippoint(self, minlink):
109 return self._revlog.getstrippoint(minlink)
119 return self._revlog.getstrippoint(minlink)
110
120
111 def strip(self, minlink, transaction):
121 def strip(self, minlink, transaction):
112 return self._revlog.strip(minlink, transaction)
122 return self._revlog.strip(minlink, transaction)
113
123
114 def censorrevision(self, tr, node, tombstone=b''):
124 def censorrevision(self, tr, node, tombstone=b''):
115 return self._revlog.censorrevision(node, tombstone=tombstone)
125 return self._revlog.censorrevision(node, tombstone=tombstone)
116
126
117 def files(self):
127 def files(self):
118 return self._revlog.files()
128 return self._revlog.files()
119
129
130 # Used by verify.
120 def checksize(self):
131 def checksize(self):
121 return self._revlog.checksize()
132 return self._revlog.checksize()
122
133
123 def read(self, node):
134 def read(self, node):
124 t = self.revision(node)
135 t = self.revision(node)
125 if not t.startswith('\1\n'):
136 if not t.startswith('\1\n'):
126 return t
137 return t
127 s = t.index('\1\n', 2)
138 s = t.index('\1\n', 2)
128 return t[s + 2:]
139 return t[s + 2:]
129
140
130 def add(self, text, meta, transaction, link, p1=None, p2=None):
141 def add(self, text, meta, transaction, link, p1=None, p2=None):
131 if meta or text.startswith('\1\n'):
142 if meta or text.startswith('\1\n'):
132 text = revlog.packmeta(meta, text)
143 text = revlog.packmeta(meta, text)
133 return self.addrevision(text, transaction, link, p1, p2)
144 return self.addrevision(text, transaction, link, p1, p2)
134
145
135 def renamed(self, node):
146 def renamed(self, node):
136 if self.parents(node)[0] != revlog.nullid:
147 if self.parents(node)[0] != revlog.nullid:
137 return False
148 return False
138 t = self.revision(node)
149 t = self.revision(node)
139 m = revlog.parsemeta(t)[0]
150 m = revlog.parsemeta(t)[0]
140 # copy and copyrev occur in pairs. In rare cases due to bugs,
151 # copy and copyrev occur in pairs. In rare cases due to bugs,
141 # one can occur without the other.
152 # one can occur without the other.
142 if m and "copy" in m and "copyrev" in m:
153 if m and "copy" in m and "copyrev" in m:
143 return (m["copy"], revlog.bin(m["copyrev"]))
154 return (m["copy"], revlog.bin(m["copyrev"]))
144 return False
155 return False
145
156
146 def size(self, rev):
157 def size(self, rev):
147 """return the size of a given revision"""
158 """return the size of a given revision"""
148
159
149 # for revisions with renames, we have to go the slow way
160 # for revisions with renames, we have to go the slow way
150 node = self.node(rev)
161 node = self.node(rev)
151 if self.renamed(node):
162 if self.renamed(node):
152 return len(self.read(node))
163 return len(self.read(node))
153 if self.iscensored(rev):
164 if self.iscensored(rev):
154 return 0
165 return 0
155
166
156 # XXX if self.read(node).startswith("\1\n"), this returns (size+4)
167 # XXX if self.read(node).startswith("\1\n"), this returns (size+4)
157 return self._revlog.size(rev)
168 return self._revlog.size(rev)
158
169
159 def cmp(self, node, text):
170 def cmp(self, node, text):
160 """compare text with a given file revision
171 """compare text with a given file revision
161
172
162 returns True if text is different than what is stored.
173 returns True if text is different than what is stored.
163 """
174 """
164
175
165 t = text
176 t = text
166 if text.startswith('\1\n'):
177 if text.startswith('\1\n'):
167 t = '\1\n\1\n' + text
178 t = '\1\n\1\n' + text
168
179
169 samehashes = not self._revlog.cmp(node, t)
180 samehashes = not self._revlog.cmp(node, t)
170 if samehashes:
181 if samehashes:
171 return False
182 return False
172
183
173 # censored files compare against the empty file
184 # censored files compare against the empty file
174 if self.iscensored(self.rev(node)):
185 if self.iscensored(self.rev(node)):
175 return text != ''
186 return text != ''
176
187
177 # renaming a file produces a different hash, even if the data
188 # renaming a file produces a different hash, even if the data
178 # remains unchanged. Check if it's the case (slow):
189 # remains unchanged. Check if it's the case (slow):
179 if self.renamed(node):
190 if self.renamed(node):
180 t2 = self.read(node)
191 t2 = self.read(node)
181 return t2 != text
192 return t2 != text
182
193
183 return True
194 return True
184
195
196 # TODO these aren't part of the interface and aren't internal methods.
197 # Callers should be fixed to not use them.
198
199 # Used by LFS.
185 @property
200 @property
186 def filename(self):
201 def filename(self):
187 return self._revlog.filename
202 return self._revlog.filename
188
203
189 @filename.setter
204 @filename.setter
190 def filename(self, value):
205 def filename(self, value):
191 self._revlog.filename = value
206 self._revlog.filename = value
192
207
193 # TODO these aren't part of the interface and aren't internal methods.
208 # Used by bundlefilelog, unionfilelog.
194 # Callers should be fixed to not use them.
195 @property
209 @property
196 def indexfile(self):
210 def indexfile(self):
197 return self._revlog.indexfile
211 return self._revlog.indexfile
198
212
199 @indexfile.setter
213 @indexfile.setter
200 def indexfile(self, value):
214 def indexfile(self, value):
201 self._revlog.indexfile = value
215 self._revlog.indexfile = value
202
216
217 # Used by LFS, repo upgrade.
203 @property
218 @property
204 def opener(self):
219 def opener(self):
205 return self._revlog.opener
220 return self._revlog.opener
206
221
222 # Used by repo upgrade.
207 def clone(self, tr, destrevlog, **kwargs):
223 def clone(self, tr, destrevlog, **kwargs):
208 if not isinstance(destrevlog, filelog):
224 if not isinstance(destrevlog, filelog):
209 raise error.ProgrammingError('expected filelog to clone()')
225 raise error.ProgrammingError('expected filelog to clone()')
210
226
211 return self._revlog.clone(tr, destrevlog._revlog, **kwargs)
227 return self._revlog.clone(tr, destrevlog._revlog, **kwargs)
212
228
213 class narrowfilelog(filelog):
229 class narrowfilelog(filelog):
214 """Filelog variation to be used with narrow stores."""
230 """Filelog variation to be used with narrow stores."""
215
231
216 def __init__(self, opener, path, narrowmatch):
232 def __init__(self, opener, path, narrowmatch):
217 super(narrowfilelog, self).__init__(opener, path)
233 super(narrowfilelog, self).__init__(opener, path)
218 self._narrowmatch = narrowmatch
234 self._narrowmatch = narrowmatch
219
235
220 def renamed(self, node):
236 def renamed(self, node):
221 res = super(narrowfilelog, self).renamed(node)
237 res = super(narrowfilelog, self).renamed(node)
222
238
223 # Renames that come from outside the narrowspec are problematic
239 # Renames that come from outside the narrowspec are problematic
224 # because we may lack the base text for the rename. This can result
240 # because we may lack the base text for the rename. This can result
225 # in code attempting to walk the ancestry or compute a diff
241 # in code attempting to walk the ancestry or compute a diff
226 # encountering a missing revision. We address this by silently
242 # encountering a missing revision. We address this by silently
227 # removing rename metadata if the source file is outside the
243 # removing rename metadata if the source file is outside the
228 # narrow spec.
244 # narrow spec.
229 #
245 #
230 # A better solution would be to see if the base revision is available,
246 # A better solution would be to see if the base revision is available,
231 # rather than assuming it isn't.
247 # rather than assuming it isn't.
232 #
248 #
233 # An even better solution would be to teach all consumers of rename
249 # An even better solution would be to teach all consumers of rename
234 # metadata that the base revision may not be available.
250 # metadata that the base revision may not be available.
235 #
251 #
236 # TODO consider better ways of doing this.
252 # TODO consider better ways of doing this.
237 if res and not self._narrowmatch(res[0]):
253 if res and not self._narrowmatch(res[0]):
238 return None
254 return None
239
255
240 return res
256 return res
241
257
242 def size(self, rev):
258 def size(self, rev):
243 # Because we have a custom renamed() that may lie, we need to call
259 # Because we have a custom renamed() that may lie, we need to call
244 # the base renamed() to report accurate results.
260 # the base renamed() to report accurate results.
245 node = self.node(rev)
261 node = self.node(rev)
246 if super(narrowfilelog, self).renamed(node):
262 if super(narrowfilelog, self).renamed(node):
247 return len(self.read(node))
263 return len(self.read(node))
248 else:
264 else:
249 return super(narrowfilelog, self).size(rev)
265 return super(narrowfilelog, self).size(rev)
250
266
251 def cmp(self, node, text):
267 def cmp(self, node, text):
252 different = super(narrowfilelog, self).cmp(node, text)
268 different = super(narrowfilelog, self).cmp(node, text)
253
269
254 # Because renamed() may lie, we may get false positives for
270 # Because renamed() may lie, we may get false positives for
255 # different content. Check for this by comparing against the original
271 # different content. Check for this by comparing against the original
256 # renamed() implementation.
272 # renamed() implementation.
257 if different:
273 if different:
258 if super(narrowfilelog, self).renamed(node):
274 if super(narrowfilelog, self).renamed(node):
259 t2 = self.read(node)
275 t2 = self.read(node)
260 return t2 != text
276 return t2 != text
261
277
262 return different
278 return different
General Comments 0
You need to be logged in to leave comments. Login now