##// END OF EJS Templates
config: simplify aliasing commands.update.check...
Boris Feld -
r34806:c4a0480d default
parent child Browse files
Show More
@@ -1,1020 +1,1018 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
185 alias=[('experimental', 'updatecheck')]
184 )
186 )
185 coreconfigitem('commands', 'update.requiredest',
187 coreconfigitem('commands', 'update.requiredest',
186 default=False,
188 default=False,
187 )
189 )
188 coreconfigitem('committemplate', '.*',
190 coreconfigitem('committemplate', '.*',
189 default=None,
191 default=None,
190 generic=True,
192 generic=True,
191 )
193 )
192 coreconfigitem('debug', 'dirstate.delaywrite',
194 coreconfigitem('debug', 'dirstate.delaywrite',
193 default=0,
195 default=0,
194 )
196 )
195 coreconfigitem('defaults', '.*',
197 coreconfigitem('defaults', '.*',
196 default=None,
198 default=None,
197 generic=True,
199 generic=True,
198 )
200 )
199 coreconfigitem('devel', 'all-warnings',
201 coreconfigitem('devel', 'all-warnings',
200 default=False,
202 default=False,
201 )
203 )
202 coreconfigitem('devel', 'bundle2.debug',
204 coreconfigitem('devel', 'bundle2.debug',
203 default=False,
205 default=False,
204 )
206 )
205 coreconfigitem('devel', 'cache-vfs',
207 coreconfigitem('devel', 'cache-vfs',
206 default=None,
208 default=None,
207 )
209 )
208 coreconfigitem('devel', 'check-locks',
210 coreconfigitem('devel', 'check-locks',
209 default=False,
211 default=False,
210 )
212 )
211 coreconfigitem('devel', 'check-relroot',
213 coreconfigitem('devel', 'check-relroot',
212 default=False,
214 default=False,
213 )
215 )
214 coreconfigitem('devel', 'default-date',
216 coreconfigitem('devel', 'default-date',
215 default=None,
217 default=None,
216 )
218 )
217 coreconfigitem('devel', 'deprec-warn',
219 coreconfigitem('devel', 'deprec-warn',
218 default=False,
220 default=False,
219 )
221 )
220 coreconfigitem('devel', 'disableloaddefaultcerts',
222 coreconfigitem('devel', 'disableloaddefaultcerts',
221 default=False,
223 default=False,
222 )
224 )
223 coreconfigitem('devel', 'warn-empty-changegroup',
225 coreconfigitem('devel', 'warn-empty-changegroup',
224 default=False,
226 default=False,
225 )
227 )
226 coreconfigitem('devel', 'legacy.exchange',
228 coreconfigitem('devel', 'legacy.exchange',
227 default=list,
229 default=list,
228 )
230 )
229 coreconfigitem('devel', 'servercafile',
231 coreconfigitem('devel', 'servercafile',
230 default='',
232 default='',
231 )
233 )
232 coreconfigitem('devel', 'serverexactprotocol',
234 coreconfigitem('devel', 'serverexactprotocol',
233 default='',
235 default='',
234 )
236 )
235 coreconfigitem('devel', 'serverrequirecert',
237 coreconfigitem('devel', 'serverrequirecert',
236 default=False,
238 default=False,
237 )
239 )
238 coreconfigitem('devel', 'strip-obsmarkers',
240 coreconfigitem('devel', 'strip-obsmarkers',
239 default=True,
241 default=True,
240 )
242 )
241 coreconfigitem('devel', 'warn-config',
243 coreconfigitem('devel', 'warn-config',
242 default=None,
244 default=None,
243 )
245 )
244 coreconfigitem('devel', 'warn-config-default',
246 coreconfigitem('devel', 'warn-config-default',
245 default=None,
247 default=None,
246 )
248 )
247 coreconfigitem('devel', 'user.obsmarker',
249 coreconfigitem('devel', 'user.obsmarker',
248 default=None,
250 default=None,
249 )
251 )
250 coreconfigitem('diff', 'nodates',
252 coreconfigitem('diff', 'nodates',
251 default=False,
253 default=False,
252 )
254 )
253 coreconfigitem('diff', 'showfunc',
255 coreconfigitem('diff', 'showfunc',
254 default=False,
256 default=False,
255 )
257 )
256 coreconfigitem('diff', 'unified',
258 coreconfigitem('diff', 'unified',
257 default=None,
259 default=None,
258 )
260 )
259 coreconfigitem('diff', 'git',
261 coreconfigitem('diff', 'git',
260 default=False,
262 default=False,
261 )
263 )
262 coreconfigitem('diff', 'ignorews',
264 coreconfigitem('diff', 'ignorews',
263 default=False,
265 default=False,
264 )
266 )
265 coreconfigitem('diff', 'ignorewsamount',
267 coreconfigitem('diff', 'ignorewsamount',
266 default=False,
268 default=False,
267 )
269 )
268 coreconfigitem('diff', 'ignoreblanklines',
270 coreconfigitem('diff', 'ignoreblanklines',
269 default=False,
271 default=False,
270 )
272 )
271 coreconfigitem('diff', 'ignorewseol',
273 coreconfigitem('diff', 'ignorewseol',
272 default=False,
274 default=False,
273 )
275 )
274 coreconfigitem('diff', 'nobinary',
276 coreconfigitem('diff', 'nobinary',
275 default=False,
277 default=False,
276 )
278 )
277 coreconfigitem('diff', 'noprefix',
279 coreconfigitem('diff', 'noprefix',
278 default=False,
280 default=False,
279 )
281 )
280 coreconfigitem('email', 'bcc',
282 coreconfigitem('email', 'bcc',
281 default=None,
283 default=None,
282 )
284 )
283 coreconfigitem('email', 'cc',
285 coreconfigitem('email', 'cc',
284 default=None,
286 default=None,
285 )
287 )
286 coreconfigitem('email', 'charsets',
288 coreconfigitem('email', 'charsets',
287 default=list,
289 default=list,
288 )
290 )
289 coreconfigitem('email', 'from',
291 coreconfigitem('email', 'from',
290 default=None,
292 default=None,
291 )
293 )
292 coreconfigitem('email', 'method',
294 coreconfigitem('email', 'method',
293 default='smtp',
295 default='smtp',
294 )
296 )
295 coreconfigitem('email', 'reply-to',
297 coreconfigitem('email', 'reply-to',
296 default=None,
298 default=None,
297 )
299 )
298 coreconfigitem('experimental', 'allowdivergence',
300 coreconfigitem('experimental', 'allowdivergence',
299 default=False,
301 default=False,
300 )
302 )
301 coreconfigitem('experimental', 'archivemetatemplate',
303 coreconfigitem('experimental', 'archivemetatemplate',
302 default=dynamicdefault,
304 default=dynamicdefault,
303 )
305 )
304 coreconfigitem('experimental', 'bundle-phases',
306 coreconfigitem('experimental', 'bundle-phases',
305 default=False,
307 default=False,
306 )
308 )
307 coreconfigitem('experimental', 'bundle2-advertise',
309 coreconfigitem('experimental', 'bundle2-advertise',
308 default=True,
310 default=True,
309 )
311 )
310 coreconfigitem('experimental', 'bundle2-output-capture',
312 coreconfigitem('experimental', 'bundle2-output-capture',
311 default=False,
313 default=False,
312 )
314 )
313 coreconfigitem('experimental', 'bundle2.pushback',
315 coreconfigitem('experimental', 'bundle2.pushback',
314 default=False,
316 default=False,
315 )
317 )
316 coreconfigitem('experimental', 'bundle2lazylocking',
318 coreconfigitem('experimental', 'bundle2lazylocking',
317 default=False,
319 default=False,
318 )
320 )
319 coreconfigitem('experimental', 'bundlecomplevel',
321 coreconfigitem('experimental', 'bundlecomplevel',
320 default=None,
322 default=None,
321 )
323 )
322 coreconfigitem('experimental', 'changegroup3',
324 coreconfigitem('experimental', 'changegroup3',
323 default=False,
325 default=False,
324 )
326 )
325 coreconfigitem('experimental', 'clientcompressionengines',
327 coreconfigitem('experimental', 'clientcompressionengines',
326 default=list,
328 default=list,
327 )
329 )
328 coreconfigitem('experimental', 'copytrace',
330 coreconfigitem('experimental', 'copytrace',
329 default='on',
331 default='on',
330 )
332 )
331 coreconfigitem('experimental', 'copytrace.sourcecommitlimit',
333 coreconfigitem('experimental', 'copytrace.sourcecommitlimit',
332 default=100,
334 default=100,
333 )
335 )
334 coreconfigitem('experimental', 'crecordtest',
336 coreconfigitem('experimental', 'crecordtest',
335 default=None,
337 default=None,
336 )
338 )
337 coreconfigitem('experimental', 'editortmpinhg',
339 coreconfigitem('experimental', 'editortmpinhg',
338 default=False,
340 default=False,
339 )
341 )
340 coreconfigitem('experimental', 'maxdeltachainspan',
342 coreconfigitem('experimental', 'maxdeltachainspan',
341 default=-1,
343 default=-1,
342 )
344 )
343 coreconfigitem('experimental', 'mmapindexthreshold',
345 coreconfigitem('experimental', 'mmapindexthreshold',
344 default=None,
346 default=None,
345 )
347 )
346 coreconfigitem('experimental', 'nonnormalparanoidcheck',
348 coreconfigitem('experimental', 'nonnormalparanoidcheck',
347 default=False,
349 default=False,
348 )
350 )
349 coreconfigitem('experimental', 'stabilization',
351 coreconfigitem('experimental', 'stabilization',
350 default=list,
352 default=list,
351 alias=[('experimental', 'evolution')],
353 alias=[('experimental', 'evolution')],
352 )
354 )
353 coreconfigitem('experimental', 'stabilization.bundle-obsmarker',
355 coreconfigitem('experimental', 'stabilization.bundle-obsmarker',
354 default=False,
356 default=False,
355 alias=[('experimental', 'evolution.bundle-obsmarker')],
357 alias=[('experimental', 'evolution.bundle-obsmarker')],
356 )
358 )
357 coreconfigitem('experimental', 'stabilization.track-operation',
359 coreconfigitem('experimental', 'stabilization.track-operation',
358 default=True,
360 default=True,
359 alias=[('experimental', 'evolution.track-operation')]
361 alias=[('experimental', 'evolution.track-operation')]
360 )
362 )
361 coreconfigitem('experimental', 'exportableenviron',
363 coreconfigitem('experimental', 'exportableenviron',
362 default=list,
364 default=list,
363 )
365 )
364 coreconfigitem('experimental', 'extendedheader.index',
366 coreconfigitem('experimental', 'extendedheader.index',
365 default=None,
367 default=None,
366 )
368 )
367 coreconfigitem('experimental', 'extendedheader.similarity',
369 coreconfigitem('experimental', 'extendedheader.similarity',
368 default=False,
370 default=False,
369 )
371 )
370 coreconfigitem('experimental', 'format.compression',
372 coreconfigitem('experimental', 'format.compression',
371 default='zlib',
373 default='zlib',
372 )
374 )
373 coreconfigitem('experimental', 'graphshorten',
375 coreconfigitem('experimental', 'graphshorten',
374 default=False,
376 default=False,
375 )
377 )
376 coreconfigitem('experimental', 'graphstyle.parent',
378 coreconfigitem('experimental', 'graphstyle.parent',
377 default=dynamicdefault,
379 default=dynamicdefault,
378 )
380 )
379 coreconfigitem('experimental', 'graphstyle.missing',
381 coreconfigitem('experimental', 'graphstyle.missing',
380 default=dynamicdefault,
382 default=dynamicdefault,
381 )
383 )
382 coreconfigitem('experimental', 'graphstyle.grandparent',
384 coreconfigitem('experimental', 'graphstyle.grandparent',
383 default=dynamicdefault,
385 default=dynamicdefault,
384 )
386 )
385 coreconfigitem('experimental', 'hook-track-tags',
387 coreconfigitem('experimental', 'hook-track-tags',
386 default=False,
388 default=False,
387 )
389 )
388 coreconfigitem('experimental', 'httppostargs',
390 coreconfigitem('experimental', 'httppostargs',
389 default=False,
391 default=False,
390 )
392 )
391 coreconfigitem('experimental', 'manifestv2',
393 coreconfigitem('experimental', 'manifestv2',
392 default=False,
394 default=False,
393 )
395 )
394 coreconfigitem('experimental', 'mergedriver',
396 coreconfigitem('experimental', 'mergedriver',
395 default=None,
397 default=None,
396 )
398 )
397 coreconfigitem('experimental', 'obsmarkers-exchange-debug',
399 coreconfigitem('experimental', 'obsmarkers-exchange-debug',
398 default=False,
400 default=False,
399 )
401 )
400 coreconfigitem('experimental', 'rebase.multidest',
402 coreconfigitem('experimental', 'rebase.multidest',
401 default=False,
403 default=False,
402 )
404 )
403 coreconfigitem('experimental', 'revertalternateinteractivemode',
405 coreconfigitem('experimental', 'revertalternateinteractivemode',
404 default=True,
406 default=True,
405 )
407 )
406 coreconfigitem('experimental', 'revlogv2',
408 coreconfigitem('experimental', 'revlogv2',
407 default=None,
409 default=None,
408 )
410 )
409 coreconfigitem('experimental', 'spacemovesdown',
411 coreconfigitem('experimental', 'spacemovesdown',
410 default=False,
412 default=False,
411 )
413 )
412 coreconfigitem('experimental', 'treemanifest',
414 coreconfigitem('experimental', 'treemanifest',
413 default=False,
415 default=False,
414 )
416 )
415 # Deprecated, remove after 4.4 release
416 coreconfigitem('experimental', 'updatecheck',
417 default=None,
418 )
419 coreconfigitem('extensions', '.*',
417 coreconfigitem('extensions', '.*',
420 default=None,
418 default=None,
421 generic=True,
419 generic=True,
422 )
420 )
423 coreconfigitem('extdata', '.*',
421 coreconfigitem('extdata', '.*',
424 default=None,
422 default=None,
425 generic=True,
423 generic=True,
426 )
424 )
427 coreconfigitem('format', 'aggressivemergedeltas',
425 coreconfigitem('format', 'aggressivemergedeltas',
428 default=False,
426 default=False,
429 )
427 )
430 coreconfigitem('format', 'chunkcachesize',
428 coreconfigitem('format', 'chunkcachesize',
431 default=None,
429 default=None,
432 )
430 )
433 coreconfigitem('format', 'dotencode',
431 coreconfigitem('format', 'dotencode',
434 default=True,
432 default=True,
435 )
433 )
436 coreconfigitem('format', 'generaldelta',
434 coreconfigitem('format', 'generaldelta',
437 default=False,
435 default=False,
438 )
436 )
439 coreconfigitem('format', 'manifestcachesize',
437 coreconfigitem('format', 'manifestcachesize',
440 default=None,
438 default=None,
441 )
439 )
442 coreconfigitem('format', 'maxchainlen',
440 coreconfigitem('format', 'maxchainlen',
443 default=None,
441 default=None,
444 )
442 )
445 coreconfigitem('format', 'obsstore-version',
443 coreconfigitem('format', 'obsstore-version',
446 default=None,
444 default=None,
447 )
445 )
448 coreconfigitem('format', 'usefncache',
446 coreconfigitem('format', 'usefncache',
449 default=True,
447 default=True,
450 )
448 )
451 coreconfigitem('format', 'usegeneraldelta',
449 coreconfigitem('format', 'usegeneraldelta',
452 default=True,
450 default=True,
453 )
451 )
454 coreconfigitem('format', 'usestore',
452 coreconfigitem('format', 'usestore',
455 default=True,
453 default=True,
456 )
454 )
457 coreconfigitem('hooks', '.*',
455 coreconfigitem('hooks', '.*',
458 default=dynamicdefault,
456 default=dynamicdefault,
459 generic=True,
457 generic=True,
460 )
458 )
461 coreconfigitem('hgweb-paths', '.*',
459 coreconfigitem('hgweb-paths', '.*',
462 default=list,
460 default=list,
463 generic=True,
461 generic=True,
464 )
462 )
465 coreconfigitem('hostfingerprints', '.*',
463 coreconfigitem('hostfingerprints', '.*',
466 default=list,
464 default=list,
467 generic=True,
465 generic=True,
468 )
466 )
469 coreconfigitem('hostsecurity', 'ciphers',
467 coreconfigitem('hostsecurity', 'ciphers',
470 default=None,
468 default=None,
471 )
469 )
472 coreconfigitem('hostsecurity', 'disabletls10warning',
470 coreconfigitem('hostsecurity', 'disabletls10warning',
473 default=False,
471 default=False,
474 )
472 )
475 coreconfigitem('hostsecurity', 'minimumprotocol',
473 coreconfigitem('hostsecurity', 'minimumprotocol',
476 default=dynamicdefault,
474 default=dynamicdefault,
477 )
475 )
478 coreconfigitem('hostsecurity', '.*:minimumprotocol$',
476 coreconfigitem('hostsecurity', '.*:minimumprotocol$',
479 default=dynamicdefault,
477 default=dynamicdefault,
480 generic=True,
478 generic=True,
481 )
479 )
482 coreconfigitem('hostsecurity', '.*:ciphers$',
480 coreconfigitem('hostsecurity', '.*:ciphers$',
483 default=dynamicdefault,
481 default=dynamicdefault,
484 generic=True,
482 generic=True,
485 )
483 )
486 coreconfigitem('hostsecurity', '.*:fingerprints$',
484 coreconfigitem('hostsecurity', '.*:fingerprints$',
487 default=list,
485 default=list,
488 generic=True,
486 generic=True,
489 )
487 )
490 coreconfigitem('hostsecurity', '.*:verifycertsfile$',
488 coreconfigitem('hostsecurity', '.*:verifycertsfile$',
491 default=None,
489 default=None,
492 generic=True,
490 generic=True,
493 )
491 )
494
492
495 coreconfigitem('http_proxy', 'always',
493 coreconfigitem('http_proxy', 'always',
496 default=False,
494 default=False,
497 )
495 )
498 coreconfigitem('http_proxy', 'host',
496 coreconfigitem('http_proxy', 'host',
499 default=None,
497 default=None,
500 )
498 )
501 coreconfigitem('http_proxy', 'no',
499 coreconfigitem('http_proxy', 'no',
502 default=list,
500 default=list,
503 )
501 )
504 coreconfigitem('http_proxy', 'passwd',
502 coreconfigitem('http_proxy', 'passwd',
505 default=None,
503 default=None,
506 )
504 )
507 coreconfigitem('http_proxy', 'user',
505 coreconfigitem('http_proxy', 'user',
508 default=None,
506 default=None,
509 )
507 )
510 coreconfigitem('logtoprocess', 'commandexception',
508 coreconfigitem('logtoprocess', 'commandexception',
511 default=None,
509 default=None,
512 )
510 )
513 coreconfigitem('logtoprocess', 'commandfinish',
511 coreconfigitem('logtoprocess', 'commandfinish',
514 default=None,
512 default=None,
515 )
513 )
516 coreconfigitem('logtoprocess', 'command',
514 coreconfigitem('logtoprocess', 'command',
517 default=None,
515 default=None,
518 )
516 )
519 coreconfigitem('logtoprocess', 'develwarn',
517 coreconfigitem('logtoprocess', 'develwarn',
520 default=None,
518 default=None,
521 )
519 )
522 coreconfigitem('logtoprocess', 'uiblocked',
520 coreconfigitem('logtoprocess', 'uiblocked',
523 default=None,
521 default=None,
524 )
522 )
525 coreconfigitem('merge', 'checkunknown',
523 coreconfigitem('merge', 'checkunknown',
526 default='abort',
524 default='abort',
527 )
525 )
528 coreconfigitem('merge', 'checkignored',
526 coreconfigitem('merge', 'checkignored',
529 default='abort',
527 default='abort',
530 )
528 )
531 coreconfigitem('merge', 'followcopies',
529 coreconfigitem('merge', 'followcopies',
532 default=True,
530 default=True,
533 )
531 )
534 coreconfigitem('merge', 'on-failure',
532 coreconfigitem('merge', 'on-failure',
535 default='continue',
533 default='continue',
536 )
534 )
537 coreconfigitem('merge', 'preferancestor',
535 coreconfigitem('merge', 'preferancestor',
538 default=lambda: ['*'],
536 default=lambda: ['*'],
539 )
537 )
540 coreconfigitem('pager', 'attend-.*',
538 coreconfigitem('pager', 'attend-.*',
541 default=dynamicdefault,
539 default=dynamicdefault,
542 generic=True,
540 generic=True,
543 )
541 )
544 coreconfigitem('pager', 'ignore',
542 coreconfigitem('pager', 'ignore',
545 default=list,
543 default=list,
546 )
544 )
547 coreconfigitem('pager', 'pager',
545 coreconfigitem('pager', 'pager',
548 default=dynamicdefault,
546 default=dynamicdefault,
549 )
547 )
550 coreconfigitem('patch', 'eol',
548 coreconfigitem('patch', 'eol',
551 default='strict',
549 default='strict',
552 )
550 )
553 coreconfigitem('patch', 'fuzz',
551 coreconfigitem('patch', 'fuzz',
554 default=2,
552 default=2,
555 )
553 )
556 coreconfigitem('paths', 'default',
554 coreconfigitem('paths', 'default',
557 default=None,
555 default=None,
558 )
556 )
559 coreconfigitem('paths', 'default-push',
557 coreconfigitem('paths', 'default-push',
560 default=None,
558 default=None,
561 )
559 )
562 coreconfigitem('paths', '.*',
560 coreconfigitem('paths', '.*',
563 default=None,
561 default=None,
564 generic=True,
562 generic=True,
565 )
563 )
566 coreconfigitem('phases', 'checksubrepos',
564 coreconfigitem('phases', 'checksubrepos',
567 default='follow',
565 default='follow',
568 )
566 )
569 coreconfigitem('phases', 'new-commit',
567 coreconfigitem('phases', 'new-commit',
570 default='draft',
568 default='draft',
571 )
569 )
572 coreconfigitem('phases', 'publish',
570 coreconfigitem('phases', 'publish',
573 default=True,
571 default=True,
574 )
572 )
575 coreconfigitem('profiling', 'enabled',
573 coreconfigitem('profiling', 'enabled',
576 default=False,
574 default=False,
577 )
575 )
578 coreconfigitem('profiling', 'format',
576 coreconfigitem('profiling', 'format',
579 default='text',
577 default='text',
580 )
578 )
581 coreconfigitem('profiling', 'freq',
579 coreconfigitem('profiling', 'freq',
582 default=1000,
580 default=1000,
583 )
581 )
584 coreconfigitem('profiling', 'limit',
582 coreconfigitem('profiling', 'limit',
585 default=30,
583 default=30,
586 )
584 )
587 coreconfigitem('profiling', 'nested',
585 coreconfigitem('profiling', 'nested',
588 default=0,
586 default=0,
589 )
587 )
590 coreconfigitem('profiling', 'output',
588 coreconfigitem('profiling', 'output',
591 default=None,
589 default=None,
592 )
590 )
593 coreconfigitem('profiling', 'showmax',
591 coreconfigitem('profiling', 'showmax',
594 default=0.999,
592 default=0.999,
595 )
593 )
596 coreconfigitem('profiling', 'showmin',
594 coreconfigitem('profiling', 'showmin',
597 default=dynamicdefault,
595 default=dynamicdefault,
598 )
596 )
599 coreconfigitem('profiling', 'sort',
597 coreconfigitem('profiling', 'sort',
600 default='inlinetime',
598 default='inlinetime',
601 )
599 )
602 coreconfigitem('profiling', 'statformat',
600 coreconfigitem('profiling', 'statformat',
603 default='hotpath',
601 default='hotpath',
604 )
602 )
605 coreconfigitem('profiling', 'type',
603 coreconfigitem('profiling', 'type',
606 default='stat',
604 default='stat',
607 )
605 )
608 coreconfigitem('progress', 'assume-tty',
606 coreconfigitem('progress', 'assume-tty',
609 default=False,
607 default=False,
610 )
608 )
611 coreconfigitem('progress', 'changedelay',
609 coreconfigitem('progress', 'changedelay',
612 default=1,
610 default=1,
613 )
611 )
614 coreconfigitem('progress', 'clear-complete',
612 coreconfigitem('progress', 'clear-complete',
615 default=True,
613 default=True,
616 )
614 )
617 coreconfigitem('progress', 'debug',
615 coreconfigitem('progress', 'debug',
618 default=False,
616 default=False,
619 )
617 )
620 coreconfigitem('progress', 'delay',
618 coreconfigitem('progress', 'delay',
621 default=3,
619 default=3,
622 )
620 )
623 coreconfigitem('progress', 'disable',
621 coreconfigitem('progress', 'disable',
624 default=False,
622 default=False,
625 )
623 )
626 coreconfigitem('progress', 'estimateinterval',
624 coreconfigitem('progress', 'estimateinterval',
627 default=60.0,
625 default=60.0,
628 )
626 )
629 coreconfigitem('progress', 'format',
627 coreconfigitem('progress', 'format',
630 default=lambda: ['topic', 'bar', 'number', 'estimate'],
628 default=lambda: ['topic', 'bar', 'number', 'estimate'],
631 )
629 )
632 coreconfigitem('progress', 'refresh',
630 coreconfigitem('progress', 'refresh',
633 default=0.1,
631 default=0.1,
634 )
632 )
635 coreconfigitem('progress', 'width',
633 coreconfigitem('progress', 'width',
636 default=dynamicdefault,
634 default=dynamicdefault,
637 )
635 )
638 coreconfigitem('push', 'pushvars.server',
636 coreconfigitem('push', 'pushvars.server',
639 default=False,
637 default=False,
640 )
638 )
641 coreconfigitem('server', 'bundle1',
639 coreconfigitem('server', 'bundle1',
642 default=True,
640 default=True,
643 )
641 )
644 coreconfigitem('server', 'bundle1gd',
642 coreconfigitem('server', 'bundle1gd',
645 default=None,
643 default=None,
646 )
644 )
647 coreconfigitem('server', 'bundle1.pull',
645 coreconfigitem('server', 'bundle1.pull',
648 default=None,
646 default=None,
649 )
647 )
650 coreconfigitem('server', 'bundle1gd.pull',
648 coreconfigitem('server', 'bundle1gd.pull',
651 default=None,
649 default=None,
652 )
650 )
653 coreconfigitem('server', 'bundle1.push',
651 coreconfigitem('server', 'bundle1.push',
654 default=None,
652 default=None,
655 )
653 )
656 coreconfigitem('server', 'bundle1gd.push',
654 coreconfigitem('server', 'bundle1gd.push',
657 default=None,
655 default=None,
658 )
656 )
659 coreconfigitem('server', 'compressionengines',
657 coreconfigitem('server', 'compressionengines',
660 default=list,
658 default=list,
661 )
659 )
662 coreconfigitem('server', 'concurrent-push-mode',
660 coreconfigitem('server', 'concurrent-push-mode',
663 default='strict',
661 default='strict',
664 )
662 )
665 coreconfigitem('server', 'disablefullbundle',
663 coreconfigitem('server', 'disablefullbundle',
666 default=False,
664 default=False,
667 )
665 )
668 coreconfigitem('server', 'maxhttpheaderlen',
666 coreconfigitem('server', 'maxhttpheaderlen',
669 default=1024,
667 default=1024,
670 )
668 )
671 coreconfigitem('server', 'preferuncompressed',
669 coreconfigitem('server', 'preferuncompressed',
672 default=False,
670 default=False,
673 )
671 )
674 coreconfigitem('server', 'uncompressed',
672 coreconfigitem('server', 'uncompressed',
675 default=True,
673 default=True,
676 )
674 )
677 coreconfigitem('server', 'uncompressedallowsecret',
675 coreconfigitem('server', 'uncompressedallowsecret',
678 default=False,
676 default=False,
679 )
677 )
680 coreconfigitem('server', 'validate',
678 coreconfigitem('server', 'validate',
681 default=False,
679 default=False,
682 )
680 )
683 coreconfigitem('server', 'zliblevel',
681 coreconfigitem('server', 'zliblevel',
684 default=-1,
682 default=-1,
685 )
683 )
686 coreconfigitem('smtp', 'host',
684 coreconfigitem('smtp', 'host',
687 default=None,
685 default=None,
688 )
686 )
689 coreconfigitem('smtp', 'local_hostname',
687 coreconfigitem('smtp', 'local_hostname',
690 default=None,
688 default=None,
691 )
689 )
692 coreconfigitem('smtp', 'password',
690 coreconfigitem('smtp', 'password',
693 default=None,
691 default=None,
694 )
692 )
695 coreconfigitem('smtp', 'port',
693 coreconfigitem('smtp', 'port',
696 default=dynamicdefault,
694 default=dynamicdefault,
697 )
695 )
698 coreconfigitem('smtp', 'tls',
696 coreconfigitem('smtp', 'tls',
699 default='none',
697 default='none',
700 )
698 )
701 coreconfigitem('smtp', 'username',
699 coreconfigitem('smtp', 'username',
702 default=None,
700 default=None,
703 )
701 )
704 coreconfigitem('sparse', 'missingwarning',
702 coreconfigitem('sparse', 'missingwarning',
705 default=True,
703 default=True,
706 )
704 )
707 coreconfigitem('templates', '.*',
705 coreconfigitem('templates', '.*',
708 default=None,
706 default=None,
709 generic=True,
707 generic=True,
710 )
708 )
711 coreconfigitem('trusted', 'groups',
709 coreconfigitem('trusted', 'groups',
712 default=list,
710 default=list,
713 )
711 )
714 coreconfigitem('trusted', 'users',
712 coreconfigitem('trusted', 'users',
715 default=list,
713 default=list,
716 )
714 )
717 coreconfigitem('ui', '_usedassubrepo',
715 coreconfigitem('ui', '_usedassubrepo',
718 default=False,
716 default=False,
719 )
717 )
720 coreconfigitem('ui', 'allowemptycommit',
718 coreconfigitem('ui', 'allowemptycommit',
721 default=False,
719 default=False,
722 )
720 )
723 coreconfigitem('ui', 'archivemeta',
721 coreconfigitem('ui', 'archivemeta',
724 default=True,
722 default=True,
725 )
723 )
726 coreconfigitem('ui', 'askusername',
724 coreconfigitem('ui', 'askusername',
727 default=False,
725 default=False,
728 )
726 )
729 coreconfigitem('ui', 'clonebundlefallback',
727 coreconfigitem('ui', 'clonebundlefallback',
730 default=False,
728 default=False,
731 )
729 )
732 coreconfigitem('ui', 'clonebundleprefers',
730 coreconfigitem('ui', 'clonebundleprefers',
733 default=list,
731 default=list,
734 )
732 )
735 coreconfigitem('ui', 'clonebundles',
733 coreconfigitem('ui', 'clonebundles',
736 default=True,
734 default=True,
737 )
735 )
738 coreconfigitem('ui', 'color',
736 coreconfigitem('ui', 'color',
739 default='auto',
737 default='auto',
740 )
738 )
741 coreconfigitem('ui', 'commitsubrepos',
739 coreconfigitem('ui', 'commitsubrepos',
742 default=False,
740 default=False,
743 )
741 )
744 coreconfigitem('ui', 'debug',
742 coreconfigitem('ui', 'debug',
745 default=False,
743 default=False,
746 )
744 )
747 coreconfigitem('ui', 'debugger',
745 coreconfigitem('ui', 'debugger',
748 default=None,
746 default=None,
749 )
747 )
750 coreconfigitem('ui', 'fallbackencoding',
748 coreconfigitem('ui', 'fallbackencoding',
751 default=None,
749 default=None,
752 )
750 )
753 coreconfigitem('ui', 'forcecwd',
751 coreconfigitem('ui', 'forcecwd',
754 default=None,
752 default=None,
755 )
753 )
756 coreconfigitem('ui', 'forcemerge',
754 coreconfigitem('ui', 'forcemerge',
757 default=None,
755 default=None,
758 )
756 )
759 coreconfigitem('ui', 'formatdebug',
757 coreconfigitem('ui', 'formatdebug',
760 default=False,
758 default=False,
761 )
759 )
762 coreconfigitem('ui', 'formatjson',
760 coreconfigitem('ui', 'formatjson',
763 default=False,
761 default=False,
764 )
762 )
765 coreconfigitem('ui', 'formatted',
763 coreconfigitem('ui', 'formatted',
766 default=None,
764 default=None,
767 )
765 )
768 coreconfigitem('ui', 'graphnodetemplate',
766 coreconfigitem('ui', 'graphnodetemplate',
769 default=None,
767 default=None,
770 )
768 )
771 coreconfigitem('ui', 'http2debuglevel',
769 coreconfigitem('ui', 'http2debuglevel',
772 default=None,
770 default=None,
773 )
771 )
774 coreconfigitem('ui', 'interactive',
772 coreconfigitem('ui', 'interactive',
775 default=None,
773 default=None,
776 )
774 )
777 coreconfigitem('ui', 'interface',
775 coreconfigitem('ui', 'interface',
778 default=None,
776 default=None,
779 )
777 )
780 coreconfigitem('ui', 'interface.chunkselector',
778 coreconfigitem('ui', 'interface.chunkselector',
781 default=None,
779 default=None,
782 )
780 )
783 coreconfigitem('ui', 'logblockedtimes',
781 coreconfigitem('ui', 'logblockedtimes',
784 default=False,
782 default=False,
785 )
783 )
786 coreconfigitem('ui', 'logtemplate',
784 coreconfigitem('ui', 'logtemplate',
787 default=None,
785 default=None,
788 )
786 )
789 coreconfigitem('ui', 'merge',
787 coreconfigitem('ui', 'merge',
790 default=None,
788 default=None,
791 )
789 )
792 coreconfigitem('ui', 'mergemarkers',
790 coreconfigitem('ui', 'mergemarkers',
793 default='basic',
791 default='basic',
794 )
792 )
795 coreconfigitem('ui', 'mergemarkertemplate',
793 coreconfigitem('ui', 'mergemarkertemplate',
796 default=('{node|short} '
794 default=('{node|short} '
797 '{ifeq(tags, "tip", "", '
795 '{ifeq(tags, "tip", "", '
798 'ifeq(tags, "", "", "{tags} "))}'
796 'ifeq(tags, "", "", "{tags} "))}'
799 '{if(bookmarks, "{bookmarks} ")}'
797 '{if(bookmarks, "{bookmarks} ")}'
800 '{ifeq(branch, "default", "", "{branch} ")}'
798 '{ifeq(branch, "default", "", "{branch} ")}'
801 '- {author|user}: {desc|firstline}')
799 '- {author|user}: {desc|firstline}')
802 )
800 )
803 coreconfigitem('ui', 'nontty',
801 coreconfigitem('ui', 'nontty',
804 default=False,
802 default=False,
805 )
803 )
806 coreconfigitem('ui', 'origbackuppath',
804 coreconfigitem('ui', 'origbackuppath',
807 default=None,
805 default=None,
808 )
806 )
809 coreconfigitem('ui', 'paginate',
807 coreconfigitem('ui', 'paginate',
810 default=True,
808 default=True,
811 )
809 )
812 coreconfigitem('ui', 'patch',
810 coreconfigitem('ui', 'patch',
813 default=None,
811 default=None,
814 )
812 )
815 coreconfigitem('ui', 'portablefilenames',
813 coreconfigitem('ui', 'portablefilenames',
816 default='warn',
814 default='warn',
817 )
815 )
818 coreconfigitem('ui', 'promptecho',
816 coreconfigitem('ui', 'promptecho',
819 default=False,
817 default=False,
820 )
818 )
821 coreconfigitem('ui', 'quiet',
819 coreconfigitem('ui', 'quiet',
822 default=False,
820 default=False,
823 )
821 )
824 coreconfigitem('ui', 'quietbookmarkmove',
822 coreconfigitem('ui', 'quietbookmarkmove',
825 default=False,
823 default=False,
826 )
824 )
827 coreconfigitem('ui', 'remotecmd',
825 coreconfigitem('ui', 'remotecmd',
828 default='hg',
826 default='hg',
829 )
827 )
830 coreconfigitem('ui', 'report_untrusted',
828 coreconfigitem('ui', 'report_untrusted',
831 default=True,
829 default=True,
832 )
830 )
833 coreconfigitem('ui', 'rollback',
831 coreconfigitem('ui', 'rollback',
834 default=True,
832 default=True,
835 )
833 )
836 coreconfigitem('ui', 'slash',
834 coreconfigitem('ui', 'slash',
837 default=False,
835 default=False,
838 )
836 )
839 coreconfigitem('ui', 'ssh',
837 coreconfigitem('ui', 'ssh',
840 default='ssh',
838 default='ssh',
841 )
839 )
842 coreconfigitem('ui', 'statuscopies',
840 coreconfigitem('ui', 'statuscopies',
843 default=False,
841 default=False,
844 )
842 )
845 coreconfigitem('ui', 'strict',
843 coreconfigitem('ui', 'strict',
846 default=False,
844 default=False,
847 )
845 )
848 coreconfigitem('ui', 'style',
846 coreconfigitem('ui', 'style',
849 default='',
847 default='',
850 )
848 )
851 coreconfigitem('ui', 'supportcontact',
849 coreconfigitem('ui', 'supportcontact',
852 default=None,
850 default=None,
853 )
851 )
854 coreconfigitem('ui', 'textwidth',
852 coreconfigitem('ui', 'textwidth',
855 default=78,
853 default=78,
856 )
854 )
857 coreconfigitem('ui', 'timeout',
855 coreconfigitem('ui', 'timeout',
858 default='600',
856 default='600',
859 )
857 )
860 coreconfigitem('ui', 'traceback',
858 coreconfigitem('ui', 'traceback',
861 default=False,
859 default=False,
862 )
860 )
863 coreconfigitem('ui', 'tweakdefaults',
861 coreconfigitem('ui', 'tweakdefaults',
864 default=False,
862 default=False,
865 )
863 )
866 coreconfigitem('ui', 'usehttp2',
864 coreconfigitem('ui', 'usehttp2',
867 default=False,
865 default=False,
868 )
866 )
869 coreconfigitem('ui', 'username',
867 coreconfigitem('ui', 'username',
870 alias=[('ui', 'user')]
868 alias=[('ui', 'user')]
871 )
869 )
872 coreconfigitem('ui', 'verbose',
870 coreconfigitem('ui', 'verbose',
873 default=False,
871 default=False,
874 )
872 )
875 coreconfigitem('verify', 'skipflags',
873 coreconfigitem('verify', 'skipflags',
876 default=None,
874 default=None,
877 )
875 )
878 coreconfigitem('web', 'allowbz2',
876 coreconfigitem('web', 'allowbz2',
879 default=False,
877 default=False,
880 )
878 )
881 coreconfigitem('web', 'allowgz',
879 coreconfigitem('web', 'allowgz',
882 default=False,
880 default=False,
883 )
881 )
884 coreconfigitem('web', 'allowpull',
882 coreconfigitem('web', 'allowpull',
885 default=True,
883 default=True,
886 )
884 )
887 coreconfigitem('web', 'allow_push',
885 coreconfigitem('web', 'allow_push',
888 default=list,
886 default=list,
889 )
887 )
890 coreconfigitem('web', 'allowzip',
888 coreconfigitem('web', 'allowzip',
891 default=False,
889 default=False,
892 )
890 )
893 coreconfigitem('web', 'cache',
891 coreconfigitem('web', 'cache',
894 default=True,
892 default=True,
895 )
893 )
896 coreconfigitem('web', 'contact',
894 coreconfigitem('web', 'contact',
897 default=None,
895 default=None,
898 )
896 )
899 coreconfigitem('web', 'deny_push',
897 coreconfigitem('web', 'deny_push',
900 default=list,
898 default=list,
901 )
899 )
902 coreconfigitem('web', 'guessmime',
900 coreconfigitem('web', 'guessmime',
903 default=False,
901 default=False,
904 )
902 )
905 coreconfigitem('web', 'hidden',
903 coreconfigitem('web', 'hidden',
906 default=False,
904 default=False,
907 )
905 )
908 coreconfigitem('web', 'labels',
906 coreconfigitem('web', 'labels',
909 default=list,
907 default=list,
910 )
908 )
911 coreconfigitem('web', 'logoimg',
909 coreconfigitem('web', 'logoimg',
912 default='hglogo.png',
910 default='hglogo.png',
913 )
911 )
914 coreconfigitem('web', 'logourl',
912 coreconfigitem('web', 'logourl',
915 default='https://mercurial-scm.org/',
913 default='https://mercurial-scm.org/',
916 )
914 )
917 coreconfigitem('web', 'accesslog',
915 coreconfigitem('web', 'accesslog',
918 default='-',
916 default='-',
919 )
917 )
920 coreconfigitem('web', 'address',
918 coreconfigitem('web', 'address',
921 default='',
919 default='',
922 )
920 )
923 coreconfigitem('web', 'allow_archive',
921 coreconfigitem('web', 'allow_archive',
924 default=list,
922 default=list,
925 )
923 )
926 coreconfigitem('web', 'allow_read',
924 coreconfigitem('web', 'allow_read',
927 default=list,
925 default=list,
928 )
926 )
929 coreconfigitem('web', 'baseurl',
927 coreconfigitem('web', 'baseurl',
930 default=None,
928 default=None,
931 )
929 )
932 coreconfigitem('web', 'cacerts',
930 coreconfigitem('web', 'cacerts',
933 default=None,
931 default=None,
934 )
932 )
935 coreconfigitem('web', 'certificate',
933 coreconfigitem('web', 'certificate',
936 default=None,
934 default=None,
937 )
935 )
938 coreconfigitem('web', 'collapse',
936 coreconfigitem('web', 'collapse',
939 default=False,
937 default=False,
940 )
938 )
941 coreconfigitem('web', 'csp',
939 coreconfigitem('web', 'csp',
942 default=None,
940 default=None,
943 )
941 )
944 coreconfigitem('web', 'deny_read',
942 coreconfigitem('web', 'deny_read',
945 default=list,
943 default=list,
946 )
944 )
947 coreconfigitem('web', 'descend',
945 coreconfigitem('web', 'descend',
948 default=True,
946 default=True,
949 )
947 )
950 coreconfigitem('web', 'description',
948 coreconfigitem('web', 'description',
951 default="",
949 default="",
952 )
950 )
953 coreconfigitem('web', 'encoding',
951 coreconfigitem('web', 'encoding',
954 default=lambda: encoding.encoding,
952 default=lambda: encoding.encoding,
955 )
953 )
956 coreconfigitem('web', 'errorlog',
954 coreconfigitem('web', 'errorlog',
957 default='-',
955 default='-',
958 )
956 )
959 coreconfigitem('web', 'ipv6',
957 coreconfigitem('web', 'ipv6',
960 default=False,
958 default=False,
961 )
959 )
962 coreconfigitem('web', 'maxchanges',
960 coreconfigitem('web', 'maxchanges',
963 default=10,
961 default=10,
964 )
962 )
965 coreconfigitem('web', 'maxfiles',
963 coreconfigitem('web', 'maxfiles',
966 default=10,
964 default=10,
967 )
965 )
968 coreconfigitem('web', 'maxshortchanges',
966 coreconfigitem('web', 'maxshortchanges',
969 default=60,
967 default=60,
970 )
968 )
971 coreconfigitem('web', 'motd',
969 coreconfigitem('web', 'motd',
972 default='',
970 default='',
973 )
971 )
974 coreconfigitem('web', 'name',
972 coreconfigitem('web', 'name',
975 default=dynamicdefault,
973 default=dynamicdefault,
976 )
974 )
977 coreconfigitem('web', 'port',
975 coreconfigitem('web', 'port',
978 default=8000,
976 default=8000,
979 )
977 )
980 coreconfigitem('web', 'prefix',
978 coreconfigitem('web', 'prefix',
981 default='',
979 default='',
982 )
980 )
983 coreconfigitem('web', 'push_ssl',
981 coreconfigitem('web', 'push_ssl',
984 default=True,
982 default=True,
985 )
983 )
986 coreconfigitem('web', 'refreshinterval',
984 coreconfigitem('web', 'refreshinterval',
987 default=20,
985 default=20,
988 )
986 )
989 coreconfigitem('web', 'staticurl',
987 coreconfigitem('web', 'staticurl',
990 default=None,
988 default=None,
991 )
989 )
992 coreconfigitem('web', 'stripes',
990 coreconfigitem('web', 'stripes',
993 default=1,
991 default=1,
994 )
992 )
995 coreconfigitem('web', 'style',
993 coreconfigitem('web', 'style',
996 default='paper',
994 default='paper',
997 )
995 )
998 coreconfigitem('web', 'templates',
996 coreconfigitem('web', 'templates',
999 default=None,
997 default=None,
1000 )
998 )
1001 coreconfigitem('web', 'view',
999 coreconfigitem('web', 'view',
1002 default='served',
1000 default='served',
1003 )
1001 )
1004 coreconfigitem('worker', 'backgroundclose',
1002 coreconfigitem('worker', 'backgroundclose',
1005 default=dynamicdefault,
1003 default=dynamicdefault,
1006 )
1004 )
1007 # Windows defaults to a limit of 512 open files. A buffer of 128
1005 # Windows defaults to a limit of 512 open files. A buffer of 128
1008 # should give us enough headway.
1006 # should give us enough headway.
1009 coreconfigitem('worker', 'backgroundclosemaxqueue',
1007 coreconfigitem('worker', 'backgroundclosemaxqueue',
1010 default=384,
1008 default=384,
1011 )
1009 )
1012 coreconfigitem('worker', 'backgroundcloseminfilecount',
1010 coreconfigitem('worker', 'backgroundcloseminfilecount',
1013 default=2048,
1011 default=2048,
1014 )
1012 )
1015 coreconfigitem('worker', 'backgroundclosethreadcount',
1013 coreconfigitem('worker', 'backgroundclosethreadcount',
1016 default=4,
1014 default=4,
1017 )
1015 )
1018 coreconfigitem('worker', 'numcpus',
1016 coreconfigitem('worker', 'numcpus',
1019 default=None,
1017 default=None,
1020 )
1018 )
@@ -1,1067 +1,1064 b''
1 # hg.py - repository classes for mercurial
1 # hg.py - repository classes for mercurial
2 #
2 #
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
4 # Copyright 2006 Vadim Gelfer <vadim.gelfer@gmail.com>
4 # Copyright 2006 Vadim Gelfer <vadim.gelfer@gmail.com>
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 from __future__ import absolute_import
9 from __future__ import absolute_import
10
10
11 import errno
11 import errno
12 import hashlib
12 import hashlib
13 import os
13 import os
14 import shutil
14 import shutil
15
15
16 from .i18n import _
16 from .i18n import _
17 from .node import nullid
17 from .node import nullid
18
18
19 from . import (
19 from . import (
20 bookmarks,
20 bookmarks,
21 bundlerepo,
21 bundlerepo,
22 cmdutil,
22 cmdutil,
23 destutil,
23 destutil,
24 discovery,
24 discovery,
25 error,
25 error,
26 exchange,
26 exchange,
27 extensions,
27 extensions,
28 httppeer,
28 httppeer,
29 localrepo,
29 localrepo,
30 lock,
30 lock,
31 merge as mergemod,
31 merge as mergemod,
32 node,
32 node,
33 phases,
33 phases,
34 repoview,
34 repoview,
35 scmutil,
35 scmutil,
36 sshpeer,
36 sshpeer,
37 statichttprepo,
37 statichttprepo,
38 ui as uimod,
38 ui as uimod,
39 unionrepo,
39 unionrepo,
40 url,
40 url,
41 util,
41 util,
42 verify as verifymod,
42 verify as verifymod,
43 vfs as vfsmod,
43 vfs as vfsmod,
44 )
44 )
45
45
46 release = lock.release
46 release = lock.release
47
47
48 # shared features
48 # shared features
49 sharedbookmarks = 'bookmarks'
49 sharedbookmarks = 'bookmarks'
50
50
51 def _local(path):
51 def _local(path):
52 path = util.expandpath(util.urllocalpath(path))
52 path = util.expandpath(util.urllocalpath(path))
53 return (os.path.isfile(path) and bundlerepo or localrepo)
53 return (os.path.isfile(path) and bundlerepo or localrepo)
54
54
55 def addbranchrevs(lrepo, other, branches, revs):
55 def addbranchrevs(lrepo, other, branches, revs):
56 peer = other.peer() # a courtesy to callers using a localrepo for other
56 peer = other.peer() # a courtesy to callers using a localrepo for other
57 hashbranch, branches = branches
57 hashbranch, branches = branches
58 if not hashbranch and not branches:
58 if not hashbranch and not branches:
59 x = revs or None
59 x = revs or None
60 if util.safehasattr(revs, 'first'):
60 if util.safehasattr(revs, 'first'):
61 y = revs.first()
61 y = revs.first()
62 elif revs:
62 elif revs:
63 y = revs[0]
63 y = revs[0]
64 else:
64 else:
65 y = None
65 y = None
66 return x, y
66 return x, y
67 if revs:
67 if revs:
68 revs = list(revs)
68 revs = list(revs)
69 else:
69 else:
70 revs = []
70 revs = []
71
71
72 if not peer.capable('branchmap'):
72 if not peer.capable('branchmap'):
73 if branches:
73 if branches:
74 raise error.Abort(_("remote branch lookup not supported"))
74 raise error.Abort(_("remote branch lookup not supported"))
75 revs.append(hashbranch)
75 revs.append(hashbranch)
76 return revs, revs[0]
76 return revs, revs[0]
77 branchmap = peer.branchmap()
77 branchmap = peer.branchmap()
78
78
79 def primary(branch):
79 def primary(branch):
80 if branch == '.':
80 if branch == '.':
81 if not lrepo:
81 if not lrepo:
82 raise error.Abort(_("dirstate branch not accessible"))
82 raise error.Abort(_("dirstate branch not accessible"))
83 branch = lrepo.dirstate.branch()
83 branch = lrepo.dirstate.branch()
84 if branch in branchmap:
84 if branch in branchmap:
85 revs.extend(node.hex(r) for r in reversed(branchmap[branch]))
85 revs.extend(node.hex(r) for r in reversed(branchmap[branch]))
86 return True
86 return True
87 else:
87 else:
88 return False
88 return False
89
89
90 for branch in branches:
90 for branch in branches:
91 if not primary(branch):
91 if not primary(branch):
92 raise error.RepoLookupError(_("unknown branch '%s'") % branch)
92 raise error.RepoLookupError(_("unknown branch '%s'") % branch)
93 if hashbranch:
93 if hashbranch:
94 if not primary(hashbranch):
94 if not primary(hashbranch):
95 revs.append(hashbranch)
95 revs.append(hashbranch)
96 return revs, revs[0]
96 return revs, revs[0]
97
97
98 def parseurl(path, branches=None):
98 def parseurl(path, branches=None):
99 '''parse url#branch, returning (url, (branch, branches))'''
99 '''parse url#branch, returning (url, (branch, branches))'''
100
100
101 u = util.url(path)
101 u = util.url(path)
102 branch = None
102 branch = None
103 if u.fragment:
103 if u.fragment:
104 branch = u.fragment
104 branch = u.fragment
105 u.fragment = None
105 u.fragment = None
106 return bytes(u), (branch, branches or [])
106 return bytes(u), (branch, branches or [])
107
107
108 schemes = {
108 schemes = {
109 'bundle': bundlerepo,
109 'bundle': bundlerepo,
110 'union': unionrepo,
110 'union': unionrepo,
111 'file': _local,
111 'file': _local,
112 'http': httppeer,
112 'http': httppeer,
113 'https': httppeer,
113 'https': httppeer,
114 'ssh': sshpeer,
114 'ssh': sshpeer,
115 'static-http': statichttprepo,
115 'static-http': statichttprepo,
116 }
116 }
117
117
118 def _peerlookup(path):
118 def _peerlookup(path):
119 u = util.url(path)
119 u = util.url(path)
120 scheme = u.scheme or 'file'
120 scheme = u.scheme or 'file'
121 thing = schemes.get(scheme) or schemes['file']
121 thing = schemes.get(scheme) or schemes['file']
122 try:
122 try:
123 return thing(path)
123 return thing(path)
124 except TypeError:
124 except TypeError:
125 # we can't test callable(thing) because 'thing' can be an unloaded
125 # we can't test callable(thing) because 'thing' can be an unloaded
126 # module that implements __call__
126 # module that implements __call__
127 if not util.safehasattr(thing, 'instance'):
127 if not util.safehasattr(thing, 'instance'):
128 raise
128 raise
129 return thing
129 return thing
130
130
131 def islocal(repo):
131 def islocal(repo):
132 '''return true if repo (or path pointing to repo) is local'''
132 '''return true if repo (or path pointing to repo) is local'''
133 if isinstance(repo, bytes):
133 if isinstance(repo, bytes):
134 try:
134 try:
135 return _peerlookup(repo).islocal(repo)
135 return _peerlookup(repo).islocal(repo)
136 except AttributeError:
136 except AttributeError:
137 return False
137 return False
138 return repo.local()
138 return repo.local()
139
139
140 def openpath(ui, path):
140 def openpath(ui, path):
141 '''open path with open if local, url.open if remote'''
141 '''open path with open if local, url.open if remote'''
142 pathurl = util.url(path, parsequery=False, parsefragment=False)
142 pathurl = util.url(path, parsequery=False, parsefragment=False)
143 if pathurl.islocal():
143 if pathurl.islocal():
144 return util.posixfile(pathurl.localpath(), 'rb')
144 return util.posixfile(pathurl.localpath(), 'rb')
145 else:
145 else:
146 return url.open(ui, path)
146 return url.open(ui, path)
147
147
148 # a list of (ui, repo) functions called for wire peer initialization
148 # a list of (ui, repo) functions called for wire peer initialization
149 wirepeersetupfuncs = []
149 wirepeersetupfuncs = []
150
150
151 def _peerorrepo(ui, path, create=False, presetupfuncs=None):
151 def _peerorrepo(ui, path, create=False, presetupfuncs=None):
152 """return a repository object for the specified path"""
152 """return a repository object for the specified path"""
153 obj = _peerlookup(path).instance(ui, path, create)
153 obj = _peerlookup(path).instance(ui, path, create)
154 ui = getattr(obj, "ui", ui)
154 ui = getattr(obj, "ui", ui)
155 for f in presetupfuncs or []:
155 for f in presetupfuncs or []:
156 f(ui, obj)
156 f(ui, obj)
157 for name, module in extensions.extensions(ui):
157 for name, module in extensions.extensions(ui):
158 hook = getattr(module, 'reposetup', None)
158 hook = getattr(module, 'reposetup', None)
159 if hook:
159 if hook:
160 hook(ui, obj)
160 hook(ui, obj)
161 if not obj.local():
161 if not obj.local():
162 for f in wirepeersetupfuncs:
162 for f in wirepeersetupfuncs:
163 f(ui, obj)
163 f(ui, obj)
164 return obj
164 return obj
165
165
166 def repository(ui, path='', create=False, presetupfuncs=None):
166 def repository(ui, path='', create=False, presetupfuncs=None):
167 """return a repository object for the specified path"""
167 """return a repository object for the specified path"""
168 peer = _peerorrepo(ui, path, create, presetupfuncs=presetupfuncs)
168 peer = _peerorrepo(ui, path, create, presetupfuncs=presetupfuncs)
169 repo = peer.local()
169 repo = peer.local()
170 if not repo:
170 if not repo:
171 raise error.Abort(_("repository '%s' is not local") %
171 raise error.Abort(_("repository '%s' is not local") %
172 (path or peer.url()))
172 (path or peer.url()))
173 return repo.filtered('visible')
173 return repo.filtered('visible')
174
174
175 def peer(uiorrepo, opts, path, create=False):
175 def peer(uiorrepo, opts, path, create=False):
176 '''return a repository peer for the specified path'''
176 '''return a repository peer for the specified path'''
177 rui = remoteui(uiorrepo, opts)
177 rui = remoteui(uiorrepo, opts)
178 return _peerorrepo(rui, path, create).peer()
178 return _peerorrepo(rui, path, create).peer()
179
179
180 def defaultdest(source):
180 def defaultdest(source):
181 '''return default destination of clone if none is given
181 '''return default destination of clone if none is given
182
182
183 >>> defaultdest(b'foo')
183 >>> defaultdest(b'foo')
184 'foo'
184 'foo'
185 >>> defaultdest(b'/foo/bar')
185 >>> defaultdest(b'/foo/bar')
186 'bar'
186 'bar'
187 >>> defaultdest(b'/')
187 >>> defaultdest(b'/')
188 ''
188 ''
189 >>> defaultdest(b'')
189 >>> defaultdest(b'')
190 ''
190 ''
191 >>> defaultdest(b'http://example.org/')
191 >>> defaultdest(b'http://example.org/')
192 ''
192 ''
193 >>> defaultdest(b'http://example.org/foo/')
193 >>> defaultdest(b'http://example.org/foo/')
194 'foo'
194 'foo'
195 '''
195 '''
196 path = util.url(source).path
196 path = util.url(source).path
197 if not path:
197 if not path:
198 return ''
198 return ''
199 return os.path.basename(os.path.normpath(path))
199 return os.path.basename(os.path.normpath(path))
200
200
201 def share(ui, source, dest=None, update=True, bookmarks=True, defaultpath=None,
201 def share(ui, source, dest=None, update=True, bookmarks=True, defaultpath=None,
202 relative=False):
202 relative=False):
203 '''create a shared repository'''
203 '''create a shared repository'''
204
204
205 if not islocal(source):
205 if not islocal(source):
206 raise error.Abort(_('can only share local repositories'))
206 raise error.Abort(_('can only share local repositories'))
207
207
208 if not dest:
208 if not dest:
209 dest = defaultdest(source)
209 dest = defaultdest(source)
210 else:
210 else:
211 dest = ui.expandpath(dest)
211 dest = ui.expandpath(dest)
212
212
213 if isinstance(source, str):
213 if isinstance(source, str):
214 origsource = ui.expandpath(source)
214 origsource = ui.expandpath(source)
215 source, branches = parseurl(origsource)
215 source, branches = parseurl(origsource)
216 srcrepo = repository(ui, source)
216 srcrepo = repository(ui, source)
217 rev, checkout = addbranchrevs(srcrepo, srcrepo, branches, None)
217 rev, checkout = addbranchrevs(srcrepo, srcrepo, branches, None)
218 else:
218 else:
219 srcrepo = source.local()
219 srcrepo = source.local()
220 origsource = source = srcrepo.url()
220 origsource = source = srcrepo.url()
221 checkout = None
221 checkout = None
222
222
223 sharedpath = srcrepo.sharedpath # if our source is already sharing
223 sharedpath = srcrepo.sharedpath # if our source is already sharing
224
224
225 destwvfs = vfsmod.vfs(dest, realpath=True)
225 destwvfs = vfsmod.vfs(dest, realpath=True)
226 destvfs = vfsmod.vfs(os.path.join(destwvfs.base, '.hg'), realpath=True)
226 destvfs = vfsmod.vfs(os.path.join(destwvfs.base, '.hg'), realpath=True)
227
227
228 if destvfs.lexists():
228 if destvfs.lexists():
229 raise error.Abort(_('destination already exists'))
229 raise error.Abort(_('destination already exists'))
230
230
231 if not destwvfs.isdir():
231 if not destwvfs.isdir():
232 destwvfs.mkdir()
232 destwvfs.mkdir()
233 destvfs.makedir()
233 destvfs.makedir()
234
234
235 requirements = ''
235 requirements = ''
236 try:
236 try:
237 requirements = srcrepo.vfs.read('requires')
237 requirements = srcrepo.vfs.read('requires')
238 except IOError as inst:
238 except IOError as inst:
239 if inst.errno != errno.ENOENT:
239 if inst.errno != errno.ENOENT:
240 raise
240 raise
241
241
242 if relative:
242 if relative:
243 try:
243 try:
244 sharedpath = os.path.relpath(sharedpath, destvfs.base)
244 sharedpath = os.path.relpath(sharedpath, destvfs.base)
245 requirements += 'relshared\n'
245 requirements += 'relshared\n'
246 except IOError as e:
246 except IOError as e:
247 raise error.Abort(_('cannot calculate relative path'),
247 raise error.Abort(_('cannot calculate relative path'),
248 hint=str(e))
248 hint=str(e))
249 else:
249 else:
250 requirements += 'shared\n'
250 requirements += 'shared\n'
251
251
252 destvfs.write('requires', requirements)
252 destvfs.write('requires', requirements)
253 destvfs.write('sharedpath', sharedpath)
253 destvfs.write('sharedpath', sharedpath)
254
254
255 r = repository(ui, destwvfs.base)
255 r = repository(ui, destwvfs.base)
256 postshare(srcrepo, r, bookmarks=bookmarks, defaultpath=defaultpath)
256 postshare(srcrepo, r, bookmarks=bookmarks, defaultpath=defaultpath)
257 _postshareupdate(r, update, checkout=checkout)
257 _postshareupdate(r, update, checkout=checkout)
258
258
259 def postshare(sourcerepo, destrepo, bookmarks=True, defaultpath=None):
259 def postshare(sourcerepo, destrepo, bookmarks=True, defaultpath=None):
260 """Called after a new shared repo is created.
260 """Called after a new shared repo is created.
261
261
262 The new repo only has a requirements file and pointer to the source.
262 The new repo only has a requirements file and pointer to the source.
263 This function configures additional shared data.
263 This function configures additional shared data.
264
264
265 Extensions can wrap this function and write additional entries to
265 Extensions can wrap this function and write additional entries to
266 destrepo/.hg/shared to indicate additional pieces of data to be shared.
266 destrepo/.hg/shared to indicate additional pieces of data to be shared.
267 """
267 """
268 default = defaultpath or sourcerepo.ui.config('paths', 'default')
268 default = defaultpath or sourcerepo.ui.config('paths', 'default')
269 if default:
269 if default:
270 fp = destrepo.vfs("hgrc", "w", text=True)
270 fp = destrepo.vfs("hgrc", "w", text=True)
271 fp.write("[paths]\n")
271 fp.write("[paths]\n")
272 fp.write("default = %s\n" % default)
272 fp.write("default = %s\n" % default)
273 fp.close()
273 fp.close()
274
274
275 with destrepo.wlock():
275 with destrepo.wlock():
276 if bookmarks:
276 if bookmarks:
277 fp = destrepo.vfs('shared', 'w')
277 fp = destrepo.vfs('shared', 'w')
278 fp.write(sharedbookmarks + '\n')
278 fp.write(sharedbookmarks + '\n')
279 fp.close()
279 fp.close()
280
280
281 def _postshareupdate(repo, update, checkout=None):
281 def _postshareupdate(repo, update, checkout=None):
282 """Maybe perform a working directory update after a shared repo is created.
282 """Maybe perform a working directory update after a shared repo is created.
283
283
284 ``update`` can be a boolean or a revision to update to.
284 ``update`` can be a boolean or a revision to update to.
285 """
285 """
286 if not update:
286 if not update:
287 return
287 return
288
288
289 repo.ui.status(_("updating working directory\n"))
289 repo.ui.status(_("updating working directory\n"))
290 if update is not True:
290 if update is not True:
291 checkout = update
291 checkout = update
292 for test in (checkout, 'default', 'tip'):
292 for test in (checkout, 'default', 'tip'):
293 if test is None:
293 if test is None:
294 continue
294 continue
295 try:
295 try:
296 uprev = repo.lookup(test)
296 uprev = repo.lookup(test)
297 break
297 break
298 except error.RepoLookupError:
298 except error.RepoLookupError:
299 continue
299 continue
300 _update(repo, uprev)
300 _update(repo, uprev)
301
301
302 def copystore(ui, srcrepo, destpath):
302 def copystore(ui, srcrepo, destpath):
303 '''copy files from store of srcrepo in destpath
303 '''copy files from store of srcrepo in destpath
304
304
305 returns destlock
305 returns destlock
306 '''
306 '''
307 destlock = None
307 destlock = None
308 try:
308 try:
309 hardlink = None
309 hardlink = None
310 num = 0
310 num = 0
311 closetopic = [None]
311 closetopic = [None]
312 def prog(topic, pos):
312 def prog(topic, pos):
313 if pos is None:
313 if pos is None:
314 closetopic[0] = topic
314 closetopic[0] = topic
315 else:
315 else:
316 ui.progress(topic, pos + num)
316 ui.progress(topic, pos + num)
317 srcpublishing = srcrepo.publishing()
317 srcpublishing = srcrepo.publishing()
318 srcvfs = vfsmod.vfs(srcrepo.sharedpath)
318 srcvfs = vfsmod.vfs(srcrepo.sharedpath)
319 dstvfs = vfsmod.vfs(destpath)
319 dstvfs = vfsmod.vfs(destpath)
320 for f in srcrepo.store.copylist():
320 for f in srcrepo.store.copylist():
321 if srcpublishing and f.endswith('phaseroots'):
321 if srcpublishing and f.endswith('phaseroots'):
322 continue
322 continue
323 dstbase = os.path.dirname(f)
323 dstbase = os.path.dirname(f)
324 if dstbase and not dstvfs.exists(dstbase):
324 if dstbase and not dstvfs.exists(dstbase):
325 dstvfs.mkdir(dstbase)
325 dstvfs.mkdir(dstbase)
326 if srcvfs.exists(f):
326 if srcvfs.exists(f):
327 if f.endswith('data'):
327 if f.endswith('data'):
328 # 'dstbase' may be empty (e.g. revlog format 0)
328 # 'dstbase' may be empty (e.g. revlog format 0)
329 lockfile = os.path.join(dstbase, "lock")
329 lockfile = os.path.join(dstbase, "lock")
330 # lock to avoid premature writing to the target
330 # lock to avoid premature writing to the target
331 destlock = lock.lock(dstvfs, lockfile)
331 destlock = lock.lock(dstvfs, lockfile)
332 hardlink, n = util.copyfiles(srcvfs.join(f), dstvfs.join(f),
332 hardlink, n = util.copyfiles(srcvfs.join(f), dstvfs.join(f),
333 hardlink, progress=prog)
333 hardlink, progress=prog)
334 num += n
334 num += n
335 if hardlink:
335 if hardlink:
336 ui.debug("linked %d files\n" % num)
336 ui.debug("linked %d files\n" % num)
337 if closetopic[0]:
337 if closetopic[0]:
338 ui.progress(closetopic[0], None)
338 ui.progress(closetopic[0], None)
339 else:
339 else:
340 ui.debug("copied %d files\n" % num)
340 ui.debug("copied %d files\n" % num)
341 if closetopic[0]:
341 if closetopic[0]:
342 ui.progress(closetopic[0], None)
342 ui.progress(closetopic[0], None)
343 return destlock
343 return destlock
344 except: # re-raises
344 except: # re-raises
345 release(destlock)
345 release(destlock)
346 raise
346 raise
347
347
348 def clonewithshare(ui, peeropts, sharepath, source, srcpeer, dest, pull=False,
348 def clonewithshare(ui, peeropts, sharepath, source, srcpeer, dest, pull=False,
349 rev=None, update=True, stream=False):
349 rev=None, update=True, stream=False):
350 """Perform a clone using a shared repo.
350 """Perform a clone using a shared repo.
351
351
352 The store for the repository will be located at <sharepath>/.hg. The
352 The store for the repository will be located at <sharepath>/.hg. The
353 specified revisions will be cloned or pulled from "source". A shared repo
353 specified revisions will be cloned or pulled from "source". A shared repo
354 will be created at "dest" and a working copy will be created if "update" is
354 will be created at "dest" and a working copy will be created if "update" is
355 True.
355 True.
356 """
356 """
357 revs = None
357 revs = None
358 if rev:
358 if rev:
359 if not srcpeer.capable('lookup'):
359 if not srcpeer.capable('lookup'):
360 raise error.Abort(_("src repository does not support "
360 raise error.Abort(_("src repository does not support "
361 "revision lookup and so doesn't "
361 "revision lookup and so doesn't "
362 "support clone by revision"))
362 "support clone by revision"))
363 revs = [srcpeer.lookup(r) for r in rev]
363 revs = [srcpeer.lookup(r) for r in rev]
364
364
365 # Obtain a lock before checking for or cloning the pooled repo otherwise
365 # Obtain a lock before checking for or cloning the pooled repo otherwise
366 # 2 clients may race creating or populating it.
366 # 2 clients may race creating or populating it.
367 pooldir = os.path.dirname(sharepath)
367 pooldir = os.path.dirname(sharepath)
368 # lock class requires the directory to exist.
368 # lock class requires the directory to exist.
369 try:
369 try:
370 util.makedir(pooldir, False)
370 util.makedir(pooldir, False)
371 except OSError as e:
371 except OSError as e:
372 if e.errno != errno.EEXIST:
372 if e.errno != errno.EEXIST:
373 raise
373 raise
374
374
375 poolvfs = vfsmod.vfs(pooldir)
375 poolvfs = vfsmod.vfs(pooldir)
376 basename = os.path.basename(sharepath)
376 basename = os.path.basename(sharepath)
377
377
378 with lock.lock(poolvfs, '%s.lock' % basename):
378 with lock.lock(poolvfs, '%s.lock' % basename):
379 if os.path.exists(sharepath):
379 if os.path.exists(sharepath):
380 ui.status(_('(sharing from existing pooled repository %s)\n') %
380 ui.status(_('(sharing from existing pooled repository %s)\n') %
381 basename)
381 basename)
382 else:
382 else:
383 ui.status(_('(sharing from new pooled repository %s)\n') % basename)
383 ui.status(_('(sharing from new pooled repository %s)\n') % basename)
384 # Always use pull mode because hardlinks in share mode don't work
384 # Always use pull mode because hardlinks in share mode don't work
385 # well. Never update because working copies aren't necessary in
385 # well. Never update because working copies aren't necessary in
386 # share mode.
386 # share mode.
387 clone(ui, peeropts, source, dest=sharepath, pull=True,
387 clone(ui, peeropts, source, dest=sharepath, pull=True,
388 rev=rev, update=False, stream=stream)
388 rev=rev, update=False, stream=stream)
389
389
390 # Resolve the value to put in [paths] section for the source.
390 # Resolve the value to put in [paths] section for the source.
391 if islocal(source):
391 if islocal(source):
392 defaultpath = os.path.abspath(util.urllocalpath(source))
392 defaultpath = os.path.abspath(util.urllocalpath(source))
393 else:
393 else:
394 defaultpath = source
394 defaultpath = source
395
395
396 sharerepo = repository(ui, path=sharepath)
396 sharerepo = repository(ui, path=sharepath)
397 share(ui, sharerepo, dest=dest, update=False, bookmarks=False,
397 share(ui, sharerepo, dest=dest, update=False, bookmarks=False,
398 defaultpath=defaultpath)
398 defaultpath=defaultpath)
399
399
400 # We need to perform a pull against the dest repo to fetch bookmarks
400 # We need to perform a pull against the dest repo to fetch bookmarks
401 # and other non-store data that isn't shared by default. In the case of
401 # and other non-store data that isn't shared by default. In the case of
402 # non-existing shared repo, this means we pull from the remote twice. This
402 # non-existing shared repo, this means we pull from the remote twice. This
403 # is a bit weird. But at the time it was implemented, there wasn't an easy
403 # is a bit weird. But at the time it was implemented, there wasn't an easy
404 # way to pull just non-changegroup data.
404 # way to pull just non-changegroup data.
405 destrepo = repository(ui, path=dest)
405 destrepo = repository(ui, path=dest)
406 exchange.pull(destrepo, srcpeer, heads=revs)
406 exchange.pull(destrepo, srcpeer, heads=revs)
407
407
408 _postshareupdate(destrepo, update)
408 _postshareupdate(destrepo, update)
409
409
410 return srcpeer, peer(ui, peeropts, dest)
410 return srcpeer, peer(ui, peeropts, dest)
411
411
412 # Recomputing branch cache might be slow on big repos,
412 # Recomputing branch cache might be slow on big repos,
413 # so just copy it
413 # so just copy it
414 def _copycache(srcrepo, dstcachedir, fname):
414 def _copycache(srcrepo, dstcachedir, fname):
415 """copy a cache from srcrepo to destcachedir (if it exists)"""
415 """copy a cache from srcrepo to destcachedir (if it exists)"""
416 srcbranchcache = srcrepo.vfs.join('cache/%s' % fname)
416 srcbranchcache = srcrepo.vfs.join('cache/%s' % fname)
417 dstbranchcache = os.path.join(dstcachedir, fname)
417 dstbranchcache = os.path.join(dstcachedir, fname)
418 if os.path.exists(srcbranchcache):
418 if os.path.exists(srcbranchcache):
419 if not os.path.exists(dstcachedir):
419 if not os.path.exists(dstcachedir):
420 os.mkdir(dstcachedir)
420 os.mkdir(dstcachedir)
421 util.copyfile(srcbranchcache, dstbranchcache)
421 util.copyfile(srcbranchcache, dstbranchcache)
422
422
423 def _cachetocopy(srcrepo):
423 def _cachetocopy(srcrepo):
424 """return the list of cache file valuable to copy during a clone"""
424 """return the list of cache file valuable to copy during a clone"""
425 # In local clones we're copying all nodes, not just served
425 # In local clones we're copying all nodes, not just served
426 # ones. Therefore copy all branch caches over.
426 # ones. Therefore copy all branch caches over.
427 cachefiles = ['branch2']
427 cachefiles = ['branch2']
428 cachefiles += ['branch2-%s' % f for f in repoview.filtertable]
428 cachefiles += ['branch2-%s' % f for f in repoview.filtertable]
429 cachefiles += ['rbc-names-v1', 'rbc-revs-v1']
429 cachefiles += ['rbc-names-v1', 'rbc-revs-v1']
430 cachefiles += ['tags2']
430 cachefiles += ['tags2']
431 cachefiles += ['tags2-%s' % f for f in repoview.filtertable]
431 cachefiles += ['tags2-%s' % f for f in repoview.filtertable]
432 cachefiles += ['hgtagsfnodes1']
432 cachefiles += ['hgtagsfnodes1']
433 return cachefiles
433 return cachefiles
434
434
435 def clone(ui, peeropts, source, dest=None, pull=False, rev=None,
435 def clone(ui, peeropts, source, dest=None, pull=False, rev=None,
436 update=True, stream=False, branch=None, shareopts=None):
436 update=True, stream=False, branch=None, shareopts=None):
437 """Make a copy of an existing repository.
437 """Make a copy of an existing repository.
438
438
439 Create a copy of an existing repository in a new directory. The
439 Create a copy of an existing repository in a new directory. The
440 source and destination are URLs, as passed to the repository
440 source and destination are URLs, as passed to the repository
441 function. Returns a pair of repository peers, the source and
441 function. Returns a pair of repository peers, the source and
442 newly created destination.
442 newly created destination.
443
443
444 The location of the source is added to the new repository's
444 The location of the source is added to the new repository's
445 .hg/hgrc file, as the default to be used for future pulls and
445 .hg/hgrc file, as the default to be used for future pulls and
446 pushes.
446 pushes.
447
447
448 If an exception is raised, the partly cloned/updated destination
448 If an exception is raised, the partly cloned/updated destination
449 repository will be deleted.
449 repository will be deleted.
450
450
451 Arguments:
451 Arguments:
452
452
453 source: repository object or URL
453 source: repository object or URL
454
454
455 dest: URL of destination repository to create (defaults to base
455 dest: URL of destination repository to create (defaults to base
456 name of source repository)
456 name of source repository)
457
457
458 pull: always pull from source repository, even in local case or if the
458 pull: always pull from source repository, even in local case or if the
459 server prefers streaming
459 server prefers streaming
460
460
461 stream: stream raw data uncompressed from repository (fast over
461 stream: stream raw data uncompressed from repository (fast over
462 LAN, slow over WAN)
462 LAN, slow over WAN)
463
463
464 rev: revision to clone up to (implies pull=True)
464 rev: revision to clone up to (implies pull=True)
465
465
466 update: update working directory after clone completes, if
466 update: update working directory after clone completes, if
467 destination is local repository (True means update to default rev,
467 destination is local repository (True means update to default rev,
468 anything else is treated as a revision)
468 anything else is treated as a revision)
469
469
470 branch: branches to clone
470 branch: branches to clone
471
471
472 shareopts: dict of options to control auto sharing behavior. The "pool" key
472 shareopts: dict of options to control auto sharing behavior. The "pool" key
473 activates auto sharing mode and defines the directory for stores. The
473 activates auto sharing mode and defines the directory for stores. The
474 "mode" key determines how to construct the directory name of the shared
474 "mode" key determines how to construct the directory name of the shared
475 repository. "identity" means the name is derived from the node of the first
475 repository. "identity" means the name is derived from the node of the first
476 changeset in the repository. "remote" means the name is derived from the
476 changeset in the repository. "remote" means the name is derived from the
477 remote's path/URL. Defaults to "identity."
477 remote's path/URL. Defaults to "identity."
478 """
478 """
479
479
480 if isinstance(source, bytes):
480 if isinstance(source, bytes):
481 origsource = ui.expandpath(source)
481 origsource = ui.expandpath(source)
482 source, branch = parseurl(origsource, branch)
482 source, branch = parseurl(origsource, branch)
483 srcpeer = peer(ui, peeropts, source)
483 srcpeer = peer(ui, peeropts, source)
484 else:
484 else:
485 srcpeer = source.peer() # in case we were called with a localrepo
485 srcpeer = source.peer() # in case we were called with a localrepo
486 branch = (None, branch or [])
486 branch = (None, branch or [])
487 origsource = source = srcpeer.url()
487 origsource = source = srcpeer.url()
488 rev, checkout = addbranchrevs(srcpeer, srcpeer, branch, rev)
488 rev, checkout = addbranchrevs(srcpeer, srcpeer, branch, rev)
489
489
490 if dest is None:
490 if dest is None:
491 dest = defaultdest(source)
491 dest = defaultdest(source)
492 if dest:
492 if dest:
493 ui.status(_("destination directory: %s\n") % dest)
493 ui.status(_("destination directory: %s\n") % dest)
494 else:
494 else:
495 dest = ui.expandpath(dest)
495 dest = ui.expandpath(dest)
496
496
497 dest = util.urllocalpath(dest)
497 dest = util.urllocalpath(dest)
498 source = util.urllocalpath(source)
498 source = util.urllocalpath(source)
499
499
500 if not dest:
500 if not dest:
501 raise error.Abort(_("empty destination path is not valid"))
501 raise error.Abort(_("empty destination path is not valid"))
502
502
503 destvfs = vfsmod.vfs(dest, expandpath=True)
503 destvfs = vfsmod.vfs(dest, expandpath=True)
504 if destvfs.lexists():
504 if destvfs.lexists():
505 if not destvfs.isdir():
505 if not destvfs.isdir():
506 raise error.Abort(_("destination '%s' already exists") % dest)
506 raise error.Abort(_("destination '%s' already exists") % dest)
507 elif destvfs.listdir():
507 elif destvfs.listdir():
508 raise error.Abort(_("destination '%s' is not empty") % dest)
508 raise error.Abort(_("destination '%s' is not empty") % dest)
509
509
510 shareopts = shareopts or {}
510 shareopts = shareopts or {}
511 sharepool = shareopts.get('pool')
511 sharepool = shareopts.get('pool')
512 sharenamemode = shareopts.get('mode')
512 sharenamemode = shareopts.get('mode')
513 if sharepool and islocal(dest):
513 if sharepool and islocal(dest):
514 sharepath = None
514 sharepath = None
515 if sharenamemode == 'identity':
515 if sharenamemode == 'identity':
516 # Resolve the name from the initial changeset in the remote
516 # Resolve the name from the initial changeset in the remote
517 # repository. This returns nullid when the remote is empty. It
517 # repository. This returns nullid when the remote is empty. It
518 # raises RepoLookupError if revision 0 is filtered or otherwise
518 # raises RepoLookupError if revision 0 is filtered or otherwise
519 # not available. If we fail to resolve, sharing is not enabled.
519 # not available. If we fail to resolve, sharing is not enabled.
520 try:
520 try:
521 rootnode = srcpeer.lookup('0')
521 rootnode = srcpeer.lookup('0')
522 if rootnode != node.nullid:
522 if rootnode != node.nullid:
523 sharepath = os.path.join(sharepool, node.hex(rootnode))
523 sharepath = os.path.join(sharepool, node.hex(rootnode))
524 else:
524 else:
525 ui.status(_('(not using pooled storage: '
525 ui.status(_('(not using pooled storage: '
526 'remote appears to be empty)\n'))
526 'remote appears to be empty)\n'))
527 except error.RepoLookupError:
527 except error.RepoLookupError:
528 ui.status(_('(not using pooled storage: '
528 ui.status(_('(not using pooled storage: '
529 'unable to resolve identity of remote)\n'))
529 'unable to resolve identity of remote)\n'))
530 elif sharenamemode == 'remote':
530 elif sharenamemode == 'remote':
531 sharepath = os.path.join(
531 sharepath = os.path.join(
532 sharepool, hashlib.sha1(source).hexdigest())
532 sharepool, hashlib.sha1(source).hexdigest())
533 else:
533 else:
534 raise error.Abort(_('unknown share naming mode: %s') %
534 raise error.Abort(_('unknown share naming mode: %s') %
535 sharenamemode)
535 sharenamemode)
536
536
537 if sharepath:
537 if sharepath:
538 return clonewithshare(ui, peeropts, sharepath, source, srcpeer,
538 return clonewithshare(ui, peeropts, sharepath, source, srcpeer,
539 dest, pull=pull, rev=rev, update=update,
539 dest, pull=pull, rev=rev, update=update,
540 stream=stream)
540 stream=stream)
541
541
542 srclock = destlock = cleandir = None
542 srclock = destlock = cleandir = None
543 srcrepo = srcpeer.local()
543 srcrepo = srcpeer.local()
544 try:
544 try:
545 abspath = origsource
545 abspath = origsource
546 if islocal(origsource):
546 if islocal(origsource):
547 abspath = os.path.abspath(util.urllocalpath(origsource))
547 abspath = os.path.abspath(util.urllocalpath(origsource))
548
548
549 if islocal(dest):
549 if islocal(dest):
550 cleandir = dest
550 cleandir = dest
551
551
552 copy = False
552 copy = False
553 if (srcrepo and srcrepo.cancopy() and islocal(dest)
553 if (srcrepo and srcrepo.cancopy() and islocal(dest)
554 and not phases.hassecret(srcrepo)):
554 and not phases.hassecret(srcrepo)):
555 copy = not pull and not rev
555 copy = not pull and not rev
556
556
557 if copy:
557 if copy:
558 try:
558 try:
559 # we use a lock here because if we race with commit, we
559 # we use a lock here because if we race with commit, we
560 # can end up with extra data in the cloned revlogs that's
560 # can end up with extra data in the cloned revlogs that's
561 # not pointed to by changesets, thus causing verify to
561 # not pointed to by changesets, thus causing verify to
562 # fail
562 # fail
563 srclock = srcrepo.lock(wait=False)
563 srclock = srcrepo.lock(wait=False)
564 except error.LockError:
564 except error.LockError:
565 copy = False
565 copy = False
566
566
567 if copy:
567 if copy:
568 srcrepo.hook('preoutgoing', throw=True, source='clone')
568 srcrepo.hook('preoutgoing', throw=True, source='clone')
569 hgdir = os.path.realpath(os.path.join(dest, ".hg"))
569 hgdir = os.path.realpath(os.path.join(dest, ".hg"))
570 if not os.path.exists(dest):
570 if not os.path.exists(dest):
571 os.mkdir(dest)
571 os.mkdir(dest)
572 else:
572 else:
573 # only clean up directories we create ourselves
573 # only clean up directories we create ourselves
574 cleandir = hgdir
574 cleandir = hgdir
575 try:
575 try:
576 destpath = hgdir
576 destpath = hgdir
577 util.makedir(destpath, notindexed=True)
577 util.makedir(destpath, notindexed=True)
578 except OSError as inst:
578 except OSError as inst:
579 if inst.errno == errno.EEXIST:
579 if inst.errno == errno.EEXIST:
580 cleandir = None
580 cleandir = None
581 raise error.Abort(_("destination '%s' already exists")
581 raise error.Abort(_("destination '%s' already exists")
582 % dest)
582 % dest)
583 raise
583 raise
584
584
585 destlock = copystore(ui, srcrepo, destpath)
585 destlock = copystore(ui, srcrepo, destpath)
586 # copy bookmarks over
586 # copy bookmarks over
587 srcbookmarks = srcrepo.vfs.join('bookmarks')
587 srcbookmarks = srcrepo.vfs.join('bookmarks')
588 dstbookmarks = os.path.join(destpath, 'bookmarks')
588 dstbookmarks = os.path.join(destpath, 'bookmarks')
589 if os.path.exists(srcbookmarks):
589 if os.path.exists(srcbookmarks):
590 util.copyfile(srcbookmarks, dstbookmarks)
590 util.copyfile(srcbookmarks, dstbookmarks)
591
591
592 dstcachedir = os.path.join(destpath, 'cache')
592 dstcachedir = os.path.join(destpath, 'cache')
593 for cache in _cachetocopy(srcrepo):
593 for cache in _cachetocopy(srcrepo):
594 _copycache(srcrepo, dstcachedir, cache)
594 _copycache(srcrepo, dstcachedir, cache)
595
595
596 # we need to re-init the repo after manually copying the data
596 # we need to re-init the repo after manually copying the data
597 # into it
597 # into it
598 destpeer = peer(srcrepo, peeropts, dest)
598 destpeer = peer(srcrepo, peeropts, dest)
599 srcrepo.hook('outgoing', source='clone',
599 srcrepo.hook('outgoing', source='clone',
600 node=node.hex(node.nullid))
600 node=node.hex(node.nullid))
601 else:
601 else:
602 try:
602 try:
603 destpeer = peer(srcrepo or ui, peeropts, dest, create=True)
603 destpeer = peer(srcrepo or ui, peeropts, dest, create=True)
604 # only pass ui when no srcrepo
604 # only pass ui when no srcrepo
605 except OSError as inst:
605 except OSError as inst:
606 if inst.errno == errno.EEXIST:
606 if inst.errno == errno.EEXIST:
607 cleandir = None
607 cleandir = None
608 raise error.Abort(_("destination '%s' already exists")
608 raise error.Abort(_("destination '%s' already exists")
609 % dest)
609 % dest)
610 raise
610 raise
611
611
612 revs = None
612 revs = None
613 if rev:
613 if rev:
614 if not srcpeer.capable('lookup'):
614 if not srcpeer.capable('lookup'):
615 raise error.Abort(_("src repository does not support "
615 raise error.Abort(_("src repository does not support "
616 "revision lookup and so doesn't "
616 "revision lookup and so doesn't "
617 "support clone by revision"))
617 "support clone by revision"))
618 revs = [srcpeer.lookup(r) for r in rev]
618 revs = [srcpeer.lookup(r) for r in rev]
619 checkout = revs[0]
619 checkout = revs[0]
620 local = destpeer.local()
620 local = destpeer.local()
621 if local:
621 if local:
622 if not stream:
622 if not stream:
623 if pull:
623 if pull:
624 stream = False
624 stream = False
625 else:
625 else:
626 stream = None
626 stream = None
627 # internal config: ui.quietbookmarkmove
627 # internal config: ui.quietbookmarkmove
628 overrides = {('ui', 'quietbookmarkmove'): True}
628 overrides = {('ui', 'quietbookmarkmove'): True}
629 with local.ui.configoverride(overrides, 'clone'):
629 with local.ui.configoverride(overrides, 'clone'):
630 exchange.pull(local, srcpeer, revs,
630 exchange.pull(local, srcpeer, revs,
631 streamclonerequested=stream)
631 streamclonerequested=stream)
632 elif srcrepo:
632 elif srcrepo:
633 exchange.push(srcrepo, destpeer, revs=revs,
633 exchange.push(srcrepo, destpeer, revs=revs,
634 bookmarks=srcrepo._bookmarks.keys())
634 bookmarks=srcrepo._bookmarks.keys())
635 else:
635 else:
636 raise error.Abort(_("clone from remote to remote not supported")
636 raise error.Abort(_("clone from remote to remote not supported")
637 )
637 )
638
638
639 cleandir = None
639 cleandir = None
640
640
641 destrepo = destpeer.local()
641 destrepo = destpeer.local()
642 if destrepo:
642 if destrepo:
643 template = uimod.samplehgrcs['cloned']
643 template = uimod.samplehgrcs['cloned']
644 fp = destrepo.vfs("hgrc", "wb")
644 fp = destrepo.vfs("hgrc", "wb")
645 u = util.url(abspath)
645 u = util.url(abspath)
646 u.passwd = None
646 u.passwd = None
647 defaulturl = bytes(u)
647 defaulturl = bytes(u)
648 fp.write(util.tonativeeol(template % defaulturl))
648 fp.write(util.tonativeeol(template % defaulturl))
649 fp.close()
649 fp.close()
650
650
651 destrepo.ui.setconfig('paths', 'default', defaulturl, 'clone')
651 destrepo.ui.setconfig('paths', 'default', defaulturl, 'clone')
652
652
653 if update:
653 if update:
654 if update is not True:
654 if update is not True:
655 checkout = srcpeer.lookup(update)
655 checkout = srcpeer.lookup(update)
656 uprev = None
656 uprev = None
657 status = None
657 status = None
658 if checkout is not None:
658 if checkout is not None:
659 try:
659 try:
660 uprev = destrepo.lookup(checkout)
660 uprev = destrepo.lookup(checkout)
661 except error.RepoLookupError:
661 except error.RepoLookupError:
662 if update is not True:
662 if update is not True:
663 try:
663 try:
664 uprev = destrepo.lookup(update)
664 uprev = destrepo.lookup(update)
665 except error.RepoLookupError:
665 except error.RepoLookupError:
666 pass
666 pass
667 if uprev is None:
667 if uprev is None:
668 try:
668 try:
669 uprev = destrepo._bookmarks['@']
669 uprev = destrepo._bookmarks['@']
670 update = '@'
670 update = '@'
671 bn = destrepo[uprev].branch()
671 bn = destrepo[uprev].branch()
672 if bn == 'default':
672 if bn == 'default':
673 status = _("updating to bookmark @\n")
673 status = _("updating to bookmark @\n")
674 else:
674 else:
675 status = (_("updating to bookmark @ on branch %s\n")
675 status = (_("updating to bookmark @ on branch %s\n")
676 % bn)
676 % bn)
677 except KeyError:
677 except KeyError:
678 try:
678 try:
679 uprev = destrepo.branchtip('default')
679 uprev = destrepo.branchtip('default')
680 except error.RepoLookupError:
680 except error.RepoLookupError:
681 uprev = destrepo.lookup('tip')
681 uprev = destrepo.lookup('tip')
682 if not status:
682 if not status:
683 bn = destrepo[uprev].branch()
683 bn = destrepo[uprev].branch()
684 status = _("updating to branch %s\n") % bn
684 status = _("updating to branch %s\n") % bn
685 destrepo.ui.status(status)
685 destrepo.ui.status(status)
686 _update(destrepo, uprev)
686 _update(destrepo, uprev)
687 if update in destrepo._bookmarks:
687 if update in destrepo._bookmarks:
688 bookmarks.activate(destrepo, update)
688 bookmarks.activate(destrepo, update)
689 finally:
689 finally:
690 release(srclock, destlock)
690 release(srclock, destlock)
691 if cleandir is not None:
691 if cleandir is not None:
692 shutil.rmtree(cleandir, True)
692 shutil.rmtree(cleandir, True)
693 if srcpeer is not None:
693 if srcpeer is not None:
694 srcpeer.close()
694 srcpeer.close()
695 return srcpeer, destpeer
695 return srcpeer, destpeer
696
696
697 def _showstats(repo, stats, quietempty=False):
697 def _showstats(repo, stats, quietempty=False):
698 if quietempty and not any(stats):
698 if quietempty and not any(stats):
699 return
699 return
700 repo.ui.status(_("%d files updated, %d files merged, "
700 repo.ui.status(_("%d files updated, %d files merged, "
701 "%d files removed, %d files unresolved\n") % stats)
701 "%d files removed, %d files unresolved\n") % stats)
702
702
703 def updaterepo(repo, node, overwrite, updatecheck=None):
703 def updaterepo(repo, node, overwrite, updatecheck=None):
704 """Update the working directory to node.
704 """Update the working directory to node.
705
705
706 When overwrite is set, changes are clobbered, merged else
706 When overwrite is set, changes are clobbered, merged else
707
707
708 returns stats (see pydoc mercurial.merge.applyupdates)"""
708 returns stats (see pydoc mercurial.merge.applyupdates)"""
709 return mergemod.update(repo, node, False, overwrite,
709 return mergemod.update(repo, node, False, overwrite,
710 labels=['working copy', 'destination'],
710 labels=['working copy', 'destination'],
711 updatecheck=updatecheck)
711 updatecheck=updatecheck)
712
712
713 def update(repo, node, quietempty=False, updatecheck=None):
713 def update(repo, node, quietempty=False, updatecheck=None):
714 """update the working directory to node"""
714 """update the working directory to node"""
715 stats = updaterepo(repo, node, False, updatecheck=updatecheck)
715 stats = updaterepo(repo, node, False, updatecheck=updatecheck)
716 _showstats(repo, stats, quietempty)
716 _showstats(repo, stats, quietempty)
717 if stats[3]:
717 if stats[3]:
718 repo.ui.status(_("use 'hg resolve' to retry unresolved file merges\n"))
718 repo.ui.status(_("use 'hg resolve' to retry unresolved file merges\n"))
719 return stats[3] > 0
719 return stats[3] > 0
720
720
721 # naming conflict in clone()
721 # naming conflict in clone()
722 _update = update
722 _update = update
723
723
724 def clean(repo, node, show_stats=True, quietempty=False):
724 def clean(repo, node, show_stats=True, quietempty=False):
725 """forcibly switch the working directory to node, clobbering changes"""
725 """forcibly switch the working directory to node, clobbering changes"""
726 stats = updaterepo(repo, node, True)
726 stats = updaterepo(repo, node, True)
727 repo.vfs.unlinkpath('graftstate', ignoremissing=True)
727 repo.vfs.unlinkpath('graftstate', ignoremissing=True)
728 if show_stats:
728 if show_stats:
729 _showstats(repo, stats, quietempty)
729 _showstats(repo, stats, quietempty)
730 return stats[3] > 0
730 return stats[3] > 0
731
731
732 # naming conflict in updatetotally()
732 # naming conflict in updatetotally()
733 _clean = clean
733 _clean = clean
734
734
735 def updatetotally(ui, repo, checkout, brev, clean=False, updatecheck=None):
735 def updatetotally(ui, repo, checkout, brev, clean=False, updatecheck=None):
736 """Update the working directory with extra care for non-file components
736 """Update the working directory with extra care for non-file components
737
737
738 This takes care of non-file components below:
738 This takes care of non-file components below:
739
739
740 :bookmark: might be advanced or (in)activated
740 :bookmark: might be advanced or (in)activated
741
741
742 This takes arguments below:
742 This takes arguments below:
743
743
744 :checkout: to which revision the working directory is updated
744 :checkout: to which revision the working directory is updated
745 :brev: a name, which might be a bookmark to be activated after updating
745 :brev: a name, which might be a bookmark to be activated after updating
746 :clean: whether changes in the working directory can be discarded
746 :clean: whether changes in the working directory can be discarded
747 :updatecheck: how to deal with a dirty working directory
747 :updatecheck: how to deal with a dirty working directory
748
748
749 Valid values for updatecheck are (None => linear):
749 Valid values for updatecheck are (None => linear):
750
750
751 * abort: abort if the working directory is dirty
751 * abort: abort if the working directory is dirty
752 * none: don't check (merge working directory changes into destination)
752 * none: don't check (merge working directory changes into destination)
753 * linear: check that update is linear before merging working directory
753 * linear: check that update is linear before merging working directory
754 changes into destination
754 changes into destination
755 * noconflict: check that the update does not result in file merges
755 * noconflict: check that the update does not result in file merges
756
756
757 This returns whether conflict is detected at updating or not.
757 This returns whether conflict is detected at updating or not.
758 """
758 """
759 if updatecheck is None:
759 if updatecheck is None:
760 updatecheck = ui.config('commands', 'update.check')
760 updatecheck = ui.config('commands', 'update.check')
761 if updatecheck is None:
762 # pre-4.4 compat on the old spelling of this config item
763 updatecheck = ui.config('experimental', 'updatecheck')
764 if updatecheck not in ('abort', 'none', 'linear', 'noconflict'):
761 if updatecheck not in ('abort', 'none', 'linear', 'noconflict'):
765 # If not configured, or invalid value configured
762 # If not configured, or invalid value configured
766 updatecheck = 'linear'
763 updatecheck = 'linear'
767 with repo.wlock():
764 with repo.wlock():
768 movemarkfrom = None
765 movemarkfrom = None
769 warndest = False
766 warndest = False
770 if checkout is None:
767 if checkout is None:
771 updata = destutil.destupdate(repo, clean=clean)
768 updata = destutil.destupdate(repo, clean=clean)
772 checkout, movemarkfrom, brev = updata
769 checkout, movemarkfrom, brev = updata
773 warndest = True
770 warndest = True
774
771
775 if clean:
772 if clean:
776 ret = _clean(repo, checkout)
773 ret = _clean(repo, checkout)
777 else:
774 else:
778 if updatecheck == 'abort':
775 if updatecheck == 'abort':
779 cmdutil.bailifchanged(repo, merge=False)
776 cmdutil.bailifchanged(repo, merge=False)
780 updatecheck = 'none'
777 updatecheck = 'none'
781 ret = _update(repo, checkout, updatecheck=updatecheck)
778 ret = _update(repo, checkout, updatecheck=updatecheck)
782
779
783 if not ret and movemarkfrom:
780 if not ret and movemarkfrom:
784 if movemarkfrom == repo['.'].node():
781 if movemarkfrom == repo['.'].node():
785 pass # no-op update
782 pass # no-op update
786 elif bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
783 elif bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
787 b = ui.label(repo._activebookmark, 'bookmarks.active')
784 b = ui.label(repo._activebookmark, 'bookmarks.active')
788 ui.status(_("updating bookmark %s\n") % b)
785 ui.status(_("updating bookmark %s\n") % b)
789 else:
786 else:
790 # this can happen with a non-linear update
787 # this can happen with a non-linear update
791 b = ui.label(repo._activebookmark, 'bookmarks')
788 b = ui.label(repo._activebookmark, 'bookmarks')
792 ui.status(_("(leaving bookmark %s)\n") % b)
789 ui.status(_("(leaving bookmark %s)\n") % b)
793 bookmarks.deactivate(repo)
790 bookmarks.deactivate(repo)
794 elif brev in repo._bookmarks:
791 elif brev in repo._bookmarks:
795 if brev != repo._activebookmark:
792 if brev != repo._activebookmark:
796 b = ui.label(brev, 'bookmarks.active')
793 b = ui.label(brev, 'bookmarks.active')
797 ui.status(_("(activating bookmark %s)\n") % b)
794 ui.status(_("(activating bookmark %s)\n") % b)
798 bookmarks.activate(repo, brev)
795 bookmarks.activate(repo, brev)
799 elif brev:
796 elif brev:
800 if repo._activebookmark:
797 if repo._activebookmark:
801 b = ui.label(repo._activebookmark, 'bookmarks')
798 b = ui.label(repo._activebookmark, 'bookmarks')
802 ui.status(_("(leaving bookmark %s)\n") % b)
799 ui.status(_("(leaving bookmark %s)\n") % b)
803 bookmarks.deactivate(repo)
800 bookmarks.deactivate(repo)
804
801
805 if warndest:
802 if warndest:
806 destutil.statusotherdests(ui, repo)
803 destutil.statusotherdests(ui, repo)
807
804
808 return ret
805 return ret
809
806
810 def merge(repo, node, force=None, remind=True, mergeforce=False, labels=None):
807 def merge(repo, node, force=None, remind=True, mergeforce=False, labels=None):
811 """Branch merge with node, resolving changes. Return true if any
808 """Branch merge with node, resolving changes. Return true if any
812 unresolved conflicts."""
809 unresolved conflicts."""
813 stats = mergemod.update(repo, node, True, force, mergeforce=mergeforce,
810 stats = mergemod.update(repo, node, True, force, mergeforce=mergeforce,
814 labels=labels)
811 labels=labels)
815 _showstats(repo, stats)
812 _showstats(repo, stats)
816 if stats[3]:
813 if stats[3]:
817 repo.ui.status(_("use 'hg resolve' to retry unresolved file merges "
814 repo.ui.status(_("use 'hg resolve' to retry unresolved file merges "
818 "or 'hg update -C .' to abandon\n"))
815 "or 'hg update -C .' to abandon\n"))
819 elif remind:
816 elif remind:
820 repo.ui.status(_("(branch merge, don't forget to commit)\n"))
817 repo.ui.status(_("(branch merge, don't forget to commit)\n"))
821 return stats[3] > 0
818 return stats[3] > 0
822
819
823 def _incoming(displaychlist, subreporecurse, ui, repo, source,
820 def _incoming(displaychlist, subreporecurse, ui, repo, source,
824 opts, buffered=False):
821 opts, buffered=False):
825 """
822 """
826 Helper for incoming / gincoming.
823 Helper for incoming / gincoming.
827 displaychlist gets called with
824 displaychlist gets called with
828 (remoterepo, incomingchangesetlist, displayer) parameters,
825 (remoterepo, incomingchangesetlist, displayer) parameters,
829 and is supposed to contain only code that can't be unified.
826 and is supposed to contain only code that can't be unified.
830 """
827 """
831 source, branches = parseurl(ui.expandpath(source), opts.get('branch'))
828 source, branches = parseurl(ui.expandpath(source), opts.get('branch'))
832 other = peer(repo, opts, source)
829 other = peer(repo, opts, source)
833 ui.status(_('comparing with %s\n') % util.hidepassword(source))
830 ui.status(_('comparing with %s\n') % util.hidepassword(source))
834 revs, checkout = addbranchrevs(repo, other, branches, opts.get('rev'))
831 revs, checkout = addbranchrevs(repo, other, branches, opts.get('rev'))
835
832
836 if revs:
833 if revs:
837 revs = [other.lookup(rev) for rev in revs]
834 revs = [other.lookup(rev) for rev in revs]
838 other, chlist, cleanupfn = bundlerepo.getremotechanges(ui, repo, other,
835 other, chlist, cleanupfn = bundlerepo.getremotechanges(ui, repo, other,
839 revs, opts["bundle"], opts["force"])
836 revs, opts["bundle"], opts["force"])
840 try:
837 try:
841 if not chlist:
838 if not chlist:
842 ui.status(_("no changes found\n"))
839 ui.status(_("no changes found\n"))
843 return subreporecurse()
840 return subreporecurse()
844 ui.pager('incoming')
841 ui.pager('incoming')
845 displayer = cmdutil.show_changeset(ui, other, opts, buffered)
842 displayer = cmdutil.show_changeset(ui, other, opts, buffered)
846 displaychlist(other, chlist, displayer)
843 displaychlist(other, chlist, displayer)
847 displayer.close()
844 displayer.close()
848 finally:
845 finally:
849 cleanupfn()
846 cleanupfn()
850 subreporecurse()
847 subreporecurse()
851 return 0 # exit code is zero since we found incoming changes
848 return 0 # exit code is zero since we found incoming changes
852
849
853 def incoming(ui, repo, source, opts):
850 def incoming(ui, repo, source, opts):
854 def subreporecurse():
851 def subreporecurse():
855 ret = 1
852 ret = 1
856 if opts.get('subrepos'):
853 if opts.get('subrepos'):
857 ctx = repo[None]
854 ctx = repo[None]
858 for subpath in sorted(ctx.substate):
855 for subpath in sorted(ctx.substate):
859 sub = ctx.sub(subpath)
856 sub = ctx.sub(subpath)
860 ret = min(ret, sub.incoming(ui, source, opts))
857 ret = min(ret, sub.incoming(ui, source, opts))
861 return ret
858 return ret
862
859
863 def display(other, chlist, displayer):
860 def display(other, chlist, displayer):
864 limit = cmdutil.loglimit(opts)
861 limit = cmdutil.loglimit(opts)
865 if opts.get('newest_first'):
862 if opts.get('newest_first'):
866 chlist.reverse()
863 chlist.reverse()
867 count = 0
864 count = 0
868 for n in chlist:
865 for n in chlist:
869 if limit is not None and count >= limit:
866 if limit is not None and count >= limit:
870 break
867 break
871 parents = [p for p in other.changelog.parents(n) if p != nullid]
868 parents = [p for p in other.changelog.parents(n) if p != nullid]
872 if opts.get('no_merges') and len(parents) == 2:
869 if opts.get('no_merges') and len(parents) == 2:
873 continue
870 continue
874 count += 1
871 count += 1
875 displayer.show(other[n])
872 displayer.show(other[n])
876 return _incoming(display, subreporecurse, ui, repo, source, opts)
873 return _incoming(display, subreporecurse, ui, repo, source, opts)
877
874
878 def _outgoing(ui, repo, dest, opts):
875 def _outgoing(ui, repo, dest, opts):
879 dest = ui.expandpath(dest or 'default-push', dest or 'default')
876 dest = ui.expandpath(dest or 'default-push', dest or 'default')
880 dest, branches = parseurl(dest, opts.get('branch'))
877 dest, branches = parseurl(dest, opts.get('branch'))
881 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
878 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
882 revs, checkout = addbranchrevs(repo, repo, branches, opts.get('rev'))
879 revs, checkout = addbranchrevs(repo, repo, branches, opts.get('rev'))
883 if revs:
880 if revs:
884 revs = [repo.lookup(rev) for rev in scmutil.revrange(repo, revs)]
881 revs = [repo.lookup(rev) for rev in scmutil.revrange(repo, revs)]
885
882
886 other = peer(repo, opts, dest)
883 other = peer(repo, opts, dest)
887 outgoing = discovery.findcommonoutgoing(repo, other, revs,
884 outgoing = discovery.findcommonoutgoing(repo, other, revs,
888 force=opts.get('force'))
885 force=opts.get('force'))
889 o = outgoing.missing
886 o = outgoing.missing
890 if not o:
887 if not o:
891 scmutil.nochangesfound(repo.ui, repo, outgoing.excluded)
888 scmutil.nochangesfound(repo.ui, repo, outgoing.excluded)
892 return o, other
889 return o, other
893
890
894 def outgoing(ui, repo, dest, opts):
891 def outgoing(ui, repo, dest, opts):
895 def recurse():
892 def recurse():
896 ret = 1
893 ret = 1
897 if opts.get('subrepos'):
894 if opts.get('subrepos'):
898 ctx = repo[None]
895 ctx = repo[None]
899 for subpath in sorted(ctx.substate):
896 for subpath in sorted(ctx.substate):
900 sub = ctx.sub(subpath)
897 sub = ctx.sub(subpath)
901 ret = min(ret, sub.outgoing(ui, dest, opts))
898 ret = min(ret, sub.outgoing(ui, dest, opts))
902 return ret
899 return ret
903
900
904 limit = cmdutil.loglimit(opts)
901 limit = cmdutil.loglimit(opts)
905 o, other = _outgoing(ui, repo, dest, opts)
902 o, other = _outgoing(ui, repo, dest, opts)
906 if not o:
903 if not o:
907 cmdutil.outgoinghooks(ui, repo, other, opts, o)
904 cmdutil.outgoinghooks(ui, repo, other, opts, o)
908 return recurse()
905 return recurse()
909
906
910 if opts.get('newest_first'):
907 if opts.get('newest_first'):
911 o.reverse()
908 o.reverse()
912 ui.pager('outgoing')
909 ui.pager('outgoing')
913 displayer = cmdutil.show_changeset(ui, repo, opts)
910 displayer = cmdutil.show_changeset(ui, repo, opts)
914 count = 0
911 count = 0
915 for n in o:
912 for n in o:
916 if limit is not None and count >= limit:
913 if limit is not None and count >= limit:
917 break
914 break
918 parents = [p for p in repo.changelog.parents(n) if p != nullid]
915 parents = [p for p in repo.changelog.parents(n) if p != nullid]
919 if opts.get('no_merges') and len(parents) == 2:
916 if opts.get('no_merges') and len(parents) == 2:
920 continue
917 continue
921 count += 1
918 count += 1
922 displayer.show(repo[n])
919 displayer.show(repo[n])
923 displayer.close()
920 displayer.close()
924 cmdutil.outgoinghooks(ui, repo, other, opts, o)
921 cmdutil.outgoinghooks(ui, repo, other, opts, o)
925 recurse()
922 recurse()
926 return 0 # exit code is zero since we found outgoing changes
923 return 0 # exit code is zero since we found outgoing changes
927
924
928 def verify(repo):
925 def verify(repo):
929 """verify the consistency of a repository"""
926 """verify the consistency of a repository"""
930 ret = verifymod.verify(repo)
927 ret = verifymod.verify(repo)
931
928
932 # Broken subrepo references in hidden csets don't seem worth worrying about,
929 # Broken subrepo references in hidden csets don't seem worth worrying about,
933 # since they can't be pushed/pulled, and --hidden can be used if they are a
930 # since they can't be pushed/pulled, and --hidden can be used if they are a
934 # concern.
931 # concern.
935
932
936 # pathto() is needed for -R case
933 # pathto() is needed for -R case
937 revs = repo.revs("filelog(%s)",
934 revs = repo.revs("filelog(%s)",
938 util.pathto(repo.root, repo.getcwd(), '.hgsubstate'))
935 util.pathto(repo.root, repo.getcwd(), '.hgsubstate'))
939
936
940 if revs:
937 if revs:
941 repo.ui.status(_('checking subrepo links\n'))
938 repo.ui.status(_('checking subrepo links\n'))
942 for rev in revs:
939 for rev in revs:
943 ctx = repo[rev]
940 ctx = repo[rev]
944 try:
941 try:
945 for subpath in ctx.substate:
942 for subpath in ctx.substate:
946 try:
943 try:
947 ret = (ctx.sub(subpath, allowcreate=False).verify()
944 ret = (ctx.sub(subpath, allowcreate=False).verify()
948 or ret)
945 or ret)
949 except error.RepoError as e:
946 except error.RepoError as e:
950 repo.ui.warn(('%s: %s\n') % (rev, e))
947 repo.ui.warn(('%s: %s\n') % (rev, e))
951 except Exception:
948 except Exception:
952 repo.ui.warn(_('.hgsubstate is corrupt in revision %s\n') %
949 repo.ui.warn(_('.hgsubstate is corrupt in revision %s\n') %
953 node.short(ctx.node()))
950 node.short(ctx.node()))
954
951
955 return ret
952 return ret
956
953
957 def remoteui(src, opts):
954 def remoteui(src, opts):
958 'build a remote ui from ui or repo and opts'
955 'build a remote ui from ui or repo and opts'
959 if util.safehasattr(src, 'baseui'): # looks like a repository
956 if util.safehasattr(src, 'baseui'): # looks like a repository
960 dst = src.baseui.copy() # drop repo-specific config
957 dst = src.baseui.copy() # drop repo-specific config
961 src = src.ui # copy target options from repo
958 src = src.ui # copy target options from repo
962 else: # assume it's a global ui object
959 else: # assume it's a global ui object
963 dst = src.copy() # keep all global options
960 dst = src.copy() # keep all global options
964
961
965 # copy ssh-specific options
962 # copy ssh-specific options
966 for o in 'ssh', 'remotecmd':
963 for o in 'ssh', 'remotecmd':
967 v = opts.get(o) or src.config('ui', o)
964 v = opts.get(o) or src.config('ui', o)
968 if v:
965 if v:
969 dst.setconfig("ui", o, v, 'copied')
966 dst.setconfig("ui", o, v, 'copied')
970
967
971 # copy bundle-specific options
968 # copy bundle-specific options
972 r = src.config('bundle', 'mainreporoot')
969 r = src.config('bundle', 'mainreporoot')
973 if r:
970 if r:
974 dst.setconfig('bundle', 'mainreporoot', r, 'copied')
971 dst.setconfig('bundle', 'mainreporoot', r, 'copied')
975
972
976 # copy selected local settings to the remote ui
973 # copy selected local settings to the remote ui
977 for sect in ('auth', 'hostfingerprints', 'hostsecurity', 'http_proxy'):
974 for sect in ('auth', 'hostfingerprints', 'hostsecurity', 'http_proxy'):
978 for key, val in src.configitems(sect):
975 for key, val in src.configitems(sect):
979 dst.setconfig(sect, key, val, 'copied')
976 dst.setconfig(sect, key, val, 'copied')
980 v = src.config('web', 'cacerts')
977 v = src.config('web', 'cacerts')
981 if v:
978 if v:
982 dst.setconfig('web', 'cacerts', util.expandpath(v), 'copied')
979 dst.setconfig('web', 'cacerts', util.expandpath(v), 'copied')
983
980
984 return dst
981 return dst
985
982
986 # Files of interest
983 # Files of interest
987 # Used to check if the repository has changed looking at mtime and size of
984 # Used to check if the repository has changed looking at mtime and size of
988 # these files.
985 # these files.
989 foi = [('spath', '00changelog.i'),
986 foi = [('spath', '00changelog.i'),
990 ('spath', 'phaseroots'), # ! phase can change content at the same size
987 ('spath', 'phaseroots'), # ! phase can change content at the same size
991 ('spath', 'obsstore'),
988 ('spath', 'obsstore'),
992 ('path', 'bookmarks'), # ! bookmark can change content at the same size
989 ('path', 'bookmarks'), # ! bookmark can change content at the same size
993 ]
990 ]
994
991
995 class cachedlocalrepo(object):
992 class cachedlocalrepo(object):
996 """Holds a localrepository that can be cached and reused."""
993 """Holds a localrepository that can be cached and reused."""
997
994
998 def __init__(self, repo):
995 def __init__(self, repo):
999 """Create a new cached repo from an existing repo.
996 """Create a new cached repo from an existing repo.
1000
997
1001 We assume the passed in repo was recently created. If the
998 We assume the passed in repo was recently created. If the
1002 repo has changed between when it was created and when it was
999 repo has changed between when it was created and when it was
1003 turned into a cache, it may not refresh properly.
1000 turned into a cache, it may not refresh properly.
1004 """
1001 """
1005 assert isinstance(repo, localrepo.localrepository)
1002 assert isinstance(repo, localrepo.localrepository)
1006 self._repo = repo
1003 self._repo = repo
1007 self._state, self.mtime = self._repostate()
1004 self._state, self.mtime = self._repostate()
1008 self._filtername = repo.filtername
1005 self._filtername = repo.filtername
1009
1006
1010 def fetch(self):
1007 def fetch(self):
1011 """Refresh (if necessary) and return a repository.
1008 """Refresh (if necessary) and return a repository.
1012
1009
1013 If the cached instance is out of date, it will be recreated
1010 If the cached instance is out of date, it will be recreated
1014 automatically and returned.
1011 automatically and returned.
1015
1012
1016 Returns a tuple of the repo and a boolean indicating whether a new
1013 Returns a tuple of the repo and a boolean indicating whether a new
1017 repo instance was created.
1014 repo instance was created.
1018 """
1015 """
1019 # We compare the mtimes and sizes of some well-known files to
1016 # We compare the mtimes and sizes of some well-known files to
1020 # determine if the repo changed. This is not precise, as mtimes
1017 # determine if the repo changed. This is not precise, as mtimes
1021 # are susceptible to clock skew and imprecise filesystems and
1018 # are susceptible to clock skew and imprecise filesystems and
1022 # file content can change while maintaining the same size.
1019 # file content can change while maintaining the same size.
1023
1020
1024 state, mtime = self._repostate()
1021 state, mtime = self._repostate()
1025 if state == self._state:
1022 if state == self._state:
1026 return self._repo, False
1023 return self._repo, False
1027
1024
1028 repo = repository(self._repo.baseui, self._repo.url())
1025 repo = repository(self._repo.baseui, self._repo.url())
1029 if self._filtername:
1026 if self._filtername:
1030 self._repo = repo.filtered(self._filtername)
1027 self._repo = repo.filtered(self._filtername)
1031 else:
1028 else:
1032 self._repo = repo.unfiltered()
1029 self._repo = repo.unfiltered()
1033 self._state = state
1030 self._state = state
1034 self.mtime = mtime
1031 self.mtime = mtime
1035
1032
1036 return self._repo, True
1033 return self._repo, True
1037
1034
1038 def _repostate(self):
1035 def _repostate(self):
1039 state = []
1036 state = []
1040 maxmtime = -1
1037 maxmtime = -1
1041 for attr, fname in foi:
1038 for attr, fname in foi:
1042 prefix = getattr(self._repo, attr)
1039 prefix = getattr(self._repo, attr)
1043 p = os.path.join(prefix, fname)
1040 p = os.path.join(prefix, fname)
1044 try:
1041 try:
1045 st = os.stat(p)
1042 st = os.stat(p)
1046 except OSError:
1043 except OSError:
1047 st = os.stat(prefix)
1044 st = os.stat(prefix)
1048 state.append((st.st_mtime, st.st_size))
1045 state.append((st.st_mtime, st.st_size))
1049 maxmtime = max(maxmtime, st.st_mtime)
1046 maxmtime = max(maxmtime, st.st_mtime)
1050
1047
1051 return tuple(state), maxmtime
1048 return tuple(state), maxmtime
1052
1049
1053 def copy(self):
1050 def copy(self):
1054 """Obtain a copy of this class instance.
1051 """Obtain a copy of this class instance.
1055
1052
1056 A new localrepository instance is obtained. The new instance should be
1053 A new localrepository instance is obtained. The new instance should be
1057 completely independent of the original.
1054 completely independent of the original.
1058 """
1055 """
1059 repo = repository(self._repo.baseui, self._repo.origroot)
1056 repo = repository(self._repo.baseui, self._repo.origroot)
1060 if self._filtername:
1057 if self._filtername:
1061 repo = repo.filtered(self._filtername)
1058 repo = repo.filtered(self._filtername)
1062 else:
1059 else:
1063 repo = repo.unfiltered()
1060 repo = repo.unfiltered()
1064 c = cachedlocalrepo(repo)
1061 c = cachedlocalrepo(repo)
1065 c._state = self._state
1062 c._state = self._state
1066 c.mtime = self.mtime
1063 c.mtime = self.mtime
1067 return c
1064 return c
General Comments 0
You need to be logged in to leave comments. Login now