##// END OF EJS Templates
lookup: add option to disambiguate prefix within revset...
Martin von Zweigbergk -
r38878:503f9364 default
parent child Browse files
Show More
@@ -0,0 +1,37
1 $ hg init repo
2 $ cd repo
3
4 $ echo 0 > a
5 $ hg ci -qAm 0
6 $ for i in 5 8 14 43; do
7 > hg up -q 0
8 > echo $i > a
9 > hg ci -qm $i
10 > done
11 $ cat <<EOF >> .hg/hgrc
12 > [alias]
13 > l = log -T '{rev}:{shortest(node,1)}\n'
14 > EOF
15
16 $ hg l
17 4:7ba5d
18 3:7ba57
19 2:72
20 1:9
21 0:b
22 $ cat <<EOF >> .hg/hgrc
23 > [experimental]
24 > revisions.disambiguatewithin=:3
25 > EOF
26 9 was unambiguous and still is
27 $ hg l -r 9
28 1:9
29 7 was ambiguous and still is
30 $ hg l -r 7
31 abort: 00changelog.i@7: ambiguous identifier!
32 [255]
33 7b is no longer ambiguous
34 $ hg l -r 7b
35 3:7ba57
36
37 $ cd ..
@@ -1,1389 +1,1392
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 sorted(configtable.items()):
20 for section, items in sorted(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 baseitem = super(itemregister, self).get(key)
70 baseitem = super(itemregister, self).get(key)
71 if baseitem is not None and not baseitem.generic:
71 if baseitem is not None and not baseitem.generic:
72 return baseitem
72 return baseitem
73
73
74 # search for a matching generic item
74 # search for a matching generic item
75 generics = sorted(self._generics, key=(lambda x: (x.priority, x.name)))
75 generics = sorted(self._generics, key=(lambda x: (x.priority, x.name)))
76 for item in generics:
76 for item in generics:
77 # we use 'match' instead of 'search' to make the matching simpler
77 # we use 'match' instead of 'search' to make the matching simpler
78 # for people unfamiliar with regular expression. Having the match
78 # for people unfamiliar with regular expression. Having the match
79 # rooted to the start of the string will produce less surprising
79 # rooted to the start of the string will produce less surprising
80 # result for user writing simple regex for sub-attribute.
80 # result for user writing simple regex for sub-attribute.
81 #
81 #
82 # For example using "color\..*" match produces an unsurprising
82 # For example using "color\..*" match produces an unsurprising
83 # result, while using search could suddenly match apparently
83 # result, while using search could suddenly match apparently
84 # unrelated configuration that happens to contains "color."
84 # unrelated configuration that happens to contains "color."
85 # anywhere. This is a tradeoff where we favor requiring ".*" on
85 # anywhere. This is a tradeoff where we favor requiring ".*" on
86 # some match to avoid the need to prefix most pattern with "^".
86 # some match to avoid the need to prefix most pattern with "^".
87 # The "^" seems more error prone.
87 # The "^" seems more error prone.
88 if item._re.match(key):
88 if item._re.match(key):
89 return item
89 return item
90
90
91 return None
91 return None
92
92
93 coreitems = {}
93 coreitems = {}
94
94
95 def _register(configtable, *args, **kwargs):
95 def _register(configtable, *args, **kwargs):
96 item = configitem(*args, **kwargs)
96 item = configitem(*args, **kwargs)
97 section = configtable.setdefault(item.section, itemregister())
97 section = configtable.setdefault(item.section, itemregister())
98 if item.name in section:
98 if item.name in section:
99 msg = "duplicated config item registration for '%s.%s'"
99 msg = "duplicated config item registration for '%s.%s'"
100 raise error.ProgrammingError(msg % (item.section, item.name))
100 raise error.ProgrammingError(msg % (item.section, item.name))
101 section[item.name] = item
101 section[item.name] = item
102
102
103 # special value for case where the default is derived from other values
103 # special value for case where the default is derived from other values
104 dynamicdefault = object()
104 dynamicdefault = object()
105
105
106 # Registering actual config items
106 # Registering actual config items
107
107
108 def getitemregister(configtable):
108 def getitemregister(configtable):
109 f = functools.partial(_register, configtable)
109 f = functools.partial(_register, configtable)
110 # export pseudo enum as configitem.*
110 # export pseudo enum as configitem.*
111 f.dynamicdefault = dynamicdefault
111 f.dynamicdefault = dynamicdefault
112 return f
112 return f
113
113
114 coreconfigitem = getitemregister(coreitems)
114 coreconfigitem = getitemregister(coreitems)
115
115
116 coreconfigitem('alias', '.*',
116 coreconfigitem('alias', '.*',
117 default=dynamicdefault,
117 default=dynamicdefault,
118 generic=True,
118 generic=True,
119 )
119 )
120 coreconfigitem('annotate', 'nodates',
120 coreconfigitem('annotate', 'nodates',
121 default=False,
121 default=False,
122 )
122 )
123 coreconfigitem('annotate', 'showfunc',
123 coreconfigitem('annotate', 'showfunc',
124 default=False,
124 default=False,
125 )
125 )
126 coreconfigitem('annotate', 'unified',
126 coreconfigitem('annotate', 'unified',
127 default=None,
127 default=None,
128 )
128 )
129 coreconfigitem('annotate', 'git',
129 coreconfigitem('annotate', 'git',
130 default=False,
130 default=False,
131 )
131 )
132 coreconfigitem('annotate', 'ignorews',
132 coreconfigitem('annotate', 'ignorews',
133 default=False,
133 default=False,
134 )
134 )
135 coreconfigitem('annotate', 'ignorewsamount',
135 coreconfigitem('annotate', 'ignorewsamount',
136 default=False,
136 default=False,
137 )
137 )
138 coreconfigitem('annotate', 'ignoreblanklines',
138 coreconfigitem('annotate', 'ignoreblanklines',
139 default=False,
139 default=False,
140 )
140 )
141 coreconfigitem('annotate', 'ignorewseol',
141 coreconfigitem('annotate', 'ignorewseol',
142 default=False,
142 default=False,
143 )
143 )
144 coreconfigitem('annotate', 'nobinary',
144 coreconfigitem('annotate', 'nobinary',
145 default=False,
145 default=False,
146 )
146 )
147 coreconfigitem('annotate', 'noprefix',
147 coreconfigitem('annotate', 'noprefix',
148 default=False,
148 default=False,
149 )
149 )
150 coreconfigitem('annotate', 'word-diff',
150 coreconfigitem('annotate', 'word-diff',
151 default=False,
151 default=False,
152 )
152 )
153 coreconfigitem('auth', 'cookiefile',
153 coreconfigitem('auth', 'cookiefile',
154 default=None,
154 default=None,
155 )
155 )
156 # bookmarks.pushing: internal hack for discovery
156 # bookmarks.pushing: internal hack for discovery
157 coreconfigitem('bookmarks', 'pushing',
157 coreconfigitem('bookmarks', 'pushing',
158 default=list,
158 default=list,
159 )
159 )
160 # bundle.mainreporoot: internal hack for bundlerepo
160 # bundle.mainreporoot: internal hack for bundlerepo
161 coreconfigitem('bundle', 'mainreporoot',
161 coreconfigitem('bundle', 'mainreporoot',
162 default='',
162 default='',
163 )
163 )
164 # bundle.reorder: experimental config
164 # bundle.reorder: experimental config
165 coreconfigitem('bundle', 'reorder',
165 coreconfigitem('bundle', 'reorder',
166 default='auto',
166 default='auto',
167 )
167 )
168 coreconfigitem('censor', 'policy',
168 coreconfigitem('censor', 'policy',
169 default='abort',
169 default='abort',
170 )
170 )
171 coreconfigitem('chgserver', 'idletimeout',
171 coreconfigitem('chgserver', 'idletimeout',
172 default=3600,
172 default=3600,
173 )
173 )
174 coreconfigitem('chgserver', 'skiphash',
174 coreconfigitem('chgserver', 'skiphash',
175 default=False,
175 default=False,
176 )
176 )
177 coreconfigitem('cmdserver', 'log',
177 coreconfigitem('cmdserver', 'log',
178 default=None,
178 default=None,
179 )
179 )
180 coreconfigitem('color', '.*',
180 coreconfigitem('color', '.*',
181 default=None,
181 default=None,
182 generic=True,
182 generic=True,
183 )
183 )
184 coreconfigitem('color', 'mode',
184 coreconfigitem('color', 'mode',
185 default='auto',
185 default='auto',
186 )
186 )
187 coreconfigitem('color', 'pagermode',
187 coreconfigitem('color', 'pagermode',
188 default=dynamicdefault,
188 default=dynamicdefault,
189 )
189 )
190 coreconfigitem('commands', 'grep.all-files',
190 coreconfigitem('commands', 'grep.all-files',
191 default=False,
191 default=False,
192 )
192 )
193 coreconfigitem('commands', 'resolve.confirm',
193 coreconfigitem('commands', 'resolve.confirm',
194 default=False,
194 default=False,
195 )
195 )
196 coreconfigitem('commands', 'show.aliasprefix',
196 coreconfigitem('commands', 'show.aliasprefix',
197 default=list,
197 default=list,
198 )
198 )
199 coreconfigitem('commands', 'status.relative',
199 coreconfigitem('commands', 'status.relative',
200 default=False,
200 default=False,
201 )
201 )
202 coreconfigitem('commands', 'status.skipstates',
202 coreconfigitem('commands', 'status.skipstates',
203 default=[],
203 default=[],
204 )
204 )
205 coreconfigitem('commands', 'status.terse',
205 coreconfigitem('commands', 'status.terse',
206 default='',
206 default='',
207 )
207 )
208 coreconfigitem('commands', 'status.verbose',
208 coreconfigitem('commands', 'status.verbose',
209 default=False,
209 default=False,
210 )
210 )
211 coreconfigitem('commands', 'update.check',
211 coreconfigitem('commands', 'update.check',
212 default=None,
212 default=None,
213 )
213 )
214 coreconfigitem('commands', 'update.requiredest',
214 coreconfigitem('commands', 'update.requiredest',
215 default=False,
215 default=False,
216 )
216 )
217 coreconfigitem('committemplate', '.*',
217 coreconfigitem('committemplate', '.*',
218 default=None,
218 default=None,
219 generic=True,
219 generic=True,
220 )
220 )
221 coreconfigitem('convert', 'bzr.saverev',
221 coreconfigitem('convert', 'bzr.saverev',
222 default=True,
222 default=True,
223 )
223 )
224 coreconfigitem('convert', 'cvsps.cache',
224 coreconfigitem('convert', 'cvsps.cache',
225 default=True,
225 default=True,
226 )
226 )
227 coreconfigitem('convert', 'cvsps.fuzz',
227 coreconfigitem('convert', 'cvsps.fuzz',
228 default=60,
228 default=60,
229 )
229 )
230 coreconfigitem('convert', 'cvsps.logencoding',
230 coreconfigitem('convert', 'cvsps.logencoding',
231 default=None,
231 default=None,
232 )
232 )
233 coreconfigitem('convert', 'cvsps.mergefrom',
233 coreconfigitem('convert', 'cvsps.mergefrom',
234 default=None,
234 default=None,
235 )
235 )
236 coreconfigitem('convert', 'cvsps.mergeto',
236 coreconfigitem('convert', 'cvsps.mergeto',
237 default=None,
237 default=None,
238 )
238 )
239 coreconfigitem('convert', 'git.committeractions',
239 coreconfigitem('convert', 'git.committeractions',
240 default=lambda: ['messagedifferent'],
240 default=lambda: ['messagedifferent'],
241 )
241 )
242 coreconfigitem('convert', 'git.extrakeys',
242 coreconfigitem('convert', 'git.extrakeys',
243 default=list,
243 default=list,
244 )
244 )
245 coreconfigitem('convert', 'git.findcopiesharder',
245 coreconfigitem('convert', 'git.findcopiesharder',
246 default=False,
246 default=False,
247 )
247 )
248 coreconfigitem('convert', 'git.remoteprefix',
248 coreconfigitem('convert', 'git.remoteprefix',
249 default='remote',
249 default='remote',
250 )
250 )
251 coreconfigitem('convert', 'git.renamelimit',
251 coreconfigitem('convert', 'git.renamelimit',
252 default=400,
252 default=400,
253 )
253 )
254 coreconfigitem('convert', 'git.saverev',
254 coreconfigitem('convert', 'git.saverev',
255 default=True,
255 default=True,
256 )
256 )
257 coreconfigitem('convert', 'git.similarity',
257 coreconfigitem('convert', 'git.similarity',
258 default=50,
258 default=50,
259 )
259 )
260 coreconfigitem('convert', 'git.skipsubmodules',
260 coreconfigitem('convert', 'git.skipsubmodules',
261 default=False,
261 default=False,
262 )
262 )
263 coreconfigitem('convert', 'hg.clonebranches',
263 coreconfigitem('convert', 'hg.clonebranches',
264 default=False,
264 default=False,
265 )
265 )
266 coreconfigitem('convert', 'hg.ignoreerrors',
266 coreconfigitem('convert', 'hg.ignoreerrors',
267 default=False,
267 default=False,
268 )
268 )
269 coreconfigitem('convert', 'hg.revs',
269 coreconfigitem('convert', 'hg.revs',
270 default=None,
270 default=None,
271 )
271 )
272 coreconfigitem('convert', 'hg.saverev',
272 coreconfigitem('convert', 'hg.saverev',
273 default=False,
273 default=False,
274 )
274 )
275 coreconfigitem('convert', 'hg.sourcename',
275 coreconfigitem('convert', 'hg.sourcename',
276 default=None,
276 default=None,
277 )
277 )
278 coreconfigitem('convert', 'hg.startrev',
278 coreconfigitem('convert', 'hg.startrev',
279 default=None,
279 default=None,
280 )
280 )
281 coreconfigitem('convert', 'hg.tagsbranch',
281 coreconfigitem('convert', 'hg.tagsbranch',
282 default='default',
282 default='default',
283 )
283 )
284 coreconfigitem('convert', 'hg.usebranchnames',
284 coreconfigitem('convert', 'hg.usebranchnames',
285 default=True,
285 default=True,
286 )
286 )
287 coreconfigitem('convert', 'ignoreancestorcheck',
287 coreconfigitem('convert', 'ignoreancestorcheck',
288 default=False,
288 default=False,
289 )
289 )
290 coreconfigitem('convert', 'localtimezone',
290 coreconfigitem('convert', 'localtimezone',
291 default=False,
291 default=False,
292 )
292 )
293 coreconfigitem('convert', 'p4.encoding',
293 coreconfigitem('convert', 'p4.encoding',
294 default=dynamicdefault,
294 default=dynamicdefault,
295 )
295 )
296 coreconfigitem('convert', 'p4.startrev',
296 coreconfigitem('convert', 'p4.startrev',
297 default=0,
297 default=0,
298 )
298 )
299 coreconfigitem('convert', 'skiptags',
299 coreconfigitem('convert', 'skiptags',
300 default=False,
300 default=False,
301 )
301 )
302 coreconfigitem('convert', 'svn.debugsvnlog',
302 coreconfigitem('convert', 'svn.debugsvnlog',
303 default=True,
303 default=True,
304 )
304 )
305 coreconfigitem('convert', 'svn.trunk',
305 coreconfigitem('convert', 'svn.trunk',
306 default=None,
306 default=None,
307 )
307 )
308 coreconfigitem('convert', 'svn.tags',
308 coreconfigitem('convert', 'svn.tags',
309 default=None,
309 default=None,
310 )
310 )
311 coreconfigitem('convert', 'svn.branches',
311 coreconfigitem('convert', 'svn.branches',
312 default=None,
312 default=None,
313 )
313 )
314 coreconfigitem('convert', 'svn.startrev',
314 coreconfigitem('convert', 'svn.startrev',
315 default=0,
315 default=0,
316 )
316 )
317 coreconfigitem('debug', 'dirstate.delaywrite',
317 coreconfigitem('debug', 'dirstate.delaywrite',
318 default=0,
318 default=0,
319 )
319 )
320 coreconfigitem('defaults', '.*',
320 coreconfigitem('defaults', '.*',
321 default=None,
321 default=None,
322 generic=True,
322 generic=True,
323 )
323 )
324 coreconfigitem('devel', 'all-warnings',
324 coreconfigitem('devel', 'all-warnings',
325 default=False,
325 default=False,
326 )
326 )
327 coreconfigitem('devel', 'bundle2.debug',
327 coreconfigitem('devel', 'bundle2.debug',
328 default=False,
328 default=False,
329 )
329 )
330 coreconfigitem('devel', 'cache-vfs',
330 coreconfigitem('devel', 'cache-vfs',
331 default=None,
331 default=None,
332 )
332 )
333 coreconfigitem('devel', 'check-locks',
333 coreconfigitem('devel', 'check-locks',
334 default=False,
334 default=False,
335 )
335 )
336 coreconfigitem('devel', 'check-relroot',
336 coreconfigitem('devel', 'check-relroot',
337 default=False,
337 default=False,
338 )
338 )
339 coreconfigitem('devel', 'default-date',
339 coreconfigitem('devel', 'default-date',
340 default=None,
340 default=None,
341 )
341 )
342 coreconfigitem('devel', 'deprec-warn',
342 coreconfigitem('devel', 'deprec-warn',
343 default=False,
343 default=False,
344 )
344 )
345 coreconfigitem('devel', 'disableloaddefaultcerts',
345 coreconfigitem('devel', 'disableloaddefaultcerts',
346 default=False,
346 default=False,
347 )
347 )
348 coreconfigitem('devel', 'warn-empty-changegroup',
348 coreconfigitem('devel', 'warn-empty-changegroup',
349 default=False,
349 default=False,
350 )
350 )
351 coreconfigitem('devel', 'legacy.exchange',
351 coreconfigitem('devel', 'legacy.exchange',
352 default=list,
352 default=list,
353 )
353 )
354 coreconfigitem('devel', 'servercafile',
354 coreconfigitem('devel', 'servercafile',
355 default='',
355 default='',
356 )
356 )
357 coreconfigitem('devel', 'serverexactprotocol',
357 coreconfigitem('devel', 'serverexactprotocol',
358 default='',
358 default='',
359 )
359 )
360 coreconfigitem('devel', 'serverrequirecert',
360 coreconfigitem('devel', 'serverrequirecert',
361 default=False,
361 default=False,
362 )
362 )
363 coreconfigitem('devel', 'strip-obsmarkers',
363 coreconfigitem('devel', 'strip-obsmarkers',
364 default=True,
364 default=True,
365 )
365 )
366 coreconfigitem('devel', 'warn-config',
366 coreconfigitem('devel', 'warn-config',
367 default=None,
367 default=None,
368 )
368 )
369 coreconfigitem('devel', 'warn-config-default',
369 coreconfigitem('devel', 'warn-config-default',
370 default=None,
370 default=None,
371 )
371 )
372 coreconfigitem('devel', 'user.obsmarker',
372 coreconfigitem('devel', 'user.obsmarker',
373 default=None,
373 default=None,
374 )
374 )
375 coreconfigitem('devel', 'warn-config-unknown',
375 coreconfigitem('devel', 'warn-config-unknown',
376 default=None,
376 default=None,
377 )
377 )
378 coreconfigitem('devel', 'debug.extensions',
378 coreconfigitem('devel', 'debug.extensions',
379 default=False,
379 default=False,
380 )
380 )
381 coreconfigitem('devel', 'debug.peer-request',
381 coreconfigitem('devel', 'debug.peer-request',
382 default=False,
382 default=False,
383 )
383 )
384 coreconfigitem('diff', 'nodates',
384 coreconfigitem('diff', 'nodates',
385 default=False,
385 default=False,
386 )
386 )
387 coreconfigitem('diff', 'showfunc',
387 coreconfigitem('diff', 'showfunc',
388 default=False,
388 default=False,
389 )
389 )
390 coreconfigitem('diff', 'unified',
390 coreconfigitem('diff', 'unified',
391 default=None,
391 default=None,
392 )
392 )
393 coreconfigitem('diff', 'git',
393 coreconfigitem('diff', 'git',
394 default=False,
394 default=False,
395 )
395 )
396 coreconfigitem('diff', 'ignorews',
396 coreconfigitem('diff', 'ignorews',
397 default=False,
397 default=False,
398 )
398 )
399 coreconfigitem('diff', 'ignorewsamount',
399 coreconfigitem('diff', 'ignorewsamount',
400 default=False,
400 default=False,
401 )
401 )
402 coreconfigitem('diff', 'ignoreblanklines',
402 coreconfigitem('diff', 'ignoreblanklines',
403 default=False,
403 default=False,
404 )
404 )
405 coreconfigitem('diff', 'ignorewseol',
405 coreconfigitem('diff', 'ignorewseol',
406 default=False,
406 default=False,
407 )
407 )
408 coreconfigitem('diff', 'nobinary',
408 coreconfigitem('diff', 'nobinary',
409 default=False,
409 default=False,
410 )
410 )
411 coreconfigitem('diff', 'noprefix',
411 coreconfigitem('diff', 'noprefix',
412 default=False,
412 default=False,
413 )
413 )
414 coreconfigitem('diff', 'word-diff',
414 coreconfigitem('diff', 'word-diff',
415 default=False,
415 default=False,
416 )
416 )
417 coreconfigitem('email', 'bcc',
417 coreconfigitem('email', 'bcc',
418 default=None,
418 default=None,
419 )
419 )
420 coreconfigitem('email', 'cc',
420 coreconfigitem('email', 'cc',
421 default=None,
421 default=None,
422 )
422 )
423 coreconfigitem('email', 'charsets',
423 coreconfigitem('email', 'charsets',
424 default=list,
424 default=list,
425 )
425 )
426 coreconfigitem('email', 'from',
426 coreconfigitem('email', 'from',
427 default=None,
427 default=None,
428 )
428 )
429 coreconfigitem('email', 'method',
429 coreconfigitem('email', 'method',
430 default='smtp',
430 default='smtp',
431 )
431 )
432 coreconfigitem('email', 'reply-to',
432 coreconfigitem('email', 'reply-to',
433 default=None,
433 default=None,
434 )
434 )
435 coreconfigitem('email', 'to',
435 coreconfigitem('email', 'to',
436 default=None,
436 default=None,
437 )
437 )
438 coreconfigitem('experimental', 'archivemetatemplate',
438 coreconfigitem('experimental', 'archivemetatemplate',
439 default=dynamicdefault,
439 default=dynamicdefault,
440 )
440 )
441 coreconfigitem('experimental', 'bundle-phases',
441 coreconfigitem('experimental', 'bundle-phases',
442 default=False,
442 default=False,
443 )
443 )
444 coreconfigitem('experimental', 'bundle2-advertise',
444 coreconfigitem('experimental', 'bundle2-advertise',
445 default=True,
445 default=True,
446 )
446 )
447 coreconfigitem('experimental', 'bundle2-output-capture',
447 coreconfigitem('experimental', 'bundle2-output-capture',
448 default=False,
448 default=False,
449 )
449 )
450 coreconfigitem('experimental', 'bundle2.pushback',
450 coreconfigitem('experimental', 'bundle2.pushback',
451 default=False,
451 default=False,
452 )
452 )
453 coreconfigitem('experimental', 'bundle2.stream',
453 coreconfigitem('experimental', 'bundle2.stream',
454 default=False,
454 default=False,
455 )
455 )
456 coreconfigitem('experimental', 'bundle2lazylocking',
456 coreconfigitem('experimental', 'bundle2lazylocking',
457 default=False,
457 default=False,
458 )
458 )
459 coreconfigitem('experimental', 'bundlecomplevel',
459 coreconfigitem('experimental', 'bundlecomplevel',
460 default=None,
460 default=None,
461 )
461 )
462 coreconfigitem('experimental', 'bundlecomplevel.bzip2',
462 coreconfigitem('experimental', 'bundlecomplevel.bzip2',
463 default=None,
463 default=None,
464 )
464 )
465 coreconfigitem('experimental', 'bundlecomplevel.gzip',
465 coreconfigitem('experimental', 'bundlecomplevel.gzip',
466 default=None,
466 default=None,
467 )
467 )
468 coreconfigitem('experimental', 'bundlecomplevel.none',
468 coreconfigitem('experimental', 'bundlecomplevel.none',
469 default=None,
469 default=None,
470 )
470 )
471 coreconfigitem('experimental', 'bundlecomplevel.zstd',
471 coreconfigitem('experimental', 'bundlecomplevel.zstd',
472 default=None,
472 default=None,
473 )
473 )
474 coreconfigitem('experimental', 'changegroup3',
474 coreconfigitem('experimental', 'changegroup3',
475 default=False,
475 default=False,
476 )
476 )
477 coreconfigitem('experimental', 'clientcompressionengines',
477 coreconfigitem('experimental', 'clientcompressionengines',
478 default=list,
478 default=list,
479 )
479 )
480 coreconfigitem('experimental', 'copytrace',
480 coreconfigitem('experimental', 'copytrace',
481 default='on',
481 default='on',
482 )
482 )
483 coreconfigitem('experimental', 'copytrace.movecandidateslimit',
483 coreconfigitem('experimental', 'copytrace.movecandidateslimit',
484 default=100,
484 default=100,
485 )
485 )
486 coreconfigitem('experimental', 'copytrace.sourcecommitlimit',
486 coreconfigitem('experimental', 'copytrace.sourcecommitlimit',
487 default=100,
487 default=100,
488 )
488 )
489 coreconfigitem('experimental', 'crecordtest',
489 coreconfigitem('experimental', 'crecordtest',
490 default=None,
490 default=None,
491 )
491 )
492 coreconfigitem('experimental', 'directaccess',
492 coreconfigitem('experimental', 'directaccess',
493 default=False,
493 default=False,
494 )
494 )
495 coreconfigitem('experimental', 'directaccess.revnums',
495 coreconfigitem('experimental', 'directaccess.revnums',
496 default=False,
496 default=False,
497 )
497 )
498 coreconfigitem('experimental', 'editortmpinhg',
498 coreconfigitem('experimental', 'editortmpinhg',
499 default=False,
499 default=False,
500 )
500 )
501 coreconfigitem('experimental', 'evolution',
501 coreconfigitem('experimental', 'evolution',
502 default=list,
502 default=list,
503 )
503 )
504 coreconfigitem('experimental', 'evolution.allowdivergence',
504 coreconfigitem('experimental', 'evolution.allowdivergence',
505 default=False,
505 default=False,
506 alias=[('experimental', 'allowdivergence')]
506 alias=[('experimental', 'allowdivergence')]
507 )
507 )
508 coreconfigitem('experimental', 'evolution.allowunstable',
508 coreconfigitem('experimental', 'evolution.allowunstable',
509 default=None,
509 default=None,
510 )
510 )
511 coreconfigitem('experimental', 'evolution.createmarkers',
511 coreconfigitem('experimental', 'evolution.createmarkers',
512 default=None,
512 default=None,
513 )
513 )
514 coreconfigitem('experimental', 'evolution.effect-flags',
514 coreconfigitem('experimental', 'evolution.effect-flags',
515 default=True,
515 default=True,
516 alias=[('experimental', 'effect-flags')]
516 alias=[('experimental', 'effect-flags')]
517 )
517 )
518 coreconfigitem('experimental', 'evolution.exchange',
518 coreconfigitem('experimental', 'evolution.exchange',
519 default=None,
519 default=None,
520 )
520 )
521 coreconfigitem('experimental', 'evolution.bundle-obsmarker',
521 coreconfigitem('experimental', 'evolution.bundle-obsmarker',
522 default=False,
522 default=False,
523 )
523 )
524 coreconfigitem('experimental', 'evolution.report-instabilities',
524 coreconfigitem('experimental', 'evolution.report-instabilities',
525 default=True,
525 default=True,
526 )
526 )
527 coreconfigitem('experimental', 'evolution.track-operation',
527 coreconfigitem('experimental', 'evolution.track-operation',
528 default=True,
528 default=True,
529 )
529 )
530 coreconfigitem('experimental', 'maxdeltachainspan',
530 coreconfigitem('experimental', 'maxdeltachainspan',
531 default=-1,
531 default=-1,
532 )
532 )
533 coreconfigitem('experimental', 'mergetempdirprefix',
533 coreconfigitem('experimental', 'mergetempdirprefix',
534 default=None,
534 default=None,
535 )
535 )
536 coreconfigitem('experimental', 'mmapindexthreshold',
536 coreconfigitem('experimental', 'mmapindexthreshold',
537 default=None,
537 default=None,
538 )
538 )
539 coreconfigitem('experimental', 'nonnormalparanoidcheck',
539 coreconfigitem('experimental', 'nonnormalparanoidcheck',
540 default=False,
540 default=False,
541 )
541 )
542 coreconfigitem('experimental', 'exportableenviron',
542 coreconfigitem('experimental', 'exportableenviron',
543 default=list,
543 default=list,
544 )
544 )
545 coreconfigitem('experimental', 'extendedheader.index',
545 coreconfigitem('experimental', 'extendedheader.index',
546 default=None,
546 default=None,
547 )
547 )
548 coreconfigitem('experimental', 'extendedheader.similarity',
548 coreconfigitem('experimental', 'extendedheader.similarity',
549 default=False,
549 default=False,
550 )
550 )
551 coreconfigitem('experimental', 'format.compression',
551 coreconfigitem('experimental', 'format.compression',
552 default='zlib',
552 default='zlib',
553 )
553 )
554 coreconfigitem('experimental', 'graphshorten',
554 coreconfigitem('experimental', 'graphshorten',
555 default=False,
555 default=False,
556 )
556 )
557 coreconfigitem('experimental', 'graphstyle.parent',
557 coreconfigitem('experimental', 'graphstyle.parent',
558 default=dynamicdefault,
558 default=dynamicdefault,
559 )
559 )
560 coreconfigitem('experimental', 'graphstyle.missing',
560 coreconfigitem('experimental', 'graphstyle.missing',
561 default=dynamicdefault,
561 default=dynamicdefault,
562 )
562 )
563 coreconfigitem('experimental', 'graphstyle.grandparent',
563 coreconfigitem('experimental', 'graphstyle.grandparent',
564 default=dynamicdefault,
564 default=dynamicdefault,
565 )
565 )
566 coreconfigitem('experimental', 'hook-track-tags',
566 coreconfigitem('experimental', 'hook-track-tags',
567 default=False,
567 default=False,
568 )
568 )
569 coreconfigitem('experimental', 'httppeer.advertise-v2',
569 coreconfigitem('experimental', 'httppeer.advertise-v2',
570 default=False,
570 default=False,
571 )
571 )
572 coreconfigitem('experimental', 'httppostargs',
572 coreconfigitem('experimental', 'httppostargs',
573 default=False,
573 default=False,
574 )
574 )
575 coreconfigitem('experimental', 'mergedriver',
575 coreconfigitem('experimental', 'mergedriver',
576 default=None,
576 default=None,
577 )
577 )
578 coreconfigitem('experimental', 'nointerrupt', default=False)
578 coreconfigitem('experimental', 'nointerrupt', default=False)
579 coreconfigitem('experimental', 'nointerrupt-interactiveonly', default=True)
579 coreconfigitem('experimental', 'nointerrupt-interactiveonly', default=True)
580
580
581 coreconfigitem('experimental', 'obsmarkers-exchange-debug',
581 coreconfigitem('experimental', 'obsmarkers-exchange-debug',
582 default=False,
582 default=False,
583 )
583 )
584 coreconfigitem('experimental', 'remotenames',
584 coreconfigitem('experimental', 'remotenames',
585 default=False,
585 default=False,
586 )
586 )
587 coreconfigitem('experimental', 'removeemptydirs',
587 coreconfigitem('experimental', 'removeemptydirs',
588 default=True,
588 default=True,
589 )
589 )
590 coreconfigitem('experimental', 'revlogv2',
590 coreconfigitem('experimental', 'revlogv2',
591 default=None,
591 default=None,
592 )
592 )
593 coreconfigitem('experimental', 'revisions.disambiguatewithin',
594 default=None,
595 )
593 coreconfigitem('experimental', 'single-head-per-branch',
596 coreconfigitem('experimental', 'single-head-per-branch',
594 default=False,
597 default=False,
595 )
598 )
596 coreconfigitem('experimental', 'sshserver.support-v2',
599 coreconfigitem('experimental', 'sshserver.support-v2',
597 default=False,
600 default=False,
598 )
601 )
599 coreconfigitem('experimental', 'spacemovesdown',
602 coreconfigitem('experimental', 'spacemovesdown',
600 default=False,
603 default=False,
601 )
604 )
602 coreconfigitem('experimental', 'sparse-read',
605 coreconfigitem('experimental', 'sparse-read',
603 default=False,
606 default=False,
604 )
607 )
605 coreconfigitem('experimental', 'sparse-read.density-threshold',
608 coreconfigitem('experimental', 'sparse-read.density-threshold',
606 default=0.50,
609 default=0.50,
607 )
610 )
608 coreconfigitem('experimental', 'sparse-read.min-gap-size',
611 coreconfigitem('experimental', 'sparse-read.min-gap-size',
609 default='65K',
612 default='65K',
610 )
613 )
611 coreconfigitem('experimental', 'treemanifest',
614 coreconfigitem('experimental', 'treemanifest',
612 default=False,
615 default=False,
613 )
616 )
614 coreconfigitem('experimental', 'update.atomic-file',
617 coreconfigitem('experimental', 'update.atomic-file',
615 default=False,
618 default=False,
616 )
619 )
617 coreconfigitem('experimental', 'sshpeer.advertise-v2',
620 coreconfigitem('experimental', 'sshpeer.advertise-v2',
618 default=False,
621 default=False,
619 )
622 )
620 coreconfigitem('experimental', 'web.apiserver',
623 coreconfigitem('experimental', 'web.apiserver',
621 default=False,
624 default=False,
622 )
625 )
623 coreconfigitem('experimental', 'web.api.http-v2',
626 coreconfigitem('experimental', 'web.api.http-v2',
624 default=False,
627 default=False,
625 )
628 )
626 coreconfigitem('experimental', 'web.api.debugreflect',
629 coreconfigitem('experimental', 'web.api.debugreflect',
627 default=False,
630 default=False,
628 )
631 )
629 coreconfigitem('experimental', 'worker.wdir-get-thread-safe',
632 coreconfigitem('experimental', 'worker.wdir-get-thread-safe',
630 default=False,
633 default=False,
631 )
634 )
632 coreconfigitem('experimental', 'xdiff',
635 coreconfigitem('experimental', 'xdiff',
633 default=False,
636 default=False,
634 )
637 )
635 coreconfigitem('extensions', '.*',
638 coreconfigitem('extensions', '.*',
636 default=None,
639 default=None,
637 generic=True,
640 generic=True,
638 )
641 )
639 coreconfigitem('extdata', '.*',
642 coreconfigitem('extdata', '.*',
640 default=None,
643 default=None,
641 generic=True,
644 generic=True,
642 )
645 )
643 coreconfigitem('format', 'chunkcachesize',
646 coreconfigitem('format', 'chunkcachesize',
644 default=None,
647 default=None,
645 )
648 )
646 coreconfigitem('format', 'dotencode',
649 coreconfigitem('format', 'dotencode',
647 default=True,
650 default=True,
648 )
651 )
649 coreconfigitem('format', 'generaldelta',
652 coreconfigitem('format', 'generaldelta',
650 default=False,
653 default=False,
651 )
654 )
652 coreconfigitem('format', 'manifestcachesize',
655 coreconfigitem('format', 'manifestcachesize',
653 default=None,
656 default=None,
654 )
657 )
655 coreconfigitem('format', 'maxchainlen',
658 coreconfigitem('format', 'maxchainlen',
656 default=None,
659 default=None,
657 )
660 )
658 coreconfigitem('format', 'obsstore-version',
661 coreconfigitem('format', 'obsstore-version',
659 default=None,
662 default=None,
660 )
663 )
661 coreconfigitem('format', 'sparse-revlog',
664 coreconfigitem('format', 'sparse-revlog',
662 default=False,
665 default=False,
663 )
666 )
664 coreconfigitem('format', 'usefncache',
667 coreconfigitem('format', 'usefncache',
665 default=True,
668 default=True,
666 )
669 )
667 coreconfigitem('format', 'usegeneraldelta',
670 coreconfigitem('format', 'usegeneraldelta',
668 default=True,
671 default=True,
669 )
672 )
670 coreconfigitem('format', 'usestore',
673 coreconfigitem('format', 'usestore',
671 default=True,
674 default=True,
672 )
675 )
673 coreconfigitem('fsmonitor', 'warn_when_unused',
676 coreconfigitem('fsmonitor', 'warn_when_unused',
674 default=True,
677 default=True,
675 )
678 )
676 coreconfigitem('fsmonitor', 'warn_update_file_count',
679 coreconfigitem('fsmonitor', 'warn_update_file_count',
677 default=50000,
680 default=50000,
678 )
681 )
679 coreconfigitem('hooks', '.*',
682 coreconfigitem('hooks', '.*',
680 default=dynamicdefault,
683 default=dynamicdefault,
681 generic=True,
684 generic=True,
682 )
685 )
683 coreconfigitem('hgweb-paths', '.*',
686 coreconfigitem('hgweb-paths', '.*',
684 default=list,
687 default=list,
685 generic=True,
688 generic=True,
686 )
689 )
687 coreconfigitem('hostfingerprints', '.*',
690 coreconfigitem('hostfingerprints', '.*',
688 default=list,
691 default=list,
689 generic=True,
692 generic=True,
690 )
693 )
691 coreconfigitem('hostsecurity', 'ciphers',
694 coreconfigitem('hostsecurity', 'ciphers',
692 default=None,
695 default=None,
693 )
696 )
694 coreconfigitem('hostsecurity', 'disabletls10warning',
697 coreconfigitem('hostsecurity', 'disabletls10warning',
695 default=False,
698 default=False,
696 )
699 )
697 coreconfigitem('hostsecurity', 'minimumprotocol',
700 coreconfigitem('hostsecurity', 'minimumprotocol',
698 default=dynamicdefault,
701 default=dynamicdefault,
699 )
702 )
700 coreconfigitem('hostsecurity', '.*:minimumprotocol$',
703 coreconfigitem('hostsecurity', '.*:minimumprotocol$',
701 default=dynamicdefault,
704 default=dynamicdefault,
702 generic=True,
705 generic=True,
703 )
706 )
704 coreconfigitem('hostsecurity', '.*:ciphers$',
707 coreconfigitem('hostsecurity', '.*:ciphers$',
705 default=dynamicdefault,
708 default=dynamicdefault,
706 generic=True,
709 generic=True,
707 )
710 )
708 coreconfigitem('hostsecurity', '.*:fingerprints$',
711 coreconfigitem('hostsecurity', '.*:fingerprints$',
709 default=list,
712 default=list,
710 generic=True,
713 generic=True,
711 )
714 )
712 coreconfigitem('hostsecurity', '.*:verifycertsfile$',
715 coreconfigitem('hostsecurity', '.*:verifycertsfile$',
713 default=None,
716 default=None,
714 generic=True,
717 generic=True,
715 )
718 )
716
719
717 coreconfigitem('http_proxy', 'always',
720 coreconfigitem('http_proxy', 'always',
718 default=False,
721 default=False,
719 )
722 )
720 coreconfigitem('http_proxy', 'host',
723 coreconfigitem('http_proxy', 'host',
721 default=None,
724 default=None,
722 )
725 )
723 coreconfigitem('http_proxy', 'no',
726 coreconfigitem('http_proxy', 'no',
724 default=list,
727 default=list,
725 )
728 )
726 coreconfigitem('http_proxy', 'passwd',
729 coreconfigitem('http_proxy', 'passwd',
727 default=None,
730 default=None,
728 )
731 )
729 coreconfigitem('http_proxy', 'user',
732 coreconfigitem('http_proxy', 'user',
730 default=None,
733 default=None,
731 )
734 )
732 coreconfigitem('logtoprocess', 'commandexception',
735 coreconfigitem('logtoprocess', 'commandexception',
733 default=None,
736 default=None,
734 )
737 )
735 coreconfigitem('logtoprocess', 'commandfinish',
738 coreconfigitem('logtoprocess', 'commandfinish',
736 default=None,
739 default=None,
737 )
740 )
738 coreconfigitem('logtoprocess', 'command',
741 coreconfigitem('logtoprocess', 'command',
739 default=None,
742 default=None,
740 )
743 )
741 coreconfigitem('logtoprocess', 'develwarn',
744 coreconfigitem('logtoprocess', 'develwarn',
742 default=None,
745 default=None,
743 )
746 )
744 coreconfigitem('logtoprocess', 'uiblocked',
747 coreconfigitem('logtoprocess', 'uiblocked',
745 default=None,
748 default=None,
746 )
749 )
747 coreconfigitem('merge', 'checkunknown',
750 coreconfigitem('merge', 'checkunknown',
748 default='abort',
751 default='abort',
749 )
752 )
750 coreconfigitem('merge', 'checkignored',
753 coreconfigitem('merge', 'checkignored',
751 default='abort',
754 default='abort',
752 )
755 )
753 coreconfigitem('experimental', 'merge.checkpathconflicts',
756 coreconfigitem('experimental', 'merge.checkpathconflicts',
754 default=False,
757 default=False,
755 )
758 )
756 coreconfigitem('merge', 'followcopies',
759 coreconfigitem('merge', 'followcopies',
757 default=True,
760 default=True,
758 )
761 )
759 coreconfigitem('merge', 'on-failure',
762 coreconfigitem('merge', 'on-failure',
760 default='continue',
763 default='continue',
761 )
764 )
762 coreconfigitem('merge', 'preferancestor',
765 coreconfigitem('merge', 'preferancestor',
763 default=lambda: ['*'],
766 default=lambda: ['*'],
764 )
767 )
765 coreconfigitem('merge-tools', '.*',
768 coreconfigitem('merge-tools', '.*',
766 default=None,
769 default=None,
767 generic=True,
770 generic=True,
768 )
771 )
769 coreconfigitem('merge-tools', br'.*\.args$',
772 coreconfigitem('merge-tools', br'.*\.args$',
770 default="$local $base $other",
773 default="$local $base $other",
771 generic=True,
774 generic=True,
772 priority=-1,
775 priority=-1,
773 )
776 )
774 coreconfigitem('merge-tools', br'.*\.binary$',
777 coreconfigitem('merge-tools', br'.*\.binary$',
775 default=False,
778 default=False,
776 generic=True,
779 generic=True,
777 priority=-1,
780 priority=-1,
778 )
781 )
779 coreconfigitem('merge-tools', br'.*\.check$',
782 coreconfigitem('merge-tools', br'.*\.check$',
780 default=list,
783 default=list,
781 generic=True,
784 generic=True,
782 priority=-1,
785 priority=-1,
783 )
786 )
784 coreconfigitem('merge-tools', br'.*\.checkchanged$',
787 coreconfigitem('merge-tools', br'.*\.checkchanged$',
785 default=False,
788 default=False,
786 generic=True,
789 generic=True,
787 priority=-1,
790 priority=-1,
788 )
791 )
789 coreconfigitem('merge-tools', br'.*\.executable$',
792 coreconfigitem('merge-tools', br'.*\.executable$',
790 default=dynamicdefault,
793 default=dynamicdefault,
791 generic=True,
794 generic=True,
792 priority=-1,
795 priority=-1,
793 )
796 )
794 coreconfigitem('merge-tools', br'.*\.fixeol$',
797 coreconfigitem('merge-tools', br'.*\.fixeol$',
795 default=False,
798 default=False,
796 generic=True,
799 generic=True,
797 priority=-1,
800 priority=-1,
798 )
801 )
799 coreconfigitem('merge-tools', br'.*\.gui$',
802 coreconfigitem('merge-tools', br'.*\.gui$',
800 default=False,
803 default=False,
801 generic=True,
804 generic=True,
802 priority=-1,
805 priority=-1,
803 )
806 )
804 coreconfigitem('merge-tools', br'.*\.mergemarkers$',
807 coreconfigitem('merge-tools', br'.*\.mergemarkers$',
805 default='basic',
808 default='basic',
806 generic=True,
809 generic=True,
807 priority=-1,
810 priority=-1,
808 )
811 )
809 coreconfigitem('merge-tools', br'.*\.mergemarkertemplate$',
812 coreconfigitem('merge-tools', br'.*\.mergemarkertemplate$',
810 default=dynamicdefault, # take from ui.mergemarkertemplate
813 default=dynamicdefault, # take from ui.mergemarkertemplate
811 generic=True,
814 generic=True,
812 priority=-1,
815 priority=-1,
813 )
816 )
814 coreconfigitem('merge-tools', br'.*\.priority$',
817 coreconfigitem('merge-tools', br'.*\.priority$',
815 default=0,
818 default=0,
816 generic=True,
819 generic=True,
817 priority=-1,
820 priority=-1,
818 )
821 )
819 coreconfigitem('merge-tools', br'.*\.premerge$',
822 coreconfigitem('merge-tools', br'.*\.premerge$',
820 default=dynamicdefault,
823 default=dynamicdefault,
821 generic=True,
824 generic=True,
822 priority=-1,
825 priority=-1,
823 )
826 )
824 coreconfigitem('merge-tools', br'.*\.symlink$',
827 coreconfigitem('merge-tools', br'.*\.symlink$',
825 default=False,
828 default=False,
826 generic=True,
829 generic=True,
827 priority=-1,
830 priority=-1,
828 )
831 )
829 coreconfigitem('pager', 'attend-.*',
832 coreconfigitem('pager', 'attend-.*',
830 default=dynamicdefault,
833 default=dynamicdefault,
831 generic=True,
834 generic=True,
832 )
835 )
833 coreconfigitem('pager', 'ignore',
836 coreconfigitem('pager', 'ignore',
834 default=list,
837 default=list,
835 )
838 )
836 coreconfigitem('pager', 'pager',
839 coreconfigitem('pager', 'pager',
837 default=dynamicdefault,
840 default=dynamicdefault,
838 )
841 )
839 coreconfigitem('patch', 'eol',
842 coreconfigitem('patch', 'eol',
840 default='strict',
843 default='strict',
841 )
844 )
842 coreconfigitem('patch', 'fuzz',
845 coreconfigitem('patch', 'fuzz',
843 default=2,
846 default=2,
844 )
847 )
845 coreconfigitem('paths', 'default',
848 coreconfigitem('paths', 'default',
846 default=None,
849 default=None,
847 )
850 )
848 coreconfigitem('paths', 'default-push',
851 coreconfigitem('paths', 'default-push',
849 default=None,
852 default=None,
850 )
853 )
851 coreconfigitem('paths', '.*',
854 coreconfigitem('paths', '.*',
852 default=None,
855 default=None,
853 generic=True,
856 generic=True,
854 )
857 )
855 coreconfigitem('phases', 'checksubrepos',
858 coreconfigitem('phases', 'checksubrepos',
856 default='follow',
859 default='follow',
857 )
860 )
858 coreconfigitem('phases', 'new-commit',
861 coreconfigitem('phases', 'new-commit',
859 default='draft',
862 default='draft',
860 )
863 )
861 coreconfigitem('phases', 'publish',
864 coreconfigitem('phases', 'publish',
862 default=True,
865 default=True,
863 )
866 )
864 coreconfigitem('profiling', 'enabled',
867 coreconfigitem('profiling', 'enabled',
865 default=False,
868 default=False,
866 )
869 )
867 coreconfigitem('profiling', 'format',
870 coreconfigitem('profiling', 'format',
868 default='text',
871 default='text',
869 )
872 )
870 coreconfigitem('profiling', 'freq',
873 coreconfigitem('profiling', 'freq',
871 default=1000,
874 default=1000,
872 )
875 )
873 coreconfigitem('profiling', 'limit',
876 coreconfigitem('profiling', 'limit',
874 default=30,
877 default=30,
875 )
878 )
876 coreconfigitem('profiling', 'nested',
879 coreconfigitem('profiling', 'nested',
877 default=0,
880 default=0,
878 )
881 )
879 coreconfigitem('profiling', 'output',
882 coreconfigitem('profiling', 'output',
880 default=None,
883 default=None,
881 )
884 )
882 coreconfigitem('profiling', 'showmax',
885 coreconfigitem('profiling', 'showmax',
883 default=0.999,
886 default=0.999,
884 )
887 )
885 coreconfigitem('profiling', 'showmin',
888 coreconfigitem('profiling', 'showmin',
886 default=dynamicdefault,
889 default=dynamicdefault,
887 )
890 )
888 coreconfigitem('profiling', 'sort',
891 coreconfigitem('profiling', 'sort',
889 default='inlinetime',
892 default='inlinetime',
890 )
893 )
891 coreconfigitem('profiling', 'statformat',
894 coreconfigitem('profiling', 'statformat',
892 default='hotpath',
895 default='hotpath',
893 )
896 )
894 coreconfigitem('profiling', 'time-track',
897 coreconfigitem('profiling', 'time-track',
895 default='cpu',
898 default='cpu',
896 )
899 )
897 coreconfigitem('profiling', 'type',
900 coreconfigitem('profiling', 'type',
898 default='stat',
901 default='stat',
899 )
902 )
900 coreconfigitem('progress', 'assume-tty',
903 coreconfigitem('progress', 'assume-tty',
901 default=False,
904 default=False,
902 )
905 )
903 coreconfigitem('progress', 'changedelay',
906 coreconfigitem('progress', 'changedelay',
904 default=1,
907 default=1,
905 )
908 )
906 coreconfigitem('progress', 'clear-complete',
909 coreconfigitem('progress', 'clear-complete',
907 default=True,
910 default=True,
908 )
911 )
909 coreconfigitem('progress', 'debug',
912 coreconfigitem('progress', 'debug',
910 default=False,
913 default=False,
911 )
914 )
912 coreconfigitem('progress', 'delay',
915 coreconfigitem('progress', 'delay',
913 default=3,
916 default=3,
914 )
917 )
915 coreconfigitem('progress', 'disable',
918 coreconfigitem('progress', 'disable',
916 default=False,
919 default=False,
917 )
920 )
918 coreconfigitem('progress', 'estimateinterval',
921 coreconfigitem('progress', 'estimateinterval',
919 default=60.0,
922 default=60.0,
920 )
923 )
921 coreconfigitem('progress', 'format',
924 coreconfigitem('progress', 'format',
922 default=lambda: ['topic', 'bar', 'number', 'estimate'],
925 default=lambda: ['topic', 'bar', 'number', 'estimate'],
923 )
926 )
924 coreconfigitem('progress', 'refresh',
927 coreconfigitem('progress', 'refresh',
925 default=0.1,
928 default=0.1,
926 )
929 )
927 coreconfigitem('progress', 'width',
930 coreconfigitem('progress', 'width',
928 default=dynamicdefault,
931 default=dynamicdefault,
929 )
932 )
930 coreconfigitem('push', 'pushvars.server',
933 coreconfigitem('push', 'pushvars.server',
931 default=False,
934 default=False,
932 )
935 )
933 coreconfigitem('storage', 'revlog.optimize-delta-parent-choice',
936 coreconfigitem('storage', 'revlog.optimize-delta-parent-choice',
934 default=True,
937 default=True,
935 alias=[('format', 'aggressivemergedeltas')],
938 alias=[('format', 'aggressivemergedeltas')],
936 )
939 )
937 coreconfigitem('experimental', 'resolve.mark-check',
940 coreconfigitem('experimental', 'resolve.mark-check',
938 default=None,
941 default=None,
939 )
942 )
940 coreconfigitem('server', 'bookmarks-pushkey-compat',
943 coreconfigitem('server', 'bookmarks-pushkey-compat',
941 default=True,
944 default=True,
942 )
945 )
943 coreconfigitem('server', 'bundle1',
946 coreconfigitem('server', 'bundle1',
944 default=True,
947 default=True,
945 )
948 )
946 coreconfigitem('server', 'bundle1gd',
949 coreconfigitem('server', 'bundle1gd',
947 default=None,
950 default=None,
948 )
951 )
949 coreconfigitem('server', 'bundle1.pull',
952 coreconfigitem('server', 'bundle1.pull',
950 default=None,
953 default=None,
951 )
954 )
952 coreconfigitem('server', 'bundle1gd.pull',
955 coreconfigitem('server', 'bundle1gd.pull',
953 default=None,
956 default=None,
954 )
957 )
955 coreconfigitem('server', 'bundle1.push',
958 coreconfigitem('server', 'bundle1.push',
956 default=None,
959 default=None,
957 )
960 )
958 coreconfigitem('server', 'bundle1gd.push',
961 coreconfigitem('server', 'bundle1gd.push',
959 default=None,
962 default=None,
960 )
963 )
961 coreconfigitem('server', 'compressionengines',
964 coreconfigitem('server', 'compressionengines',
962 default=list,
965 default=list,
963 )
966 )
964 coreconfigitem('server', 'concurrent-push-mode',
967 coreconfigitem('server', 'concurrent-push-mode',
965 default='strict',
968 default='strict',
966 )
969 )
967 coreconfigitem('server', 'disablefullbundle',
970 coreconfigitem('server', 'disablefullbundle',
968 default=False,
971 default=False,
969 )
972 )
970 coreconfigitem('server', 'maxhttpheaderlen',
973 coreconfigitem('server', 'maxhttpheaderlen',
971 default=1024,
974 default=1024,
972 )
975 )
973 coreconfigitem('server', 'pullbundle',
976 coreconfigitem('server', 'pullbundle',
974 default=False,
977 default=False,
975 )
978 )
976 coreconfigitem('server', 'preferuncompressed',
979 coreconfigitem('server', 'preferuncompressed',
977 default=False,
980 default=False,
978 )
981 )
979 coreconfigitem('server', 'streamunbundle',
982 coreconfigitem('server', 'streamunbundle',
980 default=False,
983 default=False,
981 )
984 )
982 coreconfigitem('server', 'uncompressed',
985 coreconfigitem('server', 'uncompressed',
983 default=True,
986 default=True,
984 )
987 )
985 coreconfigitem('server', 'uncompressedallowsecret',
988 coreconfigitem('server', 'uncompressedallowsecret',
986 default=False,
989 default=False,
987 )
990 )
988 coreconfigitem('server', 'validate',
991 coreconfigitem('server', 'validate',
989 default=False,
992 default=False,
990 )
993 )
991 coreconfigitem('server', 'zliblevel',
994 coreconfigitem('server', 'zliblevel',
992 default=-1,
995 default=-1,
993 )
996 )
994 coreconfigitem('server', 'zstdlevel',
997 coreconfigitem('server', 'zstdlevel',
995 default=3,
998 default=3,
996 )
999 )
997 coreconfigitem('share', 'pool',
1000 coreconfigitem('share', 'pool',
998 default=None,
1001 default=None,
999 )
1002 )
1000 coreconfigitem('share', 'poolnaming',
1003 coreconfigitem('share', 'poolnaming',
1001 default='identity',
1004 default='identity',
1002 )
1005 )
1003 coreconfigitem('smtp', 'host',
1006 coreconfigitem('smtp', 'host',
1004 default=None,
1007 default=None,
1005 )
1008 )
1006 coreconfigitem('smtp', 'local_hostname',
1009 coreconfigitem('smtp', 'local_hostname',
1007 default=None,
1010 default=None,
1008 )
1011 )
1009 coreconfigitem('smtp', 'password',
1012 coreconfigitem('smtp', 'password',
1010 default=None,
1013 default=None,
1011 )
1014 )
1012 coreconfigitem('smtp', 'port',
1015 coreconfigitem('smtp', 'port',
1013 default=dynamicdefault,
1016 default=dynamicdefault,
1014 )
1017 )
1015 coreconfigitem('smtp', 'tls',
1018 coreconfigitem('smtp', 'tls',
1016 default='none',
1019 default='none',
1017 )
1020 )
1018 coreconfigitem('smtp', 'username',
1021 coreconfigitem('smtp', 'username',
1019 default=None,
1022 default=None,
1020 )
1023 )
1021 coreconfigitem('sparse', 'missingwarning',
1024 coreconfigitem('sparse', 'missingwarning',
1022 default=True,
1025 default=True,
1023 )
1026 )
1024 coreconfigitem('subrepos', 'allowed',
1027 coreconfigitem('subrepos', 'allowed',
1025 default=dynamicdefault, # to make backporting simpler
1028 default=dynamicdefault, # to make backporting simpler
1026 )
1029 )
1027 coreconfigitem('subrepos', 'hg:allowed',
1030 coreconfigitem('subrepos', 'hg:allowed',
1028 default=dynamicdefault,
1031 default=dynamicdefault,
1029 )
1032 )
1030 coreconfigitem('subrepos', 'git:allowed',
1033 coreconfigitem('subrepos', 'git:allowed',
1031 default=dynamicdefault,
1034 default=dynamicdefault,
1032 )
1035 )
1033 coreconfigitem('subrepos', 'svn:allowed',
1036 coreconfigitem('subrepos', 'svn:allowed',
1034 default=dynamicdefault,
1037 default=dynamicdefault,
1035 )
1038 )
1036 coreconfigitem('templates', '.*',
1039 coreconfigitem('templates', '.*',
1037 default=None,
1040 default=None,
1038 generic=True,
1041 generic=True,
1039 )
1042 )
1040 coreconfigitem('trusted', 'groups',
1043 coreconfigitem('trusted', 'groups',
1041 default=list,
1044 default=list,
1042 )
1045 )
1043 coreconfigitem('trusted', 'users',
1046 coreconfigitem('trusted', 'users',
1044 default=list,
1047 default=list,
1045 )
1048 )
1046 coreconfigitem('ui', '_usedassubrepo',
1049 coreconfigitem('ui', '_usedassubrepo',
1047 default=False,
1050 default=False,
1048 )
1051 )
1049 coreconfigitem('ui', 'allowemptycommit',
1052 coreconfigitem('ui', 'allowemptycommit',
1050 default=False,
1053 default=False,
1051 )
1054 )
1052 coreconfigitem('ui', 'archivemeta',
1055 coreconfigitem('ui', 'archivemeta',
1053 default=True,
1056 default=True,
1054 )
1057 )
1055 coreconfigitem('ui', 'askusername',
1058 coreconfigitem('ui', 'askusername',
1056 default=False,
1059 default=False,
1057 )
1060 )
1058 coreconfigitem('ui', 'clonebundlefallback',
1061 coreconfigitem('ui', 'clonebundlefallback',
1059 default=False,
1062 default=False,
1060 )
1063 )
1061 coreconfigitem('ui', 'clonebundleprefers',
1064 coreconfigitem('ui', 'clonebundleprefers',
1062 default=list,
1065 default=list,
1063 )
1066 )
1064 coreconfigitem('ui', 'clonebundles',
1067 coreconfigitem('ui', 'clonebundles',
1065 default=True,
1068 default=True,
1066 )
1069 )
1067 coreconfigitem('ui', 'color',
1070 coreconfigitem('ui', 'color',
1068 default='auto',
1071 default='auto',
1069 )
1072 )
1070 coreconfigitem('ui', 'commitsubrepos',
1073 coreconfigitem('ui', 'commitsubrepos',
1071 default=False,
1074 default=False,
1072 )
1075 )
1073 coreconfigitem('ui', 'debug',
1076 coreconfigitem('ui', 'debug',
1074 default=False,
1077 default=False,
1075 )
1078 )
1076 coreconfigitem('ui', 'debugger',
1079 coreconfigitem('ui', 'debugger',
1077 default=None,
1080 default=None,
1078 )
1081 )
1079 coreconfigitem('ui', 'editor',
1082 coreconfigitem('ui', 'editor',
1080 default=dynamicdefault,
1083 default=dynamicdefault,
1081 )
1084 )
1082 coreconfigitem('ui', 'fallbackencoding',
1085 coreconfigitem('ui', 'fallbackencoding',
1083 default=None,
1086 default=None,
1084 )
1087 )
1085 coreconfigitem('ui', 'forcecwd',
1088 coreconfigitem('ui', 'forcecwd',
1086 default=None,
1089 default=None,
1087 )
1090 )
1088 coreconfigitem('ui', 'forcemerge',
1091 coreconfigitem('ui', 'forcemerge',
1089 default=None,
1092 default=None,
1090 )
1093 )
1091 coreconfigitem('ui', 'formatdebug',
1094 coreconfigitem('ui', 'formatdebug',
1092 default=False,
1095 default=False,
1093 )
1096 )
1094 coreconfigitem('ui', 'formatjson',
1097 coreconfigitem('ui', 'formatjson',
1095 default=False,
1098 default=False,
1096 )
1099 )
1097 coreconfigitem('ui', 'formatted',
1100 coreconfigitem('ui', 'formatted',
1098 default=None,
1101 default=None,
1099 )
1102 )
1100 coreconfigitem('ui', 'graphnodetemplate',
1103 coreconfigitem('ui', 'graphnodetemplate',
1101 default=None,
1104 default=None,
1102 )
1105 )
1103 coreconfigitem('ui', 'history-editing-backup',
1106 coreconfigitem('ui', 'history-editing-backup',
1104 default=True,
1107 default=True,
1105 )
1108 )
1106 coreconfigitem('ui', 'interactive',
1109 coreconfigitem('ui', 'interactive',
1107 default=None,
1110 default=None,
1108 )
1111 )
1109 coreconfigitem('ui', 'interface',
1112 coreconfigitem('ui', 'interface',
1110 default=None,
1113 default=None,
1111 )
1114 )
1112 coreconfigitem('ui', 'interface.chunkselector',
1115 coreconfigitem('ui', 'interface.chunkselector',
1113 default=None,
1116 default=None,
1114 )
1117 )
1115 coreconfigitem('ui', 'large-file-limit',
1118 coreconfigitem('ui', 'large-file-limit',
1116 default=10000000,
1119 default=10000000,
1117 )
1120 )
1118 coreconfigitem('ui', 'logblockedtimes',
1121 coreconfigitem('ui', 'logblockedtimes',
1119 default=False,
1122 default=False,
1120 )
1123 )
1121 coreconfigitem('ui', 'logtemplate',
1124 coreconfigitem('ui', 'logtemplate',
1122 default=None,
1125 default=None,
1123 )
1126 )
1124 coreconfigitem('ui', 'merge',
1127 coreconfigitem('ui', 'merge',
1125 default=None,
1128 default=None,
1126 )
1129 )
1127 coreconfigitem('ui', 'mergemarkers',
1130 coreconfigitem('ui', 'mergemarkers',
1128 default='basic',
1131 default='basic',
1129 )
1132 )
1130 coreconfigitem('ui', 'mergemarkertemplate',
1133 coreconfigitem('ui', 'mergemarkertemplate',
1131 default=('{node|short} '
1134 default=('{node|short} '
1132 '{ifeq(tags, "tip", "", '
1135 '{ifeq(tags, "tip", "", '
1133 'ifeq(tags, "", "", "{tags} "))}'
1136 'ifeq(tags, "", "", "{tags} "))}'
1134 '{if(bookmarks, "{bookmarks} ")}'
1137 '{if(bookmarks, "{bookmarks} ")}'
1135 '{ifeq(branch, "default", "", "{branch} ")}'
1138 '{ifeq(branch, "default", "", "{branch} ")}'
1136 '- {author|user}: {desc|firstline}')
1139 '- {author|user}: {desc|firstline}')
1137 )
1140 )
1138 coreconfigitem('ui', 'nontty',
1141 coreconfigitem('ui', 'nontty',
1139 default=False,
1142 default=False,
1140 )
1143 )
1141 coreconfigitem('ui', 'origbackuppath',
1144 coreconfigitem('ui', 'origbackuppath',
1142 default=None,
1145 default=None,
1143 )
1146 )
1144 coreconfigitem('ui', 'paginate',
1147 coreconfigitem('ui', 'paginate',
1145 default=True,
1148 default=True,
1146 )
1149 )
1147 coreconfigitem('ui', 'patch',
1150 coreconfigitem('ui', 'patch',
1148 default=None,
1151 default=None,
1149 )
1152 )
1150 coreconfigitem('ui', 'portablefilenames',
1153 coreconfigitem('ui', 'portablefilenames',
1151 default='warn',
1154 default='warn',
1152 )
1155 )
1153 coreconfigitem('ui', 'promptecho',
1156 coreconfigitem('ui', 'promptecho',
1154 default=False,
1157 default=False,
1155 )
1158 )
1156 coreconfigitem('ui', 'quiet',
1159 coreconfigitem('ui', 'quiet',
1157 default=False,
1160 default=False,
1158 )
1161 )
1159 coreconfigitem('ui', 'quietbookmarkmove',
1162 coreconfigitem('ui', 'quietbookmarkmove',
1160 default=False,
1163 default=False,
1161 )
1164 )
1162 coreconfigitem('ui', 'remotecmd',
1165 coreconfigitem('ui', 'remotecmd',
1163 default='hg',
1166 default='hg',
1164 )
1167 )
1165 coreconfigitem('ui', 'report_untrusted',
1168 coreconfigitem('ui', 'report_untrusted',
1166 default=True,
1169 default=True,
1167 )
1170 )
1168 coreconfigitem('ui', 'rollback',
1171 coreconfigitem('ui', 'rollback',
1169 default=True,
1172 default=True,
1170 )
1173 )
1171 coreconfigitem('ui', 'signal-safe-lock',
1174 coreconfigitem('ui', 'signal-safe-lock',
1172 default=True,
1175 default=True,
1173 )
1176 )
1174 coreconfigitem('ui', 'slash',
1177 coreconfigitem('ui', 'slash',
1175 default=False,
1178 default=False,
1176 )
1179 )
1177 coreconfigitem('ui', 'ssh',
1180 coreconfigitem('ui', 'ssh',
1178 default='ssh',
1181 default='ssh',
1179 )
1182 )
1180 coreconfigitem('ui', 'ssherrorhint',
1183 coreconfigitem('ui', 'ssherrorhint',
1181 default=None,
1184 default=None,
1182 )
1185 )
1183 coreconfigitem('ui', 'statuscopies',
1186 coreconfigitem('ui', 'statuscopies',
1184 default=False,
1187 default=False,
1185 )
1188 )
1186 coreconfigitem('ui', 'strict',
1189 coreconfigitem('ui', 'strict',
1187 default=False,
1190 default=False,
1188 )
1191 )
1189 coreconfigitem('ui', 'style',
1192 coreconfigitem('ui', 'style',
1190 default='',
1193 default='',
1191 )
1194 )
1192 coreconfigitem('ui', 'supportcontact',
1195 coreconfigitem('ui', 'supportcontact',
1193 default=None,
1196 default=None,
1194 )
1197 )
1195 coreconfigitem('ui', 'textwidth',
1198 coreconfigitem('ui', 'textwidth',
1196 default=78,
1199 default=78,
1197 )
1200 )
1198 coreconfigitem('ui', 'timeout',
1201 coreconfigitem('ui', 'timeout',
1199 default='600',
1202 default='600',
1200 )
1203 )
1201 coreconfigitem('ui', 'timeout.warn',
1204 coreconfigitem('ui', 'timeout.warn',
1202 default=0,
1205 default=0,
1203 )
1206 )
1204 coreconfigitem('ui', 'traceback',
1207 coreconfigitem('ui', 'traceback',
1205 default=False,
1208 default=False,
1206 )
1209 )
1207 coreconfigitem('ui', 'tweakdefaults',
1210 coreconfigitem('ui', 'tweakdefaults',
1208 default=False,
1211 default=False,
1209 )
1212 )
1210 coreconfigitem('ui', 'username',
1213 coreconfigitem('ui', 'username',
1211 alias=[('ui', 'user')]
1214 alias=[('ui', 'user')]
1212 )
1215 )
1213 coreconfigitem('ui', 'verbose',
1216 coreconfigitem('ui', 'verbose',
1214 default=False,
1217 default=False,
1215 )
1218 )
1216 coreconfigitem('verify', 'skipflags',
1219 coreconfigitem('verify', 'skipflags',
1217 default=None,
1220 default=None,
1218 )
1221 )
1219 coreconfigitem('web', 'allowbz2',
1222 coreconfigitem('web', 'allowbz2',
1220 default=False,
1223 default=False,
1221 )
1224 )
1222 coreconfigitem('web', 'allowgz',
1225 coreconfigitem('web', 'allowgz',
1223 default=False,
1226 default=False,
1224 )
1227 )
1225 coreconfigitem('web', 'allow-pull',
1228 coreconfigitem('web', 'allow-pull',
1226 alias=[('web', 'allowpull')],
1229 alias=[('web', 'allowpull')],
1227 default=True,
1230 default=True,
1228 )
1231 )
1229 coreconfigitem('web', 'allow-push',
1232 coreconfigitem('web', 'allow-push',
1230 alias=[('web', 'allow_push')],
1233 alias=[('web', 'allow_push')],
1231 default=list,
1234 default=list,
1232 )
1235 )
1233 coreconfigitem('web', 'allowzip',
1236 coreconfigitem('web', 'allowzip',
1234 default=False,
1237 default=False,
1235 )
1238 )
1236 coreconfigitem('web', 'archivesubrepos',
1239 coreconfigitem('web', 'archivesubrepos',
1237 default=False,
1240 default=False,
1238 )
1241 )
1239 coreconfigitem('web', 'cache',
1242 coreconfigitem('web', 'cache',
1240 default=True,
1243 default=True,
1241 )
1244 )
1242 coreconfigitem('web', 'contact',
1245 coreconfigitem('web', 'contact',
1243 default=None,
1246 default=None,
1244 )
1247 )
1245 coreconfigitem('web', 'deny_push',
1248 coreconfigitem('web', 'deny_push',
1246 default=list,
1249 default=list,
1247 )
1250 )
1248 coreconfigitem('web', 'guessmime',
1251 coreconfigitem('web', 'guessmime',
1249 default=False,
1252 default=False,
1250 )
1253 )
1251 coreconfigitem('web', 'hidden',
1254 coreconfigitem('web', 'hidden',
1252 default=False,
1255 default=False,
1253 )
1256 )
1254 coreconfigitem('web', 'labels',
1257 coreconfigitem('web', 'labels',
1255 default=list,
1258 default=list,
1256 )
1259 )
1257 coreconfigitem('web', 'logoimg',
1260 coreconfigitem('web', 'logoimg',
1258 default='hglogo.png',
1261 default='hglogo.png',
1259 )
1262 )
1260 coreconfigitem('web', 'logourl',
1263 coreconfigitem('web', 'logourl',
1261 default='https://mercurial-scm.org/',
1264 default='https://mercurial-scm.org/',
1262 )
1265 )
1263 coreconfigitem('web', 'accesslog',
1266 coreconfigitem('web', 'accesslog',
1264 default='-',
1267 default='-',
1265 )
1268 )
1266 coreconfigitem('web', 'address',
1269 coreconfigitem('web', 'address',
1267 default='',
1270 default='',
1268 )
1271 )
1269 coreconfigitem('web', 'allow-archive',
1272 coreconfigitem('web', 'allow-archive',
1270 alias=[('web', 'allow_archive')],
1273 alias=[('web', 'allow_archive')],
1271 default=list,
1274 default=list,
1272 )
1275 )
1273 coreconfigitem('web', 'allow_read',
1276 coreconfigitem('web', 'allow_read',
1274 default=list,
1277 default=list,
1275 )
1278 )
1276 coreconfigitem('web', 'baseurl',
1279 coreconfigitem('web', 'baseurl',
1277 default=None,
1280 default=None,
1278 )
1281 )
1279 coreconfigitem('web', 'cacerts',
1282 coreconfigitem('web', 'cacerts',
1280 default=None,
1283 default=None,
1281 )
1284 )
1282 coreconfigitem('web', 'certificate',
1285 coreconfigitem('web', 'certificate',
1283 default=None,
1286 default=None,
1284 )
1287 )
1285 coreconfigitem('web', 'collapse',
1288 coreconfigitem('web', 'collapse',
1286 default=False,
1289 default=False,
1287 )
1290 )
1288 coreconfigitem('web', 'csp',
1291 coreconfigitem('web', 'csp',
1289 default=None,
1292 default=None,
1290 )
1293 )
1291 coreconfigitem('web', 'deny_read',
1294 coreconfigitem('web', 'deny_read',
1292 default=list,
1295 default=list,
1293 )
1296 )
1294 coreconfigitem('web', 'descend',
1297 coreconfigitem('web', 'descend',
1295 default=True,
1298 default=True,
1296 )
1299 )
1297 coreconfigitem('web', 'description',
1300 coreconfigitem('web', 'description',
1298 default="",
1301 default="",
1299 )
1302 )
1300 coreconfigitem('web', 'encoding',
1303 coreconfigitem('web', 'encoding',
1301 default=lambda: encoding.encoding,
1304 default=lambda: encoding.encoding,
1302 )
1305 )
1303 coreconfigitem('web', 'errorlog',
1306 coreconfigitem('web', 'errorlog',
1304 default='-',
1307 default='-',
1305 )
1308 )
1306 coreconfigitem('web', 'ipv6',
1309 coreconfigitem('web', 'ipv6',
1307 default=False,
1310 default=False,
1308 )
1311 )
1309 coreconfigitem('web', 'maxchanges',
1312 coreconfigitem('web', 'maxchanges',
1310 default=10,
1313 default=10,
1311 )
1314 )
1312 coreconfigitem('web', 'maxfiles',
1315 coreconfigitem('web', 'maxfiles',
1313 default=10,
1316 default=10,
1314 )
1317 )
1315 coreconfigitem('web', 'maxshortchanges',
1318 coreconfigitem('web', 'maxshortchanges',
1316 default=60,
1319 default=60,
1317 )
1320 )
1318 coreconfigitem('web', 'motd',
1321 coreconfigitem('web', 'motd',
1319 default='',
1322 default='',
1320 )
1323 )
1321 coreconfigitem('web', 'name',
1324 coreconfigitem('web', 'name',
1322 default=dynamicdefault,
1325 default=dynamicdefault,
1323 )
1326 )
1324 coreconfigitem('web', 'port',
1327 coreconfigitem('web', 'port',
1325 default=8000,
1328 default=8000,
1326 )
1329 )
1327 coreconfigitem('web', 'prefix',
1330 coreconfigitem('web', 'prefix',
1328 default='',
1331 default='',
1329 )
1332 )
1330 coreconfigitem('web', 'push_ssl',
1333 coreconfigitem('web', 'push_ssl',
1331 default=True,
1334 default=True,
1332 )
1335 )
1333 coreconfigitem('web', 'refreshinterval',
1336 coreconfigitem('web', 'refreshinterval',
1334 default=20,
1337 default=20,
1335 )
1338 )
1336 coreconfigitem('web', 'server-header',
1339 coreconfigitem('web', 'server-header',
1337 default=None,
1340 default=None,
1338 )
1341 )
1339 coreconfigitem('web', 'staticurl',
1342 coreconfigitem('web', 'staticurl',
1340 default=None,
1343 default=None,
1341 )
1344 )
1342 coreconfigitem('web', 'stripes',
1345 coreconfigitem('web', 'stripes',
1343 default=1,
1346 default=1,
1344 )
1347 )
1345 coreconfigitem('web', 'style',
1348 coreconfigitem('web', 'style',
1346 default='paper',
1349 default='paper',
1347 )
1350 )
1348 coreconfigitem('web', 'templates',
1351 coreconfigitem('web', 'templates',
1349 default=None,
1352 default=None,
1350 )
1353 )
1351 coreconfigitem('web', 'view',
1354 coreconfigitem('web', 'view',
1352 default='served',
1355 default='served',
1353 )
1356 )
1354 coreconfigitem('worker', 'backgroundclose',
1357 coreconfigitem('worker', 'backgroundclose',
1355 default=dynamicdefault,
1358 default=dynamicdefault,
1356 )
1359 )
1357 # Windows defaults to a limit of 512 open files. A buffer of 128
1360 # Windows defaults to a limit of 512 open files. A buffer of 128
1358 # should give us enough headway.
1361 # should give us enough headway.
1359 coreconfigitem('worker', 'backgroundclosemaxqueue',
1362 coreconfigitem('worker', 'backgroundclosemaxqueue',
1360 default=384,
1363 default=384,
1361 )
1364 )
1362 coreconfigitem('worker', 'backgroundcloseminfilecount',
1365 coreconfigitem('worker', 'backgroundcloseminfilecount',
1363 default=2048,
1366 default=2048,
1364 )
1367 )
1365 coreconfigitem('worker', 'backgroundclosethreadcount',
1368 coreconfigitem('worker', 'backgroundclosethreadcount',
1366 default=4,
1369 default=4,
1367 )
1370 )
1368 coreconfigitem('worker', 'enabled',
1371 coreconfigitem('worker', 'enabled',
1369 default=True,
1372 default=True,
1370 )
1373 )
1371 coreconfigitem('worker', 'numcpus',
1374 coreconfigitem('worker', 'numcpus',
1372 default=None,
1375 default=None,
1373 )
1376 )
1374
1377
1375 # Rebase related configuration moved to core because other extension are doing
1378 # Rebase related configuration moved to core because other extension are doing
1376 # strange things. For example, shelve import the extensions to reuse some bit
1379 # strange things. For example, shelve import the extensions to reuse some bit
1377 # without formally loading it.
1380 # without formally loading it.
1378 coreconfigitem('commands', 'rebase.requiredest',
1381 coreconfigitem('commands', 'rebase.requiredest',
1379 default=False,
1382 default=False,
1380 )
1383 )
1381 coreconfigitem('experimental', 'rebaseskipobsolete',
1384 coreconfigitem('experimental', 'rebaseskipobsolete',
1382 default=True,
1385 default=True,
1383 )
1386 )
1384 coreconfigitem('rebase', 'singletransaction',
1387 coreconfigitem('rebase', 'singletransaction',
1385 default=False,
1388 default=False,
1386 )
1389 )
1387 coreconfigitem('rebase', 'experimental.inmemory',
1390 coreconfigitem('rebase', 'experimental.inmemory',
1388 default=False,
1391 default=False,
1389 )
1392 )
@@ -1,1701 +1,1718
1 # scmutil.py - Mercurial core utility functions
1 # scmutil.py - Mercurial core utility functions
2 #
2 #
3 # Copyright Matt Mackall <mpm@selenic.com>
3 # Copyright Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 from __future__ import absolute_import
8 from __future__ import absolute_import
9
9
10 import errno
10 import errno
11 import glob
11 import glob
12 import hashlib
12 import hashlib
13 import os
13 import os
14 import re
14 import re
15 import socket
15 import socket
16 import subprocess
16 import subprocess
17 import weakref
17 import weakref
18
18
19 from .i18n import _
19 from .i18n import _
20 from .node import (
20 from .node import (
21 bin,
21 bin,
22 hex,
22 hex,
23 nullid,
23 nullid,
24 short,
24 short,
25 wdirid,
25 wdirid,
26 wdirrev,
26 wdirrev,
27 )
27 )
28
28
29 from . import (
29 from . import (
30 encoding,
30 encoding,
31 error,
31 error,
32 match as matchmod,
32 match as matchmod,
33 obsolete,
33 obsolete,
34 obsutil,
34 obsutil,
35 pathutil,
35 pathutil,
36 phases,
36 phases,
37 pycompat,
37 pycompat,
38 revsetlang,
38 revsetlang,
39 similar,
39 similar,
40 url,
40 url,
41 util,
41 util,
42 vfs,
42 vfs,
43 )
43 )
44
44
45 from .utils import (
45 from .utils import (
46 procutil,
46 procutil,
47 stringutil,
47 stringutil,
48 )
48 )
49
49
50 if pycompat.iswindows:
50 if pycompat.iswindows:
51 from . import scmwindows as scmplatform
51 from . import scmwindows as scmplatform
52 else:
52 else:
53 from . import scmposix as scmplatform
53 from . import scmposix as scmplatform
54
54
55 termsize = scmplatform.termsize
55 termsize = scmplatform.termsize
56
56
57 class status(tuple):
57 class status(tuple):
58 '''Named tuple with a list of files per status. The 'deleted', 'unknown'
58 '''Named tuple with a list of files per status. The 'deleted', 'unknown'
59 and 'ignored' properties are only relevant to the working copy.
59 and 'ignored' properties are only relevant to the working copy.
60 '''
60 '''
61
61
62 __slots__ = ()
62 __slots__ = ()
63
63
64 def __new__(cls, modified, added, removed, deleted, unknown, ignored,
64 def __new__(cls, modified, added, removed, deleted, unknown, ignored,
65 clean):
65 clean):
66 return tuple.__new__(cls, (modified, added, removed, deleted, unknown,
66 return tuple.__new__(cls, (modified, added, removed, deleted, unknown,
67 ignored, clean))
67 ignored, clean))
68
68
69 @property
69 @property
70 def modified(self):
70 def modified(self):
71 '''files that have been modified'''
71 '''files that have been modified'''
72 return self[0]
72 return self[0]
73
73
74 @property
74 @property
75 def added(self):
75 def added(self):
76 '''files that have been added'''
76 '''files that have been added'''
77 return self[1]
77 return self[1]
78
78
79 @property
79 @property
80 def removed(self):
80 def removed(self):
81 '''files that have been removed'''
81 '''files that have been removed'''
82 return self[2]
82 return self[2]
83
83
84 @property
84 @property
85 def deleted(self):
85 def deleted(self):
86 '''files that are in the dirstate, but have been deleted from the
86 '''files that are in the dirstate, but have been deleted from the
87 working copy (aka "missing")
87 working copy (aka "missing")
88 '''
88 '''
89 return self[3]
89 return self[3]
90
90
91 @property
91 @property
92 def unknown(self):
92 def unknown(self):
93 '''files not in the dirstate that are not ignored'''
93 '''files not in the dirstate that are not ignored'''
94 return self[4]
94 return self[4]
95
95
96 @property
96 @property
97 def ignored(self):
97 def ignored(self):
98 '''files not in the dirstate that are ignored (by _dirignore())'''
98 '''files not in the dirstate that are ignored (by _dirignore())'''
99 return self[5]
99 return self[5]
100
100
101 @property
101 @property
102 def clean(self):
102 def clean(self):
103 '''files that have not been modified'''
103 '''files that have not been modified'''
104 return self[6]
104 return self[6]
105
105
106 def __repr__(self, *args, **kwargs):
106 def __repr__(self, *args, **kwargs):
107 return ((r'<status modified=%s, added=%s, removed=%s, deleted=%s, '
107 return ((r'<status modified=%s, added=%s, removed=%s, deleted=%s, '
108 r'unknown=%s, ignored=%s, clean=%s>') %
108 r'unknown=%s, ignored=%s, clean=%s>') %
109 tuple(pycompat.sysstr(stringutil.pprint(v)) for v in self))
109 tuple(pycompat.sysstr(stringutil.pprint(v)) for v in self))
110
110
111 def itersubrepos(ctx1, ctx2):
111 def itersubrepos(ctx1, ctx2):
112 """find subrepos in ctx1 or ctx2"""
112 """find subrepos in ctx1 or ctx2"""
113 # Create a (subpath, ctx) mapping where we prefer subpaths from
113 # Create a (subpath, ctx) mapping where we prefer subpaths from
114 # ctx1. The subpaths from ctx2 are important when the .hgsub file
114 # ctx1. The subpaths from ctx2 are important when the .hgsub file
115 # has been modified (in ctx2) but not yet committed (in ctx1).
115 # has been modified (in ctx2) but not yet committed (in ctx1).
116 subpaths = dict.fromkeys(ctx2.substate, ctx2)
116 subpaths = dict.fromkeys(ctx2.substate, ctx2)
117 subpaths.update(dict.fromkeys(ctx1.substate, ctx1))
117 subpaths.update(dict.fromkeys(ctx1.substate, ctx1))
118
118
119 missing = set()
119 missing = set()
120
120
121 for subpath in ctx2.substate:
121 for subpath in ctx2.substate:
122 if subpath not in ctx1.substate:
122 if subpath not in ctx1.substate:
123 del subpaths[subpath]
123 del subpaths[subpath]
124 missing.add(subpath)
124 missing.add(subpath)
125
125
126 for subpath, ctx in sorted(subpaths.iteritems()):
126 for subpath, ctx in sorted(subpaths.iteritems()):
127 yield subpath, ctx.sub(subpath)
127 yield subpath, ctx.sub(subpath)
128
128
129 # Yield an empty subrepo based on ctx1 for anything only in ctx2. That way,
129 # Yield an empty subrepo based on ctx1 for anything only in ctx2. That way,
130 # status and diff will have an accurate result when it does
130 # status and diff will have an accurate result when it does
131 # 'sub.{status|diff}(rev2)'. Otherwise, the ctx2 subrepo is compared
131 # 'sub.{status|diff}(rev2)'. Otherwise, the ctx2 subrepo is compared
132 # against itself.
132 # against itself.
133 for subpath in missing:
133 for subpath in missing:
134 yield subpath, ctx2.nullsub(subpath, ctx1)
134 yield subpath, ctx2.nullsub(subpath, ctx1)
135
135
136 def nochangesfound(ui, repo, excluded=None):
136 def nochangesfound(ui, repo, excluded=None):
137 '''Report no changes for push/pull, excluded is None or a list of
137 '''Report no changes for push/pull, excluded is None or a list of
138 nodes excluded from the push/pull.
138 nodes excluded from the push/pull.
139 '''
139 '''
140 secretlist = []
140 secretlist = []
141 if excluded:
141 if excluded:
142 for n in excluded:
142 for n in excluded:
143 ctx = repo[n]
143 ctx = repo[n]
144 if ctx.phase() >= phases.secret and not ctx.extinct():
144 if ctx.phase() >= phases.secret and not ctx.extinct():
145 secretlist.append(n)
145 secretlist.append(n)
146
146
147 if secretlist:
147 if secretlist:
148 ui.status(_("no changes found (ignored %d secret changesets)\n")
148 ui.status(_("no changes found (ignored %d secret changesets)\n")
149 % len(secretlist))
149 % len(secretlist))
150 else:
150 else:
151 ui.status(_("no changes found\n"))
151 ui.status(_("no changes found\n"))
152
152
153 def callcatch(ui, func):
153 def callcatch(ui, func):
154 """call func() with global exception handling
154 """call func() with global exception handling
155
155
156 return func() if no exception happens. otherwise do some error handling
156 return func() if no exception happens. otherwise do some error handling
157 and return an exit code accordingly. does not handle all exceptions.
157 and return an exit code accordingly. does not handle all exceptions.
158 """
158 """
159 try:
159 try:
160 try:
160 try:
161 return func()
161 return func()
162 except: # re-raises
162 except: # re-raises
163 ui.traceback()
163 ui.traceback()
164 raise
164 raise
165 # Global exception handling, alphabetically
165 # Global exception handling, alphabetically
166 # Mercurial-specific first, followed by built-in and library exceptions
166 # Mercurial-specific first, followed by built-in and library exceptions
167 except error.LockHeld as inst:
167 except error.LockHeld as inst:
168 if inst.errno == errno.ETIMEDOUT:
168 if inst.errno == errno.ETIMEDOUT:
169 reason = _('timed out waiting for lock held by %r') % inst.locker
169 reason = _('timed out waiting for lock held by %r') % inst.locker
170 else:
170 else:
171 reason = _('lock held by %r') % inst.locker
171 reason = _('lock held by %r') % inst.locker
172 ui.error(_("abort: %s: %s\n") % (
172 ui.error(_("abort: %s: %s\n") % (
173 inst.desc or stringutil.forcebytestr(inst.filename), reason))
173 inst.desc or stringutil.forcebytestr(inst.filename), reason))
174 if not inst.locker:
174 if not inst.locker:
175 ui.error(_("(lock might be very busy)\n"))
175 ui.error(_("(lock might be very busy)\n"))
176 except error.LockUnavailable as inst:
176 except error.LockUnavailable as inst:
177 ui.error(_("abort: could not lock %s: %s\n") %
177 ui.error(_("abort: could not lock %s: %s\n") %
178 (inst.desc or stringutil.forcebytestr(inst.filename),
178 (inst.desc or stringutil.forcebytestr(inst.filename),
179 encoding.strtolocal(inst.strerror)))
179 encoding.strtolocal(inst.strerror)))
180 except error.OutOfBandError as inst:
180 except error.OutOfBandError as inst:
181 if inst.args:
181 if inst.args:
182 msg = _("abort: remote error:\n")
182 msg = _("abort: remote error:\n")
183 else:
183 else:
184 msg = _("abort: remote error\n")
184 msg = _("abort: remote error\n")
185 ui.error(msg)
185 ui.error(msg)
186 if inst.args:
186 if inst.args:
187 ui.error(''.join(inst.args))
187 ui.error(''.join(inst.args))
188 if inst.hint:
188 if inst.hint:
189 ui.error('(%s)\n' % inst.hint)
189 ui.error('(%s)\n' % inst.hint)
190 except error.RepoError as inst:
190 except error.RepoError as inst:
191 ui.error(_("abort: %s!\n") % inst)
191 ui.error(_("abort: %s!\n") % inst)
192 if inst.hint:
192 if inst.hint:
193 ui.error(_("(%s)\n") % inst.hint)
193 ui.error(_("(%s)\n") % inst.hint)
194 except error.ResponseError as inst:
194 except error.ResponseError as inst:
195 ui.error(_("abort: %s") % inst.args[0])
195 ui.error(_("abort: %s") % inst.args[0])
196 msg = inst.args[1]
196 msg = inst.args[1]
197 if isinstance(msg, type(u'')):
197 if isinstance(msg, type(u'')):
198 msg = pycompat.sysbytes(msg)
198 msg = pycompat.sysbytes(msg)
199 if not isinstance(msg, bytes):
199 if not isinstance(msg, bytes):
200 ui.error(" %r\n" % (msg,))
200 ui.error(" %r\n" % (msg,))
201 elif not msg:
201 elif not msg:
202 ui.error(_(" empty string\n"))
202 ui.error(_(" empty string\n"))
203 else:
203 else:
204 ui.error("\n%r\n" % pycompat.bytestr(stringutil.ellipsis(msg)))
204 ui.error("\n%r\n" % pycompat.bytestr(stringutil.ellipsis(msg)))
205 except error.CensoredNodeError as inst:
205 except error.CensoredNodeError as inst:
206 ui.error(_("abort: file censored %s!\n") % inst)
206 ui.error(_("abort: file censored %s!\n") % inst)
207 except error.RevlogError as inst:
207 except error.RevlogError as inst:
208 ui.error(_("abort: %s!\n") % inst)
208 ui.error(_("abort: %s!\n") % inst)
209 except error.InterventionRequired as inst:
209 except error.InterventionRequired as inst:
210 ui.error("%s\n" % inst)
210 ui.error("%s\n" % inst)
211 if inst.hint:
211 if inst.hint:
212 ui.error(_("(%s)\n") % inst.hint)
212 ui.error(_("(%s)\n") % inst.hint)
213 return 1
213 return 1
214 except error.WdirUnsupported:
214 except error.WdirUnsupported:
215 ui.error(_("abort: working directory revision cannot be specified\n"))
215 ui.error(_("abort: working directory revision cannot be specified\n"))
216 except error.Abort as inst:
216 except error.Abort as inst:
217 ui.error(_("abort: %s\n") % inst)
217 ui.error(_("abort: %s\n") % inst)
218 if inst.hint:
218 if inst.hint:
219 ui.error(_("(%s)\n") % inst.hint)
219 ui.error(_("(%s)\n") % inst.hint)
220 except ImportError as inst:
220 except ImportError as inst:
221 ui.error(_("abort: %s!\n") % stringutil.forcebytestr(inst))
221 ui.error(_("abort: %s!\n") % stringutil.forcebytestr(inst))
222 m = stringutil.forcebytestr(inst).split()[-1]
222 m = stringutil.forcebytestr(inst).split()[-1]
223 if m in "mpatch bdiff".split():
223 if m in "mpatch bdiff".split():
224 ui.error(_("(did you forget to compile extensions?)\n"))
224 ui.error(_("(did you forget to compile extensions?)\n"))
225 elif m in "zlib".split():
225 elif m in "zlib".split():
226 ui.error(_("(is your Python install correct?)\n"))
226 ui.error(_("(is your Python install correct?)\n"))
227 except IOError as inst:
227 except IOError as inst:
228 if util.safehasattr(inst, "code"):
228 if util.safehasattr(inst, "code"):
229 ui.error(_("abort: %s\n") % stringutil.forcebytestr(inst))
229 ui.error(_("abort: %s\n") % stringutil.forcebytestr(inst))
230 elif util.safehasattr(inst, "reason"):
230 elif util.safehasattr(inst, "reason"):
231 try: # usually it is in the form (errno, strerror)
231 try: # usually it is in the form (errno, strerror)
232 reason = inst.reason.args[1]
232 reason = inst.reason.args[1]
233 except (AttributeError, IndexError):
233 except (AttributeError, IndexError):
234 # it might be anything, for example a string
234 # it might be anything, for example a string
235 reason = inst.reason
235 reason = inst.reason
236 if isinstance(reason, pycompat.unicode):
236 if isinstance(reason, pycompat.unicode):
237 # SSLError of Python 2.7.9 contains a unicode
237 # SSLError of Python 2.7.9 contains a unicode
238 reason = encoding.unitolocal(reason)
238 reason = encoding.unitolocal(reason)
239 ui.error(_("abort: error: %s\n") % reason)
239 ui.error(_("abort: error: %s\n") % reason)
240 elif (util.safehasattr(inst, "args")
240 elif (util.safehasattr(inst, "args")
241 and inst.args and inst.args[0] == errno.EPIPE):
241 and inst.args and inst.args[0] == errno.EPIPE):
242 pass
242 pass
243 elif getattr(inst, "strerror", None):
243 elif getattr(inst, "strerror", None):
244 if getattr(inst, "filename", None):
244 if getattr(inst, "filename", None):
245 ui.error(_("abort: %s: %s\n") % (
245 ui.error(_("abort: %s: %s\n") % (
246 encoding.strtolocal(inst.strerror),
246 encoding.strtolocal(inst.strerror),
247 stringutil.forcebytestr(inst.filename)))
247 stringutil.forcebytestr(inst.filename)))
248 else:
248 else:
249 ui.error(_("abort: %s\n") % encoding.strtolocal(inst.strerror))
249 ui.error(_("abort: %s\n") % encoding.strtolocal(inst.strerror))
250 else:
250 else:
251 raise
251 raise
252 except OSError as inst:
252 except OSError as inst:
253 if getattr(inst, "filename", None) is not None:
253 if getattr(inst, "filename", None) is not None:
254 ui.error(_("abort: %s: '%s'\n") % (
254 ui.error(_("abort: %s: '%s'\n") % (
255 encoding.strtolocal(inst.strerror),
255 encoding.strtolocal(inst.strerror),
256 stringutil.forcebytestr(inst.filename)))
256 stringutil.forcebytestr(inst.filename)))
257 else:
257 else:
258 ui.error(_("abort: %s\n") % encoding.strtolocal(inst.strerror))
258 ui.error(_("abort: %s\n") % encoding.strtolocal(inst.strerror))
259 except MemoryError:
259 except MemoryError:
260 ui.error(_("abort: out of memory\n"))
260 ui.error(_("abort: out of memory\n"))
261 except SystemExit as inst:
261 except SystemExit as inst:
262 # Commands shouldn't sys.exit directly, but give a return code.
262 # Commands shouldn't sys.exit directly, but give a return code.
263 # Just in case catch this and and pass exit code to caller.
263 # Just in case catch this and and pass exit code to caller.
264 return inst.code
264 return inst.code
265 except socket.error as inst:
265 except socket.error as inst:
266 ui.error(_("abort: %s\n") % stringutil.forcebytestr(inst.args[-1]))
266 ui.error(_("abort: %s\n") % stringutil.forcebytestr(inst.args[-1]))
267
267
268 return -1
268 return -1
269
269
270 def checknewlabel(repo, lbl, kind):
270 def checknewlabel(repo, lbl, kind):
271 # Do not use the "kind" parameter in ui output.
271 # Do not use the "kind" parameter in ui output.
272 # It makes strings difficult to translate.
272 # It makes strings difficult to translate.
273 if lbl in ['tip', '.', 'null']:
273 if lbl in ['tip', '.', 'null']:
274 raise error.Abort(_("the name '%s' is reserved") % lbl)
274 raise error.Abort(_("the name '%s' is reserved") % lbl)
275 for c in (':', '\0', '\n', '\r'):
275 for c in (':', '\0', '\n', '\r'):
276 if c in lbl:
276 if c in lbl:
277 raise error.Abort(
277 raise error.Abort(
278 _("%r cannot be used in a name") % pycompat.bytestr(c))
278 _("%r cannot be used in a name") % pycompat.bytestr(c))
279 try:
279 try:
280 int(lbl)
280 int(lbl)
281 raise error.Abort(_("cannot use an integer as a name"))
281 raise error.Abort(_("cannot use an integer as a name"))
282 except ValueError:
282 except ValueError:
283 pass
283 pass
284 if lbl.strip() != lbl:
284 if lbl.strip() != lbl:
285 raise error.Abort(_("leading or trailing whitespace in name %r") % lbl)
285 raise error.Abort(_("leading or trailing whitespace in name %r") % lbl)
286
286
287 def checkfilename(f):
287 def checkfilename(f):
288 '''Check that the filename f is an acceptable filename for a tracked file'''
288 '''Check that the filename f is an acceptable filename for a tracked file'''
289 if '\r' in f or '\n' in f:
289 if '\r' in f or '\n' in f:
290 raise error.Abort(_("'\\n' and '\\r' disallowed in filenames: %r")
290 raise error.Abort(_("'\\n' and '\\r' disallowed in filenames: %r")
291 % pycompat.bytestr(f))
291 % pycompat.bytestr(f))
292
292
293 def checkportable(ui, f):
293 def checkportable(ui, f):
294 '''Check if filename f is portable and warn or abort depending on config'''
294 '''Check if filename f is portable and warn or abort depending on config'''
295 checkfilename(f)
295 checkfilename(f)
296 abort, warn = checkportabilityalert(ui)
296 abort, warn = checkportabilityalert(ui)
297 if abort or warn:
297 if abort or warn:
298 msg = util.checkwinfilename(f)
298 msg = util.checkwinfilename(f)
299 if msg:
299 if msg:
300 msg = "%s: %s" % (msg, procutil.shellquote(f))
300 msg = "%s: %s" % (msg, procutil.shellquote(f))
301 if abort:
301 if abort:
302 raise error.Abort(msg)
302 raise error.Abort(msg)
303 ui.warn(_("warning: %s\n") % msg)
303 ui.warn(_("warning: %s\n") % msg)
304
304
305 def checkportabilityalert(ui):
305 def checkportabilityalert(ui):
306 '''check if the user's config requests nothing, a warning, or abort for
306 '''check if the user's config requests nothing, a warning, or abort for
307 non-portable filenames'''
307 non-portable filenames'''
308 val = ui.config('ui', 'portablefilenames')
308 val = ui.config('ui', 'portablefilenames')
309 lval = val.lower()
309 lval = val.lower()
310 bval = stringutil.parsebool(val)
310 bval = stringutil.parsebool(val)
311 abort = pycompat.iswindows or lval == 'abort'
311 abort = pycompat.iswindows or lval == 'abort'
312 warn = bval or lval == 'warn'
312 warn = bval or lval == 'warn'
313 if bval is None and not (warn or abort or lval == 'ignore'):
313 if bval is None and not (warn or abort or lval == 'ignore'):
314 raise error.ConfigError(
314 raise error.ConfigError(
315 _("ui.portablefilenames value is invalid ('%s')") % val)
315 _("ui.portablefilenames value is invalid ('%s')") % val)
316 return abort, warn
316 return abort, warn
317
317
318 class casecollisionauditor(object):
318 class casecollisionauditor(object):
319 def __init__(self, ui, abort, dirstate):
319 def __init__(self, ui, abort, dirstate):
320 self._ui = ui
320 self._ui = ui
321 self._abort = abort
321 self._abort = abort
322 allfiles = '\0'.join(dirstate._map)
322 allfiles = '\0'.join(dirstate._map)
323 self._loweredfiles = set(encoding.lower(allfiles).split('\0'))
323 self._loweredfiles = set(encoding.lower(allfiles).split('\0'))
324 self._dirstate = dirstate
324 self._dirstate = dirstate
325 # The purpose of _newfiles is so that we don't complain about
325 # The purpose of _newfiles is so that we don't complain about
326 # case collisions if someone were to call this object with the
326 # case collisions if someone were to call this object with the
327 # same filename twice.
327 # same filename twice.
328 self._newfiles = set()
328 self._newfiles = set()
329
329
330 def __call__(self, f):
330 def __call__(self, f):
331 if f in self._newfiles:
331 if f in self._newfiles:
332 return
332 return
333 fl = encoding.lower(f)
333 fl = encoding.lower(f)
334 if fl in self._loweredfiles and f not in self._dirstate:
334 if fl in self._loweredfiles and f not in self._dirstate:
335 msg = _('possible case-folding collision for %s') % f
335 msg = _('possible case-folding collision for %s') % f
336 if self._abort:
336 if self._abort:
337 raise error.Abort(msg)
337 raise error.Abort(msg)
338 self._ui.warn(_("warning: %s\n") % msg)
338 self._ui.warn(_("warning: %s\n") % msg)
339 self._loweredfiles.add(fl)
339 self._loweredfiles.add(fl)
340 self._newfiles.add(f)
340 self._newfiles.add(f)
341
341
342 def filteredhash(repo, maxrev):
342 def filteredhash(repo, maxrev):
343 """build hash of filtered revisions in the current repoview.
343 """build hash of filtered revisions in the current repoview.
344
344
345 Multiple caches perform up-to-date validation by checking that the
345 Multiple caches perform up-to-date validation by checking that the
346 tiprev and tipnode stored in the cache file match the current repository.
346 tiprev and tipnode stored in the cache file match the current repository.
347 However, this is not sufficient for validating repoviews because the set
347 However, this is not sufficient for validating repoviews because the set
348 of revisions in the view may change without the repository tiprev and
348 of revisions in the view may change without the repository tiprev and
349 tipnode changing.
349 tipnode changing.
350
350
351 This function hashes all the revs filtered from the view and returns
351 This function hashes all the revs filtered from the view and returns
352 that SHA-1 digest.
352 that SHA-1 digest.
353 """
353 """
354 cl = repo.changelog
354 cl = repo.changelog
355 if not cl.filteredrevs:
355 if not cl.filteredrevs:
356 return None
356 return None
357 key = None
357 key = None
358 revs = sorted(r for r in cl.filteredrevs if r <= maxrev)
358 revs = sorted(r for r in cl.filteredrevs if r <= maxrev)
359 if revs:
359 if revs:
360 s = hashlib.sha1()
360 s = hashlib.sha1()
361 for rev in revs:
361 for rev in revs:
362 s.update('%d;' % rev)
362 s.update('%d;' % rev)
363 key = s.digest()
363 key = s.digest()
364 return key
364 return key
365
365
366 def walkrepos(path, followsym=False, seen_dirs=None, recurse=False):
366 def walkrepos(path, followsym=False, seen_dirs=None, recurse=False):
367 '''yield every hg repository under path, always recursively.
367 '''yield every hg repository under path, always recursively.
368 The recurse flag will only control recursion into repo working dirs'''
368 The recurse flag will only control recursion into repo working dirs'''
369 def errhandler(err):
369 def errhandler(err):
370 if err.filename == path:
370 if err.filename == path:
371 raise err
371 raise err
372 samestat = getattr(os.path, 'samestat', None)
372 samestat = getattr(os.path, 'samestat', None)
373 if followsym and samestat is not None:
373 if followsym and samestat is not None:
374 def adddir(dirlst, dirname):
374 def adddir(dirlst, dirname):
375 dirstat = os.stat(dirname)
375 dirstat = os.stat(dirname)
376 match = any(samestat(dirstat, lstdirstat) for lstdirstat in dirlst)
376 match = any(samestat(dirstat, lstdirstat) for lstdirstat in dirlst)
377 if not match:
377 if not match:
378 dirlst.append(dirstat)
378 dirlst.append(dirstat)
379 return not match
379 return not match
380 else:
380 else:
381 followsym = False
381 followsym = False
382
382
383 if (seen_dirs is None) and followsym:
383 if (seen_dirs is None) and followsym:
384 seen_dirs = []
384 seen_dirs = []
385 adddir(seen_dirs, path)
385 adddir(seen_dirs, path)
386 for root, dirs, files in os.walk(path, topdown=True, onerror=errhandler):
386 for root, dirs, files in os.walk(path, topdown=True, onerror=errhandler):
387 dirs.sort()
387 dirs.sort()
388 if '.hg' in dirs:
388 if '.hg' in dirs:
389 yield root # found a repository
389 yield root # found a repository
390 qroot = os.path.join(root, '.hg', 'patches')
390 qroot = os.path.join(root, '.hg', 'patches')
391 if os.path.isdir(os.path.join(qroot, '.hg')):
391 if os.path.isdir(os.path.join(qroot, '.hg')):
392 yield qroot # we have a patch queue repo here
392 yield qroot # we have a patch queue repo here
393 if recurse:
393 if recurse:
394 # avoid recursing inside the .hg directory
394 # avoid recursing inside the .hg directory
395 dirs.remove('.hg')
395 dirs.remove('.hg')
396 else:
396 else:
397 dirs[:] = [] # don't descend further
397 dirs[:] = [] # don't descend further
398 elif followsym:
398 elif followsym:
399 newdirs = []
399 newdirs = []
400 for d in dirs:
400 for d in dirs:
401 fname = os.path.join(root, d)
401 fname = os.path.join(root, d)
402 if adddir(seen_dirs, fname):
402 if adddir(seen_dirs, fname):
403 if os.path.islink(fname):
403 if os.path.islink(fname):
404 for hgname in walkrepos(fname, True, seen_dirs):
404 for hgname in walkrepos(fname, True, seen_dirs):
405 yield hgname
405 yield hgname
406 else:
406 else:
407 newdirs.append(d)
407 newdirs.append(d)
408 dirs[:] = newdirs
408 dirs[:] = newdirs
409
409
410 def binnode(ctx):
410 def binnode(ctx):
411 """Return binary node id for a given basectx"""
411 """Return binary node id for a given basectx"""
412 node = ctx.node()
412 node = ctx.node()
413 if node is None:
413 if node is None:
414 return wdirid
414 return wdirid
415 return node
415 return node
416
416
417 def intrev(ctx):
417 def intrev(ctx):
418 """Return integer for a given basectx that can be used in comparison or
418 """Return integer for a given basectx that can be used in comparison or
419 arithmetic operation"""
419 arithmetic operation"""
420 rev = ctx.rev()
420 rev = ctx.rev()
421 if rev is None:
421 if rev is None:
422 return wdirrev
422 return wdirrev
423 return rev
423 return rev
424
424
425 def formatchangeid(ctx):
425 def formatchangeid(ctx):
426 """Format changectx as '{rev}:{node|formatnode}', which is the default
426 """Format changectx as '{rev}:{node|formatnode}', which is the default
427 template provided by logcmdutil.changesettemplater"""
427 template provided by logcmdutil.changesettemplater"""
428 repo = ctx.repo()
428 repo = ctx.repo()
429 return formatrevnode(repo.ui, intrev(ctx), binnode(ctx))
429 return formatrevnode(repo.ui, intrev(ctx), binnode(ctx))
430
430
431 def formatrevnode(ui, rev, node):
431 def formatrevnode(ui, rev, node):
432 """Format given revision and node depending on the current verbosity"""
432 """Format given revision and node depending on the current verbosity"""
433 if ui.debugflag:
433 if ui.debugflag:
434 hexfunc = hex
434 hexfunc = hex
435 else:
435 else:
436 hexfunc = short
436 hexfunc = short
437 return '%d:%s' % (rev, hexfunc(node))
437 return '%d:%s' % (rev, hexfunc(node))
438
438
439 def resolvehexnodeidprefix(repo, prefix):
439 def resolvehexnodeidprefix(repo, prefix):
440 try:
440 # Uses unfiltered repo because it's faster when prefix is ambiguous/
441 # Uses unfiltered repo because it's faster when prefix is ambiguous/
441 # This matches the shortesthexnodeidprefix() function below.
442 # This matches the shortesthexnodeidprefix() function below.
442 node = repo.unfiltered().changelog._partialmatch(prefix)
443 node = repo.unfiltered().changelog._partialmatch(prefix)
444 except error.AmbiguousPrefixLookupError:
445 revset = repo.ui.config('experimental', 'revisions.disambiguatewithin')
446 if revset:
447 # Clear config to avoid infinite recursion
448 configoverrides = {('experimental',
449 'revisions.disambiguatewithin'): None}
450 with repo.ui.configoverride(configoverrides):
451 revs = repo.anyrevs([revset], user=True)
452 matches = []
453 for rev in revs:
454 node = repo.changelog.node(rev)
455 if hex(node).startswith(prefix):
456 matches.append(node)
457 if len(matches) == 1:
458 return matches[0]
459 raise
443 if node is None:
460 if node is None:
444 return
461 return
445 repo.changelog.rev(node) # make sure node isn't filtered
462 repo.changelog.rev(node) # make sure node isn't filtered
446 return node
463 return node
447
464
448 def shortesthexnodeidprefix(repo, node, minlength=1):
465 def shortesthexnodeidprefix(repo, node, minlength=1):
449 """Find the shortest unambiguous prefix that matches hexnode."""
466 """Find the shortest unambiguous prefix that matches hexnode."""
450 # _partialmatch() of filtered changelog could take O(len(repo)) time,
467 # _partialmatch() of filtered changelog could take O(len(repo)) time,
451 # which would be unacceptably slow. so we look for hash collision in
468 # which would be unacceptably slow. so we look for hash collision in
452 # unfiltered space, which means some hashes may be slightly longer.
469 # unfiltered space, which means some hashes may be slightly longer.
453 cl = repo.unfiltered().changelog
470 cl = repo.unfiltered().changelog
454
471
455 def isrev(prefix):
472 def isrev(prefix):
456 try:
473 try:
457 i = int(prefix)
474 i = int(prefix)
458 # if we are a pure int, then starting with zero will not be
475 # if we are a pure int, then starting with zero will not be
459 # confused as a rev; or, obviously, if the int is larger
476 # confused as a rev; or, obviously, if the int is larger
460 # than the value of the tip rev
477 # than the value of the tip rev
461 if prefix[0:1] == b'0' or i > len(cl):
478 if prefix[0:1] == b'0' or i > len(cl):
462 return False
479 return False
463 return True
480 return True
464 except ValueError:
481 except ValueError:
465 return False
482 return False
466
483
467 def disambiguate(prefix):
484 def disambiguate(prefix):
468 """Disambiguate against revnums."""
485 """Disambiguate against revnums."""
469 hexnode = hex(node)
486 hexnode = hex(node)
470 for length in range(len(prefix), len(hexnode) + 1):
487 for length in range(len(prefix), len(hexnode) + 1):
471 prefix = hexnode[:length]
488 prefix = hexnode[:length]
472 if not isrev(prefix):
489 if not isrev(prefix):
473 return prefix
490 return prefix
474
491
475 try:
492 try:
476 return disambiguate(cl.shortest(node, minlength))
493 return disambiguate(cl.shortest(node, minlength))
477 except error.LookupError:
494 except error.LookupError:
478 raise error.RepoLookupError()
495 raise error.RepoLookupError()
479
496
480 def isrevsymbol(repo, symbol):
497 def isrevsymbol(repo, symbol):
481 """Checks if a symbol exists in the repo.
498 """Checks if a symbol exists in the repo.
482
499
483 See revsymbol() for details. Raises error.AmbiguousPrefixLookupError if the
500 See revsymbol() for details. Raises error.AmbiguousPrefixLookupError if the
484 symbol is an ambiguous nodeid prefix.
501 symbol is an ambiguous nodeid prefix.
485 """
502 """
486 try:
503 try:
487 revsymbol(repo, symbol)
504 revsymbol(repo, symbol)
488 return True
505 return True
489 except error.RepoLookupError:
506 except error.RepoLookupError:
490 return False
507 return False
491
508
492 def revsymbol(repo, symbol):
509 def revsymbol(repo, symbol):
493 """Returns a context given a single revision symbol (as string).
510 """Returns a context given a single revision symbol (as string).
494
511
495 This is similar to revsingle(), but accepts only a single revision symbol,
512 This is similar to revsingle(), but accepts only a single revision symbol,
496 i.e. things like ".", "tip", "1234", "deadbeef", "my-bookmark" work, but
513 i.e. things like ".", "tip", "1234", "deadbeef", "my-bookmark" work, but
497 not "max(public())".
514 not "max(public())".
498 """
515 """
499 if not isinstance(symbol, bytes):
516 if not isinstance(symbol, bytes):
500 msg = ("symbol (%s of type %s) was not a string, did you mean "
517 msg = ("symbol (%s of type %s) was not a string, did you mean "
501 "repo[symbol]?" % (symbol, type(symbol)))
518 "repo[symbol]?" % (symbol, type(symbol)))
502 raise error.ProgrammingError(msg)
519 raise error.ProgrammingError(msg)
503 try:
520 try:
504 if symbol in ('.', 'tip', 'null'):
521 if symbol in ('.', 'tip', 'null'):
505 return repo[symbol]
522 return repo[symbol]
506
523
507 try:
524 try:
508 r = int(symbol)
525 r = int(symbol)
509 if '%d' % r != symbol:
526 if '%d' % r != symbol:
510 raise ValueError
527 raise ValueError
511 l = len(repo.changelog)
528 l = len(repo.changelog)
512 if r < 0:
529 if r < 0:
513 r += l
530 r += l
514 if r < 0 or r >= l and r != wdirrev:
531 if r < 0 or r >= l and r != wdirrev:
515 raise ValueError
532 raise ValueError
516 return repo[r]
533 return repo[r]
517 except error.FilteredIndexError:
534 except error.FilteredIndexError:
518 raise
535 raise
519 except (ValueError, OverflowError, IndexError):
536 except (ValueError, OverflowError, IndexError):
520 pass
537 pass
521
538
522 if len(symbol) == 40:
539 if len(symbol) == 40:
523 try:
540 try:
524 node = bin(symbol)
541 node = bin(symbol)
525 rev = repo.changelog.rev(node)
542 rev = repo.changelog.rev(node)
526 return repo[rev]
543 return repo[rev]
527 except error.FilteredLookupError:
544 except error.FilteredLookupError:
528 raise
545 raise
529 except (TypeError, LookupError):
546 except (TypeError, LookupError):
530 pass
547 pass
531
548
532 # look up bookmarks through the name interface
549 # look up bookmarks through the name interface
533 try:
550 try:
534 node = repo.names.singlenode(repo, symbol)
551 node = repo.names.singlenode(repo, symbol)
535 rev = repo.changelog.rev(node)
552 rev = repo.changelog.rev(node)
536 return repo[rev]
553 return repo[rev]
537 except KeyError:
554 except KeyError:
538 pass
555 pass
539
556
540 node = resolvehexnodeidprefix(repo, symbol)
557 node = resolvehexnodeidprefix(repo, symbol)
541 if node is not None:
558 if node is not None:
542 rev = repo.changelog.rev(node)
559 rev = repo.changelog.rev(node)
543 return repo[rev]
560 return repo[rev]
544
561
545 raise error.RepoLookupError(_("unknown revision '%s'") % symbol)
562 raise error.RepoLookupError(_("unknown revision '%s'") % symbol)
546
563
547 except error.WdirUnsupported:
564 except error.WdirUnsupported:
548 return repo[None]
565 return repo[None]
549 except (error.FilteredIndexError, error.FilteredLookupError,
566 except (error.FilteredIndexError, error.FilteredLookupError,
550 error.FilteredRepoLookupError):
567 error.FilteredRepoLookupError):
551 raise _filterederror(repo, symbol)
568 raise _filterederror(repo, symbol)
552
569
553 def _filterederror(repo, changeid):
570 def _filterederror(repo, changeid):
554 """build an exception to be raised about a filtered changeid
571 """build an exception to be raised about a filtered changeid
555
572
556 This is extracted in a function to help extensions (eg: evolve) to
573 This is extracted in a function to help extensions (eg: evolve) to
557 experiment with various message variants."""
574 experiment with various message variants."""
558 if repo.filtername.startswith('visible'):
575 if repo.filtername.startswith('visible'):
559
576
560 # Check if the changeset is obsolete
577 # Check if the changeset is obsolete
561 unfilteredrepo = repo.unfiltered()
578 unfilteredrepo = repo.unfiltered()
562 ctx = revsymbol(unfilteredrepo, changeid)
579 ctx = revsymbol(unfilteredrepo, changeid)
563
580
564 # If the changeset is obsolete, enrich the message with the reason
581 # If the changeset is obsolete, enrich the message with the reason
565 # that made this changeset not visible
582 # that made this changeset not visible
566 if ctx.obsolete():
583 if ctx.obsolete():
567 msg = obsutil._getfilteredreason(repo, changeid, ctx)
584 msg = obsutil._getfilteredreason(repo, changeid, ctx)
568 else:
585 else:
569 msg = _("hidden revision '%s'") % changeid
586 msg = _("hidden revision '%s'") % changeid
570
587
571 hint = _('use --hidden to access hidden revisions')
588 hint = _('use --hidden to access hidden revisions')
572
589
573 return error.FilteredRepoLookupError(msg, hint=hint)
590 return error.FilteredRepoLookupError(msg, hint=hint)
574 msg = _("filtered revision '%s' (not in '%s' subset)")
591 msg = _("filtered revision '%s' (not in '%s' subset)")
575 msg %= (changeid, repo.filtername)
592 msg %= (changeid, repo.filtername)
576 return error.FilteredRepoLookupError(msg)
593 return error.FilteredRepoLookupError(msg)
577
594
578 def revsingle(repo, revspec, default='.', localalias=None):
595 def revsingle(repo, revspec, default='.', localalias=None):
579 if not revspec and revspec != 0:
596 if not revspec and revspec != 0:
580 return repo[default]
597 return repo[default]
581
598
582 l = revrange(repo, [revspec], localalias=localalias)
599 l = revrange(repo, [revspec], localalias=localalias)
583 if not l:
600 if not l:
584 raise error.Abort(_('empty revision set'))
601 raise error.Abort(_('empty revision set'))
585 return repo[l.last()]
602 return repo[l.last()]
586
603
587 def _pairspec(revspec):
604 def _pairspec(revspec):
588 tree = revsetlang.parse(revspec)
605 tree = revsetlang.parse(revspec)
589 return tree and tree[0] in ('range', 'rangepre', 'rangepost', 'rangeall')
606 return tree and tree[0] in ('range', 'rangepre', 'rangepost', 'rangeall')
590
607
591 def revpair(repo, revs):
608 def revpair(repo, revs):
592 if not revs:
609 if not revs:
593 return repo['.'], repo[None]
610 return repo['.'], repo[None]
594
611
595 l = revrange(repo, revs)
612 l = revrange(repo, revs)
596
613
597 if not l:
614 if not l:
598 first = second = None
615 first = second = None
599 elif l.isascending():
616 elif l.isascending():
600 first = l.min()
617 first = l.min()
601 second = l.max()
618 second = l.max()
602 elif l.isdescending():
619 elif l.isdescending():
603 first = l.max()
620 first = l.max()
604 second = l.min()
621 second = l.min()
605 else:
622 else:
606 first = l.first()
623 first = l.first()
607 second = l.last()
624 second = l.last()
608
625
609 if first is None:
626 if first is None:
610 raise error.Abort(_('empty revision range'))
627 raise error.Abort(_('empty revision range'))
611 if (first == second and len(revs) >= 2
628 if (first == second and len(revs) >= 2
612 and not all(revrange(repo, [r]) for r in revs)):
629 and not all(revrange(repo, [r]) for r in revs)):
613 raise error.Abort(_('empty revision on one side of range'))
630 raise error.Abort(_('empty revision on one side of range'))
614
631
615 # if top-level is range expression, the result must always be a pair
632 # if top-level is range expression, the result must always be a pair
616 if first == second and len(revs) == 1 and not _pairspec(revs[0]):
633 if first == second and len(revs) == 1 and not _pairspec(revs[0]):
617 return repo[first], repo[None]
634 return repo[first], repo[None]
618
635
619 return repo[first], repo[second]
636 return repo[first], repo[second]
620
637
621 def revrange(repo, specs, localalias=None):
638 def revrange(repo, specs, localalias=None):
622 """Execute 1 to many revsets and return the union.
639 """Execute 1 to many revsets and return the union.
623
640
624 This is the preferred mechanism for executing revsets using user-specified
641 This is the preferred mechanism for executing revsets using user-specified
625 config options, such as revset aliases.
642 config options, such as revset aliases.
626
643
627 The revsets specified by ``specs`` will be executed via a chained ``OR``
644 The revsets specified by ``specs`` will be executed via a chained ``OR``
628 expression. If ``specs`` is empty, an empty result is returned.
645 expression. If ``specs`` is empty, an empty result is returned.
629
646
630 ``specs`` can contain integers, in which case they are assumed to be
647 ``specs`` can contain integers, in which case they are assumed to be
631 revision numbers.
648 revision numbers.
632
649
633 It is assumed the revsets are already formatted. If you have arguments
650 It is assumed the revsets are already formatted. If you have arguments
634 that need to be expanded in the revset, call ``revsetlang.formatspec()``
651 that need to be expanded in the revset, call ``revsetlang.formatspec()``
635 and pass the result as an element of ``specs``.
652 and pass the result as an element of ``specs``.
636
653
637 Specifying a single revset is allowed.
654 Specifying a single revset is allowed.
638
655
639 Returns a ``revset.abstractsmartset`` which is a list-like interface over
656 Returns a ``revset.abstractsmartset`` which is a list-like interface over
640 integer revisions.
657 integer revisions.
641 """
658 """
642 allspecs = []
659 allspecs = []
643 for spec in specs:
660 for spec in specs:
644 if isinstance(spec, int):
661 if isinstance(spec, int):
645 spec = revsetlang.formatspec('rev(%d)', spec)
662 spec = revsetlang.formatspec('rev(%d)', spec)
646 allspecs.append(spec)
663 allspecs.append(spec)
647 return repo.anyrevs(allspecs, user=True, localalias=localalias)
664 return repo.anyrevs(allspecs, user=True, localalias=localalias)
648
665
649 def meaningfulparents(repo, ctx):
666 def meaningfulparents(repo, ctx):
650 """Return list of meaningful (or all if debug) parentrevs for rev.
667 """Return list of meaningful (or all if debug) parentrevs for rev.
651
668
652 For merges (two non-nullrev revisions) both parents are meaningful.
669 For merges (two non-nullrev revisions) both parents are meaningful.
653 Otherwise the first parent revision is considered meaningful if it
670 Otherwise the first parent revision is considered meaningful if it
654 is not the preceding revision.
671 is not the preceding revision.
655 """
672 """
656 parents = ctx.parents()
673 parents = ctx.parents()
657 if len(parents) > 1:
674 if len(parents) > 1:
658 return parents
675 return parents
659 if repo.ui.debugflag:
676 if repo.ui.debugflag:
660 return [parents[0], repo['null']]
677 return [parents[0], repo['null']]
661 if parents[0].rev() >= intrev(ctx) - 1:
678 if parents[0].rev() >= intrev(ctx) - 1:
662 return []
679 return []
663 return parents
680 return parents
664
681
665 def expandpats(pats):
682 def expandpats(pats):
666 '''Expand bare globs when running on windows.
683 '''Expand bare globs when running on windows.
667 On posix we assume it already has already been done by sh.'''
684 On posix we assume it already has already been done by sh.'''
668 if not util.expandglobs:
685 if not util.expandglobs:
669 return list(pats)
686 return list(pats)
670 ret = []
687 ret = []
671 for kindpat in pats:
688 for kindpat in pats:
672 kind, pat = matchmod._patsplit(kindpat, None)
689 kind, pat = matchmod._patsplit(kindpat, None)
673 if kind is None:
690 if kind is None:
674 try:
691 try:
675 globbed = glob.glob(pat)
692 globbed = glob.glob(pat)
676 except re.error:
693 except re.error:
677 globbed = [pat]
694 globbed = [pat]
678 if globbed:
695 if globbed:
679 ret.extend(globbed)
696 ret.extend(globbed)
680 continue
697 continue
681 ret.append(kindpat)
698 ret.append(kindpat)
682 return ret
699 return ret
683
700
684 def matchandpats(ctx, pats=(), opts=None, globbed=False, default='relpath',
701 def matchandpats(ctx, pats=(), opts=None, globbed=False, default='relpath',
685 badfn=None):
702 badfn=None):
686 '''Return a matcher and the patterns that were used.
703 '''Return a matcher and the patterns that were used.
687 The matcher will warn about bad matches, unless an alternate badfn callback
704 The matcher will warn about bad matches, unless an alternate badfn callback
688 is provided.'''
705 is provided.'''
689 if pats == ("",):
706 if pats == ("",):
690 pats = []
707 pats = []
691 if opts is None:
708 if opts is None:
692 opts = {}
709 opts = {}
693 if not globbed and default == 'relpath':
710 if not globbed and default == 'relpath':
694 pats = expandpats(pats or [])
711 pats = expandpats(pats or [])
695
712
696 def bad(f, msg):
713 def bad(f, msg):
697 ctx.repo().ui.warn("%s: %s\n" % (m.rel(f), msg))
714 ctx.repo().ui.warn("%s: %s\n" % (m.rel(f), msg))
698
715
699 if badfn is None:
716 if badfn is None:
700 badfn = bad
717 badfn = bad
701
718
702 m = ctx.match(pats, opts.get('include'), opts.get('exclude'),
719 m = ctx.match(pats, opts.get('include'), opts.get('exclude'),
703 default, listsubrepos=opts.get('subrepos'), badfn=badfn)
720 default, listsubrepos=opts.get('subrepos'), badfn=badfn)
704
721
705 if m.always():
722 if m.always():
706 pats = []
723 pats = []
707 return m, pats
724 return m, pats
708
725
709 def match(ctx, pats=(), opts=None, globbed=False, default='relpath',
726 def match(ctx, pats=(), opts=None, globbed=False, default='relpath',
710 badfn=None):
727 badfn=None):
711 '''Return a matcher that will warn about bad matches.'''
728 '''Return a matcher that will warn about bad matches.'''
712 return matchandpats(ctx, pats, opts, globbed, default, badfn=badfn)[0]
729 return matchandpats(ctx, pats, opts, globbed, default, badfn=badfn)[0]
713
730
714 def matchall(repo):
731 def matchall(repo):
715 '''Return a matcher that will efficiently match everything.'''
732 '''Return a matcher that will efficiently match everything.'''
716 return matchmod.always(repo.root, repo.getcwd())
733 return matchmod.always(repo.root, repo.getcwd())
717
734
718 def matchfiles(repo, files, badfn=None):
735 def matchfiles(repo, files, badfn=None):
719 '''Return a matcher that will efficiently match exactly these files.'''
736 '''Return a matcher that will efficiently match exactly these files.'''
720 return matchmod.exact(repo.root, repo.getcwd(), files, badfn=badfn)
737 return matchmod.exact(repo.root, repo.getcwd(), files, badfn=badfn)
721
738
722 def parsefollowlinespattern(repo, rev, pat, msg):
739 def parsefollowlinespattern(repo, rev, pat, msg):
723 """Return a file name from `pat` pattern suitable for usage in followlines
740 """Return a file name from `pat` pattern suitable for usage in followlines
724 logic.
741 logic.
725 """
742 """
726 if not matchmod.patkind(pat):
743 if not matchmod.patkind(pat):
727 return pathutil.canonpath(repo.root, repo.getcwd(), pat)
744 return pathutil.canonpath(repo.root, repo.getcwd(), pat)
728 else:
745 else:
729 ctx = repo[rev]
746 ctx = repo[rev]
730 m = matchmod.match(repo.root, repo.getcwd(), [pat], ctx=ctx)
747 m = matchmod.match(repo.root, repo.getcwd(), [pat], ctx=ctx)
731 files = [f for f in ctx if m(f)]
748 files = [f for f in ctx if m(f)]
732 if len(files) != 1:
749 if len(files) != 1:
733 raise error.ParseError(msg)
750 raise error.ParseError(msg)
734 return files[0]
751 return files[0]
735
752
736 def origpath(ui, repo, filepath):
753 def origpath(ui, repo, filepath):
737 '''customize where .orig files are created
754 '''customize where .orig files are created
738
755
739 Fetch user defined path from config file: [ui] origbackuppath = <path>
756 Fetch user defined path from config file: [ui] origbackuppath = <path>
740 Fall back to default (filepath with .orig suffix) if not specified
757 Fall back to default (filepath with .orig suffix) if not specified
741 '''
758 '''
742 origbackuppath = ui.config('ui', 'origbackuppath')
759 origbackuppath = ui.config('ui', 'origbackuppath')
743 if not origbackuppath:
760 if not origbackuppath:
744 return filepath + ".orig"
761 return filepath + ".orig"
745
762
746 # Convert filepath from an absolute path into a path inside the repo.
763 # Convert filepath from an absolute path into a path inside the repo.
747 filepathfromroot = util.normpath(os.path.relpath(filepath,
764 filepathfromroot = util.normpath(os.path.relpath(filepath,
748 start=repo.root))
765 start=repo.root))
749
766
750 origvfs = vfs.vfs(repo.wjoin(origbackuppath))
767 origvfs = vfs.vfs(repo.wjoin(origbackuppath))
751 origbackupdir = origvfs.dirname(filepathfromroot)
768 origbackupdir = origvfs.dirname(filepathfromroot)
752 if not origvfs.isdir(origbackupdir) or origvfs.islink(origbackupdir):
769 if not origvfs.isdir(origbackupdir) or origvfs.islink(origbackupdir):
753 ui.note(_('creating directory: %s\n') % origvfs.join(origbackupdir))
770 ui.note(_('creating directory: %s\n') % origvfs.join(origbackupdir))
754
771
755 # Remove any files that conflict with the backup file's path
772 # Remove any files that conflict with the backup file's path
756 for f in reversed(list(util.finddirs(filepathfromroot))):
773 for f in reversed(list(util.finddirs(filepathfromroot))):
757 if origvfs.isfileorlink(f):
774 if origvfs.isfileorlink(f):
758 ui.note(_('removing conflicting file: %s\n')
775 ui.note(_('removing conflicting file: %s\n')
759 % origvfs.join(f))
776 % origvfs.join(f))
760 origvfs.unlink(f)
777 origvfs.unlink(f)
761 break
778 break
762
779
763 origvfs.makedirs(origbackupdir)
780 origvfs.makedirs(origbackupdir)
764
781
765 if origvfs.isdir(filepathfromroot) and not origvfs.islink(filepathfromroot):
782 if origvfs.isdir(filepathfromroot) and not origvfs.islink(filepathfromroot):
766 ui.note(_('removing conflicting directory: %s\n')
783 ui.note(_('removing conflicting directory: %s\n')
767 % origvfs.join(filepathfromroot))
784 % origvfs.join(filepathfromroot))
768 origvfs.rmtree(filepathfromroot, forcibly=True)
785 origvfs.rmtree(filepathfromroot, forcibly=True)
769
786
770 return origvfs.join(filepathfromroot)
787 return origvfs.join(filepathfromroot)
771
788
772 class _containsnode(object):
789 class _containsnode(object):
773 """proxy __contains__(node) to container.__contains__ which accepts revs"""
790 """proxy __contains__(node) to container.__contains__ which accepts revs"""
774
791
775 def __init__(self, repo, revcontainer):
792 def __init__(self, repo, revcontainer):
776 self._torev = repo.changelog.rev
793 self._torev = repo.changelog.rev
777 self._revcontains = revcontainer.__contains__
794 self._revcontains = revcontainer.__contains__
778
795
779 def __contains__(self, node):
796 def __contains__(self, node):
780 return self._revcontains(self._torev(node))
797 return self._revcontains(self._torev(node))
781
798
782 def cleanupnodes(repo, replacements, operation, moves=None, metadata=None,
799 def cleanupnodes(repo, replacements, operation, moves=None, metadata=None,
783 fixphase=False, targetphase=None, backup=True):
800 fixphase=False, targetphase=None, backup=True):
784 """do common cleanups when old nodes are replaced by new nodes
801 """do common cleanups when old nodes are replaced by new nodes
785
802
786 That includes writing obsmarkers or stripping nodes, and moving bookmarks.
803 That includes writing obsmarkers or stripping nodes, and moving bookmarks.
787 (we might also want to move working directory parent in the future)
804 (we might also want to move working directory parent in the future)
788
805
789 By default, bookmark moves are calculated automatically from 'replacements',
806 By default, bookmark moves are calculated automatically from 'replacements',
790 but 'moves' can be used to override that. Also, 'moves' may include
807 but 'moves' can be used to override that. Also, 'moves' may include
791 additional bookmark moves that should not have associated obsmarkers.
808 additional bookmark moves that should not have associated obsmarkers.
792
809
793 replacements is {oldnode: [newnode]} or a iterable of nodes if they do not
810 replacements is {oldnode: [newnode]} or a iterable of nodes if they do not
794 have replacements. operation is a string, like "rebase".
811 have replacements. operation is a string, like "rebase".
795
812
796 metadata is dictionary containing metadata to be stored in obsmarker if
813 metadata is dictionary containing metadata to be stored in obsmarker if
797 obsolescence is enabled.
814 obsolescence is enabled.
798 """
815 """
799 assert fixphase or targetphase is None
816 assert fixphase or targetphase is None
800 if not replacements and not moves:
817 if not replacements and not moves:
801 return
818 return
802
819
803 # translate mapping's other forms
820 # translate mapping's other forms
804 if not util.safehasattr(replacements, 'items'):
821 if not util.safehasattr(replacements, 'items'):
805 replacements = {n: () for n in replacements}
822 replacements = {n: () for n in replacements}
806
823
807 # Calculate bookmark movements
824 # Calculate bookmark movements
808 if moves is None:
825 if moves is None:
809 moves = {}
826 moves = {}
810 # Unfiltered repo is needed since nodes in replacements might be hidden.
827 # Unfiltered repo is needed since nodes in replacements might be hidden.
811 unfi = repo.unfiltered()
828 unfi = repo.unfiltered()
812 for oldnode, newnodes in replacements.items():
829 for oldnode, newnodes in replacements.items():
813 if oldnode in moves:
830 if oldnode in moves:
814 continue
831 continue
815 if len(newnodes) > 1:
832 if len(newnodes) > 1:
816 # usually a split, take the one with biggest rev number
833 # usually a split, take the one with biggest rev number
817 newnode = next(unfi.set('max(%ln)', newnodes)).node()
834 newnode = next(unfi.set('max(%ln)', newnodes)).node()
818 elif len(newnodes) == 0:
835 elif len(newnodes) == 0:
819 # move bookmark backwards
836 # move bookmark backwards
820 roots = list(unfi.set('max((::%n) - %ln)', oldnode,
837 roots = list(unfi.set('max((::%n) - %ln)', oldnode,
821 list(replacements)))
838 list(replacements)))
822 if roots:
839 if roots:
823 newnode = roots[0].node()
840 newnode = roots[0].node()
824 else:
841 else:
825 newnode = nullid
842 newnode = nullid
826 else:
843 else:
827 newnode = newnodes[0]
844 newnode = newnodes[0]
828 moves[oldnode] = newnode
845 moves[oldnode] = newnode
829
846
830 allnewnodes = [n for ns in replacements.values() for n in ns]
847 allnewnodes = [n for ns in replacements.values() for n in ns]
831 toretract = {}
848 toretract = {}
832 toadvance = {}
849 toadvance = {}
833 if fixphase:
850 if fixphase:
834 precursors = {}
851 precursors = {}
835 for oldnode, newnodes in replacements.items():
852 for oldnode, newnodes in replacements.items():
836 for newnode in newnodes:
853 for newnode in newnodes:
837 precursors.setdefault(newnode, []).append(oldnode)
854 precursors.setdefault(newnode, []).append(oldnode)
838
855
839 allnewnodes.sort(key=lambda n: unfi[n].rev())
856 allnewnodes.sort(key=lambda n: unfi[n].rev())
840 newphases = {}
857 newphases = {}
841 def phase(ctx):
858 def phase(ctx):
842 return newphases.get(ctx.node(), ctx.phase())
859 return newphases.get(ctx.node(), ctx.phase())
843 for newnode in allnewnodes:
860 for newnode in allnewnodes:
844 ctx = unfi[newnode]
861 ctx = unfi[newnode]
845 parentphase = max(phase(p) for p in ctx.parents())
862 parentphase = max(phase(p) for p in ctx.parents())
846 if targetphase is None:
863 if targetphase is None:
847 oldphase = max(unfi[oldnode].phase()
864 oldphase = max(unfi[oldnode].phase()
848 for oldnode in precursors[newnode])
865 for oldnode in precursors[newnode])
849 newphase = max(oldphase, parentphase)
866 newphase = max(oldphase, parentphase)
850 else:
867 else:
851 newphase = max(targetphase, parentphase)
868 newphase = max(targetphase, parentphase)
852 newphases[newnode] = newphase
869 newphases[newnode] = newphase
853 if newphase > ctx.phase():
870 if newphase > ctx.phase():
854 toretract.setdefault(newphase, []).append(newnode)
871 toretract.setdefault(newphase, []).append(newnode)
855 elif newphase < ctx.phase():
872 elif newphase < ctx.phase():
856 toadvance.setdefault(newphase, []).append(newnode)
873 toadvance.setdefault(newphase, []).append(newnode)
857
874
858 with repo.transaction('cleanup') as tr:
875 with repo.transaction('cleanup') as tr:
859 # Move bookmarks
876 # Move bookmarks
860 bmarks = repo._bookmarks
877 bmarks = repo._bookmarks
861 bmarkchanges = []
878 bmarkchanges = []
862 for oldnode, newnode in moves.items():
879 for oldnode, newnode in moves.items():
863 oldbmarks = repo.nodebookmarks(oldnode)
880 oldbmarks = repo.nodebookmarks(oldnode)
864 if not oldbmarks:
881 if not oldbmarks:
865 continue
882 continue
866 from . import bookmarks # avoid import cycle
883 from . import bookmarks # avoid import cycle
867 repo.ui.debug('moving bookmarks %r from %s to %s\n' %
884 repo.ui.debug('moving bookmarks %r from %s to %s\n' %
868 (pycompat.rapply(pycompat.maybebytestr, oldbmarks),
885 (pycompat.rapply(pycompat.maybebytestr, oldbmarks),
869 hex(oldnode), hex(newnode)))
886 hex(oldnode), hex(newnode)))
870 # Delete divergent bookmarks being parents of related newnodes
887 # Delete divergent bookmarks being parents of related newnodes
871 deleterevs = repo.revs('parents(roots(%ln & (::%n))) - parents(%n)',
888 deleterevs = repo.revs('parents(roots(%ln & (::%n))) - parents(%n)',
872 allnewnodes, newnode, oldnode)
889 allnewnodes, newnode, oldnode)
873 deletenodes = _containsnode(repo, deleterevs)
890 deletenodes = _containsnode(repo, deleterevs)
874 for name in oldbmarks:
891 for name in oldbmarks:
875 bmarkchanges.append((name, newnode))
892 bmarkchanges.append((name, newnode))
876 for b in bookmarks.divergent2delete(repo, deletenodes, name):
893 for b in bookmarks.divergent2delete(repo, deletenodes, name):
877 bmarkchanges.append((b, None))
894 bmarkchanges.append((b, None))
878
895
879 if bmarkchanges:
896 if bmarkchanges:
880 bmarks.applychanges(repo, tr, bmarkchanges)
897 bmarks.applychanges(repo, tr, bmarkchanges)
881
898
882 for phase, nodes in toretract.items():
899 for phase, nodes in toretract.items():
883 phases.retractboundary(repo, tr, phase, nodes)
900 phases.retractboundary(repo, tr, phase, nodes)
884 for phase, nodes in toadvance.items():
901 for phase, nodes in toadvance.items():
885 phases.advanceboundary(repo, tr, phase, nodes)
902 phases.advanceboundary(repo, tr, phase, nodes)
886
903
887 # Obsolete or strip nodes
904 # Obsolete or strip nodes
888 if obsolete.isenabled(repo, obsolete.createmarkersopt):
905 if obsolete.isenabled(repo, obsolete.createmarkersopt):
889 # If a node is already obsoleted, and we want to obsolete it
906 # If a node is already obsoleted, and we want to obsolete it
890 # without a successor, skip that obssolete request since it's
907 # without a successor, skip that obssolete request since it's
891 # unnecessary. That's the "if s or not isobs(n)" check below.
908 # unnecessary. That's the "if s or not isobs(n)" check below.
892 # Also sort the node in topology order, that might be useful for
909 # Also sort the node in topology order, that might be useful for
893 # some obsstore logic.
910 # some obsstore logic.
894 # NOTE: the filtering and sorting might belong to createmarkers.
911 # NOTE: the filtering and sorting might belong to createmarkers.
895 isobs = unfi.obsstore.successors.__contains__
912 isobs = unfi.obsstore.successors.__contains__
896 torev = unfi.changelog.rev
913 torev = unfi.changelog.rev
897 sortfunc = lambda ns: torev(ns[0])
914 sortfunc = lambda ns: torev(ns[0])
898 rels = [(unfi[n], tuple(unfi[m] for m in s))
915 rels = [(unfi[n], tuple(unfi[m] for m in s))
899 for n, s in sorted(replacements.items(), key=sortfunc)
916 for n, s in sorted(replacements.items(), key=sortfunc)
900 if s or not isobs(n)]
917 if s or not isobs(n)]
901 if rels:
918 if rels:
902 obsolete.createmarkers(repo, rels, operation=operation,
919 obsolete.createmarkers(repo, rels, operation=operation,
903 metadata=metadata)
920 metadata=metadata)
904 else:
921 else:
905 from . import repair # avoid import cycle
922 from . import repair # avoid import cycle
906 tostrip = list(replacements)
923 tostrip = list(replacements)
907 if tostrip:
924 if tostrip:
908 repair.delayedstrip(repo.ui, repo, tostrip, operation,
925 repair.delayedstrip(repo.ui, repo, tostrip, operation,
909 backup=backup)
926 backup=backup)
910
927
911 def addremove(repo, matcher, prefix, opts=None):
928 def addremove(repo, matcher, prefix, opts=None):
912 if opts is None:
929 if opts is None:
913 opts = {}
930 opts = {}
914 m = matcher
931 m = matcher
915 dry_run = opts.get('dry_run')
932 dry_run = opts.get('dry_run')
916 try:
933 try:
917 similarity = float(opts.get('similarity') or 0)
934 similarity = float(opts.get('similarity') or 0)
918 except ValueError:
935 except ValueError:
919 raise error.Abort(_('similarity must be a number'))
936 raise error.Abort(_('similarity must be a number'))
920 if similarity < 0 or similarity > 100:
937 if similarity < 0 or similarity > 100:
921 raise error.Abort(_('similarity must be between 0 and 100'))
938 raise error.Abort(_('similarity must be between 0 and 100'))
922 similarity /= 100.0
939 similarity /= 100.0
923
940
924 ret = 0
941 ret = 0
925 join = lambda f: os.path.join(prefix, f)
942 join = lambda f: os.path.join(prefix, f)
926
943
927 wctx = repo[None]
944 wctx = repo[None]
928 for subpath in sorted(wctx.substate):
945 for subpath in sorted(wctx.substate):
929 submatch = matchmod.subdirmatcher(subpath, m)
946 submatch = matchmod.subdirmatcher(subpath, m)
930 if opts.get('subrepos') or m.exact(subpath) or any(submatch.files()):
947 if opts.get('subrepos') or m.exact(subpath) or any(submatch.files()):
931 sub = wctx.sub(subpath)
948 sub = wctx.sub(subpath)
932 try:
949 try:
933 if sub.addremove(submatch, prefix, opts):
950 if sub.addremove(submatch, prefix, opts):
934 ret = 1
951 ret = 1
935 except error.LookupError:
952 except error.LookupError:
936 repo.ui.status(_("skipping missing subrepository: %s\n")
953 repo.ui.status(_("skipping missing subrepository: %s\n")
937 % join(subpath))
954 % join(subpath))
938
955
939 rejected = []
956 rejected = []
940 def badfn(f, msg):
957 def badfn(f, msg):
941 if f in m.files():
958 if f in m.files():
942 m.bad(f, msg)
959 m.bad(f, msg)
943 rejected.append(f)
960 rejected.append(f)
944
961
945 badmatch = matchmod.badmatch(m, badfn)
962 badmatch = matchmod.badmatch(m, badfn)
946 added, unknown, deleted, removed, forgotten = _interestingfiles(repo,
963 added, unknown, deleted, removed, forgotten = _interestingfiles(repo,
947 badmatch)
964 badmatch)
948
965
949 unknownset = set(unknown + forgotten)
966 unknownset = set(unknown + forgotten)
950 toprint = unknownset.copy()
967 toprint = unknownset.copy()
951 toprint.update(deleted)
968 toprint.update(deleted)
952 for abs in sorted(toprint):
969 for abs in sorted(toprint):
953 if repo.ui.verbose or not m.exact(abs):
970 if repo.ui.verbose or not m.exact(abs):
954 if abs in unknownset:
971 if abs in unknownset:
955 status = _('adding %s\n') % m.uipath(abs)
972 status = _('adding %s\n') % m.uipath(abs)
956 else:
973 else:
957 status = _('removing %s\n') % m.uipath(abs)
974 status = _('removing %s\n') % m.uipath(abs)
958 repo.ui.status(status)
975 repo.ui.status(status)
959
976
960 renames = _findrenames(repo, m, added + unknown, removed + deleted,
977 renames = _findrenames(repo, m, added + unknown, removed + deleted,
961 similarity)
978 similarity)
962
979
963 if not dry_run:
980 if not dry_run:
964 _markchanges(repo, unknown + forgotten, deleted, renames)
981 _markchanges(repo, unknown + forgotten, deleted, renames)
965
982
966 for f in rejected:
983 for f in rejected:
967 if f in m.files():
984 if f in m.files():
968 return 1
985 return 1
969 return ret
986 return ret
970
987
971 def marktouched(repo, files, similarity=0.0):
988 def marktouched(repo, files, similarity=0.0):
972 '''Assert that files have somehow been operated upon. files are relative to
989 '''Assert that files have somehow been operated upon. files are relative to
973 the repo root.'''
990 the repo root.'''
974 m = matchfiles(repo, files, badfn=lambda x, y: rejected.append(x))
991 m = matchfiles(repo, files, badfn=lambda x, y: rejected.append(x))
975 rejected = []
992 rejected = []
976
993
977 added, unknown, deleted, removed, forgotten = _interestingfiles(repo, m)
994 added, unknown, deleted, removed, forgotten = _interestingfiles(repo, m)
978
995
979 if repo.ui.verbose:
996 if repo.ui.verbose:
980 unknownset = set(unknown + forgotten)
997 unknownset = set(unknown + forgotten)
981 toprint = unknownset.copy()
998 toprint = unknownset.copy()
982 toprint.update(deleted)
999 toprint.update(deleted)
983 for abs in sorted(toprint):
1000 for abs in sorted(toprint):
984 if abs in unknownset:
1001 if abs in unknownset:
985 status = _('adding %s\n') % abs
1002 status = _('adding %s\n') % abs
986 else:
1003 else:
987 status = _('removing %s\n') % abs
1004 status = _('removing %s\n') % abs
988 repo.ui.status(status)
1005 repo.ui.status(status)
989
1006
990 renames = _findrenames(repo, m, added + unknown, removed + deleted,
1007 renames = _findrenames(repo, m, added + unknown, removed + deleted,
991 similarity)
1008 similarity)
992
1009
993 _markchanges(repo, unknown + forgotten, deleted, renames)
1010 _markchanges(repo, unknown + forgotten, deleted, renames)
994
1011
995 for f in rejected:
1012 for f in rejected:
996 if f in m.files():
1013 if f in m.files():
997 return 1
1014 return 1
998 return 0
1015 return 0
999
1016
1000 def _interestingfiles(repo, matcher):
1017 def _interestingfiles(repo, matcher):
1001 '''Walk dirstate with matcher, looking for files that addremove would care
1018 '''Walk dirstate with matcher, looking for files that addremove would care
1002 about.
1019 about.
1003
1020
1004 This is different from dirstate.status because it doesn't care about
1021 This is different from dirstate.status because it doesn't care about
1005 whether files are modified or clean.'''
1022 whether files are modified or clean.'''
1006 added, unknown, deleted, removed, forgotten = [], [], [], [], []
1023 added, unknown, deleted, removed, forgotten = [], [], [], [], []
1007 audit_path = pathutil.pathauditor(repo.root, cached=True)
1024 audit_path = pathutil.pathauditor(repo.root, cached=True)
1008
1025
1009 ctx = repo[None]
1026 ctx = repo[None]
1010 dirstate = repo.dirstate
1027 dirstate = repo.dirstate
1011 walkresults = dirstate.walk(matcher, subrepos=sorted(ctx.substate),
1028 walkresults = dirstate.walk(matcher, subrepos=sorted(ctx.substate),
1012 unknown=True, ignored=False, full=False)
1029 unknown=True, ignored=False, full=False)
1013 for abs, st in walkresults.iteritems():
1030 for abs, st in walkresults.iteritems():
1014 dstate = dirstate[abs]
1031 dstate = dirstate[abs]
1015 if dstate == '?' and audit_path.check(abs):
1032 if dstate == '?' and audit_path.check(abs):
1016 unknown.append(abs)
1033 unknown.append(abs)
1017 elif dstate != 'r' and not st:
1034 elif dstate != 'r' and not st:
1018 deleted.append(abs)
1035 deleted.append(abs)
1019 elif dstate == 'r' and st:
1036 elif dstate == 'r' and st:
1020 forgotten.append(abs)
1037 forgotten.append(abs)
1021 # for finding renames
1038 # for finding renames
1022 elif dstate == 'r' and not st:
1039 elif dstate == 'r' and not st:
1023 removed.append(abs)
1040 removed.append(abs)
1024 elif dstate == 'a':
1041 elif dstate == 'a':
1025 added.append(abs)
1042 added.append(abs)
1026
1043
1027 return added, unknown, deleted, removed, forgotten
1044 return added, unknown, deleted, removed, forgotten
1028
1045
1029 def _findrenames(repo, matcher, added, removed, similarity):
1046 def _findrenames(repo, matcher, added, removed, similarity):
1030 '''Find renames from removed files to added ones.'''
1047 '''Find renames from removed files to added ones.'''
1031 renames = {}
1048 renames = {}
1032 if similarity > 0:
1049 if similarity > 0:
1033 for old, new, score in similar.findrenames(repo, added, removed,
1050 for old, new, score in similar.findrenames(repo, added, removed,
1034 similarity):
1051 similarity):
1035 if (repo.ui.verbose or not matcher.exact(old)
1052 if (repo.ui.verbose or not matcher.exact(old)
1036 or not matcher.exact(new)):
1053 or not matcher.exact(new)):
1037 repo.ui.status(_('recording removal of %s as rename to %s '
1054 repo.ui.status(_('recording removal of %s as rename to %s '
1038 '(%d%% similar)\n') %
1055 '(%d%% similar)\n') %
1039 (matcher.rel(old), matcher.rel(new),
1056 (matcher.rel(old), matcher.rel(new),
1040 score * 100))
1057 score * 100))
1041 renames[new] = old
1058 renames[new] = old
1042 return renames
1059 return renames
1043
1060
1044 def _markchanges(repo, unknown, deleted, renames):
1061 def _markchanges(repo, unknown, deleted, renames):
1045 '''Marks the files in unknown as added, the files in deleted as removed,
1062 '''Marks the files in unknown as added, the files in deleted as removed,
1046 and the files in renames as copied.'''
1063 and the files in renames as copied.'''
1047 wctx = repo[None]
1064 wctx = repo[None]
1048 with repo.wlock():
1065 with repo.wlock():
1049 wctx.forget(deleted)
1066 wctx.forget(deleted)
1050 wctx.add(unknown)
1067 wctx.add(unknown)
1051 for new, old in renames.iteritems():
1068 for new, old in renames.iteritems():
1052 wctx.copy(old, new)
1069 wctx.copy(old, new)
1053
1070
1054 def dirstatecopy(ui, repo, wctx, src, dst, dryrun=False, cwd=None):
1071 def dirstatecopy(ui, repo, wctx, src, dst, dryrun=False, cwd=None):
1055 """Update the dirstate to reflect the intent of copying src to dst. For
1072 """Update the dirstate to reflect the intent of copying src to dst. For
1056 different reasons it might not end with dst being marked as copied from src.
1073 different reasons it might not end with dst being marked as copied from src.
1057 """
1074 """
1058 origsrc = repo.dirstate.copied(src) or src
1075 origsrc = repo.dirstate.copied(src) or src
1059 if dst == origsrc: # copying back a copy?
1076 if dst == origsrc: # copying back a copy?
1060 if repo.dirstate[dst] not in 'mn' and not dryrun:
1077 if repo.dirstate[dst] not in 'mn' and not dryrun:
1061 repo.dirstate.normallookup(dst)
1078 repo.dirstate.normallookup(dst)
1062 else:
1079 else:
1063 if repo.dirstate[origsrc] == 'a' and origsrc == src:
1080 if repo.dirstate[origsrc] == 'a' and origsrc == src:
1064 if not ui.quiet:
1081 if not ui.quiet:
1065 ui.warn(_("%s has not been committed yet, so no copy "
1082 ui.warn(_("%s has not been committed yet, so no copy "
1066 "data will be stored for %s.\n")
1083 "data will be stored for %s.\n")
1067 % (repo.pathto(origsrc, cwd), repo.pathto(dst, cwd)))
1084 % (repo.pathto(origsrc, cwd), repo.pathto(dst, cwd)))
1068 if repo.dirstate[dst] in '?r' and not dryrun:
1085 if repo.dirstate[dst] in '?r' and not dryrun:
1069 wctx.add([dst])
1086 wctx.add([dst])
1070 elif not dryrun:
1087 elif not dryrun:
1071 wctx.copy(origsrc, dst)
1088 wctx.copy(origsrc, dst)
1072
1089
1073 def readrequires(opener, supported):
1090 def readrequires(opener, supported):
1074 '''Reads and parses .hg/requires and checks if all entries found
1091 '''Reads and parses .hg/requires and checks if all entries found
1075 are in the list of supported features.'''
1092 are in the list of supported features.'''
1076 requirements = set(opener.read("requires").splitlines())
1093 requirements = set(opener.read("requires").splitlines())
1077 missings = []
1094 missings = []
1078 for r in requirements:
1095 for r in requirements:
1079 if r not in supported:
1096 if r not in supported:
1080 if not r or not r[0:1].isalnum():
1097 if not r or not r[0:1].isalnum():
1081 raise error.RequirementError(_(".hg/requires file is corrupt"))
1098 raise error.RequirementError(_(".hg/requires file is corrupt"))
1082 missings.append(r)
1099 missings.append(r)
1083 missings.sort()
1100 missings.sort()
1084 if missings:
1101 if missings:
1085 raise error.RequirementError(
1102 raise error.RequirementError(
1086 _("repository requires features unknown to this Mercurial: %s")
1103 _("repository requires features unknown to this Mercurial: %s")
1087 % " ".join(missings),
1104 % " ".join(missings),
1088 hint=_("see https://mercurial-scm.org/wiki/MissingRequirement"
1105 hint=_("see https://mercurial-scm.org/wiki/MissingRequirement"
1089 " for more information"))
1106 " for more information"))
1090 return requirements
1107 return requirements
1091
1108
1092 def writerequires(opener, requirements):
1109 def writerequires(opener, requirements):
1093 with opener('requires', 'w') as fp:
1110 with opener('requires', 'w') as fp:
1094 for r in sorted(requirements):
1111 for r in sorted(requirements):
1095 fp.write("%s\n" % r)
1112 fp.write("%s\n" % r)
1096
1113
1097 class filecachesubentry(object):
1114 class filecachesubentry(object):
1098 def __init__(self, path, stat):
1115 def __init__(self, path, stat):
1099 self.path = path
1116 self.path = path
1100 self.cachestat = None
1117 self.cachestat = None
1101 self._cacheable = None
1118 self._cacheable = None
1102
1119
1103 if stat:
1120 if stat:
1104 self.cachestat = filecachesubentry.stat(self.path)
1121 self.cachestat = filecachesubentry.stat(self.path)
1105
1122
1106 if self.cachestat:
1123 if self.cachestat:
1107 self._cacheable = self.cachestat.cacheable()
1124 self._cacheable = self.cachestat.cacheable()
1108 else:
1125 else:
1109 # None means we don't know yet
1126 # None means we don't know yet
1110 self._cacheable = None
1127 self._cacheable = None
1111
1128
1112 def refresh(self):
1129 def refresh(self):
1113 if self.cacheable():
1130 if self.cacheable():
1114 self.cachestat = filecachesubentry.stat(self.path)
1131 self.cachestat = filecachesubentry.stat(self.path)
1115
1132
1116 def cacheable(self):
1133 def cacheable(self):
1117 if self._cacheable is not None:
1134 if self._cacheable is not None:
1118 return self._cacheable
1135 return self._cacheable
1119
1136
1120 # we don't know yet, assume it is for now
1137 # we don't know yet, assume it is for now
1121 return True
1138 return True
1122
1139
1123 def changed(self):
1140 def changed(self):
1124 # no point in going further if we can't cache it
1141 # no point in going further if we can't cache it
1125 if not self.cacheable():
1142 if not self.cacheable():
1126 return True
1143 return True
1127
1144
1128 newstat = filecachesubentry.stat(self.path)
1145 newstat = filecachesubentry.stat(self.path)
1129
1146
1130 # we may not know if it's cacheable yet, check again now
1147 # we may not know if it's cacheable yet, check again now
1131 if newstat and self._cacheable is None:
1148 if newstat and self._cacheable is None:
1132 self._cacheable = newstat.cacheable()
1149 self._cacheable = newstat.cacheable()
1133
1150
1134 # check again
1151 # check again
1135 if not self._cacheable:
1152 if not self._cacheable:
1136 return True
1153 return True
1137
1154
1138 if self.cachestat != newstat:
1155 if self.cachestat != newstat:
1139 self.cachestat = newstat
1156 self.cachestat = newstat
1140 return True
1157 return True
1141 else:
1158 else:
1142 return False
1159 return False
1143
1160
1144 @staticmethod
1161 @staticmethod
1145 def stat(path):
1162 def stat(path):
1146 try:
1163 try:
1147 return util.cachestat(path)
1164 return util.cachestat(path)
1148 except OSError as e:
1165 except OSError as e:
1149 if e.errno != errno.ENOENT:
1166 if e.errno != errno.ENOENT:
1150 raise
1167 raise
1151
1168
1152 class filecacheentry(object):
1169 class filecacheentry(object):
1153 def __init__(self, paths, stat=True):
1170 def __init__(self, paths, stat=True):
1154 self._entries = []
1171 self._entries = []
1155 for path in paths:
1172 for path in paths:
1156 self._entries.append(filecachesubentry(path, stat))
1173 self._entries.append(filecachesubentry(path, stat))
1157
1174
1158 def changed(self):
1175 def changed(self):
1159 '''true if any entry has changed'''
1176 '''true if any entry has changed'''
1160 for entry in self._entries:
1177 for entry in self._entries:
1161 if entry.changed():
1178 if entry.changed():
1162 return True
1179 return True
1163 return False
1180 return False
1164
1181
1165 def refresh(self):
1182 def refresh(self):
1166 for entry in self._entries:
1183 for entry in self._entries:
1167 entry.refresh()
1184 entry.refresh()
1168
1185
1169 class filecache(object):
1186 class filecache(object):
1170 """A property like decorator that tracks files under .hg/ for updates.
1187 """A property like decorator that tracks files under .hg/ for updates.
1171
1188
1172 On first access, the files defined as arguments are stat()ed and the
1189 On first access, the files defined as arguments are stat()ed and the
1173 results cached. The decorated function is called. The results are stashed
1190 results cached. The decorated function is called. The results are stashed
1174 away in a ``_filecache`` dict on the object whose method is decorated.
1191 away in a ``_filecache`` dict on the object whose method is decorated.
1175
1192
1176 On subsequent access, the cached result is returned.
1193 On subsequent access, the cached result is returned.
1177
1194
1178 On external property set operations, stat() calls are performed and the new
1195 On external property set operations, stat() calls are performed and the new
1179 value is cached.
1196 value is cached.
1180
1197
1181 On property delete operations, cached data is removed.
1198 On property delete operations, cached data is removed.
1182
1199
1183 When using the property API, cached data is always returned, if available:
1200 When using the property API, cached data is always returned, if available:
1184 no stat() is performed to check if the file has changed and if the function
1201 no stat() is performed to check if the file has changed and if the function
1185 needs to be called to reflect file changes.
1202 needs to be called to reflect file changes.
1186
1203
1187 Others can muck about with the state of the ``_filecache`` dict. e.g. they
1204 Others can muck about with the state of the ``_filecache`` dict. e.g. they
1188 can populate an entry before the property's getter is called. In this case,
1205 can populate an entry before the property's getter is called. In this case,
1189 entries in ``_filecache`` will be used during property operations,
1206 entries in ``_filecache`` will be used during property operations,
1190 if available. If the underlying file changes, it is up to external callers
1207 if available. If the underlying file changes, it is up to external callers
1191 to reflect this by e.g. calling ``delattr(obj, attr)`` to remove the cached
1208 to reflect this by e.g. calling ``delattr(obj, attr)`` to remove the cached
1192 method result as well as possibly calling ``del obj._filecache[attr]`` to
1209 method result as well as possibly calling ``del obj._filecache[attr]`` to
1193 remove the ``filecacheentry``.
1210 remove the ``filecacheentry``.
1194 """
1211 """
1195
1212
1196 def __init__(self, *paths):
1213 def __init__(self, *paths):
1197 self.paths = paths
1214 self.paths = paths
1198
1215
1199 def join(self, obj, fname):
1216 def join(self, obj, fname):
1200 """Used to compute the runtime path of a cached file.
1217 """Used to compute the runtime path of a cached file.
1201
1218
1202 Users should subclass filecache and provide their own version of this
1219 Users should subclass filecache and provide their own version of this
1203 function to call the appropriate join function on 'obj' (an instance
1220 function to call the appropriate join function on 'obj' (an instance
1204 of the class that its member function was decorated).
1221 of the class that its member function was decorated).
1205 """
1222 """
1206 raise NotImplementedError
1223 raise NotImplementedError
1207
1224
1208 def __call__(self, func):
1225 def __call__(self, func):
1209 self.func = func
1226 self.func = func
1210 self.sname = func.__name__
1227 self.sname = func.__name__
1211 self.name = pycompat.sysbytes(self.sname)
1228 self.name = pycompat.sysbytes(self.sname)
1212 return self
1229 return self
1213
1230
1214 def __get__(self, obj, type=None):
1231 def __get__(self, obj, type=None):
1215 # if accessed on the class, return the descriptor itself.
1232 # if accessed on the class, return the descriptor itself.
1216 if obj is None:
1233 if obj is None:
1217 return self
1234 return self
1218 # do we need to check if the file changed?
1235 # do we need to check if the file changed?
1219 if self.sname in obj.__dict__:
1236 if self.sname in obj.__dict__:
1220 assert self.name in obj._filecache, self.name
1237 assert self.name in obj._filecache, self.name
1221 return obj.__dict__[self.sname]
1238 return obj.__dict__[self.sname]
1222
1239
1223 entry = obj._filecache.get(self.name)
1240 entry = obj._filecache.get(self.name)
1224
1241
1225 if entry:
1242 if entry:
1226 if entry.changed():
1243 if entry.changed():
1227 entry.obj = self.func(obj)
1244 entry.obj = self.func(obj)
1228 else:
1245 else:
1229 paths = [self.join(obj, path) for path in self.paths]
1246 paths = [self.join(obj, path) for path in self.paths]
1230
1247
1231 # We stat -before- creating the object so our cache doesn't lie if
1248 # We stat -before- creating the object so our cache doesn't lie if
1232 # a writer modified between the time we read and stat
1249 # a writer modified between the time we read and stat
1233 entry = filecacheentry(paths, True)
1250 entry = filecacheentry(paths, True)
1234 entry.obj = self.func(obj)
1251 entry.obj = self.func(obj)
1235
1252
1236 obj._filecache[self.name] = entry
1253 obj._filecache[self.name] = entry
1237
1254
1238 obj.__dict__[self.sname] = entry.obj
1255 obj.__dict__[self.sname] = entry.obj
1239 return entry.obj
1256 return entry.obj
1240
1257
1241 def __set__(self, obj, value):
1258 def __set__(self, obj, value):
1242 if self.name not in obj._filecache:
1259 if self.name not in obj._filecache:
1243 # we add an entry for the missing value because X in __dict__
1260 # we add an entry for the missing value because X in __dict__
1244 # implies X in _filecache
1261 # implies X in _filecache
1245 paths = [self.join(obj, path) for path in self.paths]
1262 paths = [self.join(obj, path) for path in self.paths]
1246 ce = filecacheentry(paths, False)
1263 ce = filecacheentry(paths, False)
1247 obj._filecache[self.name] = ce
1264 obj._filecache[self.name] = ce
1248 else:
1265 else:
1249 ce = obj._filecache[self.name]
1266 ce = obj._filecache[self.name]
1250
1267
1251 ce.obj = value # update cached copy
1268 ce.obj = value # update cached copy
1252 obj.__dict__[self.sname] = value # update copy returned by obj.x
1269 obj.__dict__[self.sname] = value # update copy returned by obj.x
1253
1270
1254 def __delete__(self, obj):
1271 def __delete__(self, obj):
1255 try:
1272 try:
1256 del obj.__dict__[self.sname]
1273 del obj.__dict__[self.sname]
1257 except KeyError:
1274 except KeyError:
1258 raise AttributeError(self.sname)
1275 raise AttributeError(self.sname)
1259
1276
1260 def extdatasource(repo, source):
1277 def extdatasource(repo, source):
1261 """Gather a map of rev -> value dict from the specified source
1278 """Gather a map of rev -> value dict from the specified source
1262
1279
1263 A source spec is treated as a URL, with a special case shell: type
1280 A source spec is treated as a URL, with a special case shell: type
1264 for parsing the output from a shell command.
1281 for parsing the output from a shell command.
1265
1282
1266 The data is parsed as a series of newline-separated records where
1283 The data is parsed as a series of newline-separated records where
1267 each record is a revision specifier optionally followed by a space
1284 each record is a revision specifier optionally followed by a space
1268 and a freeform string value. If the revision is known locally, it
1285 and a freeform string value. If the revision is known locally, it
1269 is converted to a rev, otherwise the record is skipped.
1286 is converted to a rev, otherwise the record is skipped.
1270
1287
1271 Note that both key and value are treated as UTF-8 and converted to
1288 Note that both key and value are treated as UTF-8 and converted to
1272 the local encoding. This allows uniformity between local and
1289 the local encoding. This allows uniformity between local and
1273 remote data sources.
1290 remote data sources.
1274 """
1291 """
1275
1292
1276 spec = repo.ui.config("extdata", source)
1293 spec = repo.ui.config("extdata", source)
1277 if not spec:
1294 if not spec:
1278 raise error.Abort(_("unknown extdata source '%s'") % source)
1295 raise error.Abort(_("unknown extdata source '%s'") % source)
1279
1296
1280 data = {}
1297 data = {}
1281 src = proc = None
1298 src = proc = None
1282 try:
1299 try:
1283 if spec.startswith("shell:"):
1300 if spec.startswith("shell:"):
1284 # external commands should be run relative to the repo root
1301 # external commands should be run relative to the repo root
1285 cmd = spec[6:]
1302 cmd = spec[6:]
1286 proc = subprocess.Popen(cmd, shell=True, bufsize=-1,
1303 proc = subprocess.Popen(cmd, shell=True, bufsize=-1,
1287 close_fds=procutil.closefds,
1304 close_fds=procutil.closefds,
1288 stdout=subprocess.PIPE, cwd=repo.root)
1305 stdout=subprocess.PIPE, cwd=repo.root)
1289 src = proc.stdout
1306 src = proc.stdout
1290 else:
1307 else:
1291 # treat as a URL or file
1308 # treat as a URL or file
1292 src = url.open(repo.ui, spec)
1309 src = url.open(repo.ui, spec)
1293 for l in src:
1310 for l in src:
1294 if " " in l:
1311 if " " in l:
1295 k, v = l.strip().split(" ", 1)
1312 k, v = l.strip().split(" ", 1)
1296 else:
1313 else:
1297 k, v = l.strip(), ""
1314 k, v = l.strip(), ""
1298
1315
1299 k = encoding.tolocal(k)
1316 k = encoding.tolocal(k)
1300 try:
1317 try:
1301 data[revsingle(repo, k).rev()] = encoding.tolocal(v)
1318 data[revsingle(repo, k).rev()] = encoding.tolocal(v)
1302 except (error.LookupError, error.RepoLookupError):
1319 except (error.LookupError, error.RepoLookupError):
1303 pass # we ignore data for nodes that don't exist locally
1320 pass # we ignore data for nodes that don't exist locally
1304 finally:
1321 finally:
1305 if proc:
1322 if proc:
1306 proc.communicate()
1323 proc.communicate()
1307 if src:
1324 if src:
1308 src.close()
1325 src.close()
1309 if proc and proc.returncode != 0:
1326 if proc and proc.returncode != 0:
1310 raise error.Abort(_("extdata command '%s' failed: %s")
1327 raise error.Abort(_("extdata command '%s' failed: %s")
1311 % (cmd, procutil.explainexit(proc.returncode)))
1328 % (cmd, procutil.explainexit(proc.returncode)))
1312
1329
1313 return data
1330 return data
1314
1331
1315 def _locksub(repo, lock, envvar, cmd, environ=None, *args, **kwargs):
1332 def _locksub(repo, lock, envvar, cmd, environ=None, *args, **kwargs):
1316 if lock is None:
1333 if lock is None:
1317 raise error.LockInheritanceContractViolation(
1334 raise error.LockInheritanceContractViolation(
1318 'lock can only be inherited while held')
1335 'lock can only be inherited while held')
1319 if environ is None:
1336 if environ is None:
1320 environ = {}
1337 environ = {}
1321 with lock.inherit() as locker:
1338 with lock.inherit() as locker:
1322 environ[envvar] = locker
1339 environ[envvar] = locker
1323 return repo.ui.system(cmd, environ=environ, *args, **kwargs)
1340 return repo.ui.system(cmd, environ=environ, *args, **kwargs)
1324
1341
1325 def wlocksub(repo, cmd, *args, **kwargs):
1342 def wlocksub(repo, cmd, *args, **kwargs):
1326 """run cmd as a subprocess that allows inheriting repo's wlock
1343 """run cmd as a subprocess that allows inheriting repo's wlock
1327
1344
1328 This can only be called while the wlock is held. This takes all the
1345 This can only be called while the wlock is held. This takes all the
1329 arguments that ui.system does, and returns the exit code of the
1346 arguments that ui.system does, and returns the exit code of the
1330 subprocess."""
1347 subprocess."""
1331 return _locksub(repo, repo.currentwlock(), 'HG_WLOCK_LOCKER', cmd, *args,
1348 return _locksub(repo, repo.currentwlock(), 'HG_WLOCK_LOCKER', cmd, *args,
1332 **kwargs)
1349 **kwargs)
1333
1350
1334 class progress(object):
1351 class progress(object):
1335 def __init__(self, ui, topic, unit="", total=None):
1352 def __init__(self, ui, topic, unit="", total=None):
1336 self.ui = ui
1353 self.ui = ui
1337 self.pos = 0
1354 self.pos = 0
1338 self.topic = topic
1355 self.topic = topic
1339 self.unit = unit
1356 self.unit = unit
1340 self.total = total
1357 self.total = total
1341
1358
1342 def __enter__(self):
1359 def __enter__(self):
1343 return self
1360 return self
1344
1361
1345 def __exit__(self, exc_type, exc_value, exc_tb):
1362 def __exit__(self, exc_type, exc_value, exc_tb):
1346 self.complete()
1363 self.complete()
1347
1364
1348 def update(self, pos, item="", total=None):
1365 def update(self, pos, item="", total=None):
1349 assert pos is not None
1366 assert pos is not None
1350 if total:
1367 if total:
1351 self.total = total
1368 self.total = total
1352 self.pos = pos
1369 self.pos = pos
1353 self._print(item)
1370 self._print(item)
1354
1371
1355 def increment(self, step=1, item="", total=None):
1372 def increment(self, step=1, item="", total=None):
1356 self.update(self.pos + step, item, total)
1373 self.update(self.pos + step, item, total)
1357
1374
1358 def complete(self):
1375 def complete(self):
1359 self.ui.progress(self.topic, None)
1376 self.ui.progress(self.topic, None)
1360
1377
1361 def _print(self, item):
1378 def _print(self, item):
1362 self.ui.progress(self.topic, self.pos, item, self.unit,
1379 self.ui.progress(self.topic, self.pos, item, self.unit,
1363 self.total)
1380 self.total)
1364
1381
1365 def gdinitconfig(ui):
1382 def gdinitconfig(ui):
1366 """helper function to know if a repo should be created as general delta
1383 """helper function to know if a repo should be created as general delta
1367 """
1384 """
1368 # experimental config: format.generaldelta
1385 # experimental config: format.generaldelta
1369 return (ui.configbool('format', 'generaldelta')
1386 return (ui.configbool('format', 'generaldelta')
1370 or ui.configbool('format', 'usegeneraldelta')
1387 or ui.configbool('format', 'usegeneraldelta')
1371 or ui.configbool('format', 'sparse-revlog'))
1388 or ui.configbool('format', 'sparse-revlog'))
1372
1389
1373 def gddeltaconfig(ui):
1390 def gddeltaconfig(ui):
1374 """helper function to know if incoming delta should be optimised
1391 """helper function to know if incoming delta should be optimised
1375 """
1392 """
1376 # experimental config: format.generaldelta
1393 # experimental config: format.generaldelta
1377 return ui.configbool('format', 'generaldelta')
1394 return ui.configbool('format', 'generaldelta')
1378
1395
1379 class simplekeyvaluefile(object):
1396 class simplekeyvaluefile(object):
1380 """A simple file with key=value lines
1397 """A simple file with key=value lines
1381
1398
1382 Keys must be alphanumerics and start with a letter, values must not
1399 Keys must be alphanumerics and start with a letter, values must not
1383 contain '\n' characters"""
1400 contain '\n' characters"""
1384 firstlinekey = '__firstline'
1401 firstlinekey = '__firstline'
1385
1402
1386 def __init__(self, vfs, path, keys=None):
1403 def __init__(self, vfs, path, keys=None):
1387 self.vfs = vfs
1404 self.vfs = vfs
1388 self.path = path
1405 self.path = path
1389
1406
1390 def read(self, firstlinenonkeyval=False):
1407 def read(self, firstlinenonkeyval=False):
1391 """Read the contents of a simple key-value file
1408 """Read the contents of a simple key-value file
1392
1409
1393 'firstlinenonkeyval' indicates whether the first line of file should
1410 'firstlinenonkeyval' indicates whether the first line of file should
1394 be treated as a key-value pair or reuturned fully under the
1411 be treated as a key-value pair or reuturned fully under the
1395 __firstline key."""
1412 __firstline key."""
1396 lines = self.vfs.readlines(self.path)
1413 lines = self.vfs.readlines(self.path)
1397 d = {}
1414 d = {}
1398 if firstlinenonkeyval:
1415 if firstlinenonkeyval:
1399 if not lines:
1416 if not lines:
1400 e = _("empty simplekeyvalue file")
1417 e = _("empty simplekeyvalue file")
1401 raise error.CorruptedState(e)
1418 raise error.CorruptedState(e)
1402 # we don't want to include '\n' in the __firstline
1419 # we don't want to include '\n' in the __firstline
1403 d[self.firstlinekey] = lines[0][:-1]
1420 d[self.firstlinekey] = lines[0][:-1]
1404 del lines[0]
1421 del lines[0]
1405
1422
1406 try:
1423 try:
1407 # the 'if line.strip()' part prevents us from failing on empty
1424 # the 'if line.strip()' part prevents us from failing on empty
1408 # lines which only contain '\n' therefore are not skipped
1425 # lines which only contain '\n' therefore are not skipped
1409 # by 'if line'
1426 # by 'if line'
1410 updatedict = dict(line[:-1].split('=', 1) for line in lines
1427 updatedict = dict(line[:-1].split('=', 1) for line in lines
1411 if line.strip())
1428 if line.strip())
1412 if self.firstlinekey in updatedict:
1429 if self.firstlinekey in updatedict:
1413 e = _("%r can't be used as a key")
1430 e = _("%r can't be used as a key")
1414 raise error.CorruptedState(e % self.firstlinekey)
1431 raise error.CorruptedState(e % self.firstlinekey)
1415 d.update(updatedict)
1432 d.update(updatedict)
1416 except ValueError as e:
1433 except ValueError as e:
1417 raise error.CorruptedState(str(e))
1434 raise error.CorruptedState(str(e))
1418 return d
1435 return d
1419
1436
1420 def write(self, data, firstline=None):
1437 def write(self, data, firstline=None):
1421 """Write key=>value mapping to a file
1438 """Write key=>value mapping to a file
1422 data is a dict. Keys must be alphanumerical and start with a letter.
1439 data is a dict. Keys must be alphanumerical and start with a letter.
1423 Values must not contain newline characters.
1440 Values must not contain newline characters.
1424
1441
1425 If 'firstline' is not None, it is written to file before
1442 If 'firstline' is not None, it is written to file before
1426 everything else, as it is, not in a key=value form"""
1443 everything else, as it is, not in a key=value form"""
1427 lines = []
1444 lines = []
1428 if firstline is not None:
1445 if firstline is not None:
1429 lines.append('%s\n' % firstline)
1446 lines.append('%s\n' % firstline)
1430
1447
1431 for k, v in data.items():
1448 for k, v in data.items():
1432 if k == self.firstlinekey:
1449 if k == self.firstlinekey:
1433 e = "key name '%s' is reserved" % self.firstlinekey
1450 e = "key name '%s' is reserved" % self.firstlinekey
1434 raise error.ProgrammingError(e)
1451 raise error.ProgrammingError(e)
1435 if not k[0:1].isalpha():
1452 if not k[0:1].isalpha():
1436 e = "keys must start with a letter in a key-value file"
1453 e = "keys must start with a letter in a key-value file"
1437 raise error.ProgrammingError(e)
1454 raise error.ProgrammingError(e)
1438 if not k.isalnum():
1455 if not k.isalnum():
1439 e = "invalid key name in a simple key-value file"
1456 e = "invalid key name in a simple key-value file"
1440 raise error.ProgrammingError(e)
1457 raise error.ProgrammingError(e)
1441 if '\n' in v:
1458 if '\n' in v:
1442 e = "invalid value in a simple key-value file"
1459 e = "invalid value in a simple key-value file"
1443 raise error.ProgrammingError(e)
1460 raise error.ProgrammingError(e)
1444 lines.append("%s=%s\n" % (k, v))
1461 lines.append("%s=%s\n" % (k, v))
1445 with self.vfs(self.path, mode='wb', atomictemp=True) as fp:
1462 with self.vfs(self.path, mode='wb', atomictemp=True) as fp:
1446 fp.write(''.join(lines))
1463 fp.write(''.join(lines))
1447
1464
1448 _reportobsoletedsource = [
1465 _reportobsoletedsource = [
1449 'debugobsolete',
1466 'debugobsolete',
1450 'pull',
1467 'pull',
1451 'push',
1468 'push',
1452 'serve',
1469 'serve',
1453 'unbundle',
1470 'unbundle',
1454 ]
1471 ]
1455
1472
1456 _reportnewcssource = [
1473 _reportnewcssource = [
1457 'pull',
1474 'pull',
1458 'unbundle',
1475 'unbundle',
1459 ]
1476 ]
1460
1477
1461 def prefetchfiles(repo, revs, match):
1478 def prefetchfiles(repo, revs, match):
1462 """Invokes the registered file prefetch functions, allowing extensions to
1479 """Invokes the registered file prefetch functions, allowing extensions to
1463 ensure the corresponding files are available locally, before the command
1480 ensure the corresponding files are available locally, before the command
1464 uses them."""
1481 uses them."""
1465 if match:
1482 if match:
1466 # The command itself will complain about files that don't exist, so
1483 # The command itself will complain about files that don't exist, so
1467 # don't duplicate the message.
1484 # don't duplicate the message.
1468 match = matchmod.badmatch(match, lambda fn, msg: None)
1485 match = matchmod.badmatch(match, lambda fn, msg: None)
1469 else:
1486 else:
1470 match = matchall(repo)
1487 match = matchall(repo)
1471
1488
1472 fileprefetchhooks(repo, revs, match)
1489 fileprefetchhooks(repo, revs, match)
1473
1490
1474 # a list of (repo, revs, match) prefetch functions
1491 # a list of (repo, revs, match) prefetch functions
1475 fileprefetchhooks = util.hooks()
1492 fileprefetchhooks = util.hooks()
1476
1493
1477 # A marker that tells the evolve extension to suppress its own reporting
1494 # A marker that tells the evolve extension to suppress its own reporting
1478 _reportstroubledchangesets = True
1495 _reportstroubledchangesets = True
1479
1496
1480 def registersummarycallback(repo, otr, txnname=''):
1497 def registersummarycallback(repo, otr, txnname=''):
1481 """register a callback to issue a summary after the transaction is closed
1498 """register a callback to issue a summary after the transaction is closed
1482 """
1499 """
1483 def txmatch(sources):
1500 def txmatch(sources):
1484 return any(txnname.startswith(source) for source in sources)
1501 return any(txnname.startswith(source) for source in sources)
1485
1502
1486 categories = []
1503 categories = []
1487
1504
1488 def reportsummary(func):
1505 def reportsummary(func):
1489 """decorator for report callbacks."""
1506 """decorator for report callbacks."""
1490 # The repoview life cycle is shorter than the one of the actual
1507 # The repoview life cycle is shorter than the one of the actual
1491 # underlying repository. So the filtered object can die before the
1508 # underlying repository. So the filtered object can die before the
1492 # weakref is used leading to troubles. We keep a reference to the
1509 # weakref is used leading to troubles. We keep a reference to the
1493 # unfiltered object and restore the filtering when retrieving the
1510 # unfiltered object and restore the filtering when retrieving the
1494 # repository through the weakref.
1511 # repository through the weakref.
1495 filtername = repo.filtername
1512 filtername = repo.filtername
1496 reporef = weakref.ref(repo.unfiltered())
1513 reporef = weakref.ref(repo.unfiltered())
1497 def wrapped(tr):
1514 def wrapped(tr):
1498 repo = reporef()
1515 repo = reporef()
1499 if filtername:
1516 if filtername:
1500 repo = repo.filtered(filtername)
1517 repo = repo.filtered(filtername)
1501 func(repo, tr)
1518 func(repo, tr)
1502 newcat = '%02i-txnreport' % len(categories)
1519 newcat = '%02i-txnreport' % len(categories)
1503 otr.addpostclose(newcat, wrapped)
1520 otr.addpostclose(newcat, wrapped)
1504 categories.append(newcat)
1521 categories.append(newcat)
1505 return wrapped
1522 return wrapped
1506
1523
1507 if txmatch(_reportobsoletedsource):
1524 if txmatch(_reportobsoletedsource):
1508 @reportsummary
1525 @reportsummary
1509 def reportobsoleted(repo, tr):
1526 def reportobsoleted(repo, tr):
1510 obsoleted = obsutil.getobsoleted(repo, tr)
1527 obsoleted = obsutil.getobsoleted(repo, tr)
1511 if obsoleted:
1528 if obsoleted:
1512 repo.ui.status(_('obsoleted %i changesets\n')
1529 repo.ui.status(_('obsoleted %i changesets\n')
1513 % len(obsoleted))
1530 % len(obsoleted))
1514
1531
1515 if (obsolete.isenabled(repo, obsolete.createmarkersopt) and
1532 if (obsolete.isenabled(repo, obsolete.createmarkersopt) and
1516 repo.ui.configbool('experimental', 'evolution.report-instabilities')):
1533 repo.ui.configbool('experimental', 'evolution.report-instabilities')):
1517 instabilitytypes = [
1534 instabilitytypes = [
1518 ('orphan', 'orphan'),
1535 ('orphan', 'orphan'),
1519 ('phase-divergent', 'phasedivergent'),
1536 ('phase-divergent', 'phasedivergent'),
1520 ('content-divergent', 'contentdivergent'),
1537 ('content-divergent', 'contentdivergent'),
1521 ]
1538 ]
1522
1539
1523 def getinstabilitycounts(repo):
1540 def getinstabilitycounts(repo):
1524 filtered = repo.changelog.filteredrevs
1541 filtered = repo.changelog.filteredrevs
1525 counts = {}
1542 counts = {}
1526 for instability, revset in instabilitytypes:
1543 for instability, revset in instabilitytypes:
1527 counts[instability] = len(set(obsolete.getrevs(repo, revset)) -
1544 counts[instability] = len(set(obsolete.getrevs(repo, revset)) -
1528 filtered)
1545 filtered)
1529 return counts
1546 return counts
1530
1547
1531 oldinstabilitycounts = getinstabilitycounts(repo)
1548 oldinstabilitycounts = getinstabilitycounts(repo)
1532 @reportsummary
1549 @reportsummary
1533 def reportnewinstabilities(repo, tr):
1550 def reportnewinstabilities(repo, tr):
1534 newinstabilitycounts = getinstabilitycounts(repo)
1551 newinstabilitycounts = getinstabilitycounts(repo)
1535 for instability, revset in instabilitytypes:
1552 for instability, revset in instabilitytypes:
1536 delta = (newinstabilitycounts[instability] -
1553 delta = (newinstabilitycounts[instability] -
1537 oldinstabilitycounts[instability])
1554 oldinstabilitycounts[instability])
1538 msg = getinstabilitymessage(delta, instability)
1555 msg = getinstabilitymessage(delta, instability)
1539 if msg:
1556 if msg:
1540 repo.ui.warn(msg)
1557 repo.ui.warn(msg)
1541
1558
1542 if txmatch(_reportnewcssource):
1559 if txmatch(_reportnewcssource):
1543 @reportsummary
1560 @reportsummary
1544 def reportnewcs(repo, tr):
1561 def reportnewcs(repo, tr):
1545 """Report the range of new revisions pulled/unbundled."""
1562 """Report the range of new revisions pulled/unbundled."""
1546 newrevs = tr.changes.get('revs', pycompat.xrange(0, 0))
1563 newrevs = tr.changes.get('revs', pycompat.xrange(0, 0))
1547 if not newrevs:
1564 if not newrevs:
1548 return
1565 return
1549
1566
1550 # Compute the bounds of new revisions' range, excluding obsoletes.
1567 # Compute the bounds of new revisions' range, excluding obsoletes.
1551 unfi = repo.unfiltered()
1568 unfi = repo.unfiltered()
1552 revs = unfi.revs('%ld and not obsolete()', newrevs)
1569 revs = unfi.revs('%ld and not obsolete()', newrevs)
1553 if not revs:
1570 if not revs:
1554 # Got only obsoletes.
1571 # Got only obsoletes.
1555 return
1572 return
1556 minrev, maxrev = repo[revs.min()], repo[revs.max()]
1573 minrev, maxrev = repo[revs.min()], repo[revs.max()]
1557
1574
1558 if minrev == maxrev:
1575 if minrev == maxrev:
1559 revrange = minrev
1576 revrange = minrev
1560 else:
1577 else:
1561 revrange = '%s:%s' % (minrev, maxrev)
1578 revrange = '%s:%s' % (minrev, maxrev)
1562 repo.ui.status(_('new changesets %s\n') % revrange)
1579 repo.ui.status(_('new changesets %s\n') % revrange)
1563
1580
1564 @reportsummary
1581 @reportsummary
1565 def reportphasechanges(repo, tr):
1582 def reportphasechanges(repo, tr):
1566 """Report statistics of phase changes for changesets pre-existing
1583 """Report statistics of phase changes for changesets pre-existing
1567 pull/unbundle.
1584 pull/unbundle.
1568 """
1585 """
1569 newrevs = tr.changes.get('revs', pycompat.xrange(0, 0))
1586 newrevs = tr.changes.get('revs', pycompat.xrange(0, 0))
1570 phasetracking = tr.changes.get('phases', {})
1587 phasetracking = tr.changes.get('phases', {})
1571 if not phasetracking:
1588 if not phasetracking:
1572 return
1589 return
1573 published = [
1590 published = [
1574 rev for rev, (old, new) in phasetracking.iteritems()
1591 rev for rev, (old, new) in phasetracking.iteritems()
1575 if new == phases.public and rev not in newrevs
1592 if new == phases.public and rev not in newrevs
1576 ]
1593 ]
1577 if not published:
1594 if not published:
1578 return
1595 return
1579 repo.ui.status(_('%d local changesets published\n')
1596 repo.ui.status(_('%d local changesets published\n')
1580 % len(published))
1597 % len(published))
1581
1598
1582 def getinstabilitymessage(delta, instability):
1599 def getinstabilitymessage(delta, instability):
1583 """function to return the message to show warning about new instabilities
1600 """function to return the message to show warning about new instabilities
1584
1601
1585 exists as a separate function so that extension can wrap to show more
1602 exists as a separate function so that extension can wrap to show more
1586 information like how to fix instabilities"""
1603 information like how to fix instabilities"""
1587 if delta > 0:
1604 if delta > 0:
1588 return _('%i new %s changesets\n') % (delta, instability)
1605 return _('%i new %s changesets\n') % (delta, instability)
1589
1606
1590 def nodesummaries(repo, nodes, maxnumnodes=4):
1607 def nodesummaries(repo, nodes, maxnumnodes=4):
1591 if len(nodes) <= maxnumnodes or repo.ui.verbose:
1608 if len(nodes) <= maxnumnodes or repo.ui.verbose:
1592 return ' '.join(short(h) for h in nodes)
1609 return ' '.join(short(h) for h in nodes)
1593 first = ' '.join(short(h) for h in nodes[:maxnumnodes])
1610 first = ' '.join(short(h) for h in nodes[:maxnumnodes])
1594 return _("%s and %d others") % (first, len(nodes) - maxnumnodes)
1611 return _("%s and %d others") % (first, len(nodes) - maxnumnodes)
1595
1612
1596 def enforcesinglehead(repo, tr, desc):
1613 def enforcesinglehead(repo, tr, desc):
1597 """check that no named branch has multiple heads"""
1614 """check that no named branch has multiple heads"""
1598 if desc in ('strip', 'repair'):
1615 if desc in ('strip', 'repair'):
1599 # skip the logic during strip
1616 # skip the logic during strip
1600 return
1617 return
1601 visible = repo.filtered('visible')
1618 visible = repo.filtered('visible')
1602 # possible improvement: we could restrict the check to affected branch
1619 # possible improvement: we could restrict the check to affected branch
1603 for name, heads in visible.branchmap().iteritems():
1620 for name, heads in visible.branchmap().iteritems():
1604 if len(heads) > 1:
1621 if len(heads) > 1:
1605 msg = _('rejecting multiple heads on branch "%s"')
1622 msg = _('rejecting multiple heads on branch "%s"')
1606 msg %= name
1623 msg %= name
1607 hint = _('%d heads: %s')
1624 hint = _('%d heads: %s')
1608 hint %= (len(heads), nodesummaries(repo, heads))
1625 hint %= (len(heads), nodesummaries(repo, heads))
1609 raise error.Abort(msg, hint=hint)
1626 raise error.Abort(msg, hint=hint)
1610
1627
1611 def wrapconvertsink(sink):
1628 def wrapconvertsink(sink):
1612 """Allow extensions to wrap the sink returned by convcmd.convertsink()
1629 """Allow extensions to wrap the sink returned by convcmd.convertsink()
1613 before it is used, whether or not the convert extension was formally loaded.
1630 before it is used, whether or not the convert extension was formally loaded.
1614 """
1631 """
1615 return sink
1632 return sink
1616
1633
1617 def unhidehashlikerevs(repo, specs, hiddentype):
1634 def unhidehashlikerevs(repo, specs, hiddentype):
1618 """parse the user specs and unhide changesets whose hash or revision number
1635 """parse the user specs and unhide changesets whose hash or revision number
1619 is passed.
1636 is passed.
1620
1637
1621 hiddentype can be: 1) 'warn': warn while unhiding changesets
1638 hiddentype can be: 1) 'warn': warn while unhiding changesets
1622 2) 'nowarn': don't warn while unhiding changesets
1639 2) 'nowarn': don't warn while unhiding changesets
1623
1640
1624 returns a repo object with the required changesets unhidden
1641 returns a repo object with the required changesets unhidden
1625 """
1642 """
1626 if not repo.filtername or not repo.ui.configbool('experimental',
1643 if not repo.filtername or not repo.ui.configbool('experimental',
1627 'directaccess'):
1644 'directaccess'):
1628 return repo
1645 return repo
1629
1646
1630 if repo.filtername not in ('visible', 'visible-hidden'):
1647 if repo.filtername not in ('visible', 'visible-hidden'):
1631 return repo
1648 return repo
1632
1649
1633 symbols = set()
1650 symbols = set()
1634 for spec in specs:
1651 for spec in specs:
1635 try:
1652 try:
1636 tree = revsetlang.parse(spec)
1653 tree = revsetlang.parse(spec)
1637 except error.ParseError: # will be reported by scmutil.revrange()
1654 except error.ParseError: # will be reported by scmutil.revrange()
1638 continue
1655 continue
1639
1656
1640 symbols.update(revsetlang.gethashlikesymbols(tree))
1657 symbols.update(revsetlang.gethashlikesymbols(tree))
1641
1658
1642 if not symbols:
1659 if not symbols:
1643 return repo
1660 return repo
1644
1661
1645 revs = _getrevsfromsymbols(repo, symbols)
1662 revs = _getrevsfromsymbols(repo, symbols)
1646
1663
1647 if not revs:
1664 if not revs:
1648 return repo
1665 return repo
1649
1666
1650 if hiddentype == 'warn':
1667 if hiddentype == 'warn':
1651 unfi = repo.unfiltered()
1668 unfi = repo.unfiltered()
1652 revstr = ", ".join([pycompat.bytestr(unfi[l]) for l in revs])
1669 revstr = ", ".join([pycompat.bytestr(unfi[l]) for l in revs])
1653 repo.ui.warn(_("warning: accessing hidden changesets for write "
1670 repo.ui.warn(_("warning: accessing hidden changesets for write "
1654 "operation: %s\n") % revstr)
1671 "operation: %s\n") % revstr)
1655
1672
1656 # we have to use new filtername to separate branch/tags cache until we can
1673 # we have to use new filtername to separate branch/tags cache until we can
1657 # disbale these cache when revisions are dynamically pinned.
1674 # disbale these cache when revisions are dynamically pinned.
1658 return repo.filtered('visible-hidden', revs)
1675 return repo.filtered('visible-hidden', revs)
1659
1676
1660 def _getrevsfromsymbols(repo, symbols):
1677 def _getrevsfromsymbols(repo, symbols):
1661 """parse the list of symbols and returns a set of revision numbers of hidden
1678 """parse the list of symbols and returns a set of revision numbers of hidden
1662 changesets present in symbols"""
1679 changesets present in symbols"""
1663 revs = set()
1680 revs = set()
1664 unfi = repo.unfiltered()
1681 unfi = repo.unfiltered()
1665 unficl = unfi.changelog
1682 unficl = unfi.changelog
1666 cl = repo.changelog
1683 cl = repo.changelog
1667 tiprev = len(unficl)
1684 tiprev = len(unficl)
1668 allowrevnums = repo.ui.configbool('experimental', 'directaccess.revnums')
1685 allowrevnums = repo.ui.configbool('experimental', 'directaccess.revnums')
1669 for s in symbols:
1686 for s in symbols:
1670 try:
1687 try:
1671 n = int(s)
1688 n = int(s)
1672 if n <= tiprev:
1689 if n <= tiprev:
1673 if not allowrevnums:
1690 if not allowrevnums:
1674 continue
1691 continue
1675 else:
1692 else:
1676 if n not in cl:
1693 if n not in cl:
1677 revs.add(n)
1694 revs.add(n)
1678 continue
1695 continue
1679 except ValueError:
1696 except ValueError:
1680 pass
1697 pass
1681
1698
1682 try:
1699 try:
1683 s = resolvehexnodeidprefix(unfi, s)
1700 s = resolvehexnodeidprefix(unfi, s)
1684 except (error.LookupError, error.WdirUnsupported):
1701 except (error.LookupError, error.WdirUnsupported):
1685 s = None
1702 s = None
1686
1703
1687 if s is not None:
1704 if s is not None:
1688 rev = unficl.rev(s)
1705 rev = unficl.rev(s)
1689 if rev not in cl:
1706 if rev not in cl:
1690 revs.add(rev)
1707 revs.add(rev)
1691
1708
1692 return revs
1709 return revs
1693
1710
1694 def bookmarkrevs(repo, mark):
1711 def bookmarkrevs(repo, mark):
1695 """
1712 """
1696 Select revisions reachable by a given bookmark
1713 Select revisions reachable by a given bookmark
1697 """
1714 """
1698 return repo.revs("ancestors(bookmark(%s)) - "
1715 return repo.revs("ancestors(bookmark(%s)) - "
1699 "ancestors(head() and not bookmark(%s)) - "
1716 "ancestors(head() and not bookmark(%s)) - "
1700 "ancestors(bookmark() and not bookmark(%s))",
1717 "ancestors(bookmark() and not bookmark(%s))",
1701 mark, mark, mark)
1718 mark, mark, mark)
General Comments 0
You need to be logged in to leave comments. Login now