##// END OF EJS Templates
config: update evolution-related config...
Boris Feld -
r34865:fec79a3f default
parent child Browse files
Show More
@@ -1,1106 +1,1115 b''
1 # configitems.py - centralized declaration of configuration option
1 # configitems.py - centralized declaration of configuration option
2 #
2 #
3 # Copyright 2017 Pierre-Yves David <pierre-yves.david@octobus.net>
3 # Copyright 2017 Pierre-Yves David <pierre-yves.david@octobus.net>
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 import functools
10 import functools
11 import re
11 import re
12
12
13 from . import (
13 from . import (
14 encoding,
14 encoding,
15 error,
15 error,
16 )
16 )
17
17
18 def loadconfigtable(ui, extname, configtable):
18 def loadconfigtable(ui, extname, configtable):
19 """update config item known to the ui with the extension ones"""
19 """update config item known to the ui with the extension ones"""
20 for section, items in configtable.items():
20 for section, items in configtable.items():
21 knownitems = ui._knownconfig.setdefault(section, itemregister())
21 knownitems = ui._knownconfig.setdefault(section, itemregister())
22 knownkeys = set(knownitems)
22 knownkeys = set(knownitems)
23 newkeys = set(items)
23 newkeys = set(items)
24 for key in sorted(knownkeys & newkeys):
24 for key in sorted(knownkeys & newkeys):
25 msg = "extension '%s' overwrite config item '%s.%s'"
25 msg = "extension '%s' overwrite config item '%s.%s'"
26 msg %= (extname, section, key)
26 msg %= (extname, section, key)
27 ui.develwarn(msg, config='warn-config')
27 ui.develwarn(msg, config='warn-config')
28
28
29 knownitems.update(items)
29 knownitems.update(items)
30
30
31 class configitem(object):
31 class configitem(object):
32 """represent a known config item
32 """represent a known config item
33
33
34 :section: the official config section where to find this item,
34 :section: the official config section where to find this item,
35 :name: the official name within the section,
35 :name: the official name within the section,
36 :default: default value for this item,
36 :default: default value for this item,
37 :alias: optional list of tuples as alternatives,
37 :alias: optional list of tuples as alternatives,
38 :generic: this is a generic definition, match name using regular expression.
38 :generic: this is a generic definition, match name using regular expression.
39 """
39 """
40
40
41 def __init__(self, section, name, default=None, alias=(),
41 def __init__(self, section, name, default=None, alias=(),
42 generic=False, priority=0):
42 generic=False, priority=0):
43 self.section = section
43 self.section = section
44 self.name = name
44 self.name = name
45 self.default = default
45 self.default = default
46 self.alias = list(alias)
46 self.alias = list(alias)
47 self.generic = generic
47 self.generic = generic
48 self.priority = priority
48 self.priority = priority
49 self._re = None
49 self._re = None
50 if generic:
50 if generic:
51 self._re = re.compile(self.name)
51 self._re = re.compile(self.name)
52
52
53 class itemregister(dict):
53 class itemregister(dict):
54 """A specialized dictionary that can handle wild-card selection"""
54 """A specialized dictionary that can handle wild-card selection"""
55
55
56 def __init__(self):
56 def __init__(self):
57 super(itemregister, self).__init__()
57 super(itemregister, self).__init__()
58 self._generics = set()
58 self._generics = set()
59
59
60 def update(self, other):
60 def update(self, other):
61 super(itemregister, self).update(other)
61 super(itemregister, self).update(other)
62 self._generics.update(other._generics)
62 self._generics.update(other._generics)
63
63
64 def __setitem__(self, key, item):
64 def __setitem__(self, key, item):
65 super(itemregister, self).__setitem__(key, item)
65 super(itemregister, self).__setitem__(key, item)
66 if item.generic:
66 if item.generic:
67 self._generics.add(item)
67 self._generics.add(item)
68
68
69 def get(self, key):
69 def get(self, key):
70 if key in self:
70 if key in self:
71 return self[key]
71 return self[key]
72
72
73 # search for a matching generic item
73 # search for a matching generic item
74 generics = sorted(self._generics, key=(lambda x: (x.priority, x.name)))
74 generics = sorted(self._generics, key=(lambda x: (x.priority, x.name)))
75 for item in generics:
75 for item in generics:
76 if item._re.match(key):
76 if item._re.match(key):
77 return item
77 return item
78
78
79 # fallback to dict get
79 # fallback to dict get
80 return super(itemregister, self).get(key)
80 return super(itemregister, self).get(key)
81
81
82 coreitems = {}
82 coreitems = {}
83
83
84 def _register(configtable, *args, **kwargs):
84 def _register(configtable, *args, **kwargs):
85 item = configitem(*args, **kwargs)
85 item = configitem(*args, **kwargs)
86 section = configtable.setdefault(item.section, itemregister())
86 section = configtable.setdefault(item.section, itemregister())
87 if item.name in section:
87 if item.name in section:
88 msg = "duplicated config item registration for '%s.%s'"
88 msg = "duplicated config item registration for '%s.%s'"
89 raise error.ProgrammingError(msg % (item.section, item.name))
89 raise error.ProgrammingError(msg % (item.section, item.name))
90 section[item.name] = item
90 section[item.name] = item
91
91
92 # special value for case where the default is derived from other values
92 # special value for case where the default is derived from other values
93 dynamicdefault = object()
93 dynamicdefault = object()
94
94
95 # Registering actual config items
95 # Registering actual config items
96
96
97 def getitemregister(configtable):
97 def getitemregister(configtable):
98 return functools.partial(_register, configtable)
98 return functools.partial(_register, configtable)
99
99
100 coreconfigitem = getitemregister(coreitems)
100 coreconfigitem = getitemregister(coreitems)
101
101
102 coreconfigitem('alias', '.*',
102 coreconfigitem('alias', '.*',
103 default=None,
103 default=None,
104 generic=True,
104 generic=True,
105 )
105 )
106 coreconfigitem('annotate', 'nodates',
106 coreconfigitem('annotate', 'nodates',
107 default=False,
107 default=False,
108 )
108 )
109 coreconfigitem('annotate', 'showfunc',
109 coreconfigitem('annotate', 'showfunc',
110 default=False,
110 default=False,
111 )
111 )
112 coreconfigitem('annotate', 'unified',
112 coreconfigitem('annotate', 'unified',
113 default=None,
113 default=None,
114 )
114 )
115 coreconfigitem('annotate', 'git',
115 coreconfigitem('annotate', 'git',
116 default=False,
116 default=False,
117 )
117 )
118 coreconfigitem('annotate', 'ignorews',
118 coreconfigitem('annotate', 'ignorews',
119 default=False,
119 default=False,
120 )
120 )
121 coreconfigitem('annotate', 'ignorewsamount',
121 coreconfigitem('annotate', 'ignorewsamount',
122 default=False,
122 default=False,
123 )
123 )
124 coreconfigitem('annotate', 'ignoreblanklines',
124 coreconfigitem('annotate', 'ignoreblanklines',
125 default=False,
125 default=False,
126 )
126 )
127 coreconfigitem('annotate', 'ignorewseol',
127 coreconfigitem('annotate', 'ignorewseol',
128 default=False,
128 default=False,
129 )
129 )
130 coreconfigitem('annotate', 'nobinary',
130 coreconfigitem('annotate', 'nobinary',
131 default=False,
131 default=False,
132 )
132 )
133 coreconfigitem('annotate', 'noprefix',
133 coreconfigitem('annotate', 'noprefix',
134 default=False,
134 default=False,
135 )
135 )
136 coreconfigitem('auth', 'cookiefile',
136 coreconfigitem('auth', 'cookiefile',
137 default=None,
137 default=None,
138 )
138 )
139 # bookmarks.pushing: internal hack for discovery
139 # bookmarks.pushing: internal hack for discovery
140 coreconfigitem('bookmarks', 'pushing',
140 coreconfigitem('bookmarks', 'pushing',
141 default=list,
141 default=list,
142 )
142 )
143 # bundle.mainreporoot: internal hack for bundlerepo
143 # bundle.mainreporoot: internal hack for bundlerepo
144 coreconfigitem('bundle', 'mainreporoot',
144 coreconfigitem('bundle', 'mainreporoot',
145 default='',
145 default='',
146 )
146 )
147 # bundle.reorder: experimental config
147 # bundle.reorder: experimental config
148 coreconfigitem('bundle', 'reorder',
148 coreconfigitem('bundle', 'reorder',
149 default='auto',
149 default='auto',
150 )
150 )
151 coreconfigitem('censor', 'policy',
151 coreconfigitem('censor', 'policy',
152 default='abort',
152 default='abort',
153 )
153 )
154 coreconfigitem('chgserver', 'idletimeout',
154 coreconfigitem('chgserver', 'idletimeout',
155 default=3600,
155 default=3600,
156 )
156 )
157 coreconfigitem('chgserver', 'skiphash',
157 coreconfigitem('chgserver', 'skiphash',
158 default=False,
158 default=False,
159 )
159 )
160 coreconfigitem('cmdserver', 'log',
160 coreconfigitem('cmdserver', 'log',
161 default=None,
161 default=None,
162 )
162 )
163 coreconfigitem('color', '.*',
163 coreconfigitem('color', '.*',
164 default=None,
164 default=None,
165 generic=True,
165 generic=True,
166 )
166 )
167 coreconfigitem('color', 'mode',
167 coreconfigitem('color', 'mode',
168 default='auto',
168 default='auto',
169 )
169 )
170 coreconfigitem('color', 'pagermode',
170 coreconfigitem('color', 'pagermode',
171 default=dynamicdefault,
171 default=dynamicdefault,
172 )
172 )
173 coreconfigitem('commands', 'status.relative',
173 coreconfigitem('commands', 'status.relative',
174 default=False,
174 default=False,
175 )
175 )
176 coreconfigitem('commands', 'status.skipstates',
176 coreconfigitem('commands', 'status.skipstates',
177 default=[],
177 default=[],
178 )
178 )
179 coreconfigitem('commands', 'status.verbose',
179 coreconfigitem('commands', 'status.verbose',
180 default=False,
180 default=False,
181 )
181 )
182 coreconfigitem('commands', 'update.check',
182 coreconfigitem('commands', 'update.check',
183 default=None,
183 default=None,
184 # Deprecated, remove after 4.4 release
184 # Deprecated, remove after 4.4 release
185 alias=[('experimental', 'updatecheck')]
185 alias=[('experimental', 'updatecheck')]
186 )
186 )
187 coreconfigitem('commands', 'update.requiredest',
187 coreconfigitem('commands', 'update.requiredest',
188 default=False,
188 default=False,
189 )
189 )
190 coreconfigitem('committemplate', '.*',
190 coreconfigitem('committemplate', '.*',
191 default=None,
191 default=None,
192 generic=True,
192 generic=True,
193 )
193 )
194 coreconfigitem('debug', 'dirstate.delaywrite',
194 coreconfigitem('debug', 'dirstate.delaywrite',
195 default=0,
195 default=0,
196 )
196 )
197 coreconfigitem('defaults', '.*',
197 coreconfigitem('defaults', '.*',
198 default=None,
198 default=None,
199 generic=True,
199 generic=True,
200 )
200 )
201 coreconfigitem('devel', 'all-warnings',
201 coreconfigitem('devel', 'all-warnings',
202 default=False,
202 default=False,
203 )
203 )
204 coreconfigitem('devel', 'bundle2.debug',
204 coreconfigitem('devel', 'bundle2.debug',
205 default=False,
205 default=False,
206 )
206 )
207 coreconfigitem('devel', 'cache-vfs',
207 coreconfigitem('devel', 'cache-vfs',
208 default=None,
208 default=None,
209 )
209 )
210 coreconfigitem('devel', 'check-locks',
210 coreconfigitem('devel', 'check-locks',
211 default=False,
211 default=False,
212 )
212 )
213 coreconfigitem('devel', 'check-relroot',
213 coreconfigitem('devel', 'check-relroot',
214 default=False,
214 default=False,
215 )
215 )
216 coreconfigitem('devel', 'default-date',
216 coreconfigitem('devel', 'default-date',
217 default=None,
217 default=None,
218 )
218 )
219 coreconfigitem('devel', 'deprec-warn',
219 coreconfigitem('devel', 'deprec-warn',
220 default=False,
220 default=False,
221 )
221 )
222 coreconfigitem('devel', 'disableloaddefaultcerts',
222 coreconfigitem('devel', 'disableloaddefaultcerts',
223 default=False,
223 default=False,
224 )
224 )
225 coreconfigitem('devel', 'warn-empty-changegroup',
225 coreconfigitem('devel', 'warn-empty-changegroup',
226 default=False,
226 default=False,
227 )
227 )
228 coreconfigitem('devel', 'legacy.exchange',
228 coreconfigitem('devel', 'legacy.exchange',
229 default=list,
229 default=list,
230 )
230 )
231 coreconfigitem('devel', 'servercafile',
231 coreconfigitem('devel', 'servercafile',
232 default='',
232 default='',
233 )
233 )
234 coreconfigitem('devel', 'serverexactprotocol',
234 coreconfigitem('devel', 'serverexactprotocol',
235 default='',
235 default='',
236 )
236 )
237 coreconfigitem('devel', 'serverrequirecert',
237 coreconfigitem('devel', 'serverrequirecert',
238 default=False,
238 default=False,
239 )
239 )
240 coreconfigitem('devel', 'strip-obsmarkers',
240 coreconfigitem('devel', 'strip-obsmarkers',
241 default=True,
241 default=True,
242 )
242 )
243 coreconfigitem('devel', 'warn-config',
243 coreconfigitem('devel', 'warn-config',
244 default=None,
244 default=None,
245 )
245 )
246 coreconfigitem('devel', 'warn-config-default',
246 coreconfigitem('devel', 'warn-config-default',
247 default=None,
247 default=None,
248 )
248 )
249 coreconfigitem('devel', 'user.obsmarker',
249 coreconfigitem('devel', 'user.obsmarker',
250 default=None,
250 default=None,
251 )
251 )
252 coreconfigitem('devel', 'warn-config-unknown',
252 coreconfigitem('devel', 'warn-config-unknown',
253 default=None,
253 default=None,
254 )
254 )
255 coreconfigitem('diff', 'nodates',
255 coreconfigitem('diff', 'nodates',
256 default=False,
256 default=False,
257 )
257 )
258 coreconfigitem('diff', 'showfunc',
258 coreconfigitem('diff', 'showfunc',
259 default=False,
259 default=False,
260 )
260 )
261 coreconfigitem('diff', 'unified',
261 coreconfigitem('diff', 'unified',
262 default=None,
262 default=None,
263 )
263 )
264 coreconfigitem('diff', 'git',
264 coreconfigitem('diff', 'git',
265 default=False,
265 default=False,
266 )
266 )
267 coreconfigitem('diff', 'ignorews',
267 coreconfigitem('diff', 'ignorews',
268 default=False,
268 default=False,
269 )
269 )
270 coreconfigitem('diff', 'ignorewsamount',
270 coreconfigitem('diff', 'ignorewsamount',
271 default=False,
271 default=False,
272 )
272 )
273 coreconfigitem('diff', 'ignoreblanklines',
273 coreconfigitem('diff', 'ignoreblanklines',
274 default=False,
274 default=False,
275 )
275 )
276 coreconfigitem('diff', 'ignorewseol',
276 coreconfigitem('diff', 'ignorewseol',
277 default=False,
277 default=False,
278 )
278 )
279 coreconfigitem('diff', 'nobinary',
279 coreconfigitem('diff', 'nobinary',
280 default=False,
280 default=False,
281 )
281 )
282 coreconfigitem('diff', 'noprefix',
282 coreconfigitem('diff', 'noprefix',
283 default=False,
283 default=False,
284 )
284 )
285 coreconfigitem('email', 'bcc',
285 coreconfigitem('email', 'bcc',
286 default=None,
286 default=None,
287 )
287 )
288 coreconfigitem('email', 'cc',
288 coreconfigitem('email', 'cc',
289 default=None,
289 default=None,
290 )
290 )
291 coreconfigitem('email', 'charsets',
291 coreconfigitem('email', 'charsets',
292 default=list,
292 default=list,
293 )
293 )
294 coreconfigitem('email', 'from',
294 coreconfigitem('email', 'from',
295 default=None,
295 default=None,
296 )
296 )
297 coreconfigitem('email', 'method',
297 coreconfigitem('email', 'method',
298 default='smtp',
298 default='smtp',
299 )
299 )
300 coreconfigitem('email', 'reply-to',
300 coreconfigitem('email', 'reply-to',
301 default=None,
301 default=None,
302 )
302 )
303 coreconfigitem('experimental', 'allowdivergence',
303 coreconfigitem('experimental', 'allowdivergence',
304 default=False,
304 default=False,
305 )
305 )
306 coreconfigitem('experimental', 'archivemetatemplate',
306 coreconfigitem('experimental', 'archivemetatemplate',
307 default=dynamicdefault,
307 default=dynamicdefault,
308 )
308 )
309 coreconfigitem('experimental', 'bundle-phases',
309 coreconfigitem('experimental', 'bundle-phases',
310 default=False,
310 default=False,
311 )
311 )
312 coreconfigitem('experimental', 'bundle2-advertise',
312 coreconfigitem('experimental', 'bundle2-advertise',
313 default=True,
313 default=True,
314 )
314 )
315 coreconfigitem('experimental', 'bundle2-output-capture',
315 coreconfigitem('experimental', 'bundle2-output-capture',
316 default=False,
316 default=False,
317 )
317 )
318 coreconfigitem('experimental', 'bundle2.pushback',
318 coreconfigitem('experimental', 'bundle2.pushback',
319 default=False,
319 default=False,
320 )
320 )
321 coreconfigitem('experimental', 'bundle2lazylocking',
321 coreconfigitem('experimental', 'bundle2lazylocking',
322 default=False,
322 default=False,
323 )
323 )
324 coreconfigitem('experimental', 'bundlecomplevel',
324 coreconfigitem('experimental', 'bundlecomplevel',
325 default=None,
325 default=None,
326 )
326 )
327 coreconfigitem('experimental', 'changegroup3',
327 coreconfigitem('experimental', 'changegroup3',
328 default=False,
328 default=False,
329 )
329 )
330 coreconfigitem('experimental', 'clientcompressionengines',
330 coreconfigitem('experimental', 'clientcompressionengines',
331 default=list,
331 default=list,
332 )
332 )
333 coreconfigitem('experimental', 'copytrace',
333 coreconfigitem('experimental', 'copytrace',
334 default='on',
334 default='on',
335 )
335 )
336 coreconfigitem('experimental', 'copytrace.movecandidateslimit',
336 coreconfigitem('experimental', 'copytrace.movecandidateslimit',
337 default=100,
337 default=100,
338 )
338 )
339 coreconfigitem('experimental', 'copytrace.sourcecommitlimit',
339 coreconfigitem('experimental', 'copytrace.sourcecommitlimit',
340 default=100,
340 default=100,
341 )
341 )
342 coreconfigitem('experimental', 'crecordtest',
342 coreconfigitem('experimental', 'crecordtest',
343 default=None,
343 default=None,
344 )
344 )
345 coreconfigitem('experimental', 'editortmpinhg',
345 coreconfigitem('experimental', 'editortmpinhg',
346 default=False,
346 default=False,
347 )
347 )
348 coreconfigitem('experimental', 'evolution',
348 coreconfigitem('experimental', 'evolution',
349 default=list,
349 default=list,
350 alias=[('experimental', 'stabilization')],
350 alias=[('experimental', 'stabilization')],
351 )
351 )
352 coreconfigitem('experimental', 'evolution.allowunstable',
353 default=None,
354 )
355 coreconfigitem('experimental', 'evolution.createmarkers',
356 default=None,
357 )
358 coreconfigitem('experimental', 'evolution.exchange',
359 default=None,
360 )
352 coreconfigitem('experimental', 'evolution.bundle-obsmarker',
361 coreconfigitem('experimental', 'evolution.bundle-obsmarker',
353 default=False,
362 default=False,
354 alias=[('experimental', 'stabilization.bundle-obsmarker')],
363 alias=[('experimental', 'stabilization.bundle-obsmarker')],
355 )
364 )
356 coreconfigitem('experimental', 'evolution.track-operation',
365 coreconfigitem('experimental', 'evolution.track-operation',
357 default=True,
366 default=True,
358 alias=[('experimental', 'stabilization.track-operation')]
367 alias=[('experimental', 'stabilization.track-operation')]
359 )
368 )
360 coreconfigitem('experimental', 'maxdeltachainspan',
369 coreconfigitem('experimental', 'maxdeltachainspan',
361 default=-1,
370 default=-1,
362 )
371 )
363 coreconfigitem('experimental', 'mmapindexthreshold',
372 coreconfigitem('experimental', 'mmapindexthreshold',
364 default=None,
373 default=None,
365 )
374 )
366 coreconfigitem('experimental', 'nonnormalparanoidcheck',
375 coreconfigitem('experimental', 'nonnormalparanoidcheck',
367 default=False,
376 default=False,
368 )
377 )
369 coreconfigitem('experimental', 'effect-flags',
378 coreconfigitem('experimental', 'effect-flags',
370 default=False,
379 default=False,
371 )
380 )
372 coreconfigitem('experimental', 'exportableenviron',
381 coreconfigitem('experimental', 'exportableenviron',
373 default=list,
382 default=list,
374 )
383 )
375 coreconfigitem('experimental', 'extendedheader.index',
384 coreconfigitem('experimental', 'extendedheader.index',
376 default=None,
385 default=None,
377 )
386 )
378 coreconfigitem('experimental', 'extendedheader.similarity',
387 coreconfigitem('experimental', 'extendedheader.similarity',
379 default=False,
388 default=False,
380 )
389 )
381 coreconfigitem('experimental', 'format.compression',
390 coreconfigitem('experimental', 'format.compression',
382 default='zlib',
391 default='zlib',
383 )
392 )
384 coreconfigitem('experimental', 'graphshorten',
393 coreconfigitem('experimental', 'graphshorten',
385 default=False,
394 default=False,
386 )
395 )
387 coreconfigitem('experimental', 'graphstyle.parent',
396 coreconfigitem('experimental', 'graphstyle.parent',
388 default=dynamicdefault,
397 default=dynamicdefault,
389 )
398 )
390 coreconfigitem('experimental', 'graphstyle.missing',
399 coreconfigitem('experimental', 'graphstyle.missing',
391 default=dynamicdefault,
400 default=dynamicdefault,
392 )
401 )
393 coreconfigitem('experimental', 'graphstyle.grandparent',
402 coreconfigitem('experimental', 'graphstyle.grandparent',
394 default=dynamicdefault,
403 default=dynamicdefault,
395 )
404 )
396 coreconfigitem('experimental', 'hook-track-tags',
405 coreconfigitem('experimental', 'hook-track-tags',
397 default=False,
406 default=False,
398 )
407 )
399 coreconfigitem('experimental', 'httppostargs',
408 coreconfigitem('experimental', 'httppostargs',
400 default=False,
409 default=False,
401 )
410 )
402 coreconfigitem('experimental', 'manifestv2',
411 coreconfigitem('experimental', 'manifestv2',
403 default=False,
412 default=False,
404 )
413 )
405 coreconfigitem('experimental', 'mergedriver',
414 coreconfigitem('experimental', 'mergedriver',
406 default=None,
415 default=None,
407 )
416 )
408 coreconfigitem('experimental', 'obsmarkers-exchange-debug',
417 coreconfigitem('experimental', 'obsmarkers-exchange-debug',
409 default=False,
418 default=False,
410 )
419 )
411 coreconfigitem('experimental', 'rebase.multidest',
420 coreconfigitem('experimental', 'rebase.multidest',
412 default=False,
421 default=False,
413 )
422 )
414 coreconfigitem('experimental', 'revertalternateinteractivemode',
423 coreconfigitem('experimental', 'revertalternateinteractivemode',
415 default=True,
424 default=True,
416 )
425 )
417 coreconfigitem('experimental', 'revlogv2',
426 coreconfigitem('experimental', 'revlogv2',
418 default=None,
427 default=None,
419 )
428 )
420 coreconfigitem('experimental', 'spacemovesdown',
429 coreconfigitem('experimental', 'spacemovesdown',
421 default=False,
430 default=False,
422 )
431 )
423 coreconfigitem('experimental', 'sparse-read',
432 coreconfigitem('experimental', 'sparse-read',
424 default=False,
433 default=False,
425 )
434 )
426 coreconfigitem('experimental', 'sparse-read.density-threshold',
435 coreconfigitem('experimental', 'sparse-read.density-threshold',
427 default=0.25,
436 default=0.25,
428 )
437 )
429 coreconfigitem('experimental', 'sparse-read.min-block-size',
438 coreconfigitem('experimental', 'sparse-read.min-block-size',
430 default='256K',
439 default='256K',
431 )
440 )
432 coreconfigitem('experimental', 'treemanifest',
441 coreconfigitem('experimental', 'treemanifest',
433 default=False,
442 default=False,
434 )
443 )
435 coreconfigitem('extensions', '.*',
444 coreconfigitem('extensions', '.*',
436 default=None,
445 default=None,
437 generic=True,
446 generic=True,
438 )
447 )
439 coreconfigitem('extdata', '.*',
448 coreconfigitem('extdata', '.*',
440 default=None,
449 default=None,
441 generic=True,
450 generic=True,
442 )
451 )
443 coreconfigitem('format', 'aggressivemergedeltas',
452 coreconfigitem('format', 'aggressivemergedeltas',
444 default=False,
453 default=False,
445 )
454 )
446 coreconfigitem('format', 'chunkcachesize',
455 coreconfigitem('format', 'chunkcachesize',
447 default=None,
456 default=None,
448 )
457 )
449 coreconfigitem('format', 'dotencode',
458 coreconfigitem('format', 'dotencode',
450 default=True,
459 default=True,
451 )
460 )
452 coreconfigitem('format', 'generaldelta',
461 coreconfigitem('format', 'generaldelta',
453 default=False,
462 default=False,
454 )
463 )
455 coreconfigitem('format', 'manifestcachesize',
464 coreconfigitem('format', 'manifestcachesize',
456 default=None,
465 default=None,
457 )
466 )
458 coreconfigitem('format', 'maxchainlen',
467 coreconfigitem('format', 'maxchainlen',
459 default=None,
468 default=None,
460 )
469 )
461 coreconfigitem('format', 'obsstore-version',
470 coreconfigitem('format', 'obsstore-version',
462 default=None,
471 default=None,
463 )
472 )
464 coreconfigitem('format', 'usefncache',
473 coreconfigitem('format', 'usefncache',
465 default=True,
474 default=True,
466 )
475 )
467 coreconfigitem('format', 'usegeneraldelta',
476 coreconfigitem('format', 'usegeneraldelta',
468 default=True,
477 default=True,
469 )
478 )
470 coreconfigitem('format', 'usestore',
479 coreconfigitem('format', 'usestore',
471 default=True,
480 default=True,
472 )
481 )
473 coreconfigitem('hooks', '.*',
482 coreconfigitem('hooks', '.*',
474 default=dynamicdefault,
483 default=dynamicdefault,
475 generic=True,
484 generic=True,
476 )
485 )
477 coreconfigitem('hgweb-paths', '.*',
486 coreconfigitem('hgweb-paths', '.*',
478 default=list,
487 default=list,
479 generic=True,
488 generic=True,
480 )
489 )
481 coreconfigitem('hostfingerprints', '.*',
490 coreconfigitem('hostfingerprints', '.*',
482 default=list,
491 default=list,
483 generic=True,
492 generic=True,
484 )
493 )
485 coreconfigitem('hostsecurity', 'ciphers',
494 coreconfigitem('hostsecurity', 'ciphers',
486 default=None,
495 default=None,
487 )
496 )
488 coreconfigitem('hostsecurity', 'disabletls10warning',
497 coreconfigitem('hostsecurity', 'disabletls10warning',
489 default=False,
498 default=False,
490 )
499 )
491 coreconfigitem('hostsecurity', 'minimumprotocol',
500 coreconfigitem('hostsecurity', 'minimumprotocol',
492 default=dynamicdefault,
501 default=dynamicdefault,
493 )
502 )
494 coreconfigitem('hostsecurity', '.*:minimumprotocol$',
503 coreconfigitem('hostsecurity', '.*:minimumprotocol$',
495 default=dynamicdefault,
504 default=dynamicdefault,
496 generic=True,
505 generic=True,
497 )
506 )
498 coreconfigitem('hostsecurity', '.*:ciphers$',
507 coreconfigitem('hostsecurity', '.*:ciphers$',
499 default=dynamicdefault,
508 default=dynamicdefault,
500 generic=True,
509 generic=True,
501 )
510 )
502 coreconfigitem('hostsecurity', '.*:fingerprints$',
511 coreconfigitem('hostsecurity', '.*:fingerprints$',
503 default=list,
512 default=list,
504 generic=True,
513 generic=True,
505 )
514 )
506 coreconfigitem('hostsecurity', '.*:verifycertsfile$',
515 coreconfigitem('hostsecurity', '.*:verifycertsfile$',
507 default=None,
516 default=None,
508 generic=True,
517 generic=True,
509 )
518 )
510
519
511 coreconfigitem('http_proxy', 'always',
520 coreconfigitem('http_proxy', 'always',
512 default=False,
521 default=False,
513 )
522 )
514 coreconfigitem('http_proxy', 'host',
523 coreconfigitem('http_proxy', 'host',
515 default=None,
524 default=None,
516 )
525 )
517 coreconfigitem('http_proxy', 'no',
526 coreconfigitem('http_proxy', 'no',
518 default=list,
527 default=list,
519 )
528 )
520 coreconfigitem('http_proxy', 'passwd',
529 coreconfigitem('http_proxy', 'passwd',
521 default=None,
530 default=None,
522 )
531 )
523 coreconfigitem('http_proxy', 'user',
532 coreconfigitem('http_proxy', 'user',
524 default=None,
533 default=None,
525 )
534 )
526 coreconfigitem('logtoprocess', 'commandexception',
535 coreconfigitem('logtoprocess', 'commandexception',
527 default=None,
536 default=None,
528 )
537 )
529 coreconfigitem('logtoprocess', 'commandfinish',
538 coreconfigitem('logtoprocess', 'commandfinish',
530 default=None,
539 default=None,
531 )
540 )
532 coreconfigitem('logtoprocess', 'command',
541 coreconfigitem('logtoprocess', 'command',
533 default=None,
542 default=None,
534 )
543 )
535 coreconfigitem('logtoprocess', 'develwarn',
544 coreconfigitem('logtoprocess', 'develwarn',
536 default=None,
545 default=None,
537 )
546 )
538 coreconfigitem('logtoprocess', 'uiblocked',
547 coreconfigitem('logtoprocess', 'uiblocked',
539 default=None,
548 default=None,
540 )
549 )
541 coreconfigitem('merge', 'checkunknown',
550 coreconfigitem('merge', 'checkunknown',
542 default='abort',
551 default='abort',
543 )
552 )
544 coreconfigitem('merge', 'checkignored',
553 coreconfigitem('merge', 'checkignored',
545 default='abort',
554 default='abort',
546 )
555 )
547 coreconfigitem('merge', 'followcopies',
556 coreconfigitem('merge', 'followcopies',
548 default=True,
557 default=True,
549 )
558 )
550 coreconfigitem('merge', 'on-failure',
559 coreconfigitem('merge', 'on-failure',
551 default='continue',
560 default='continue',
552 )
561 )
553 coreconfigitem('merge', 'preferancestor',
562 coreconfigitem('merge', 'preferancestor',
554 default=lambda: ['*'],
563 default=lambda: ['*'],
555 )
564 )
556 coreconfigitem('merge-tools', '.*',
565 coreconfigitem('merge-tools', '.*',
557 default=None,
566 default=None,
558 generic=True,
567 generic=True,
559 )
568 )
560 coreconfigitem('merge-tools', r'.*\.args$',
569 coreconfigitem('merge-tools', r'.*\.args$',
561 default="$local $base $other",
570 default="$local $base $other",
562 generic=True,
571 generic=True,
563 priority=-1,
572 priority=-1,
564 )
573 )
565 coreconfigitem('merge-tools', r'.*\.binary$',
574 coreconfigitem('merge-tools', r'.*\.binary$',
566 default=False,
575 default=False,
567 generic=True,
576 generic=True,
568 priority=-1,
577 priority=-1,
569 )
578 )
570 coreconfigitem('merge-tools', r'.*\.check$',
579 coreconfigitem('merge-tools', r'.*\.check$',
571 default=list,
580 default=list,
572 generic=True,
581 generic=True,
573 priority=-1,
582 priority=-1,
574 )
583 )
575 coreconfigitem('merge-tools', r'.*\.checkchanged$',
584 coreconfigitem('merge-tools', r'.*\.checkchanged$',
576 default=False,
585 default=False,
577 generic=True,
586 generic=True,
578 priority=-1,
587 priority=-1,
579 )
588 )
580 coreconfigitem('merge-tools', r'.*\.executable$',
589 coreconfigitem('merge-tools', r'.*\.executable$',
581 default=dynamicdefault,
590 default=dynamicdefault,
582 generic=True,
591 generic=True,
583 priority=-1,
592 priority=-1,
584 )
593 )
585 coreconfigitem('merge-tools', r'.*\.fixeol$',
594 coreconfigitem('merge-tools', r'.*\.fixeol$',
586 default=False,
595 default=False,
587 generic=True,
596 generic=True,
588 priority=-1,
597 priority=-1,
589 )
598 )
590 coreconfigitem('merge-tools', r'.*\.gui$',
599 coreconfigitem('merge-tools', r'.*\.gui$',
591 default=False,
600 default=False,
592 generic=True,
601 generic=True,
593 priority=-1,
602 priority=-1,
594 )
603 )
595 coreconfigitem('merge-tools', r'.*\.priority$',
604 coreconfigitem('merge-tools', r'.*\.priority$',
596 default=0,
605 default=0,
597 generic=True,
606 generic=True,
598 priority=-1,
607 priority=-1,
599 )
608 )
600 coreconfigitem('merge-tools', r'.*\.premerge$',
609 coreconfigitem('merge-tools', r'.*\.premerge$',
601 default=dynamicdefault,
610 default=dynamicdefault,
602 generic=True,
611 generic=True,
603 priority=-1,
612 priority=-1,
604 )
613 )
605 coreconfigitem('merge-tools', r'.*\.symlink$',
614 coreconfigitem('merge-tools', r'.*\.symlink$',
606 default=False,
615 default=False,
607 generic=True,
616 generic=True,
608 priority=-1,
617 priority=-1,
609 )
618 )
610 coreconfigitem('pager', 'attend-.*',
619 coreconfigitem('pager', 'attend-.*',
611 default=dynamicdefault,
620 default=dynamicdefault,
612 generic=True,
621 generic=True,
613 )
622 )
614 coreconfigitem('pager', 'ignore',
623 coreconfigitem('pager', 'ignore',
615 default=list,
624 default=list,
616 )
625 )
617 coreconfigitem('pager', 'pager',
626 coreconfigitem('pager', 'pager',
618 default=dynamicdefault,
627 default=dynamicdefault,
619 )
628 )
620 coreconfigitem('patch', 'eol',
629 coreconfigitem('patch', 'eol',
621 default='strict',
630 default='strict',
622 )
631 )
623 coreconfigitem('patch', 'fuzz',
632 coreconfigitem('patch', 'fuzz',
624 default=2,
633 default=2,
625 )
634 )
626 coreconfigitem('paths', 'default',
635 coreconfigitem('paths', 'default',
627 default=None,
636 default=None,
628 )
637 )
629 coreconfigitem('paths', 'default-push',
638 coreconfigitem('paths', 'default-push',
630 default=None,
639 default=None,
631 )
640 )
632 coreconfigitem('paths', '.*',
641 coreconfigitem('paths', '.*',
633 default=None,
642 default=None,
634 generic=True,
643 generic=True,
635 )
644 )
636 coreconfigitem('phases', 'checksubrepos',
645 coreconfigitem('phases', 'checksubrepos',
637 default='follow',
646 default='follow',
638 )
647 )
639 coreconfigitem('phases', 'new-commit',
648 coreconfigitem('phases', 'new-commit',
640 default='draft',
649 default='draft',
641 )
650 )
642 coreconfigitem('phases', 'publish',
651 coreconfigitem('phases', 'publish',
643 default=True,
652 default=True,
644 )
653 )
645 coreconfigitem('profiling', 'enabled',
654 coreconfigitem('profiling', 'enabled',
646 default=False,
655 default=False,
647 )
656 )
648 coreconfigitem('profiling', 'format',
657 coreconfigitem('profiling', 'format',
649 default='text',
658 default='text',
650 )
659 )
651 coreconfigitem('profiling', 'freq',
660 coreconfigitem('profiling', 'freq',
652 default=1000,
661 default=1000,
653 )
662 )
654 coreconfigitem('profiling', 'limit',
663 coreconfigitem('profiling', 'limit',
655 default=30,
664 default=30,
656 )
665 )
657 coreconfigitem('profiling', 'nested',
666 coreconfigitem('profiling', 'nested',
658 default=0,
667 default=0,
659 )
668 )
660 coreconfigitem('profiling', 'output',
669 coreconfigitem('profiling', 'output',
661 default=None,
670 default=None,
662 )
671 )
663 coreconfigitem('profiling', 'showmax',
672 coreconfigitem('profiling', 'showmax',
664 default=0.999,
673 default=0.999,
665 )
674 )
666 coreconfigitem('profiling', 'showmin',
675 coreconfigitem('profiling', 'showmin',
667 default=dynamicdefault,
676 default=dynamicdefault,
668 )
677 )
669 coreconfigitem('profiling', 'sort',
678 coreconfigitem('profiling', 'sort',
670 default='inlinetime',
679 default='inlinetime',
671 )
680 )
672 coreconfigitem('profiling', 'statformat',
681 coreconfigitem('profiling', 'statformat',
673 default='hotpath',
682 default='hotpath',
674 )
683 )
675 coreconfigitem('profiling', 'type',
684 coreconfigitem('profiling', 'type',
676 default='stat',
685 default='stat',
677 )
686 )
678 coreconfigitem('progress', 'assume-tty',
687 coreconfigitem('progress', 'assume-tty',
679 default=False,
688 default=False,
680 )
689 )
681 coreconfigitem('progress', 'changedelay',
690 coreconfigitem('progress', 'changedelay',
682 default=1,
691 default=1,
683 )
692 )
684 coreconfigitem('progress', 'clear-complete',
693 coreconfigitem('progress', 'clear-complete',
685 default=True,
694 default=True,
686 )
695 )
687 coreconfigitem('progress', 'debug',
696 coreconfigitem('progress', 'debug',
688 default=False,
697 default=False,
689 )
698 )
690 coreconfigitem('progress', 'delay',
699 coreconfigitem('progress', 'delay',
691 default=3,
700 default=3,
692 )
701 )
693 coreconfigitem('progress', 'disable',
702 coreconfigitem('progress', 'disable',
694 default=False,
703 default=False,
695 )
704 )
696 coreconfigitem('progress', 'estimateinterval',
705 coreconfigitem('progress', 'estimateinterval',
697 default=60.0,
706 default=60.0,
698 )
707 )
699 coreconfigitem('progress', 'format',
708 coreconfigitem('progress', 'format',
700 default=lambda: ['topic', 'bar', 'number', 'estimate'],
709 default=lambda: ['topic', 'bar', 'number', 'estimate'],
701 )
710 )
702 coreconfigitem('progress', 'refresh',
711 coreconfigitem('progress', 'refresh',
703 default=0.1,
712 default=0.1,
704 )
713 )
705 coreconfigitem('progress', 'width',
714 coreconfigitem('progress', 'width',
706 default=dynamicdefault,
715 default=dynamicdefault,
707 )
716 )
708 coreconfigitem('push', 'pushvars.server',
717 coreconfigitem('push', 'pushvars.server',
709 default=False,
718 default=False,
710 )
719 )
711 coreconfigitem('server', 'bundle1',
720 coreconfigitem('server', 'bundle1',
712 default=True,
721 default=True,
713 )
722 )
714 coreconfigitem('server', 'bundle1gd',
723 coreconfigitem('server', 'bundle1gd',
715 default=None,
724 default=None,
716 )
725 )
717 coreconfigitem('server', 'bundle1.pull',
726 coreconfigitem('server', 'bundle1.pull',
718 default=None,
727 default=None,
719 )
728 )
720 coreconfigitem('server', 'bundle1gd.pull',
729 coreconfigitem('server', 'bundle1gd.pull',
721 default=None,
730 default=None,
722 )
731 )
723 coreconfigitem('server', 'bundle1.push',
732 coreconfigitem('server', 'bundle1.push',
724 default=None,
733 default=None,
725 )
734 )
726 coreconfigitem('server', 'bundle1gd.push',
735 coreconfigitem('server', 'bundle1gd.push',
727 default=None,
736 default=None,
728 )
737 )
729 coreconfigitem('server', 'compressionengines',
738 coreconfigitem('server', 'compressionengines',
730 default=list,
739 default=list,
731 )
740 )
732 coreconfigitem('server', 'concurrent-push-mode',
741 coreconfigitem('server', 'concurrent-push-mode',
733 default='strict',
742 default='strict',
734 )
743 )
735 coreconfigitem('server', 'disablefullbundle',
744 coreconfigitem('server', 'disablefullbundle',
736 default=False,
745 default=False,
737 )
746 )
738 coreconfigitem('server', 'maxhttpheaderlen',
747 coreconfigitem('server', 'maxhttpheaderlen',
739 default=1024,
748 default=1024,
740 )
749 )
741 coreconfigitem('server', 'preferuncompressed',
750 coreconfigitem('server', 'preferuncompressed',
742 default=False,
751 default=False,
743 )
752 )
744 coreconfigitem('server', 'uncompressed',
753 coreconfigitem('server', 'uncompressed',
745 default=True,
754 default=True,
746 )
755 )
747 coreconfigitem('server', 'uncompressedallowsecret',
756 coreconfigitem('server', 'uncompressedallowsecret',
748 default=False,
757 default=False,
749 )
758 )
750 coreconfigitem('server', 'validate',
759 coreconfigitem('server', 'validate',
751 default=False,
760 default=False,
752 )
761 )
753 coreconfigitem('server', 'zliblevel',
762 coreconfigitem('server', 'zliblevel',
754 default=-1,
763 default=-1,
755 )
764 )
756 coreconfigitem('smtp', 'host',
765 coreconfigitem('smtp', 'host',
757 default=None,
766 default=None,
758 )
767 )
759 coreconfigitem('smtp', 'local_hostname',
768 coreconfigitem('smtp', 'local_hostname',
760 default=None,
769 default=None,
761 )
770 )
762 coreconfigitem('smtp', 'password',
771 coreconfigitem('smtp', 'password',
763 default=None,
772 default=None,
764 )
773 )
765 coreconfigitem('smtp', 'port',
774 coreconfigitem('smtp', 'port',
766 default=dynamicdefault,
775 default=dynamicdefault,
767 )
776 )
768 coreconfigitem('smtp', 'tls',
777 coreconfigitem('smtp', 'tls',
769 default='none',
778 default='none',
770 )
779 )
771 coreconfigitem('smtp', 'username',
780 coreconfigitem('smtp', 'username',
772 default=None,
781 default=None,
773 )
782 )
774 coreconfigitem('sparse', 'missingwarning',
783 coreconfigitem('sparse', 'missingwarning',
775 default=True,
784 default=True,
776 )
785 )
777 coreconfigitem('templates', '.*',
786 coreconfigitem('templates', '.*',
778 default=None,
787 default=None,
779 generic=True,
788 generic=True,
780 )
789 )
781 coreconfigitem('trusted', 'groups',
790 coreconfigitem('trusted', 'groups',
782 default=list,
791 default=list,
783 )
792 )
784 coreconfigitem('trusted', 'users',
793 coreconfigitem('trusted', 'users',
785 default=list,
794 default=list,
786 )
795 )
787 coreconfigitem('ui', '_usedassubrepo',
796 coreconfigitem('ui', '_usedassubrepo',
788 default=False,
797 default=False,
789 )
798 )
790 coreconfigitem('ui', 'allowemptycommit',
799 coreconfigitem('ui', 'allowemptycommit',
791 default=False,
800 default=False,
792 )
801 )
793 coreconfigitem('ui', 'archivemeta',
802 coreconfigitem('ui', 'archivemeta',
794 default=True,
803 default=True,
795 )
804 )
796 coreconfigitem('ui', 'askusername',
805 coreconfigitem('ui', 'askusername',
797 default=False,
806 default=False,
798 )
807 )
799 coreconfigitem('ui', 'clonebundlefallback',
808 coreconfigitem('ui', 'clonebundlefallback',
800 default=False,
809 default=False,
801 )
810 )
802 coreconfigitem('ui', 'clonebundleprefers',
811 coreconfigitem('ui', 'clonebundleprefers',
803 default=list,
812 default=list,
804 )
813 )
805 coreconfigitem('ui', 'clonebundles',
814 coreconfigitem('ui', 'clonebundles',
806 default=True,
815 default=True,
807 )
816 )
808 coreconfigitem('ui', 'color',
817 coreconfigitem('ui', 'color',
809 default='auto',
818 default='auto',
810 )
819 )
811 coreconfigitem('ui', 'commitsubrepos',
820 coreconfigitem('ui', 'commitsubrepos',
812 default=False,
821 default=False,
813 )
822 )
814 coreconfigitem('ui', 'debug',
823 coreconfigitem('ui', 'debug',
815 default=False,
824 default=False,
816 )
825 )
817 coreconfigitem('ui', 'debugger',
826 coreconfigitem('ui', 'debugger',
818 default=None,
827 default=None,
819 )
828 )
820 coreconfigitem('ui', 'fallbackencoding',
829 coreconfigitem('ui', 'fallbackencoding',
821 default=None,
830 default=None,
822 )
831 )
823 coreconfigitem('ui', 'forcecwd',
832 coreconfigitem('ui', 'forcecwd',
824 default=None,
833 default=None,
825 )
834 )
826 coreconfigitem('ui', 'forcemerge',
835 coreconfigitem('ui', 'forcemerge',
827 default=None,
836 default=None,
828 )
837 )
829 coreconfigitem('ui', 'formatdebug',
838 coreconfigitem('ui', 'formatdebug',
830 default=False,
839 default=False,
831 )
840 )
832 coreconfigitem('ui', 'formatjson',
841 coreconfigitem('ui', 'formatjson',
833 default=False,
842 default=False,
834 )
843 )
835 coreconfigitem('ui', 'formatted',
844 coreconfigitem('ui', 'formatted',
836 default=None,
845 default=None,
837 )
846 )
838 coreconfigitem('ui', 'graphnodetemplate',
847 coreconfigitem('ui', 'graphnodetemplate',
839 default=None,
848 default=None,
840 )
849 )
841 coreconfigitem('ui', 'http2debuglevel',
850 coreconfigitem('ui', 'http2debuglevel',
842 default=None,
851 default=None,
843 )
852 )
844 coreconfigitem('ui', 'interactive',
853 coreconfigitem('ui', 'interactive',
845 default=None,
854 default=None,
846 )
855 )
847 coreconfigitem('ui', 'interface',
856 coreconfigitem('ui', 'interface',
848 default=None,
857 default=None,
849 )
858 )
850 coreconfigitem('ui', 'interface.chunkselector',
859 coreconfigitem('ui', 'interface.chunkselector',
851 default=None,
860 default=None,
852 )
861 )
853 coreconfigitem('ui', 'logblockedtimes',
862 coreconfigitem('ui', 'logblockedtimes',
854 default=False,
863 default=False,
855 )
864 )
856 coreconfigitem('ui', 'logtemplate',
865 coreconfigitem('ui', 'logtemplate',
857 default=None,
866 default=None,
858 )
867 )
859 coreconfigitem('ui', 'merge',
868 coreconfigitem('ui', 'merge',
860 default=None,
869 default=None,
861 )
870 )
862 coreconfigitem('ui', 'mergemarkers',
871 coreconfigitem('ui', 'mergemarkers',
863 default='basic',
872 default='basic',
864 )
873 )
865 coreconfigitem('ui', 'mergemarkertemplate',
874 coreconfigitem('ui', 'mergemarkertemplate',
866 default=('{node|short} '
875 default=('{node|short} '
867 '{ifeq(tags, "tip", "", '
876 '{ifeq(tags, "tip", "", '
868 'ifeq(tags, "", "", "{tags} "))}'
877 'ifeq(tags, "", "", "{tags} "))}'
869 '{if(bookmarks, "{bookmarks} ")}'
878 '{if(bookmarks, "{bookmarks} ")}'
870 '{ifeq(branch, "default", "", "{branch} ")}'
879 '{ifeq(branch, "default", "", "{branch} ")}'
871 '- {author|user}: {desc|firstline}')
880 '- {author|user}: {desc|firstline}')
872 )
881 )
873 coreconfigitem('ui', 'nontty',
882 coreconfigitem('ui', 'nontty',
874 default=False,
883 default=False,
875 )
884 )
876 coreconfigitem('ui', 'origbackuppath',
885 coreconfigitem('ui', 'origbackuppath',
877 default=None,
886 default=None,
878 )
887 )
879 coreconfigitem('ui', 'paginate',
888 coreconfigitem('ui', 'paginate',
880 default=True,
889 default=True,
881 )
890 )
882 coreconfigitem('ui', 'patch',
891 coreconfigitem('ui', 'patch',
883 default=None,
892 default=None,
884 )
893 )
885 coreconfigitem('ui', 'portablefilenames',
894 coreconfigitem('ui', 'portablefilenames',
886 default='warn',
895 default='warn',
887 )
896 )
888 coreconfigitem('ui', 'promptecho',
897 coreconfigitem('ui', 'promptecho',
889 default=False,
898 default=False,
890 )
899 )
891 coreconfigitem('ui', 'quiet',
900 coreconfigitem('ui', 'quiet',
892 default=False,
901 default=False,
893 )
902 )
894 coreconfigitem('ui', 'quietbookmarkmove',
903 coreconfigitem('ui', 'quietbookmarkmove',
895 default=False,
904 default=False,
896 )
905 )
897 coreconfigitem('ui', 'remotecmd',
906 coreconfigitem('ui', 'remotecmd',
898 default='hg',
907 default='hg',
899 )
908 )
900 coreconfigitem('ui', 'report_untrusted',
909 coreconfigitem('ui', 'report_untrusted',
901 default=True,
910 default=True,
902 )
911 )
903 coreconfigitem('ui', 'rollback',
912 coreconfigitem('ui', 'rollback',
904 default=True,
913 default=True,
905 )
914 )
906 coreconfigitem('ui', 'slash',
915 coreconfigitem('ui', 'slash',
907 default=False,
916 default=False,
908 )
917 )
909 coreconfigitem('ui', 'ssh',
918 coreconfigitem('ui', 'ssh',
910 default='ssh',
919 default='ssh',
911 )
920 )
912 coreconfigitem('ui', 'statuscopies',
921 coreconfigitem('ui', 'statuscopies',
913 default=False,
922 default=False,
914 )
923 )
915 coreconfigitem('ui', 'strict',
924 coreconfigitem('ui', 'strict',
916 default=False,
925 default=False,
917 )
926 )
918 coreconfigitem('ui', 'style',
927 coreconfigitem('ui', 'style',
919 default='',
928 default='',
920 )
929 )
921 coreconfigitem('ui', 'supportcontact',
930 coreconfigitem('ui', 'supportcontact',
922 default=None,
931 default=None,
923 )
932 )
924 coreconfigitem('ui', 'textwidth',
933 coreconfigitem('ui', 'textwidth',
925 default=78,
934 default=78,
926 )
935 )
927 coreconfigitem('ui', 'timeout',
936 coreconfigitem('ui', 'timeout',
928 default='600',
937 default='600',
929 )
938 )
930 coreconfigitem('ui', 'traceback',
939 coreconfigitem('ui', 'traceback',
931 default=False,
940 default=False,
932 )
941 )
933 coreconfigitem('ui', 'tweakdefaults',
942 coreconfigitem('ui', 'tweakdefaults',
934 default=False,
943 default=False,
935 )
944 )
936 coreconfigitem('ui', 'usehttp2',
945 coreconfigitem('ui', 'usehttp2',
937 default=False,
946 default=False,
938 )
947 )
939 coreconfigitem('ui', 'username',
948 coreconfigitem('ui', 'username',
940 alias=[('ui', 'user')]
949 alias=[('ui', 'user')]
941 )
950 )
942 coreconfigitem('ui', 'verbose',
951 coreconfigitem('ui', 'verbose',
943 default=False,
952 default=False,
944 )
953 )
945 coreconfigitem('verify', 'skipflags',
954 coreconfigitem('verify', 'skipflags',
946 default=None,
955 default=None,
947 )
956 )
948 coreconfigitem('web', 'allowbz2',
957 coreconfigitem('web', 'allowbz2',
949 default=False,
958 default=False,
950 )
959 )
951 coreconfigitem('web', 'allowgz',
960 coreconfigitem('web', 'allowgz',
952 default=False,
961 default=False,
953 )
962 )
954 coreconfigitem('web', 'allowpull',
963 coreconfigitem('web', 'allowpull',
955 default=True,
964 default=True,
956 )
965 )
957 coreconfigitem('web', 'allow_push',
966 coreconfigitem('web', 'allow_push',
958 default=list,
967 default=list,
959 )
968 )
960 coreconfigitem('web', 'allowzip',
969 coreconfigitem('web', 'allowzip',
961 default=False,
970 default=False,
962 )
971 )
963 coreconfigitem('web', 'archivesubrepos',
972 coreconfigitem('web', 'archivesubrepos',
964 default=False,
973 default=False,
965 )
974 )
966 coreconfigitem('web', 'cache',
975 coreconfigitem('web', 'cache',
967 default=True,
976 default=True,
968 )
977 )
969 coreconfigitem('web', 'contact',
978 coreconfigitem('web', 'contact',
970 default=None,
979 default=None,
971 )
980 )
972 coreconfigitem('web', 'deny_push',
981 coreconfigitem('web', 'deny_push',
973 default=list,
982 default=list,
974 )
983 )
975 coreconfigitem('web', 'guessmime',
984 coreconfigitem('web', 'guessmime',
976 default=False,
985 default=False,
977 )
986 )
978 coreconfigitem('web', 'hidden',
987 coreconfigitem('web', 'hidden',
979 default=False,
988 default=False,
980 )
989 )
981 coreconfigitem('web', 'labels',
990 coreconfigitem('web', 'labels',
982 default=list,
991 default=list,
983 )
992 )
984 coreconfigitem('web', 'logoimg',
993 coreconfigitem('web', 'logoimg',
985 default='hglogo.png',
994 default='hglogo.png',
986 )
995 )
987 coreconfigitem('web', 'logourl',
996 coreconfigitem('web', 'logourl',
988 default='https://mercurial-scm.org/',
997 default='https://mercurial-scm.org/',
989 )
998 )
990 coreconfigitem('web', 'accesslog',
999 coreconfigitem('web', 'accesslog',
991 default='-',
1000 default='-',
992 )
1001 )
993 coreconfigitem('web', 'address',
1002 coreconfigitem('web', 'address',
994 default='',
1003 default='',
995 )
1004 )
996 coreconfigitem('web', 'allow_archive',
1005 coreconfigitem('web', 'allow_archive',
997 default=list,
1006 default=list,
998 )
1007 )
999 coreconfigitem('web', 'allow_read',
1008 coreconfigitem('web', 'allow_read',
1000 default=list,
1009 default=list,
1001 )
1010 )
1002 coreconfigitem('web', 'baseurl',
1011 coreconfigitem('web', 'baseurl',
1003 default=None,
1012 default=None,
1004 )
1013 )
1005 coreconfigitem('web', 'cacerts',
1014 coreconfigitem('web', 'cacerts',
1006 default=None,
1015 default=None,
1007 )
1016 )
1008 coreconfigitem('web', 'certificate',
1017 coreconfigitem('web', 'certificate',
1009 default=None,
1018 default=None,
1010 )
1019 )
1011 coreconfigitem('web', 'collapse',
1020 coreconfigitem('web', 'collapse',
1012 default=False,
1021 default=False,
1013 )
1022 )
1014 coreconfigitem('web', 'csp',
1023 coreconfigitem('web', 'csp',
1015 default=None,
1024 default=None,
1016 )
1025 )
1017 coreconfigitem('web', 'deny_read',
1026 coreconfigitem('web', 'deny_read',
1018 default=list,
1027 default=list,
1019 )
1028 )
1020 coreconfigitem('web', 'descend',
1029 coreconfigitem('web', 'descend',
1021 default=True,
1030 default=True,
1022 )
1031 )
1023 coreconfigitem('web', 'description',
1032 coreconfigitem('web', 'description',
1024 default="",
1033 default="",
1025 )
1034 )
1026 coreconfigitem('web', 'encoding',
1035 coreconfigitem('web', 'encoding',
1027 default=lambda: encoding.encoding,
1036 default=lambda: encoding.encoding,
1028 )
1037 )
1029 coreconfigitem('web', 'errorlog',
1038 coreconfigitem('web', 'errorlog',
1030 default='-',
1039 default='-',
1031 )
1040 )
1032 coreconfigitem('web', 'ipv6',
1041 coreconfigitem('web', 'ipv6',
1033 default=False,
1042 default=False,
1034 )
1043 )
1035 coreconfigitem('web', 'maxchanges',
1044 coreconfigitem('web', 'maxchanges',
1036 default=10,
1045 default=10,
1037 )
1046 )
1038 coreconfigitem('web', 'maxfiles',
1047 coreconfigitem('web', 'maxfiles',
1039 default=10,
1048 default=10,
1040 )
1049 )
1041 coreconfigitem('web', 'maxshortchanges',
1050 coreconfigitem('web', 'maxshortchanges',
1042 default=60,
1051 default=60,
1043 )
1052 )
1044 coreconfigitem('web', 'motd',
1053 coreconfigitem('web', 'motd',
1045 default='',
1054 default='',
1046 )
1055 )
1047 coreconfigitem('web', 'name',
1056 coreconfigitem('web', 'name',
1048 default=dynamicdefault,
1057 default=dynamicdefault,
1049 )
1058 )
1050 coreconfigitem('web', 'port',
1059 coreconfigitem('web', 'port',
1051 default=8000,
1060 default=8000,
1052 )
1061 )
1053 coreconfigitem('web', 'prefix',
1062 coreconfigitem('web', 'prefix',
1054 default='',
1063 default='',
1055 )
1064 )
1056 coreconfigitem('web', 'push_ssl',
1065 coreconfigitem('web', 'push_ssl',
1057 default=True,
1066 default=True,
1058 )
1067 )
1059 coreconfigitem('web', 'refreshinterval',
1068 coreconfigitem('web', 'refreshinterval',
1060 default=20,
1069 default=20,
1061 )
1070 )
1062 coreconfigitem('web', 'staticurl',
1071 coreconfigitem('web', 'staticurl',
1063 default=None,
1072 default=None,
1064 )
1073 )
1065 coreconfigitem('web', 'stripes',
1074 coreconfigitem('web', 'stripes',
1066 default=1,
1075 default=1,
1067 )
1076 )
1068 coreconfigitem('web', 'style',
1077 coreconfigitem('web', 'style',
1069 default='paper',
1078 default='paper',
1070 )
1079 )
1071 coreconfigitem('web', 'templates',
1080 coreconfigitem('web', 'templates',
1072 default=None,
1081 default=None,
1073 )
1082 )
1074 coreconfigitem('web', 'view',
1083 coreconfigitem('web', 'view',
1075 default='served',
1084 default='served',
1076 )
1085 )
1077 coreconfigitem('worker', 'backgroundclose',
1086 coreconfigitem('worker', 'backgroundclose',
1078 default=dynamicdefault,
1087 default=dynamicdefault,
1079 )
1088 )
1080 # Windows defaults to a limit of 512 open files. A buffer of 128
1089 # Windows defaults to a limit of 512 open files. A buffer of 128
1081 # should give us enough headway.
1090 # should give us enough headway.
1082 coreconfigitem('worker', 'backgroundclosemaxqueue',
1091 coreconfigitem('worker', 'backgroundclosemaxqueue',
1083 default=384,
1092 default=384,
1084 )
1093 )
1085 coreconfigitem('worker', 'backgroundcloseminfilecount',
1094 coreconfigitem('worker', 'backgroundcloseminfilecount',
1086 default=2048,
1095 default=2048,
1087 )
1096 )
1088 coreconfigitem('worker', 'backgroundclosethreadcount',
1097 coreconfigitem('worker', 'backgroundclosethreadcount',
1089 default=4,
1098 default=4,
1090 )
1099 )
1091 coreconfigitem('worker', 'numcpus',
1100 coreconfigitem('worker', 'numcpus',
1092 default=None,
1101 default=None,
1093 )
1102 )
1094
1103
1095 # Rebase related configuration moved to core because other extension are doing
1104 # Rebase related configuration moved to core because other extension are doing
1096 # strange things. For example, shelve import the extensions to reuse some bit
1105 # strange things. For example, shelve import the extensions to reuse some bit
1097 # without formally loading it.
1106 # without formally loading it.
1098 coreconfigitem('commands', 'rebase.requiredest',
1107 coreconfigitem('commands', 'rebase.requiredest',
1099 default=False,
1108 default=False,
1100 )
1109 )
1101 coreconfigitem('experimental', 'rebaseskipobsolete',
1110 coreconfigitem('experimental', 'rebaseskipobsolete',
1102 default=True,
1111 default=True,
1103 )
1112 )
1104 coreconfigitem('rebase', 'singletransaction',
1113 coreconfigitem('rebase', 'singletransaction',
1105 default=False,
1114 default=False,
1106 )
1115 )
@@ -1,1098 +1,1126 b''
1 # obsolete.py - obsolete markers handling
1 # obsolete.py - obsolete markers handling
2 #
2 #
3 # Copyright 2012 Pierre-Yves David <pierre-yves.david@ens-lyon.org>
3 # Copyright 2012 Pierre-Yves David <pierre-yves.david@ens-lyon.org>
4 # Logilab SA <contact@logilab.fr>
4 # Logilab SA <contact@logilab.fr>
5 #
5 #
6 # This software may be used and distributed according to the terms of the
6 # This software may be used and distributed according to the terms of the
7 # GNU General Public License version 2 or any later version.
7 # GNU General Public License version 2 or any later version.
8
8
9 """Obsolete marker handling
9 """Obsolete marker handling
10
10
11 An obsolete marker maps an old changeset to a list of new
11 An obsolete marker maps an old changeset to a list of new
12 changesets. If the list of new changesets is empty, the old changeset
12 changesets. If the list of new changesets is empty, the old changeset
13 is said to be "killed". Otherwise, the old changeset is being
13 is said to be "killed". Otherwise, the old changeset is being
14 "replaced" by the new changesets.
14 "replaced" by the new changesets.
15
15
16 Obsolete markers can be used to record and distribute changeset graph
16 Obsolete markers can be used to record and distribute changeset graph
17 transformations performed by history rewrite operations, and help
17 transformations performed by history rewrite operations, and help
18 building new tools to reconcile conflicting rewrite actions. To
18 building new tools to reconcile conflicting rewrite actions. To
19 facilitate conflict resolution, markers include various annotations
19 facilitate conflict resolution, markers include various annotations
20 besides old and news changeset identifiers, such as creation date or
20 besides old and news changeset identifiers, such as creation date or
21 author name.
21 author name.
22
22
23 The old obsoleted changeset is called a "predecessor" and possible
23 The old obsoleted changeset is called a "predecessor" and possible
24 replacements are called "successors". Markers that used changeset X as
24 replacements are called "successors". Markers that used changeset X as
25 a predecessor are called "successor markers of X" because they hold
25 a predecessor are called "successor markers of X" because they hold
26 information about the successors of X. Markers that use changeset Y as
26 information about the successors of X. Markers that use changeset Y as
27 a successors are call "predecessor markers of Y" because they hold
27 a successors are call "predecessor markers of Y" because they hold
28 information about the predecessors of Y.
28 information about the predecessors of Y.
29
29
30 Examples:
30 Examples:
31
31
32 - When changeset A is replaced by changeset A', one marker is stored:
32 - When changeset A is replaced by changeset A', one marker is stored:
33
33
34 (A, (A',))
34 (A, (A',))
35
35
36 - When changesets A and B are folded into a new changeset C, two markers are
36 - When changesets A and B are folded into a new changeset C, two markers are
37 stored:
37 stored:
38
38
39 (A, (C,)) and (B, (C,))
39 (A, (C,)) and (B, (C,))
40
40
41 - When changeset A is simply "pruned" from the graph, a marker is created:
41 - When changeset A is simply "pruned" from the graph, a marker is created:
42
42
43 (A, ())
43 (A, ())
44
44
45 - When changeset A is split into B and C, a single marker is used:
45 - When changeset A is split into B and C, a single marker is used:
46
46
47 (A, (B, C))
47 (A, (B, C))
48
48
49 We use a single marker to distinguish the "split" case from the "divergence"
49 We use a single marker to distinguish the "split" case from the "divergence"
50 case. If two independent operations rewrite the same changeset A in to A' and
50 case. If two independent operations rewrite the same changeset A in to A' and
51 A'', we have an error case: divergent rewriting. We can detect it because
51 A'', we have an error case: divergent rewriting. We can detect it because
52 two markers will be created independently:
52 two markers will be created independently:
53
53
54 (A, (B,)) and (A, (C,))
54 (A, (B,)) and (A, (C,))
55
55
56 Format
56 Format
57 ------
57 ------
58
58
59 Markers are stored in an append-only file stored in
59 Markers are stored in an append-only file stored in
60 '.hg/store/obsstore'.
60 '.hg/store/obsstore'.
61
61
62 The file starts with a version header:
62 The file starts with a version header:
63
63
64 - 1 unsigned byte: version number, starting at zero.
64 - 1 unsigned byte: version number, starting at zero.
65
65
66 The header is followed by the markers. Marker format depend of the version. See
66 The header is followed by the markers. Marker format depend of the version. See
67 comment associated with each format for details.
67 comment associated with each format for details.
68
68
69 """
69 """
70 from __future__ import absolute_import
70 from __future__ import absolute_import
71
71
72 import errno
72 import errno
73 import struct
73 import struct
74
74
75 from .i18n import _
75 from .i18n import _
76 from . import (
76 from . import (
77 error,
77 error,
78 node,
78 node,
79 obsutil,
79 obsutil,
80 phases,
80 phases,
81 policy,
81 policy,
82 util,
82 util,
83 )
83 )
84
84
85 parsers = policy.importmod(r'parsers')
85 parsers = policy.importmod(r'parsers')
86
86
87 _pack = struct.pack
87 _pack = struct.pack
88 _unpack = struct.unpack
88 _unpack = struct.unpack
89 _calcsize = struct.calcsize
89 _calcsize = struct.calcsize
90 propertycache = util.propertycache
90 propertycache = util.propertycache
91
91
92 # the obsolete feature is not mature enough to be enabled by default.
92 # the obsolete feature is not mature enough to be enabled by default.
93 # you have to rely on third party extension extension to enable this.
93 # you have to rely on third party extension extension to enable this.
94 _enabled = False
94 _enabled = False
95
95
96 # Options for obsolescence
96 # Options for obsolescence
97 createmarkersopt = 'createmarkers'
97 createmarkersopt = 'createmarkers'
98 allowunstableopt = 'allowunstable'
98 allowunstableopt = 'allowunstable'
99 exchangeopt = 'exchange'
99 exchangeopt = 'exchange'
100
100
101 def _getoptionvalue(repo, option):
102 """Returns True if the given repository has the given obsolete option
103 enabled.
104 """
105 configkey = 'evolution.%s' % option
106 newconfig = repo.ui.configbool('experimental', configkey)
107
108 # Return the value only if defined
109 if newconfig is not None:
110 return newconfig
111
112 # Fallback on generic option
113 try:
114 return repo.ui.configbool('experimental', 'evolution')
115 except (error.ConfigError, AttributeError):
116 # Fallback on old-fashion config
117 # inconsistent config: experimental.evolution
118 result = set(repo.ui.configlist('experimental', 'evolution'))
119
120 if 'all' in result:
121 return True
122
123 # For migration purposes, temporarily return true if the config hasn't
124 # been set but _enabled is true.
125 if len(result) == 0 and _enabled:
126 return True
127
128 # Temporary hack for next check
129 newconfig = repo.ui.config('experimental', 'evolution.createmarkers')
130 if newconfig:
131 result.add('createmarkers')
132
133 return option in result
134
101 def isenabled(repo, option):
135 def isenabled(repo, option):
102 """Returns True if the given repository has the given obsolete option
136 """Returns True if the given repository has the given obsolete option
103 enabled.
137 enabled.
104 """
138 """
105 result = set(repo.ui.configlist('experimental', 'evolution'))
139 createmarkersvalue = _getoptionvalue(repo, createmarkersopt)
106 if 'all' in result:
140 unstabluevalue = _getoptionvalue(repo, allowunstableopt)
107 return True
141 exchangevalue = _getoptionvalue(repo, exchangeopt)
108
109 # For migration purposes, temporarily return true if the config hasn't been
110 # set but _enabled is true.
111 if len(result) == 0 and _enabled:
112 return True
113
142
114 # createmarkers must be enabled if other options are enabled
143 # createmarkers must be enabled if other options are enabled
115 if ((allowunstableopt in result or exchangeopt in result) and
144 if ((unstabluevalue or exchangevalue) and not createmarkersvalue):
116 not createmarkersopt in result):
117 raise error.Abort(_("'createmarkers' obsolete option must be enabled "
145 raise error.Abort(_("'createmarkers' obsolete option must be enabled "
118 "if other obsolete options are enabled"))
146 "if other obsolete options are enabled"))
119
147
120 return option in result
148 return _getoptionvalue(repo, option)
121
149
122 ### obsolescence marker flag
150 ### obsolescence marker flag
123
151
124 ## bumpedfix flag
152 ## bumpedfix flag
125 #
153 #
126 # When a changeset A' succeed to a changeset A which became public, we call A'
154 # When a changeset A' succeed to a changeset A which became public, we call A'
127 # "bumped" because it's a successors of a public changesets
155 # "bumped" because it's a successors of a public changesets
128 #
156 #
129 # o A' (bumped)
157 # o A' (bumped)
130 # |`:
158 # |`:
131 # | o A
159 # | o A
132 # |/
160 # |/
133 # o Z
161 # o Z
134 #
162 #
135 # The way to solve this situation is to create a new changeset Ad as children
163 # The way to solve this situation is to create a new changeset Ad as children
136 # of A. This changeset have the same content than A'. So the diff from A to A'
164 # of A. This changeset have the same content than A'. So the diff from A to A'
137 # is the same than the diff from A to Ad. Ad is marked as a successors of A'
165 # is the same than the diff from A to Ad. Ad is marked as a successors of A'
138 #
166 #
139 # o Ad
167 # o Ad
140 # |`:
168 # |`:
141 # | x A'
169 # | x A'
142 # |'|
170 # |'|
143 # o | A
171 # o | A
144 # |/
172 # |/
145 # o Z
173 # o Z
146 #
174 #
147 # But by transitivity Ad is also a successors of A. To avoid having Ad marked
175 # But by transitivity Ad is also a successors of A. To avoid having Ad marked
148 # as bumped too, we add the `bumpedfix` flag to the marker. <A', (Ad,)>.
176 # as bumped too, we add the `bumpedfix` flag to the marker. <A', (Ad,)>.
149 # This flag mean that the successors express the changes between the public and
177 # This flag mean that the successors express the changes between the public and
150 # bumped version and fix the situation, breaking the transitivity of
178 # bumped version and fix the situation, breaking the transitivity of
151 # "bumped" here.
179 # "bumped" here.
152 bumpedfix = 1
180 bumpedfix = 1
153 usingsha256 = 2
181 usingsha256 = 2
154
182
155 ## Parsing and writing of version "0"
183 ## Parsing and writing of version "0"
156 #
184 #
157 # The header is followed by the markers. Each marker is made of:
185 # The header is followed by the markers. Each marker is made of:
158 #
186 #
159 # - 1 uint8 : number of new changesets "N", can be zero.
187 # - 1 uint8 : number of new changesets "N", can be zero.
160 #
188 #
161 # - 1 uint32: metadata size "M" in bytes.
189 # - 1 uint32: metadata size "M" in bytes.
162 #
190 #
163 # - 1 byte: a bit field. It is reserved for flags used in common
191 # - 1 byte: a bit field. It is reserved for flags used in common
164 # obsolete marker operations, to avoid repeated decoding of metadata
192 # obsolete marker operations, to avoid repeated decoding of metadata
165 # entries.
193 # entries.
166 #
194 #
167 # - 20 bytes: obsoleted changeset identifier.
195 # - 20 bytes: obsoleted changeset identifier.
168 #
196 #
169 # - N*20 bytes: new changesets identifiers.
197 # - N*20 bytes: new changesets identifiers.
170 #
198 #
171 # - M bytes: metadata as a sequence of nul-terminated strings. Each
199 # - M bytes: metadata as a sequence of nul-terminated strings. Each
172 # string contains a key and a value, separated by a colon ':', without
200 # string contains a key and a value, separated by a colon ':', without
173 # additional encoding. Keys cannot contain '\0' or ':' and values
201 # additional encoding. Keys cannot contain '\0' or ':' and values
174 # cannot contain '\0'.
202 # cannot contain '\0'.
175 _fm0version = 0
203 _fm0version = 0
176 _fm0fixed = '>BIB20s'
204 _fm0fixed = '>BIB20s'
177 _fm0node = '20s'
205 _fm0node = '20s'
178 _fm0fsize = _calcsize(_fm0fixed)
206 _fm0fsize = _calcsize(_fm0fixed)
179 _fm0fnodesize = _calcsize(_fm0node)
207 _fm0fnodesize = _calcsize(_fm0node)
180
208
181 def _fm0readmarkers(data, off, stop):
209 def _fm0readmarkers(data, off, stop):
182 # Loop on markers
210 # Loop on markers
183 while off < stop:
211 while off < stop:
184 # read fixed part
212 # read fixed part
185 cur = data[off:off + _fm0fsize]
213 cur = data[off:off + _fm0fsize]
186 off += _fm0fsize
214 off += _fm0fsize
187 numsuc, mdsize, flags, pre = _unpack(_fm0fixed, cur)
215 numsuc, mdsize, flags, pre = _unpack(_fm0fixed, cur)
188 # read replacement
216 # read replacement
189 sucs = ()
217 sucs = ()
190 if numsuc:
218 if numsuc:
191 s = (_fm0fnodesize * numsuc)
219 s = (_fm0fnodesize * numsuc)
192 cur = data[off:off + s]
220 cur = data[off:off + s]
193 sucs = _unpack(_fm0node * numsuc, cur)
221 sucs = _unpack(_fm0node * numsuc, cur)
194 off += s
222 off += s
195 # read metadata
223 # read metadata
196 # (metadata will be decoded on demand)
224 # (metadata will be decoded on demand)
197 metadata = data[off:off + mdsize]
225 metadata = data[off:off + mdsize]
198 if len(metadata) != mdsize:
226 if len(metadata) != mdsize:
199 raise error.Abort(_('parsing obsolete marker: metadata is too '
227 raise error.Abort(_('parsing obsolete marker: metadata is too '
200 'short, %d bytes expected, got %d')
228 'short, %d bytes expected, got %d')
201 % (mdsize, len(metadata)))
229 % (mdsize, len(metadata)))
202 off += mdsize
230 off += mdsize
203 metadata = _fm0decodemeta(metadata)
231 metadata = _fm0decodemeta(metadata)
204 try:
232 try:
205 when, offset = metadata.pop('date', '0 0').split(' ')
233 when, offset = metadata.pop('date', '0 0').split(' ')
206 date = float(when), int(offset)
234 date = float(when), int(offset)
207 except ValueError:
235 except ValueError:
208 date = (0., 0)
236 date = (0., 0)
209 parents = None
237 parents = None
210 if 'p2' in metadata:
238 if 'p2' in metadata:
211 parents = (metadata.pop('p1', None), metadata.pop('p2', None))
239 parents = (metadata.pop('p1', None), metadata.pop('p2', None))
212 elif 'p1' in metadata:
240 elif 'p1' in metadata:
213 parents = (metadata.pop('p1', None),)
241 parents = (metadata.pop('p1', None),)
214 elif 'p0' in metadata:
242 elif 'p0' in metadata:
215 parents = ()
243 parents = ()
216 if parents is not None:
244 if parents is not None:
217 try:
245 try:
218 parents = tuple(node.bin(p) for p in parents)
246 parents = tuple(node.bin(p) for p in parents)
219 # if parent content is not a nodeid, drop the data
247 # if parent content is not a nodeid, drop the data
220 for p in parents:
248 for p in parents:
221 if len(p) != 20:
249 if len(p) != 20:
222 parents = None
250 parents = None
223 break
251 break
224 except TypeError:
252 except TypeError:
225 # if content cannot be translated to nodeid drop the data.
253 # if content cannot be translated to nodeid drop the data.
226 parents = None
254 parents = None
227
255
228 metadata = tuple(sorted(metadata.iteritems()))
256 metadata = tuple(sorted(metadata.iteritems()))
229
257
230 yield (pre, sucs, flags, metadata, date, parents)
258 yield (pre, sucs, flags, metadata, date, parents)
231
259
232 def _fm0encodeonemarker(marker):
260 def _fm0encodeonemarker(marker):
233 pre, sucs, flags, metadata, date, parents = marker
261 pre, sucs, flags, metadata, date, parents = marker
234 if flags & usingsha256:
262 if flags & usingsha256:
235 raise error.Abort(_('cannot handle sha256 with old obsstore format'))
263 raise error.Abort(_('cannot handle sha256 with old obsstore format'))
236 metadata = dict(metadata)
264 metadata = dict(metadata)
237 time, tz = date
265 time, tz = date
238 metadata['date'] = '%r %i' % (time, tz)
266 metadata['date'] = '%r %i' % (time, tz)
239 if parents is not None:
267 if parents is not None:
240 if not parents:
268 if not parents:
241 # mark that we explicitly recorded no parents
269 # mark that we explicitly recorded no parents
242 metadata['p0'] = ''
270 metadata['p0'] = ''
243 for i, p in enumerate(parents, 1):
271 for i, p in enumerate(parents, 1):
244 metadata['p%i' % i] = node.hex(p)
272 metadata['p%i' % i] = node.hex(p)
245 metadata = _fm0encodemeta(metadata)
273 metadata = _fm0encodemeta(metadata)
246 numsuc = len(sucs)
274 numsuc = len(sucs)
247 format = _fm0fixed + (_fm0node * numsuc)
275 format = _fm0fixed + (_fm0node * numsuc)
248 data = [numsuc, len(metadata), flags, pre]
276 data = [numsuc, len(metadata), flags, pre]
249 data.extend(sucs)
277 data.extend(sucs)
250 return _pack(format, *data) + metadata
278 return _pack(format, *data) + metadata
251
279
252 def _fm0encodemeta(meta):
280 def _fm0encodemeta(meta):
253 """Return encoded metadata string to string mapping.
281 """Return encoded metadata string to string mapping.
254
282
255 Assume no ':' in key and no '\0' in both key and value."""
283 Assume no ':' in key and no '\0' in both key and value."""
256 for key, value in meta.iteritems():
284 for key, value in meta.iteritems():
257 if ':' in key or '\0' in key:
285 if ':' in key or '\0' in key:
258 raise ValueError("':' and '\0' are forbidden in metadata key'")
286 raise ValueError("':' and '\0' are forbidden in metadata key'")
259 if '\0' in value:
287 if '\0' in value:
260 raise ValueError("':' is forbidden in metadata value'")
288 raise ValueError("':' is forbidden in metadata value'")
261 return '\0'.join(['%s:%s' % (k, meta[k]) for k in sorted(meta)])
289 return '\0'.join(['%s:%s' % (k, meta[k]) for k in sorted(meta)])
262
290
263 def _fm0decodemeta(data):
291 def _fm0decodemeta(data):
264 """Return string to string dictionary from encoded version."""
292 """Return string to string dictionary from encoded version."""
265 d = {}
293 d = {}
266 for l in data.split('\0'):
294 for l in data.split('\0'):
267 if l:
295 if l:
268 key, value = l.split(':')
296 key, value = l.split(':')
269 d[key] = value
297 d[key] = value
270 return d
298 return d
271
299
272 ## Parsing and writing of version "1"
300 ## Parsing and writing of version "1"
273 #
301 #
274 # The header is followed by the markers. Each marker is made of:
302 # The header is followed by the markers. Each marker is made of:
275 #
303 #
276 # - uint32: total size of the marker (including this field)
304 # - uint32: total size of the marker (including this field)
277 #
305 #
278 # - float64: date in seconds since epoch
306 # - float64: date in seconds since epoch
279 #
307 #
280 # - int16: timezone offset in minutes
308 # - int16: timezone offset in minutes
281 #
309 #
282 # - uint16: a bit field. It is reserved for flags used in common
310 # - uint16: a bit field. It is reserved for flags used in common
283 # obsolete marker operations, to avoid repeated decoding of metadata
311 # obsolete marker operations, to avoid repeated decoding of metadata
284 # entries.
312 # entries.
285 #
313 #
286 # - uint8: number of successors "N", can be zero.
314 # - uint8: number of successors "N", can be zero.
287 #
315 #
288 # - uint8: number of parents "P", can be zero.
316 # - uint8: number of parents "P", can be zero.
289 #
317 #
290 # 0: parents data stored but no parent,
318 # 0: parents data stored but no parent,
291 # 1: one parent stored,
319 # 1: one parent stored,
292 # 2: two parents stored,
320 # 2: two parents stored,
293 # 3: no parent data stored
321 # 3: no parent data stored
294 #
322 #
295 # - uint8: number of metadata entries M
323 # - uint8: number of metadata entries M
296 #
324 #
297 # - 20 or 32 bytes: predecessor changeset identifier.
325 # - 20 or 32 bytes: predecessor changeset identifier.
298 #
326 #
299 # - N*(20 or 32) bytes: successors changesets identifiers.
327 # - N*(20 or 32) bytes: successors changesets identifiers.
300 #
328 #
301 # - P*(20 or 32) bytes: parents of the predecessors changesets.
329 # - P*(20 or 32) bytes: parents of the predecessors changesets.
302 #
330 #
303 # - M*(uint8, uint8): size of all metadata entries (key and value)
331 # - M*(uint8, uint8): size of all metadata entries (key and value)
304 #
332 #
305 # - remaining bytes: the metadata, each (key, value) pair after the other.
333 # - remaining bytes: the metadata, each (key, value) pair after the other.
306 _fm1version = 1
334 _fm1version = 1
307 _fm1fixed = '>IdhHBBB20s'
335 _fm1fixed = '>IdhHBBB20s'
308 _fm1nodesha1 = '20s'
336 _fm1nodesha1 = '20s'
309 _fm1nodesha256 = '32s'
337 _fm1nodesha256 = '32s'
310 _fm1nodesha1size = _calcsize(_fm1nodesha1)
338 _fm1nodesha1size = _calcsize(_fm1nodesha1)
311 _fm1nodesha256size = _calcsize(_fm1nodesha256)
339 _fm1nodesha256size = _calcsize(_fm1nodesha256)
312 _fm1fsize = _calcsize(_fm1fixed)
340 _fm1fsize = _calcsize(_fm1fixed)
313 _fm1parentnone = 3
341 _fm1parentnone = 3
314 _fm1parentshift = 14
342 _fm1parentshift = 14
315 _fm1parentmask = (_fm1parentnone << _fm1parentshift)
343 _fm1parentmask = (_fm1parentnone << _fm1parentshift)
316 _fm1metapair = 'BB'
344 _fm1metapair = 'BB'
317 _fm1metapairsize = _calcsize(_fm1metapair)
345 _fm1metapairsize = _calcsize(_fm1metapair)
318
346
319 def _fm1purereadmarkers(data, off, stop):
347 def _fm1purereadmarkers(data, off, stop):
320 # make some global constants local for performance
348 # make some global constants local for performance
321 noneflag = _fm1parentnone
349 noneflag = _fm1parentnone
322 sha2flag = usingsha256
350 sha2flag = usingsha256
323 sha1size = _fm1nodesha1size
351 sha1size = _fm1nodesha1size
324 sha2size = _fm1nodesha256size
352 sha2size = _fm1nodesha256size
325 sha1fmt = _fm1nodesha1
353 sha1fmt = _fm1nodesha1
326 sha2fmt = _fm1nodesha256
354 sha2fmt = _fm1nodesha256
327 metasize = _fm1metapairsize
355 metasize = _fm1metapairsize
328 metafmt = _fm1metapair
356 metafmt = _fm1metapair
329 fsize = _fm1fsize
357 fsize = _fm1fsize
330 unpack = _unpack
358 unpack = _unpack
331
359
332 # Loop on markers
360 # Loop on markers
333 ufixed = struct.Struct(_fm1fixed).unpack
361 ufixed = struct.Struct(_fm1fixed).unpack
334
362
335 while off < stop:
363 while off < stop:
336 # read fixed part
364 # read fixed part
337 o1 = off + fsize
365 o1 = off + fsize
338 t, secs, tz, flags, numsuc, numpar, nummeta, prec = ufixed(data[off:o1])
366 t, secs, tz, flags, numsuc, numpar, nummeta, prec = ufixed(data[off:o1])
339
367
340 if flags & sha2flag:
368 if flags & sha2flag:
341 # FIXME: prec was read as a SHA1, needs to be amended
369 # FIXME: prec was read as a SHA1, needs to be amended
342
370
343 # read 0 or more successors
371 # read 0 or more successors
344 if numsuc == 1:
372 if numsuc == 1:
345 o2 = o1 + sha2size
373 o2 = o1 + sha2size
346 sucs = (data[o1:o2],)
374 sucs = (data[o1:o2],)
347 else:
375 else:
348 o2 = o1 + sha2size * numsuc
376 o2 = o1 + sha2size * numsuc
349 sucs = unpack(sha2fmt * numsuc, data[o1:o2])
377 sucs = unpack(sha2fmt * numsuc, data[o1:o2])
350
378
351 # read parents
379 # read parents
352 if numpar == noneflag:
380 if numpar == noneflag:
353 o3 = o2
381 o3 = o2
354 parents = None
382 parents = None
355 elif numpar == 1:
383 elif numpar == 1:
356 o3 = o2 + sha2size
384 o3 = o2 + sha2size
357 parents = (data[o2:o3],)
385 parents = (data[o2:o3],)
358 else:
386 else:
359 o3 = o2 + sha2size * numpar
387 o3 = o2 + sha2size * numpar
360 parents = unpack(sha2fmt * numpar, data[o2:o3])
388 parents = unpack(sha2fmt * numpar, data[o2:o3])
361 else:
389 else:
362 # read 0 or more successors
390 # read 0 or more successors
363 if numsuc == 1:
391 if numsuc == 1:
364 o2 = o1 + sha1size
392 o2 = o1 + sha1size
365 sucs = (data[o1:o2],)
393 sucs = (data[o1:o2],)
366 else:
394 else:
367 o2 = o1 + sha1size * numsuc
395 o2 = o1 + sha1size * numsuc
368 sucs = unpack(sha1fmt * numsuc, data[o1:o2])
396 sucs = unpack(sha1fmt * numsuc, data[o1:o2])
369
397
370 # read parents
398 # read parents
371 if numpar == noneflag:
399 if numpar == noneflag:
372 o3 = o2
400 o3 = o2
373 parents = None
401 parents = None
374 elif numpar == 1:
402 elif numpar == 1:
375 o3 = o2 + sha1size
403 o3 = o2 + sha1size
376 parents = (data[o2:o3],)
404 parents = (data[o2:o3],)
377 else:
405 else:
378 o3 = o2 + sha1size * numpar
406 o3 = o2 + sha1size * numpar
379 parents = unpack(sha1fmt * numpar, data[o2:o3])
407 parents = unpack(sha1fmt * numpar, data[o2:o3])
380
408
381 # read metadata
409 # read metadata
382 off = o3 + metasize * nummeta
410 off = o3 + metasize * nummeta
383 metapairsize = unpack('>' + (metafmt * nummeta), data[o3:off])
411 metapairsize = unpack('>' + (metafmt * nummeta), data[o3:off])
384 metadata = []
412 metadata = []
385 for idx in xrange(0, len(metapairsize), 2):
413 for idx in xrange(0, len(metapairsize), 2):
386 o1 = off + metapairsize[idx]
414 o1 = off + metapairsize[idx]
387 o2 = o1 + metapairsize[idx + 1]
415 o2 = o1 + metapairsize[idx + 1]
388 metadata.append((data[off:o1], data[o1:o2]))
416 metadata.append((data[off:o1], data[o1:o2]))
389 off = o2
417 off = o2
390
418
391 yield (prec, sucs, flags, tuple(metadata), (secs, tz * 60), parents)
419 yield (prec, sucs, flags, tuple(metadata), (secs, tz * 60), parents)
392
420
393 def _fm1encodeonemarker(marker):
421 def _fm1encodeonemarker(marker):
394 pre, sucs, flags, metadata, date, parents = marker
422 pre, sucs, flags, metadata, date, parents = marker
395 # determine node size
423 # determine node size
396 _fm1node = _fm1nodesha1
424 _fm1node = _fm1nodesha1
397 if flags & usingsha256:
425 if flags & usingsha256:
398 _fm1node = _fm1nodesha256
426 _fm1node = _fm1nodesha256
399 numsuc = len(sucs)
427 numsuc = len(sucs)
400 numextranodes = numsuc
428 numextranodes = numsuc
401 if parents is None:
429 if parents is None:
402 numpar = _fm1parentnone
430 numpar = _fm1parentnone
403 else:
431 else:
404 numpar = len(parents)
432 numpar = len(parents)
405 numextranodes += numpar
433 numextranodes += numpar
406 formatnodes = _fm1node * numextranodes
434 formatnodes = _fm1node * numextranodes
407 formatmeta = _fm1metapair * len(metadata)
435 formatmeta = _fm1metapair * len(metadata)
408 format = _fm1fixed + formatnodes + formatmeta
436 format = _fm1fixed + formatnodes + formatmeta
409 # tz is stored in minutes so we divide by 60
437 # tz is stored in minutes so we divide by 60
410 tz = date[1]//60
438 tz = date[1]//60
411 data = [None, date[0], tz, flags, numsuc, numpar, len(metadata), pre]
439 data = [None, date[0], tz, flags, numsuc, numpar, len(metadata), pre]
412 data.extend(sucs)
440 data.extend(sucs)
413 if parents is not None:
441 if parents is not None:
414 data.extend(parents)
442 data.extend(parents)
415 totalsize = _calcsize(format)
443 totalsize = _calcsize(format)
416 for key, value in metadata:
444 for key, value in metadata:
417 lk = len(key)
445 lk = len(key)
418 lv = len(value)
446 lv = len(value)
419 if lk > 255:
447 if lk > 255:
420 msg = ('obsstore metadata key cannot be longer than 255 bytes'
448 msg = ('obsstore metadata key cannot be longer than 255 bytes'
421 ' (key "%s" is %u bytes)') % (key, lk)
449 ' (key "%s" is %u bytes)') % (key, lk)
422 raise error.ProgrammingError(msg)
450 raise error.ProgrammingError(msg)
423 if lv > 255:
451 if lv > 255:
424 msg = ('obsstore metadata value cannot be longer than 255 bytes'
452 msg = ('obsstore metadata value cannot be longer than 255 bytes'
425 ' (value "%s" for key "%s" is %u bytes)') % (value, key, lv)
453 ' (value "%s" for key "%s" is %u bytes)') % (value, key, lv)
426 raise error.ProgrammingError(msg)
454 raise error.ProgrammingError(msg)
427 data.append(lk)
455 data.append(lk)
428 data.append(lv)
456 data.append(lv)
429 totalsize += lk + lv
457 totalsize += lk + lv
430 data[0] = totalsize
458 data[0] = totalsize
431 data = [_pack(format, *data)]
459 data = [_pack(format, *data)]
432 for key, value in metadata:
460 for key, value in metadata:
433 data.append(key)
461 data.append(key)
434 data.append(value)
462 data.append(value)
435 return ''.join(data)
463 return ''.join(data)
436
464
437 def _fm1readmarkers(data, off, stop):
465 def _fm1readmarkers(data, off, stop):
438 native = getattr(parsers, 'fm1readmarkers', None)
466 native = getattr(parsers, 'fm1readmarkers', None)
439 if not native:
467 if not native:
440 return _fm1purereadmarkers(data, off, stop)
468 return _fm1purereadmarkers(data, off, stop)
441 return native(data, off, stop)
469 return native(data, off, stop)
442
470
443 # mapping to read/write various marker formats
471 # mapping to read/write various marker formats
444 # <version> -> (decoder, encoder)
472 # <version> -> (decoder, encoder)
445 formats = {_fm0version: (_fm0readmarkers, _fm0encodeonemarker),
473 formats = {_fm0version: (_fm0readmarkers, _fm0encodeonemarker),
446 _fm1version: (_fm1readmarkers, _fm1encodeonemarker)}
474 _fm1version: (_fm1readmarkers, _fm1encodeonemarker)}
447
475
448 def _readmarkerversion(data):
476 def _readmarkerversion(data):
449 return _unpack('>B', data[0:1])[0]
477 return _unpack('>B', data[0:1])[0]
450
478
451 @util.nogc
479 @util.nogc
452 def _readmarkers(data, off=None, stop=None):
480 def _readmarkers(data, off=None, stop=None):
453 """Read and enumerate markers from raw data"""
481 """Read and enumerate markers from raw data"""
454 diskversion = _readmarkerversion(data)
482 diskversion = _readmarkerversion(data)
455 if not off:
483 if not off:
456 off = 1 # skip 1 byte version number
484 off = 1 # skip 1 byte version number
457 if stop is None:
485 if stop is None:
458 stop = len(data)
486 stop = len(data)
459 if diskversion not in formats:
487 if diskversion not in formats:
460 msg = _('parsing obsolete marker: unknown version %r') % diskversion
488 msg = _('parsing obsolete marker: unknown version %r') % diskversion
461 raise error.UnknownVersion(msg, version=diskversion)
489 raise error.UnknownVersion(msg, version=diskversion)
462 return diskversion, formats[diskversion][0](data, off, stop)
490 return diskversion, formats[diskversion][0](data, off, stop)
463
491
464 def encodeheader(version=_fm0version):
492 def encodeheader(version=_fm0version):
465 return _pack('>B', version)
493 return _pack('>B', version)
466
494
467 def encodemarkers(markers, addheader=False, version=_fm0version):
495 def encodemarkers(markers, addheader=False, version=_fm0version):
468 # Kept separate from flushmarkers(), it will be reused for
496 # Kept separate from flushmarkers(), it will be reused for
469 # markers exchange.
497 # markers exchange.
470 encodeone = formats[version][1]
498 encodeone = formats[version][1]
471 if addheader:
499 if addheader:
472 yield encodeheader(version)
500 yield encodeheader(version)
473 for marker in markers:
501 for marker in markers:
474 yield encodeone(marker)
502 yield encodeone(marker)
475
503
476 @util.nogc
504 @util.nogc
477 def _addsuccessors(successors, markers):
505 def _addsuccessors(successors, markers):
478 for mark in markers:
506 for mark in markers:
479 successors.setdefault(mark[0], set()).add(mark)
507 successors.setdefault(mark[0], set()).add(mark)
480
508
481 def _addprecursors(*args, **kwargs):
509 def _addprecursors(*args, **kwargs):
482 msg = ("'obsolete._addprecursors' is deprecated, "
510 msg = ("'obsolete._addprecursors' is deprecated, "
483 "use 'obsolete._addpredecessors'")
511 "use 'obsolete._addpredecessors'")
484 util.nouideprecwarn(msg, '4.4')
512 util.nouideprecwarn(msg, '4.4')
485
513
486 return _addpredecessors(*args, **kwargs)
514 return _addpredecessors(*args, **kwargs)
487
515
488 @util.nogc
516 @util.nogc
489 def _addpredecessors(predecessors, markers):
517 def _addpredecessors(predecessors, markers):
490 for mark in markers:
518 for mark in markers:
491 for suc in mark[1]:
519 for suc in mark[1]:
492 predecessors.setdefault(suc, set()).add(mark)
520 predecessors.setdefault(suc, set()).add(mark)
493
521
494 @util.nogc
522 @util.nogc
495 def _addchildren(children, markers):
523 def _addchildren(children, markers):
496 for mark in markers:
524 for mark in markers:
497 parents = mark[5]
525 parents = mark[5]
498 if parents is not None:
526 if parents is not None:
499 for p in parents:
527 for p in parents:
500 children.setdefault(p, set()).add(mark)
528 children.setdefault(p, set()).add(mark)
501
529
502 def _checkinvalidmarkers(markers):
530 def _checkinvalidmarkers(markers):
503 """search for marker with invalid data and raise error if needed
531 """search for marker with invalid data and raise error if needed
504
532
505 Exist as a separated function to allow the evolve extension for a more
533 Exist as a separated function to allow the evolve extension for a more
506 subtle handling.
534 subtle handling.
507 """
535 """
508 for mark in markers:
536 for mark in markers:
509 if node.nullid in mark[1]:
537 if node.nullid in mark[1]:
510 raise error.Abort(_('bad obsolescence marker detected: '
538 raise error.Abort(_('bad obsolescence marker detected: '
511 'invalid successors nullid'))
539 'invalid successors nullid'))
512
540
513 class obsstore(object):
541 class obsstore(object):
514 """Store obsolete markers
542 """Store obsolete markers
515
543
516 Markers can be accessed with two mappings:
544 Markers can be accessed with two mappings:
517 - predecessors[x] -> set(markers on predecessors edges of x)
545 - predecessors[x] -> set(markers on predecessors edges of x)
518 - successors[x] -> set(markers on successors edges of x)
546 - successors[x] -> set(markers on successors edges of x)
519 - children[x] -> set(markers on predecessors edges of children(x)
547 - children[x] -> set(markers on predecessors edges of children(x)
520 """
548 """
521
549
522 fields = ('prec', 'succs', 'flag', 'meta', 'date', 'parents')
550 fields = ('prec', 'succs', 'flag', 'meta', 'date', 'parents')
523 # prec: nodeid, predecessors changesets
551 # prec: nodeid, predecessors changesets
524 # succs: tuple of nodeid, successor changesets (0-N length)
552 # succs: tuple of nodeid, successor changesets (0-N length)
525 # flag: integer, flag field carrying modifier for the markers (see doc)
553 # flag: integer, flag field carrying modifier for the markers (see doc)
526 # meta: binary blob, encoded metadata dictionary
554 # meta: binary blob, encoded metadata dictionary
527 # date: (float, int) tuple, date of marker creation
555 # date: (float, int) tuple, date of marker creation
528 # parents: (tuple of nodeid) or None, parents of predecessors
556 # parents: (tuple of nodeid) or None, parents of predecessors
529 # None is used when no data has been recorded
557 # None is used when no data has been recorded
530
558
531 def __init__(self, svfs, defaultformat=_fm1version, readonly=False):
559 def __init__(self, svfs, defaultformat=_fm1version, readonly=False):
532 # caches for various obsolescence related cache
560 # caches for various obsolescence related cache
533 self.caches = {}
561 self.caches = {}
534 self.svfs = svfs
562 self.svfs = svfs
535 self._defaultformat = defaultformat
563 self._defaultformat = defaultformat
536 self._readonly = readonly
564 self._readonly = readonly
537
565
538 def __iter__(self):
566 def __iter__(self):
539 return iter(self._all)
567 return iter(self._all)
540
568
541 def __len__(self):
569 def __len__(self):
542 return len(self._all)
570 return len(self._all)
543
571
544 def __nonzero__(self):
572 def __nonzero__(self):
545 if not self._cached('_all'):
573 if not self._cached('_all'):
546 try:
574 try:
547 return self.svfs.stat('obsstore').st_size > 1
575 return self.svfs.stat('obsstore').st_size > 1
548 except OSError as inst:
576 except OSError as inst:
549 if inst.errno != errno.ENOENT:
577 if inst.errno != errno.ENOENT:
550 raise
578 raise
551 # just build an empty _all list if no obsstore exists, which
579 # just build an empty _all list if no obsstore exists, which
552 # avoids further stat() syscalls
580 # avoids further stat() syscalls
553 return bool(self._all)
581 return bool(self._all)
554
582
555 __bool__ = __nonzero__
583 __bool__ = __nonzero__
556
584
557 @property
585 @property
558 def readonly(self):
586 def readonly(self):
559 """True if marker creation is disabled
587 """True if marker creation is disabled
560
588
561 Remove me in the future when obsolete marker is always on."""
589 Remove me in the future when obsolete marker is always on."""
562 return self._readonly
590 return self._readonly
563
591
564 def create(self, transaction, prec, succs=(), flag=0, parents=None,
592 def create(self, transaction, prec, succs=(), flag=0, parents=None,
565 date=None, metadata=None, ui=None):
593 date=None, metadata=None, ui=None):
566 """obsolete: add a new obsolete marker
594 """obsolete: add a new obsolete marker
567
595
568 * ensuring it is hashable
596 * ensuring it is hashable
569 * check mandatory metadata
597 * check mandatory metadata
570 * encode metadata
598 * encode metadata
571
599
572 If you are a human writing code creating marker you want to use the
600 If you are a human writing code creating marker you want to use the
573 `createmarkers` function in this module instead.
601 `createmarkers` function in this module instead.
574
602
575 return True if a new marker have been added, False if the markers
603 return True if a new marker have been added, False if the markers
576 already existed (no op).
604 already existed (no op).
577 """
605 """
578 if metadata is None:
606 if metadata is None:
579 metadata = {}
607 metadata = {}
580 if date is None:
608 if date is None:
581 if 'date' in metadata:
609 if 'date' in metadata:
582 # as a courtesy for out-of-tree extensions
610 # as a courtesy for out-of-tree extensions
583 date = util.parsedate(metadata.pop('date'))
611 date = util.parsedate(metadata.pop('date'))
584 elif ui is not None:
612 elif ui is not None:
585 date = ui.configdate('devel', 'default-date')
613 date = ui.configdate('devel', 'default-date')
586 if date is None:
614 if date is None:
587 date = util.makedate()
615 date = util.makedate()
588 else:
616 else:
589 date = util.makedate()
617 date = util.makedate()
590 if len(prec) != 20:
618 if len(prec) != 20:
591 raise ValueError(prec)
619 raise ValueError(prec)
592 for succ in succs:
620 for succ in succs:
593 if len(succ) != 20:
621 if len(succ) != 20:
594 raise ValueError(succ)
622 raise ValueError(succ)
595 if prec in succs:
623 if prec in succs:
596 raise ValueError(_('in-marker cycle with %s') % node.hex(prec))
624 raise ValueError(_('in-marker cycle with %s') % node.hex(prec))
597
625
598 metadata = tuple(sorted(metadata.iteritems()))
626 metadata = tuple(sorted(metadata.iteritems()))
599
627
600 marker = (bytes(prec), tuple(succs), int(flag), metadata, date, parents)
628 marker = (bytes(prec), tuple(succs), int(flag), metadata, date, parents)
601 return bool(self.add(transaction, [marker]))
629 return bool(self.add(transaction, [marker]))
602
630
603 def add(self, transaction, markers):
631 def add(self, transaction, markers):
604 """Add new markers to the store
632 """Add new markers to the store
605
633
606 Take care of filtering duplicate.
634 Take care of filtering duplicate.
607 Return the number of new marker."""
635 Return the number of new marker."""
608 if self._readonly:
636 if self._readonly:
609 raise error.Abort(_('creating obsolete markers is not enabled on '
637 raise error.Abort(_('creating obsolete markers is not enabled on '
610 'this repo'))
638 'this repo'))
611 known = set()
639 known = set()
612 getsuccessors = self.successors.get
640 getsuccessors = self.successors.get
613 new = []
641 new = []
614 for m in markers:
642 for m in markers:
615 if m not in getsuccessors(m[0], ()) and m not in known:
643 if m not in getsuccessors(m[0], ()) and m not in known:
616 known.add(m)
644 known.add(m)
617 new.append(m)
645 new.append(m)
618 if new:
646 if new:
619 f = self.svfs('obsstore', 'ab')
647 f = self.svfs('obsstore', 'ab')
620 try:
648 try:
621 offset = f.tell()
649 offset = f.tell()
622 transaction.add('obsstore', offset)
650 transaction.add('obsstore', offset)
623 # offset == 0: new file - add the version header
651 # offset == 0: new file - add the version header
624 data = b''.join(encodemarkers(new, offset == 0, self._version))
652 data = b''.join(encodemarkers(new, offset == 0, self._version))
625 f.write(data)
653 f.write(data)
626 finally:
654 finally:
627 # XXX: f.close() == filecache invalidation == obsstore rebuilt.
655 # XXX: f.close() == filecache invalidation == obsstore rebuilt.
628 # call 'filecacheentry.refresh()' here
656 # call 'filecacheentry.refresh()' here
629 f.close()
657 f.close()
630 addedmarkers = transaction.changes.get('obsmarkers')
658 addedmarkers = transaction.changes.get('obsmarkers')
631 if addedmarkers is not None:
659 if addedmarkers is not None:
632 addedmarkers.update(new)
660 addedmarkers.update(new)
633 self._addmarkers(new, data)
661 self._addmarkers(new, data)
634 # new marker *may* have changed several set. invalidate the cache.
662 # new marker *may* have changed several set. invalidate the cache.
635 self.caches.clear()
663 self.caches.clear()
636 # records the number of new markers for the transaction hooks
664 # records the number of new markers for the transaction hooks
637 previous = int(transaction.hookargs.get('new_obsmarkers', '0'))
665 previous = int(transaction.hookargs.get('new_obsmarkers', '0'))
638 transaction.hookargs['new_obsmarkers'] = str(previous + len(new))
666 transaction.hookargs['new_obsmarkers'] = str(previous + len(new))
639 return len(new)
667 return len(new)
640
668
641 def mergemarkers(self, transaction, data):
669 def mergemarkers(self, transaction, data):
642 """merge a binary stream of markers inside the obsstore
670 """merge a binary stream of markers inside the obsstore
643
671
644 Returns the number of new markers added."""
672 Returns the number of new markers added."""
645 version, markers = _readmarkers(data)
673 version, markers = _readmarkers(data)
646 return self.add(transaction, markers)
674 return self.add(transaction, markers)
647
675
648 @propertycache
676 @propertycache
649 def _data(self):
677 def _data(self):
650 return self.svfs.tryread('obsstore')
678 return self.svfs.tryread('obsstore')
651
679
652 @propertycache
680 @propertycache
653 def _version(self):
681 def _version(self):
654 if len(self._data) >= 1:
682 if len(self._data) >= 1:
655 return _readmarkerversion(self._data)
683 return _readmarkerversion(self._data)
656 else:
684 else:
657 return self._defaultformat
685 return self._defaultformat
658
686
659 @propertycache
687 @propertycache
660 def _all(self):
688 def _all(self):
661 data = self._data
689 data = self._data
662 if not data:
690 if not data:
663 return []
691 return []
664 self._version, markers = _readmarkers(data)
692 self._version, markers = _readmarkers(data)
665 markers = list(markers)
693 markers = list(markers)
666 _checkinvalidmarkers(markers)
694 _checkinvalidmarkers(markers)
667 return markers
695 return markers
668
696
669 @propertycache
697 @propertycache
670 def successors(self):
698 def successors(self):
671 successors = {}
699 successors = {}
672 _addsuccessors(successors, self._all)
700 _addsuccessors(successors, self._all)
673 return successors
701 return successors
674
702
675 @property
703 @property
676 def precursors(self):
704 def precursors(self):
677 msg = ("'obsstore.precursors' is deprecated, "
705 msg = ("'obsstore.precursors' is deprecated, "
678 "use 'obsstore.predecessors'")
706 "use 'obsstore.predecessors'")
679 util.nouideprecwarn(msg, '4.4')
707 util.nouideprecwarn(msg, '4.4')
680
708
681 return self.predecessors
709 return self.predecessors
682
710
683 @propertycache
711 @propertycache
684 def predecessors(self):
712 def predecessors(self):
685 predecessors = {}
713 predecessors = {}
686 _addpredecessors(predecessors, self._all)
714 _addpredecessors(predecessors, self._all)
687 return predecessors
715 return predecessors
688
716
689 @propertycache
717 @propertycache
690 def children(self):
718 def children(self):
691 children = {}
719 children = {}
692 _addchildren(children, self._all)
720 _addchildren(children, self._all)
693 return children
721 return children
694
722
695 def _cached(self, attr):
723 def _cached(self, attr):
696 return attr in self.__dict__
724 return attr in self.__dict__
697
725
698 def _addmarkers(self, markers, rawdata):
726 def _addmarkers(self, markers, rawdata):
699 markers = list(markers) # to allow repeated iteration
727 markers = list(markers) # to allow repeated iteration
700 self._data = self._data + rawdata
728 self._data = self._data + rawdata
701 self._all.extend(markers)
729 self._all.extend(markers)
702 if self._cached('successors'):
730 if self._cached('successors'):
703 _addsuccessors(self.successors, markers)
731 _addsuccessors(self.successors, markers)
704 if self._cached('predecessors'):
732 if self._cached('predecessors'):
705 _addpredecessors(self.predecessors, markers)
733 _addpredecessors(self.predecessors, markers)
706 if self._cached('children'):
734 if self._cached('children'):
707 _addchildren(self.children, markers)
735 _addchildren(self.children, markers)
708 _checkinvalidmarkers(markers)
736 _checkinvalidmarkers(markers)
709
737
710 def relevantmarkers(self, nodes):
738 def relevantmarkers(self, nodes):
711 """return a set of all obsolescence markers relevant to a set of nodes.
739 """return a set of all obsolescence markers relevant to a set of nodes.
712
740
713 "relevant" to a set of nodes mean:
741 "relevant" to a set of nodes mean:
714
742
715 - marker that use this changeset as successor
743 - marker that use this changeset as successor
716 - prune marker of direct children on this changeset
744 - prune marker of direct children on this changeset
717 - recursive application of the two rules on predecessors of these
745 - recursive application of the two rules on predecessors of these
718 markers
746 markers
719
747
720 It is a set so you cannot rely on order."""
748 It is a set so you cannot rely on order."""
721
749
722 pendingnodes = set(nodes)
750 pendingnodes = set(nodes)
723 seenmarkers = set()
751 seenmarkers = set()
724 seennodes = set(pendingnodes)
752 seennodes = set(pendingnodes)
725 precursorsmarkers = self.predecessors
753 precursorsmarkers = self.predecessors
726 succsmarkers = self.successors
754 succsmarkers = self.successors
727 children = self.children
755 children = self.children
728 while pendingnodes:
756 while pendingnodes:
729 direct = set()
757 direct = set()
730 for current in pendingnodes:
758 for current in pendingnodes:
731 direct.update(precursorsmarkers.get(current, ()))
759 direct.update(precursorsmarkers.get(current, ()))
732 pruned = [m for m in children.get(current, ()) if not m[1]]
760 pruned = [m for m in children.get(current, ()) if not m[1]]
733 direct.update(pruned)
761 direct.update(pruned)
734 pruned = [m for m in succsmarkers.get(current, ()) if not m[1]]
762 pruned = [m for m in succsmarkers.get(current, ()) if not m[1]]
735 direct.update(pruned)
763 direct.update(pruned)
736 direct -= seenmarkers
764 direct -= seenmarkers
737 pendingnodes = set([m[0] for m in direct])
765 pendingnodes = set([m[0] for m in direct])
738 seenmarkers |= direct
766 seenmarkers |= direct
739 pendingnodes -= seennodes
767 pendingnodes -= seennodes
740 seennodes |= pendingnodes
768 seennodes |= pendingnodes
741 return seenmarkers
769 return seenmarkers
742
770
743 def makestore(ui, repo):
771 def makestore(ui, repo):
744 """Create an obsstore instance from a repo."""
772 """Create an obsstore instance from a repo."""
745 # read default format for new obsstore.
773 # read default format for new obsstore.
746 # developer config: format.obsstore-version
774 # developer config: format.obsstore-version
747 defaultformat = ui.configint('format', 'obsstore-version')
775 defaultformat = ui.configint('format', 'obsstore-version')
748 # rely on obsstore class default when possible.
776 # rely on obsstore class default when possible.
749 kwargs = {}
777 kwargs = {}
750 if defaultformat is not None:
778 if defaultformat is not None:
751 kwargs['defaultformat'] = defaultformat
779 kwargs['defaultformat'] = defaultformat
752 readonly = not isenabled(repo, createmarkersopt)
780 readonly = not isenabled(repo, createmarkersopt)
753 store = obsstore(repo.svfs, readonly=readonly, **kwargs)
781 store = obsstore(repo.svfs, readonly=readonly, **kwargs)
754 if store and readonly:
782 if store and readonly:
755 ui.warn(_('obsolete feature not enabled but %i markers found!\n')
783 ui.warn(_('obsolete feature not enabled but %i markers found!\n')
756 % len(list(store)))
784 % len(list(store)))
757 return store
785 return store
758
786
759 def commonversion(versions):
787 def commonversion(versions):
760 """Return the newest version listed in both versions and our local formats.
788 """Return the newest version listed in both versions and our local formats.
761
789
762 Returns None if no common version exists.
790 Returns None if no common version exists.
763 """
791 """
764 versions.sort(reverse=True)
792 versions.sort(reverse=True)
765 # search for highest version known on both side
793 # search for highest version known on both side
766 for v in versions:
794 for v in versions:
767 if v in formats:
795 if v in formats:
768 return v
796 return v
769 return None
797 return None
770
798
771 # arbitrary picked to fit into 8K limit from HTTP server
799 # arbitrary picked to fit into 8K limit from HTTP server
772 # you have to take in account:
800 # you have to take in account:
773 # - the version header
801 # - the version header
774 # - the base85 encoding
802 # - the base85 encoding
775 _maxpayload = 5300
803 _maxpayload = 5300
776
804
777 def _pushkeyescape(markers):
805 def _pushkeyescape(markers):
778 """encode markers into a dict suitable for pushkey exchange
806 """encode markers into a dict suitable for pushkey exchange
779
807
780 - binary data is base85 encoded
808 - binary data is base85 encoded
781 - split in chunks smaller than 5300 bytes"""
809 - split in chunks smaller than 5300 bytes"""
782 keys = {}
810 keys = {}
783 parts = []
811 parts = []
784 currentlen = _maxpayload * 2 # ensure we create a new part
812 currentlen = _maxpayload * 2 # ensure we create a new part
785 for marker in markers:
813 for marker in markers:
786 nextdata = _fm0encodeonemarker(marker)
814 nextdata = _fm0encodeonemarker(marker)
787 if (len(nextdata) + currentlen > _maxpayload):
815 if (len(nextdata) + currentlen > _maxpayload):
788 currentpart = []
816 currentpart = []
789 currentlen = 0
817 currentlen = 0
790 parts.append(currentpart)
818 parts.append(currentpart)
791 currentpart.append(nextdata)
819 currentpart.append(nextdata)
792 currentlen += len(nextdata)
820 currentlen += len(nextdata)
793 for idx, part in enumerate(reversed(parts)):
821 for idx, part in enumerate(reversed(parts)):
794 data = ''.join([_pack('>B', _fm0version)] + part)
822 data = ''.join([_pack('>B', _fm0version)] + part)
795 keys['dump%i' % idx] = util.b85encode(data)
823 keys['dump%i' % idx] = util.b85encode(data)
796 return keys
824 return keys
797
825
798 def listmarkers(repo):
826 def listmarkers(repo):
799 """List markers over pushkey"""
827 """List markers over pushkey"""
800 if not repo.obsstore:
828 if not repo.obsstore:
801 return {}
829 return {}
802 return _pushkeyescape(sorted(repo.obsstore))
830 return _pushkeyescape(sorted(repo.obsstore))
803
831
804 def pushmarker(repo, key, old, new):
832 def pushmarker(repo, key, old, new):
805 """Push markers over pushkey"""
833 """Push markers over pushkey"""
806 if not key.startswith('dump'):
834 if not key.startswith('dump'):
807 repo.ui.warn(_('unknown key: %r') % key)
835 repo.ui.warn(_('unknown key: %r') % key)
808 return False
836 return False
809 if old:
837 if old:
810 repo.ui.warn(_('unexpected old value for %r') % key)
838 repo.ui.warn(_('unexpected old value for %r') % key)
811 return False
839 return False
812 data = util.b85decode(new)
840 data = util.b85decode(new)
813 lock = repo.lock()
841 lock = repo.lock()
814 try:
842 try:
815 tr = repo.transaction('pushkey: obsolete markers')
843 tr = repo.transaction('pushkey: obsolete markers')
816 try:
844 try:
817 repo.obsstore.mergemarkers(tr, data)
845 repo.obsstore.mergemarkers(tr, data)
818 repo.invalidatevolatilesets()
846 repo.invalidatevolatilesets()
819 tr.close()
847 tr.close()
820 return True
848 return True
821 finally:
849 finally:
822 tr.release()
850 tr.release()
823 finally:
851 finally:
824 lock.release()
852 lock.release()
825
853
826 # keep compatibility for the 4.3 cycle
854 # keep compatibility for the 4.3 cycle
827 def allprecursors(obsstore, nodes, ignoreflags=0):
855 def allprecursors(obsstore, nodes, ignoreflags=0):
828 movemsg = 'obsolete.allprecursors moved to obsutil.allprecursors'
856 movemsg = 'obsolete.allprecursors moved to obsutil.allprecursors'
829 util.nouideprecwarn(movemsg, '4.3')
857 util.nouideprecwarn(movemsg, '4.3')
830 return obsutil.allprecursors(obsstore, nodes, ignoreflags)
858 return obsutil.allprecursors(obsstore, nodes, ignoreflags)
831
859
832 def allsuccessors(obsstore, nodes, ignoreflags=0):
860 def allsuccessors(obsstore, nodes, ignoreflags=0):
833 movemsg = 'obsolete.allsuccessors moved to obsutil.allsuccessors'
861 movemsg = 'obsolete.allsuccessors moved to obsutil.allsuccessors'
834 util.nouideprecwarn(movemsg, '4.3')
862 util.nouideprecwarn(movemsg, '4.3')
835 return obsutil.allsuccessors(obsstore, nodes, ignoreflags)
863 return obsutil.allsuccessors(obsstore, nodes, ignoreflags)
836
864
837 def marker(repo, data):
865 def marker(repo, data):
838 movemsg = 'obsolete.marker moved to obsutil.marker'
866 movemsg = 'obsolete.marker moved to obsutil.marker'
839 repo.ui.deprecwarn(movemsg, '4.3')
867 repo.ui.deprecwarn(movemsg, '4.3')
840 return obsutil.marker(repo, data)
868 return obsutil.marker(repo, data)
841
869
842 def getmarkers(repo, nodes=None, exclusive=False):
870 def getmarkers(repo, nodes=None, exclusive=False):
843 movemsg = 'obsolete.getmarkers moved to obsutil.getmarkers'
871 movemsg = 'obsolete.getmarkers moved to obsutil.getmarkers'
844 repo.ui.deprecwarn(movemsg, '4.3')
872 repo.ui.deprecwarn(movemsg, '4.3')
845 return obsutil.getmarkers(repo, nodes=nodes, exclusive=exclusive)
873 return obsutil.getmarkers(repo, nodes=nodes, exclusive=exclusive)
846
874
847 def exclusivemarkers(repo, nodes):
875 def exclusivemarkers(repo, nodes):
848 movemsg = 'obsolete.exclusivemarkers moved to obsutil.exclusivemarkers'
876 movemsg = 'obsolete.exclusivemarkers moved to obsutil.exclusivemarkers'
849 repo.ui.deprecwarn(movemsg, '4.3')
877 repo.ui.deprecwarn(movemsg, '4.3')
850 return obsutil.exclusivemarkers(repo, nodes)
878 return obsutil.exclusivemarkers(repo, nodes)
851
879
852 def foreground(repo, nodes):
880 def foreground(repo, nodes):
853 movemsg = 'obsolete.foreground moved to obsutil.foreground'
881 movemsg = 'obsolete.foreground moved to obsutil.foreground'
854 repo.ui.deprecwarn(movemsg, '4.3')
882 repo.ui.deprecwarn(movemsg, '4.3')
855 return obsutil.foreground(repo, nodes)
883 return obsutil.foreground(repo, nodes)
856
884
857 def successorssets(repo, initialnode, cache=None):
885 def successorssets(repo, initialnode, cache=None):
858 movemsg = 'obsolete.successorssets moved to obsutil.successorssets'
886 movemsg = 'obsolete.successorssets moved to obsutil.successorssets'
859 repo.ui.deprecwarn(movemsg, '4.3')
887 repo.ui.deprecwarn(movemsg, '4.3')
860 return obsutil.successorssets(repo, initialnode, cache=cache)
888 return obsutil.successorssets(repo, initialnode, cache=cache)
861
889
862 # mapping of 'set-name' -> <function to compute this set>
890 # mapping of 'set-name' -> <function to compute this set>
863 cachefuncs = {}
891 cachefuncs = {}
864 def cachefor(name):
892 def cachefor(name):
865 """Decorator to register a function as computing the cache for a set"""
893 """Decorator to register a function as computing the cache for a set"""
866 def decorator(func):
894 def decorator(func):
867 if name in cachefuncs:
895 if name in cachefuncs:
868 msg = "duplicated registration for volatileset '%s' (existing: %r)"
896 msg = "duplicated registration for volatileset '%s' (existing: %r)"
869 raise error.ProgrammingError(msg % (name, cachefuncs[name]))
897 raise error.ProgrammingError(msg % (name, cachefuncs[name]))
870 cachefuncs[name] = func
898 cachefuncs[name] = func
871 return func
899 return func
872 return decorator
900 return decorator
873
901
874 def getrevs(repo, name):
902 def getrevs(repo, name):
875 """Return the set of revision that belong to the <name> set
903 """Return the set of revision that belong to the <name> set
876
904
877 Such access may compute the set and cache it for future use"""
905 Such access may compute the set and cache it for future use"""
878 repo = repo.unfiltered()
906 repo = repo.unfiltered()
879 if not repo.obsstore:
907 if not repo.obsstore:
880 return frozenset()
908 return frozenset()
881 if name not in repo.obsstore.caches:
909 if name not in repo.obsstore.caches:
882 repo.obsstore.caches[name] = cachefuncs[name](repo)
910 repo.obsstore.caches[name] = cachefuncs[name](repo)
883 return repo.obsstore.caches[name]
911 return repo.obsstore.caches[name]
884
912
885 # To be simple we need to invalidate obsolescence cache when:
913 # To be simple we need to invalidate obsolescence cache when:
886 #
914 #
887 # - new changeset is added:
915 # - new changeset is added:
888 # - public phase is changed
916 # - public phase is changed
889 # - obsolescence marker are added
917 # - obsolescence marker are added
890 # - strip is used a repo
918 # - strip is used a repo
891 def clearobscaches(repo):
919 def clearobscaches(repo):
892 """Remove all obsolescence related cache from a repo
920 """Remove all obsolescence related cache from a repo
893
921
894 This remove all cache in obsstore is the obsstore already exist on the
922 This remove all cache in obsstore is the obsstore already exist on the
895 repo.
923 repo.
896
924
897 (We could be smarter here given the exact event that trigger the cache
925 (We could be smarter here given the exact event that trigger the cache
898 clearing)"""
926 clearing)"""
899 # only clear cache is there is obsstore data in this repo
927 # only clear cache is there is obsstore data in this repo
900 if 'obsstore' in repo._filecache:
928 if 'obsstore' in repo._filecache:
901 repo.obsstore.caches.clear()
929 repo.obsstore.caches.clear()
902
930
903 def _mutablerevs(repo):
931 def _mutablerevs(repo):
904 """the set of mutable revision in the repository"""
932 """the set of mutable revision in the repository"""
905 return repo._phasecache.getrevset(repo, (phases.draft, phases.secret))
933 return repo._phasecache.getrevset(repo, (phases.draft, phases.secret))
906
934
907 @cachefor('obsolete')
935 @cachefor('obsolete')
908 def _computeobsoleteset(repo):
936 def _computeobsoleteset(repo):
909 """the set of obsolete revisions"""
937 """the set of obsolete revisions"""
910 getnode = repo.changelog.node
938 getnode = repo.changelog.node
911 notpublic = _mutablerevs(repo)
939 notpublic = _mutablerevs(repo)
912 isobs = repo.obsstore.successors.__contains__
940 isobs = repo.obsstore.successors.__contains__
913 obs = set(r for r in notpublic if isobs(getnode(r)))
941 obs = set(r for r in notpublic if isobs(getnode(r)))
914 return obs
942 return obs
915
943
916 @cachefor('unstable')
944 @cachefor('unstable')
917 def _computeunstableset(repo):
945 def _computeunstableset(repo):
918 msg = ("'unstable' volatile set is deprecated, "
946 msg = ("'unstable' volatile set is deprecated, "
919 "use 'orphan'")
947 "use 'orphan'")
920 repo.ui.deprecwarn(msg, '4.4')
948 repo.ui.deprecwarn(msg, '4.4')
921
949
922 return _computeorphanset(repo)
950 return _computeorphanset(repo)
923
951
924 @cachefor('orphan')
952 @cachefor('orphan')
925 def _computeorphanset(repo):
953 def _computeorphanset(repo):
926 """the set of non obsolete revisions with obsolete parents"""
954 """the set of non obsolete revisions with obsolete parents"""
927 pfunc = repo.changelog.parentrevs
955 pfunc = repo.changelog.parentrevs
928 mutable = _mutablerevs(repo)
956 mutable = _mutablerevs(repo)
929 obsolete = getrevs(repo, 'obsolete')
957 obsolete = getrevs(repo, 'obsolete')
930 others = mutable - obsolete
958 others = mutable - obsolete
931 unstable = set()
959 unstable = set()
932 for r in sorted(others):
960 for r in sorted(others):
933 # A rev is unstable if one of its parent is obsolete or unstable
961 # A rev is unstable if one of its parent is obsolete or unstable
934 # this works since we traverse following growing rev order
962 # this works since we traverse following growing rev order
935 for p in pfunc(r):
963 for p in pfunc(r):
936 if p in obsolete or p in unstable:
964 if p in obsolete or p in unstable:
937 unstable.add(r)
965 unstable.add(r)
938 break
966 break
939 return unstable
967 return unstable
940
968
941 @cachefor('suspended')
969 @cachefor('suspended')
942 def _computesuspendedset(repo):
970 def _computesuspendedset(repo):
943 """the set of obsolete parents with non obsolete descendants"""
971 """the set of obsolete parents with non obsolete descendants"""
944 suspended = repo.changelog.ancestors(getrevs(repo, 'orphan'))
972 suspended = repo.changelog.ancestors(getrevs(repo, 'orphan'))
945 return set(r for r in getrevs(repo, 'obsolete') if r in suspended)
973 return set(r for r in getrevs(repo, 'obsolete') if r in suspended)
946
974
947 @cachefor('extinct')
975 @cachefor('extinct')
948 def _computeextinctset(repo):
976 def _computeextinctset(repo):
949 """the set of obsolete parents without non obsolete descendants"""
977 """the set of obsolete parents without non obsolete descendants"""
950 return getrevs(repo, 'obsolete') - getrevs(repo, 'suspended')
978 return getrevs(repo, 'obsolete') - getrevs(repo, 'suspended')
951
979
952 @cachefor('bumped')
980 @cachefor('bumped')
953 def _computebumpedset(repo):
981 def _computebumpedset(repo):
954 msg = ("'bumped' volatile set is deprecated, "
982 msg = ("'bumped' volatile set is deprecated, "
955 "use 'phasedivergent'")
983 "use 'phasedivergent'")
956 repo.ui.deprecwarn(msg, '4.4')
984 repo.ui.deprecwarn(msg, '4.4')
957
985
958 return _computephasedivergentset(repo)
986 return _computephasedivergentset(repo)
959
987
960 @cachefor('phasedivergent')
988 @cachefor('phasedivergent')
961 def _computephasedivergentset(repo):
989 def _computephasedivergentset(repo):
962 """the set of revs trying to obsolete public revisions"""
990 """the set of revs trying to obsolete public revisions"""
963 bumped = set()
991 bumped = set()
964 # util function (avoid attribute lookup in the loop)
992 # util function (avoid attribute lookup in the loop)
965 phase = repo._phasecache.phase # would be faster to grab the full list
993 phase = repo._phasecache.phase # would be faster to grab the full list
966 public = phases.public
994 public = phases.public
967 cl = repo.changelog
995 cl = repo.changelog
968 torev = cl.nodemap.get
996 torev = cl.nodemap.get
969 for ctx in repo.set('(not public()) and (not obsolete())'):
997 for ctx in repo.set('(not public()) and (not obsolete())'):
970 rev = ctx.rev()
998 rev = ctx.rev()
971 # We only evaluate mutable, non-obsolete revision
999 # We only evaluate mutable, non-obsolete revision
972 node = ctx.node()
1000 node = ctx.node()
973 # (future) A cache of predecessors may worth if split is very common
1001 # (future) A cache of predecessors may worth if split is very common
974 for pnode in obsutil.allpredecessors(repo.obsstore, [node],
1002 for pnode in obsutil.allpredecessors(repo.obsstore, [node],
975 ignoreflags=bumpedfix):
1003 ignoreflags=bumpedfix):
976 prev = torev(pnode) # unfiltered! but so is phasecache
1004 prev = torev(pnode) # unfiltered! but so is phasecache
977 if (prev is not None) and (phase(repo, prev) <= public):
1005 if (prev is not None) and (phase(repo, prev) <= public):
978 # we have a public predecessor
1006 # we have a public predecessor
979 bumped.add(rev)
1007 bumped.add(rev)
980 break # Next draft!
1008 break # Next draft!
981 return bumped
1009 return bumped
982
1010
983 @cachefor('divergent')
1011 @cachefor('divergent')
984 def _computedivergentset(repo):
1012 def _computedivergentset(repo):
985 msg = ("'divergent' volatile set is deprecated, "
1013 msg = ("'divergent' volatile set is deprecated, "
986 "use 'contentdivergent'")
1014 "use 'contentdivergent'")
987 repo.ui.deprecwarn(msg, '4.4')
1015 repo.ui.deprecwarn(msg, '4.4')
988
1016
989 return _computecontentdivergentset(repo)
1017 return _computecontentdivergentset(repo)
990
1018
991 @cachefor('contentdivergent')
1019 @cachefor('contentdivergent')
992 def _computecontentdivergentset(repo):
1020 def _computecontentdivergentset(repo):
993 """the set of rev that compete to be the final successors of some revision.
1021 """the set of rev that compete to be the final successors of some revision.
994 """
1022 """
995 divergent = set()
1023 divergent = set()
996 obsstore = repo.obsstore
1024 obsstore = repo.obsstore
997 newermap = {}
1025 newermap = {}
998 for ctx in repo.set('(not public()) - obsolete()'):
1026 for ctx in repo.set('(not public()) - obsolete()'):
999 mark = obsstore.predecessors.get(ctx.node(), ())
1027 mark = obsstore.predecessors.get(ctx.node(), ())
1000 toprocess = set(mark)
1028 toprocess = set(mark)
1001 seen = set()
1029 seen = set()
1002 while toprocess:
1030 while toprocess:
1003 prec = toprocess.pop()[0]
1031 prec = toprocess.pop()[0]
1004 if prec in seen:
1032 if prec in seen:
1005 continue # emergency cycle hanging prevention
1033 continue # emergency cycle hanging prevention
1006 seen.add(prec)
1034 seen.add(prec)
1007 if prec not in newermap:
1035 if prec not in newermap:
1008 obsutil.successorssets(repo, prec, cache=newermap)
1036 obsutil.successorssets(repo, prec, cache=newermap)
1009 newer = [n for n in newermap[prec] if n]
1037 newer = [n for n in newermap[prec] if n]
1010 if len(newer) > 1:
1038 if len(newer) > 1:
1011 divergent.add(ctx.rev())
1039 divergent.add(ctx.rev())
1012 break
1040 break
1013 toprocess.update(obsstore.predecessors.get(prec, ()))
1041 toprocess.update(obsstore.predecessors.get(prec, ()))
1014 return divergent
1042 return divergent
1015
1043
1016
1044
1017 def createmarkers(repo, relations, flag=0, date=None, metadata=None,
1045 def createmarkers(repo, relations, flag=0, date=None, metadata=None,
1018 operation=None):
1046 operation=None):
1019 """Add obsolete markers between changesets in a repo
1047 """Add obsolete markers between changesets in a repo
1020
1048
1021 <relations> must be an iterable of (<old>, (<new>, ...)[,{metadata}])
1049 <relations> must be an iterable of (<old>, (<new>, ...)[,{metadata}])
1022 tuple. `old` and `news` are changectx. metadata is an optional dictionary
1050 tuple. `old` and `news` are changectx. metadata is an optional dictionary
1023 containing metadata for this marker only. It is merged with the global
1051 containing metadata for this marker only. It is merged with the global
1024 metadata specified through the `metadata` argument of this function,
1052 metadata specified through the `metadata` argument of this function,
1025
1053
1026 Trying to obsolete a public changeset will raise an exception.
1054 Trying to obsolete a public changeset will raise an exception.
1027
1055
1028 Current user and date are used except if specified otherwise in the
1056 Current user and date are used except if specified otherwise in the
1029 metadata attribute.
1057 metadata attribute.
1030
1058
1031 This function operates within a transaction of its own, but does
1059 This function operates within a transaction of its own, but does
1032 not take any lock on the repo.
1060 not take any lock on the repo.
1033 """
1061 """
1034 # prepare metadata
1062 # prepare metadata
1035 if metadata is None:
1063 if metadata is None:
1036 metadata = {}
1064 metadata = {}
1037 if 'user' not in metadata:
1065 if 'user' not in metadata:
1038 develuser = repo.ui.config('devel', 'user.obsmarker')
1066 develuser = repo.ui.config('devel', 'user.obsmarker')
1039 if develuser:
1067 if develuser:
1040 metadata['user'] = develuser
1068 metadata['user'] = develuser
1041 else:
1069 else:
1042 metadata['user'] = repo.ui.username()
1070 metadata['user'] = repo.ui.username()
1043
1071
1044 # Operation metadata handling
1072 # Operation metadata handling
1045 useoperation = repo.ui.configbool('experimental',
1073 useoperation = repo.ui.configbool('experimental',
1046 'evolution.track-operation')
1074 'evolution.track-operation')
1047 if useoperation and operation:
1075 if useoperation and operation:
1048 metadata['operation'] = operation
1076 metadata['operation'] = operation
1049
1077
1050 # Effect flag metadata handling
1078 # Effect flag metadata handling
1051 saveeffectflag = repo.ui.configbool('experimental',
1079 saveeffectflag = repo.ui.configbool('experimental',
1052 'effect-flags')
1080 'effect-flags')
1053
1081
1054 tr = repo.transaction('add-obsolescence-marker')
1082 tr = repo.transaction('add-obsolescence-marker')
1055 try:
1083 try:
1056 markerargs = []
1084 markerargs = []
1057 for rel in relations:
1085 for rel in relations:
1058 prec = rel[0]
1086 prec = rel[0]
1059 sucs = rel[1]
1087 sucs = rel[1]
1060 localmetadata = metadata.copy()
1088 localmetadata = metadata.copy()
1061 if 2 < len(rel):
1089 if 2 < len(rel):
1062 localmetadata.update(rel[2])
1090 localmetadata.update(rel[2])
1063
1091
1064 if not prec.mutable():
1092 if not prec.mutable():
1065 raise error.Abort(_("cannot obsolete public changeset: %s")
1093 raise error.Abort(_("cannot obsolete public changeset: %s")
1066 % prec,
1094 % prec,
1067 hint="see 'hg help phases' for details")
1095 hint="see 'hg help phases' for details")
1068 nprec = prec.node()
1096 nprec = prec.node()
1069 nsucs = tuple(s.node() for s in sucs)
1097 nsucs = tuple(s.node() for s in sucs)
1070 npare = None
1098 npare = None
1071 if not nsucs:
1099 if not nsucs:
1072 npare = tuple(p.node() for p in prec.parents())
1100 npare = tuple(p.node() for p in prec.parents())
1073 if nprec in nsucs:
1101 if nprec in nsucs:
1074 raise error.Abort(_("changeset %s cannot obsolete itself")
1102 raise error.Abort(_("changeset %s cannot obsolete itself")
1075 % prec)
1103 % prec)
1076
1104
1077 # Effect flag can be different by relation
1105 # Effect flag can be different by relation
1078 if saveeffectflag:
1106 if saveeffectflag:
1079 # The effect flag is saved in a versioned field name for future
1107 # The effect flag is saved in a versioned field name for future
1080 # evolution
1108 # evolution
1081 effectflag = obsutil.geteffectflag(rel)
1109 effectflag = obsutil.geteffectflag(rel)
1082 localmetadata[obsutil.EFFECTFLAGFIELD] = "%d" % effectflag
1110 localmetadata[obsutil.EFFECTFLAGFIELD] = "%d" % effectflag
1083
1111
1084 # Creating the marker causes the hidden cache to become invalid,
1112 # Creating the marker causes the hidden cache to become invalid,
1085 # which causes recomputation when we ask for prec.parents() above.
1113 # which causes recomputation when we ask for prec.parents() above.
1086 # Resulting in n^2 behavior. So let's prepare all of the args
1114 # Resulting in n^2 behavior. So let's prepare all of the args
1087 # first, then create the markers.
1115 # first, then create the markers.
1088 markerargs.append((nprec, nsucs, npare, localmetadata))
1116 markerargs.append((nprec, nsucs, npare, localmetadata))
1089
1117
1090 for args in markerargs:
1118 for args in markerargs:
1091 nprec, nsucs, npare, localmetadata = args
1119 nprec, nsucs, npare, localmetadata = args
1092 repo.obsstore.create(tr, nprec, nsucs, flag, parents=npare,
1120 repo.obsstore.create(tr, nprec, nsucs, flag, parents=npare,
1093 date=date, metadata=localmetadata,
1121 date=date, metadata=localmetadata,
1094 ui=repo.ui)
1122 ui=repo.ui)
1095 repo.filteredrevcache.clear()
1123 repo.filteredrevcache.clear()
1096 tr.close()
1124 tr.close()
1097 finally:
1125 finally:
1098 tr.release()
1126 tr.release()
General Comments 0
You need to be logged in to leave comments. Login now