##// END OF EJS Templates
filelog: open the writing context a bit earlier in `addgroup`...
marmoute -
r48628:436932c2 stable
parent child Browse files
Show More
@@ -1,286 +1,287 b''
1 # filelog.py - file history class for mercurial
1 # filelog.py - file history class for mercurial
2 #
2 #
3 # Copyright 2005-2007 Olivia Mackall <olivia@selenic.com>
3 # Copyright 2005-2007 Olivia Mackall <olivia@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 .i18n import _
10 from .i18n import _
11 from .node import nullrev
11 from .node import nullrev
12 from . import (
12 from . import (
13 error,
13 error,
14 revlog,
14 revlog,
15 )
15 )
16 from .interfaces import (
16 from .interfaces import (
17 repository,
17 repository,
18 util as interfaceutil,
18 util as interfaceutil,
19 )
19 )
20 from .utils import storageutil
20 from .utils import storageutil
21 from .revlogutils import (
21 from .revlogutils import (
22 constants as revlog_constants,
22 constants as revlog_constants,
23 )
23 )
24
24
25
25
26 @interfaceutil.implementer(repository.ifilestorage)
26 @interfaceutil.implementer(repository.ifilestorage)
27 class filelog(object):
27 class filelog(object):
28 def __init__(self, opener, path):
28 def __init__(self, opener, path):
29 self._revlog = revlog.revlog(
29 self._revlog = revlog.revlog(
30 opener,
30 opener,
31 # XXX should use the unencoded path
31 # XXX should use the unencoded path
32 target=(revlog_constants.KIND_FILELOG, path),
32 target=(revlog_constants.KIND_FILELOG, path),
33 radix=b'/'.join((b'data', path)),
33 radix=b'/'.join((b'data', path)),
34 censorable=True,
34 censorable=True,
35 )
35 )
36 # Full name of the user visible file, relative to the repository root.
36 # Full name of the user visible file, relative to the repository root.
37 # Used by LFS.
37 # Used by LFS.
38 self._revlog.filename = path
38 self._revlog.filename = path
39 self.nullid = self._revlog.nullid
39 self.nullid = self._revlog.nullid
40
40
41 def __len__(self):
41 def __len__(self):
42 return len(self._revlog)
42 return len(self._revlog)
43
43
44 def __iter__(self):
44 def __iter__(self):
45 return self._revlog.__iter__()
45 return self._revlog.__iter__()
46
46
47 def hasnode(self, node):
47 def hasnode(self, node):
48 if node in (self.nullid, nullrev):
48 if node in (self.nullid, nullrev):
49 return False
49 return False
50
50
51 try:
51 try:
52 self._revlog.rev(node)
52 self._revlog.rev(node)
53 return True
53 return True
54 except (TypeError, ValueError, IndexError, error.LookupError):
54 except (TypeError, ValueError, IndexError, error.LookupError):
55 return False
55 return False
56
56
57 def revs(self, start=0, stop=None):
57 def revs(self, start=0, stop=None):
58 return self._revlog.revs(start=start, stop=stop)
58 return self._revlog.revs(start=start, stop=stop)
59
59
60 def parents(self, node):
60 def parents(self, node):
61 return self._revlog.parents(node)
61 return self._revlog.parents(node)
62
62
63 def parentrevs(self, rev):
63 def parentrevs(self, rev):
64 return self._revlog.parentrevs(rev)
64 return self._revlog.parentrevs(rev)
65
65
66 def rev(self, node):
66 def rev(self, node):
67 return self._revlog.rev(node)
67 return self._revlog.rev(node)
68
68
69 def node(self, rev):
69 def node(self, rev):
70 return self._revlog.node(rev)
70 return self._revlog.node(rev)
71
71
72 def lookup(self, node):
72 def lookup(self, node):
73 return storageutil.fileidlookup(
73 return storageutil.fileidlookup(
74 self._revlog, node, self._revlog.display_id
74 self._revlog, node, self._revlog.display_id
75 )
75 )
76
76
77 def linkrev(self, rev):
77 def linkrev(self, rev):
78 return self._revlog.linkrev(rev)
78 return self._revlog.linkrev(rev)
79
79
80 def commonancestorsheads(self, node1, node2):
80 def commonancestorsheads(self, node1, node2):
81 return self._revlog.commonancestorsheads(node1, node2)
81 return self._revlog.commonancestorsheads(node1, node2)
82
82
83 # Used by dagop.blockdescendants().
83 # Used by dagop.blockdescendants().
84 def descendants(self, revs):
84 def descendants(self, revs):
85 return self._revlog.descendants(revs)
85 return self._revlog.descendants(revs)
86
86
87 def heads(self, start=None, stop=None):
87 def heads(self, start=None, stop=None):
88 return self._revlog.heads(start, stop)
88 return self._revlog.heads(start, stop)
89
89
90 # Used by hgweb, children extension.
90 # Used by hgweb, children extension.
91 def children(self, node):
91 def children(self, node):
92 return self._revlog.children(node)
92 return self._revlog.children(node)
93
93
94 def iscensored(self, rev):
94 def iscensored(self, rev):
95 return self._revlog.iscensored(rev)
95 return self._revlog.iscensored(rev)
96
96
97 def revision(self, node, _df=None, raw=False):
97 def revision(self, node, _df=None, raw=False):
98 return self._revlog.revision(node, _df=_df, raw=raw)
98 return self._revlog.revision(node, _df=_df, raw=raw)
99
99
100 def rawdata(self, node, _df=None):
100 def rawdata(self, node, _df=None):
101 return self._revlog.rawdata(node, _df=_df)
101 return self._revlog.rawdata(node, _df=_df)
102
102
103 def emitrevisions(
103 def emitrevisions(
104 self,
104 self,
105 nodes,
105 nodes,
106 nodesorder=None,
106 nodesorder=None,
107 revisiondata=False,
107 revisiondata=False,
108 assumehaveparentrevisions=False,
108 assumehaveparentrevisions=False,
109 deltamode=repository.CG_DELTAMODE_STD,
109 deltamode=repository.CG_DELTAMODE_STD,
110 sidedata_helpers=None,
110 sidedata_helpers=None,
111 ):
111 ):
112 return self._revlog.emitrevisions(
112 return self._revlog.emitrevisions(
113 nodes,
113 nodes,
114 nodesorder=nodesorder,
114 nodesorder=nodesorder,
115 revisiondata=revisiondata,
115 revisiondata=revisiondata,
116 assumehaveparentrevisions=assumehaveparentrevisions,
116 assumehaveparentrevisions=assumehaveparentrevisions,
117 deltamode=deltamode,
117 deltamode=deltamode,
118 sidedata_helpers=sidedata_helpers,
118 sidedata_helpers=sidedata_helpers,
119 )
119 )
120
120
121 def addrevision(
121 def addrevision(
122 self,
122 self,
123 revisiondata,
123 revisiondata,
124 transaction,
124 transaction,
125 linkrev,
125 linkrev,
126 p1,
126 p1,
127 p2,
127 p2,
128 node=None,
128 node=None,
129 flags=revlog.REVIDX_DEFAULT_FLAGS,
129 flags=revlog.REVIDX_DEFAULT_FLAGS,
130 cachedelta=None,
130 cachedelta=None,
131 ):
131 ):
132 return self._revlog.addrevision(
132 return self._revlog.addrevision(
133 revisiondata,
133 revisiondata,
134 transaction,
134 transaction,
135 linkrev,
135 linkrev,
136 p1,
136 p1,
137 p2,
137 p2,
138 node=node,
138 node=node,
139 flags=flags,
139 flags=flags,
140 cachedelta=cachedelta,
140 cachedelta=cachedelta,
141 )
141 )
142
142
143 def addgroup(
143 def addgroup(
144 self,
144 self,
145 deltas,
145 deltas,
146 linkmapper,
146 linkmapper,
147 transaction,
147 transaction,
148 addrevisioncb=None,
148 addrevisioncb=None,
149 duplicaterevisioncb=None,
149 duplicaterevisioncb=None,
150 maybemissingparents=False,
150 maybemissingparents=False,
151 ):
151 ):
152 if maybemissingparents:
152 if maybemissingparents:
153 raise error.Abort(
153 raise error.Abort(
154 _(
154 _(
155 b'revlog storage does not support missing '
155 b'revlog storage does not support missing '
156 b'parents write mode'
156 b'parents write mode'
157 )
157 )
158 )
158 )
159
159
160 return self._revlog.addgroup(
160 with self._revlog._writing(transaction):
161 deltas,
161 return self._revlog.addgroup(
162 linkmapper,
162 deltas,
163 transaction,
163 linkmapper,
164 addrevisioncb=addrevisioncb,
164 transaction,
165 duplicaterevisioncb=duplicaterevisioncb,
165 addrevisioncb=addrevisioncb,
166 )
166 duplicaterevisioncb=duplicaterevisioncb,
167 )
167
168
168 def getstrippoint(self, minlink):
169 def getstrippoint(self, minlink):
169 return self._revlog.getstrippoint(minlink)
170 return self._revlog.getstrippoint(minlink)
170
171
171 def strip(self, minlink, transaction):
172 def strip(self, minlink, transaction):
172 return self._revlog.strip(minlink, transaction)
173 return self._revlog.strip(minlink, transaction)
173
174
174 def censorrevision(self, tr, node, tombstone=b''):
175 def censorrevision(self, tr, node, tombstone=b''):
175 return self._revlog.censorrevision(tr, node, tombstone=tombstone)
176 return self._revlog.censorrevision(tr, node, tombstone=tombstone)
176
177
177 def files(self):
178 def files(self):
178 return self._revlog.files()
179 return self._revlog.files()
179
180
180 def read(self, node):
181 def read(self, node):
181 return storageutil.filtermetadata(self.revision(node))
182 return storageutil.filtermetadata(self.revision(node))
182
183
183 def add(self, text, meta, transaction, link, p1=None, p2=None):
184 def add(self, text, meta, transaction, link, p1=None, p2=None):
184 if meta or text.startswith(b'\1\n'):
185 if meta or text.startswith(b'\1\n'):
185 text = storageutil.packmeta(meta, text)
186 text = storageutil.packmeta(meta, text)
186 rev = self.addrevision(text, transaction, link, p1, p2)
187 rev = self.addrevision(text, transaction, link, p1, p2)
187 return self.node(rev)
188 return self.node(rev)
188
189
189 def renamed(self, node):
190 def renamed(self, node):
190 return storageutil.filerevisioncopied(self, node)
191 return storageutil.filerevisioncopied(self, node)
191
192
192 def size(self, rev):
193 def size(self, rev):
193 """return the size of a given revision"""
194 """return the size of a given revision"""
194
195
195 # for revisions with renames, we have to go the slow way
196 # for revisions with renames, we have to go the slow way
196 node = self.node(rev)
197 node = self.node(rev)
197 if self.renamed(node):
198 if self.renamed(node):
198 return len(self.read(node))
199 return len(self.read(node))
199 if self.iscensored(rev):
200 if self.iscensored(rev):
200 return 0
201 return 0
201
202
202 # XXX if self.read(node).startswith("\1\n"), this returns (size+4)
203 # XXX if self.read(node).startswith("\1\n"), this returns (size+4)
203 return self._revlog.size(rev)
204 return self._revlog.size(rev)
204
205
205 def cmp(self, node, text):
206 def cmp(self, node, text):
206 """compare text with a given file revision
207 """compare text with a given file revision
207
208
208 returns True if text is different than what is stored.
209 returns True if text is different than what is stored.
209 """
210 """
210 return not storageutil.filedataequivalent(self, node, text)
211 return not storageutil.filedataequivalent(self, node, text)
211
212
212 def verifyintegrity(self, state):
213 def verifyintegrity(self, state):
213 return self._revlog.verifyintegrity(state)
214 return self._revlog.verifyintegrity(state)
214
215
215 def storageinfo(
216 def storageinfo(
216 self,
217 self,
217 exclusivefiles=False,
218 exclusivefiles=False,
218 sharedfiles=False,
219 sharedfiles=False,
219 revisionscount=False,
220 revisionscount=False,
220 trackedsize=False,
221 trackedsize=False,
221 storedsize=False,
222 storedsize=False,
222 ):
223 ):
223 return self._revlog.storageinfo(
224 return self._revlog.storageinfo(
224 exclusivefiles=exclusivefiles,
225 exclusivefiles=exclusivefiles,
225 sharedfiles=sharedfiles,
226 sharedfiles=sharedfiles,
226 revisionscount=revisionscount,
227 revisionscount=revisionscount,
227 trackedsize=trackedsize,
228 trackedsize=trackedsize,
228 storedsize=storedsize,
229 storedsize=storedsize,
229 )
230 )
230
231
231 # Used by repo upgrade.
232 # Used by repo upgrade.
232 def clone(self, tr, destrevlog, **kwargs):
233 def clone(self, tr, destrevlog, **kwargs):
233 if not isinstance(destrevlog, filelog):
234 if not isinstance(destrevlog, filelog):
234 raise error.ProgrammingError(b'expected filelog to clone()')
235 raise error.ProgrammingError(b'expected filelog to clone()')
235
236
236 return self._revlog.clone(tr, destrevlog._revlog, **kwargs)
237 return self._revlog.clone(tr, destrevlog._revlog, **kwargs)
237
238
238
239
239 class narrowfilelog(filelog):
240 class narrowfilelog(filelog):
240 """Filelog variation to be used with narrow stores."""
241 """Filelog variation to be used with narrow stores."""
241
242
242 def __init__(self, opener, path, narrowmatch):
243 def __init__(self, opener, path, narrowmatch):
243 super(narrowfilelog, self).__init__(opener, path)
244 super(narrowfilelog, self).__init__(opener, path)
244 self._narrowmatch = narrowmatch
245 self._narrowmatch = narrowmatch
245
246
246 def renamed(self, node):
247 def renamed(self, node):
247 res = super(narrowfilelog, self).renamed(node)
248 res = super(narrowfilelog, self).renamed(node)
248
249
249 # Renames that come from outside the narrowspec are problematic
250 # Renames that come from outside the narrowspec are problematic
250 # because we may lack the base text for the rename. This can result
251 # because we may lack the base text for the rename. This can result
251 # in code attempting to walk the ancestry or compute a diff
252 # in code attempting to walk the ancestry or compute a diff
252 # encountering a missing revision. We address this by silently
253 # encountering a missing revision. We address this by silently
253 # removing rename metadata if the source file is outside the
254 # removing rename metadata if the source file is outside the
254 # narrow spec.
255 # narrow spec.
255 #
256 #
256 # A better solution would be to see if the base revision is available,
257 # A better solution would be to see if the base revision is available,
257 # rather than assuming it isn't.
258 # rather than assuming it isn't.
258 #
259 #
259 # An even better solution would be to teach all consumers of rename
260 # An even better solution would be to teach all consumers of rename
260 # metadata that the base revision may not be available.
261 # metadata that the base revision may not be available.
261 #
262 #
262 # TODO consider better ways of doing this.
263 # TODO consider better ways of doing this.
263 if res and not self._narrowmatch(res[0]):
264 if res and not self._narrowmatch(res[0]):
264 return None
265 return None
265
266
266 return res
267 return res
267
268
268 def size(self, rev):
269 def size(self, rev):
269 # Because we have a custom renamed() that may lie, we need to call
270 # Because we have a custom renamed() that may lie, we need to call
270 # the base renamed() to report accurate results.
271 # the base renamed() to report accurate results.
271 node = self.node(rev)
272 node = self.node(rev)
272 if super(narrowfilelog, self).renamed(node):
273 if super(narrowfilelog, self).renamed(node):
273 return len(self.read(node))
274 return len(self.read(node))
274 else:
275 else:
275 return super(narrowfilelog, self).size(rev)
276 return super(narrowfilelog, self).size(rev)
276
277
277 def cmp(self, node, text):
278 def cmp(self, node, text):
278 # We don't call `super` because narrow parents can be buggy in case of a
279 # We don't call `super` because narrow parents can be buggy in case of a
279 # ambiguous dirstate. Always take the slow path until there is a better
280 # ambiguous dirstate. Always take the slow path until there is a better
280 # fix, see issue6150.
281 # fix, see issue6150.
281
282
282 # Censored files compare against the empty file.
283 # Censored files compare against the empty file.
283 if self.iscensored(self.rev(node)):
284 if self.iscensored(self.rev(node)):
284 return text != b''
285 return text != b''
285
286
286 return self.read(node) != text
287 return self.read(node) != text
General Comments 0
You need to be logged in to leave comments. Login now