##// END OF EJS Templates
help: supporting both help and doc for aliases...
Rodrigo Damazio -
r37152:6890b7e9 default
parent child Browse files
Show More
@@ -1,469 +1,469 b''
1 1 # show.py - Extension implementing `hg show`
2 2 #
3 3 # Copyright 2017 Gregory Szorc <gregory.szorc@gmail.com>
4 4 #
5 5 # This software may be used and distributed according to the terms of the
6 6 # GNU General Public License version 2 or any later version.
7 7
8 8 """unified command to show various repository information (EXPERIMENTAL)
9 9
10 10 This extension provides the :hg:`show` command, which provides a central
11 11 command for displaying commonly-accessed repository data and views of that
12 12 data.
13 13
14 14 The following config options can influence operation.
15 15
16 16 ``commands``
17 17 ------------
18 18
19 19 ``show.aliasprefix``
20 20 List of strings that will register aliases for views. e.g. ``s`` will
21 21 effectively set config options ``alias.s<view> = show <view>`` for all
22 22 views. i.e. `hg swork` would execute `hg show work`.
23 23
24 24 Aliases that would conflict with existing registrations will not be
25 25 performed.
26 26 """
27 27
28 28 from __future__ import absolute_import
29 29
30 30 from mercurial.i18n import _
31 31 from mercurial.node import (
32 32 hex,
33 33 nullrev,
34 34 )
35 35 from mercurial import (
36 36 cmdutil,
37 37 commands,
38 38 destutil,
39 39 error,
40 40 formatter,
41 41 graphmod,
42 42 logcmdutil,
43 43 phases,
44 44 pycompat,
45 45 registrar,
46 46 revset,
47 47 revsetlang,
48 48 )
49 49
50 50 # Note for extension authors: ONLY specify testedwith = 'ships-with-hg-core' for
51 51 # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should
52 52 # be specifying the version(s) of Mercurial they are tested with, or
53 53 # leave the attribute unspecified.
54 54 testedwith = 'ships-with-hg-core'
55 55
56 56 cmdtable = {}
57 57 command = registrar.command(cmdtable)
58 58
59 59 revsetpredicate = registrar.revsetpredicate()
60 60
61 61 class showcmdfunc(registrar._funcregistrarbase):
62 62 """Register a function to be invoked for an `hg show <thing>`."""
63 63
64 64 # Used by _formatdoc().
65 65 _docformat = '%s -- %s'
66 66
67 67 def _extrasetup(self, name, func, fmtopic=None, csettopic=None):
68 68 """Called with decorator arguments to register a show view.
69 69
70 70 ``name`` is the sub-command name.
71 71
72 72 ``func`` is the function being decorated.
73 73
74 74 ``fmtopic`` is the topic in the style that will be rendered for
75 75 this view.
76 76
77 77 ``csettopic`` is the topic in the style to be used for a changeset
78 78 printer.
79 79
80 80 If ``fmtopic`` is specified, the view function will receive a
81 81 formatter instance. If ``csettopic`` is specified, the view
82 82 function will receive a changeset printer.
83 83 """
84 84 func._fmtopic = fmtopic
85 85 func._csettopic = csettopic
86 86
87 87 showview = showcmdfunc()
88 88
89 89 @command('show', [
90 90 # TODO: Switch this template flag to use cmdutil.formatteropts if
91 91 # 'hg show' becomes stable before --template/-T is stable. For now,
92 92 # we are putting it here without the '(EXPERIMENTAL)' flag because it
93 93 # is an important part of the 'hg show' user experience and the entire
94 94 # 'hg show' experience is experimental.
95 95 ('T', 'template', '', ('display with template'), _('TEMPLATE')),
96 96 ], _('VIEW'))
97 97 def show(ui, repo, view=None, template=None):
98 98 """show various repository information
99 99
100 100 A requested view of repository data is displayed.
101 101
102 102 If no view is requested, the list of available views is shown and the
103 103 command aborts.
104 104
105 105 .. note::
106 106
107 107 There are no backwards compatibility guarantees for the output of this
108 108 command. Output may change in any future Mercurial release.
109 109
110 110 Consumers wanting stable command output should specify a template via
111 111 ``-T/--template``.
112 112
113 113 List of available views:
114 114 """
115 115 if ui.plain() and not template:
116 116 hint = _('invoke with -T/--template to control output format')
117 117 raise error.Abort(_('must specify a template in plain mode'), hint=hint)
118 118
119 119 views = showview._table
120 120
121 121 if not view:
122 122 ui.pager('show')
123 123 # TODO consider using formatter here so available views can be
124 124 # rendered to custom format.
125 125 ui.write(_('available views:\n'))
126 126 ui.write('\n')
127 127
128 128 for name, func in sorted(views.items()):
129 129 ui.write(('%s\n') % pycompat.sysbytes(func.__doc__))
130 130
131 131 ui.write('\n')
132 132 raise error.Abort(_('no view requested'),
133 133 hint=_('use "hg show VIEW" to choose a view'))
134 134
135 135 # TODO use same logic as dispatch to perform prefix matching.
136 136 if view not in views:
137 137 raise error.Abort(_('unknown view: %s') % view,
138 138 hint=_('run "hg show" to see available views'))
139 139
140 140 template = template or 'show'
141 141
142 142 fn = views[view]
143 143 ui.pager('show')
144 144
145 145 if fn._fmtopic:
146 146 fmtopic = 'show%s' % fn._fmtopic
147 147 with ui.formatter(fmtopic, {'template': template}) as fm:
148 148 return fn(ui, repo, fm)
149 149 elif fn._csettopic:
150 150 ref = 'show%s' % fn._csettopic
151 151 spec = formatter.lookuptemplate(ui, ref, template)
152 152 displayer = logcmdutil.changesettemplater(ui, repo, spec, buffered=True)
153 153 return fn(ui, repo, displayer)
154 154 else:
155 155 return fn(ui, repo)
156 156
157 157 @showview('bookmarks', fmtopic='bookmarks')
158 158 def showbookmarks(ui, repo, fm):
159 159 """bookmarks and their associated changeset"""
160 160 marks = repo._bookmarks
161 161 if not len(marks):
162 162 # This is a bit hacky. Ideally, templates would have a way to
163 163 # specify an empty output, but we shouldn't corrupt JSON while
164 164 # waiting for this functionality.
165 165 if not isinstance(fm, formatter.jsonformatter):
166 166 ui.write(_('(no bookmarks set)\n'))
167 167 return
168 168
169 169 revs = [repo[node].rev() for node in marks.values()]
170 170 active = repo._activebookmark
171 171 longestname = max(len(b) for b in marks)
172 172 nodelen = longestshortest(repo, revs)
173 173
174 174 for bm, node in sorted(marks.items()):
175 175 fm.startitem()
176 176 fm.context(ctx=repo[node])
177 177 fm.write('bookmark', '%s', bm)
178 178 fm.write('node', fm.hexfunc(node), fm.hexfunc(node))
179 179 fm.data(active=bm == active,
180 180 longestbookmarklen=longestname,
181 181 nodelen=nodelen)
182 182
183 183 @showview('stack', csettopic='stack')
184 184 def showstack(ui, repo, displayer):
185 185 """current line of work"""
186 186 wdirctx = repo['.']
187 187 if wdirctx.rev() == nullrev:
188 188 raise error.Abort(_('stack view only available when there is a '
189 189 'working directory'))
190 190
191 191 if wdirctx.phase() == phases.public:
192 192 ui.write(_('(empty stack; working directory parent is a published '
193 193 'changeset)\n'))
194 194 return
195 195
196 196 # TODO extract "find stack" into a function to facilitate
197 197 # customization and reuse.
198 198
199 199 baserev = destutil.stackbase(ui, repo)
200 200 basectx = None
201 201
202 202 if baserev is None:
203 203 baserev = wdirctx.rev()
204 204 stackrevs = {wdirctx.rev()}
205 205 else:
206 206 stackrevs = set(repo.revs('%d::.', baserev))
207 207
208 208 ctx = repo[baserev]
209 209 if ctx.p1().rev() != nullrev:
210 210 basectx = ctx.p1()
211 211
212 212 # And relevant descendants.
213 213 branchpointattip = False
214 214 cl = repo.changelog
215 215
216 216 for rev in cl.descendants([wdirctx.rev()]):
217 217 ctx = repo[rev]
218 218
219 219 # Will only happen if . is public.
220 220 if ctx.phase() == phases.public:
221 221 break
222 222
223 223 stackrevs.add(ctx.rev())
224 224
225 225 # ctx.children() within a function iterating on descandants
226 226 # potentially has severe performance concerns because revlog.children()
227 227 # iterates over all revisions after ctx's node. However, the number of
228 228 # draft changesets should be a reasonably small number. So even if
229 229 # this is quadratic, the perf impact should be minimal.
230 230 if len(ctx.children()) > 1:
231 231 branchpointattip = True
232 232 break
233 233
234 234 stackrevs = list(sorted(stackrevs, reverse=True))
235 235
236 236 # Find likely target heads for the current stack. These are likely
237 237 # merge or rebase targets.
238 238 if basectx:
239 239 # TODO make this customizable?
240 240 newheads = set(repo.revs('heads(%d::) - %ld - not public()',
241 241 basectx.rev(), stackrevs))
242 242 else:
243 243 newheads = set()
244 244
245 245 allrevs = set(stackrevs) | newheads | set([baserev])
246 246 nodelen = longestshortest(repo, allrevs)
247 247
248 248 try:
249 249 cmdutil.findcmd('rebase', commands.table)
250 250 haverebase = True
251 251 except (error.AmbiguousCommand, error.UnknownCommand):
252 252 haverebase = False
253 253
254 254 # TODO use templating.
255 255 # TODO consider using graphmod. But it may not be necessary given
256 256 # our simplicity and the customizations required.
257 257 # TODO use proper graph symbols from graphmod
258 258
259 259 tres = formatter.templateresources(ui, repo)
260 260 shortesttmpl = formatter.maketemplater(ui, '{shortest(node, %d)}' % nodelen,
261 261 resources=tres)
262 262 def shortest(ctx):
263 263 return shortesttmpl.renderdefault({'ctx': ctx, 'node': ctx.hex()})
264 264
265 265 # We write out new heads to aid in DAG awareness and to help with decision
266 266 # making on how the stack should be reconciled with commits made since the
267 267 # branch point.
268 268 if newheads:
269 269 # Calculate distance from base so we can render the count and so we can
270 270 # sort display order by commit distance.
271 271 revdistance = {}
272 272 for head in newheads:
273 273 # There is some redundancy in DAG traversal here and therefore
274 274 # room to optimize.
275 275 ancestors = cl.ancestors([head], stoprev=basectx.rev())
276 276 revdistance[head] = len(list(ancestors))
277 277
278 278 sourcectx = repo[stackrevs[-1]]
279 279
280 280 sortedheads = sorted(newheads, key=lambda x: revdistance[x],
281 281 reverse=True)
282 282
283 283 for i, rev in enumerate(sortedheads):
284 284 ctx = repo[rev]
285 285
286 286 if i:
287 287 ui.write(': ')
288 288 else:
289 289 ui.write(' ')
290 290
291 291 ui.write(('o '))
292 292 displayer.show(ctx, nodelen=nodelen)
293 293 displayer.flush(ctx)
294 294 ui.write('\n')
295 295
296 296 if i:
297 297 ui.write(':/')
298 298 else:
299 299 ui.write(' /')
300 300
301 301 ui.write(' (')
302 302 ui.write(_('%d commits ahead') % revdistance[rev],
303 303 label='stack.commitdistance')
304 304
305 305 if haverebase:
306 306 # TODO may be able to omit --source in some scenarios
307 307 ui.write('; ')
308 308 ui.write(('hg rebase --source %s --dest %s' % (
309 309 shortest(sourcectx), shortest(ctx))),
310 310 label='stack.rebasehint')
311 311
312 312 ui.write(')\n')
313 313
314 314 ui.write(':\n: ')
315 315 ui.write(_('(stack head)\n'), label='stack.label')
316 316
317 317 if branchpointattip:
318 318 ui.write(' \\ / ')
319 319 ui.write(_('(multiple children)\n'), label='stack.label')
320 320 ui.write(' |\n')
321 321
322 322 for rev in stackrevs:
323 323 ctx = repo[rev]
324 324 symbol = '@' if rev == wdirctx.rev() else 'o'
325 325
326 326 if newheads:
327 327 ui.write(': ')
328 328 else:
329 329 ui.write(' ')
330 330
331 331 ui.write(symbol, ' ')
332 332 displayer.show(ctx, nodelen=nodelen)
333 333 displayer.flush(ctx)
334 334 ui.write('\n')
335 335
336 336 # TODO display histedit hint?
337 337
338 338 if basectx:
339 339 # Vertically and horizontally separate stack base from parent
340 340 # to reinforce stack boundary.
341 341 if newheads:
342 342 ui.write(':/ ')
343 343 else:
344 344 ui.write(' / ')
345 345
346 346 ui.write(_('(stack base)'), '\n', label='stack.label')
347 347 ui.write(('o '))
348 348
349 349 displayer.show(basectx, nodelen=nodelen)
350 350 displayer.flush(basectx)
351 351 ui.write('\n')
352 352
353 353 @revsetpredicate('_underway([commitage[, headage]])')
354 354 def underwayrevset(repo, subset, x):
355 355 args = revset.getargsdict(x, 'underway', 'commitage headage')
356 356 if 'commitage' not in args:
357 357 args['commitage'] = None
358 358 if 'headage' not in args:
359 359 args['headage'] = None
360 360
361 361 # We assume callers of this revset add a topographical sort on the
362 362 # result. This means there is no benefit to making the revset lazy
363 363 # since the topographical sort needs to consume all revs.
364 364 #
365 365 # With this in mind, we build up the set manually instead of constructing
366 366 # a complex revset. This enables faster execution.
367 367
368 368 # Mutable changesets (non-public) are the most important changesets
369 369 # to return. ``not public()`` will also pull in obsolete changesets if
370 370 # there is a non-obsolete changeset with obsolete ancestors. This is
371 371 # why we exclude obsolete changesets from this query.
372 372 rs = 'not public() and not obsolete()'
373 373 rsargs = []
374 374 if args['commitage']:
375 375 rs += ' and date(%s)'
376 376 rsargs.append(revsetlang.getstring(args['commitage'],
377 377 _('commitage requires a string')))
378 378
379 379 mutable = repo.revs(rs, *rsargs)
380 380 relevant = revset.baseset(mutable)
381 381
382 382 # Add parents of mutable changesets to provide context.
383 383 relevant += repo.revs('parents(%ld)', mutable)
384 384
385 385 # We also pull in (public) heads if they a) aren't closing a branch
386 386 # b) are recent.
387 387 rs = 'head() and not closed()'
388 388 rsargs = []
389 389 if args['headage']:
390 390 rs += ' and date(%s)'
391 391 rsargs.append(revsetlang.getstring(args['headage'],
392 392 _('headage requires a string')))
393 393
394 394 relevant += repo.revs(rs, *rsargs)
395 395
396 396 # Add working directory parent.
397 397 wdirrev = repo['.'].rev()
398 398 if wdirrev != nullrev:
399 399 relevant += revset.baseset({wdirrev})
400 400
401 401 return subset & relevant
402 402
403 403 @showview('work', csettopic='work')
404 404 def showwork(ui, repo, displayer):
405 405 """changesets that aren't finished"""
406 406 # TODO support date-based limiting when calling revset.
407 407 revs = repo.revs('sort(_underway(), topo)')
408 408 nodelen = longestshortest(repo, revs)
409 409
410 410 revdag = graphmod.dagwalker(repo, revs)
411 411
412 412 ui.setconfig('experimental', 'graphshorten', True)
413 413 logcmdutil.displaygraph(ui, repo, revdag, displayer, graphmod.asciiedges,
414 414 props={'nodelen': nodelen})
415 415
416 416 def extsetup(ui):
417 417 # Alias `hg <prefix><view>` to `hg show <view>`.
418 418 for prefix in ui.configlist('commands', 'show.aliasprefix'):
419 419 for view in showview._table:
420 420 name = '%s%s' % (prefix, view)
421 421
422 422 choice, allcommands = cmdutil.findpossible(name, commands.table,
423 423 strict=True)
424 424
425 425 # This alias is already a command name. Don't set it.
426 426 if name in choice:
427 427 continue
428 428
429 429 # Same for aliases.
430 if ui.config('alias', name):
430 if ui.config('alias', name, None):
431 431 continue
432 432
433 433 ui.setconfig('alias', name, 'show %s' % view, source='show')
434 434
435 435 def longestshortest(repo, revs, minlen=4):
436 436 """Return the length of the longest shortest node to identify revisions.
437 437
438 438 The result of this function can be used with the ``shortest()`` template
439 439 function to ensure that a value is unique and unambiguous for a given
440 440 set of nodes.
441 441
442 442 The number of revisions in the repo is taken into account to prevent
443 443 a numeric node prefix from conflicting with an integer revision number.
444 444 If we fail to do this, a value of e.g. ``10023`` could mean either
445 445 revision 10023 or node ``10023abc...``.
446 446 """
447 447 if not revs:
448 448 return minlen
449 449 # don't use filtered repo because it's slow. see templater.shortest().
450 450 cl = repo.unfiltered().changelog
451 451 return max(len(cl.shortest(hex(cl.node(r)), minlen)) for r in revs)
452 452
453 453 # Adjust the docstring of the show command so it shows all registered views.
454 454 # This is a bit hacky because it runs at the end of module load. When moved
455 455 # into core or when another extension wants to provide a view, we'll need
456 456 # to do this more robustly.
457 457 # TODO make this more robust.
458 458 def _updatedocstring():
459 459 longest = max(map(len, showview._table.keys()))
460 460 entries = []
461 461 for key in sorted(showview._table.keys()):
462 462 entries.append(pycompat.sysstr(' %s %s' % (
463 463 key.ljust(longest), showview._table[key]._origdoc)))
464 464
465 465 cmdtable['show'][0].__doc__ = pycompat.sysstr('%s\n\n%s\n ') % (
466 466 cmdtable['show'][0].__doc__.rstrip(),
467 467 pycompat.sysstr('\n\n').join(entries))
468 468
469 469 _updatedocstring()
@@ -1,1320 +1,1320 b''
1 1 # configitems.py - centralized declaration of configuration option
2 2 #
3 3 # Copyright 2017 Pierre-Yves David <pierre-yves.david@octobus.net>
4 4 #
5 5 # This software may be used and distributed according to the terms of the
6 6 # GNU General Public License version 2 or any later version.
7 7
8 8 from __future__ import absolute_import
9 9
10 10 import functools
11 11 import re
12 12
13 13 from . import (
14 14 encoding,
15 15 error,
16 16 )
17 17
18 18 def loadconfigtable(ui, extname, configtable):
19 19 """update config item known to the ui with the extension ones"""
20 20 for section, items in sorted(configtable.items()):
21 21 knownitems = ui._knownconfig.setdefault(section, itemregister())
22 22 knownkeys = set(knownitems)
23 23 newkeys = set(items)
24 24 for key in sorted(knownkeys & newkeys):
25 25 msg = "extension '%s' overwrite config item '%s.%s'"
26 26 msg %= (extname, section, key)
27 27 ui.develwarn(msg, config='warn-config')
28 28
29 29 knownitems.update(items)
30 30
31 31 class configitem(object):
32 32 """represent a known config item
33 33
34 34 :section: the official config section where to find this item,
35 35 :name: the official name within the section,
36 36 :default: default value for this item,
37 37 :alias: optional list of tuples as alternatives,
38 38 :generic: this is a generic definition, match name using regular expression.
39 39 """
40 40
41 41 def __init__(self, section, name, default=None, alias=(),
42 42 generic=False, priority=0):
43 43 self.section = section
44 44 self.name = name
45 45 self.default = default
46 46 self.alias = list(alias)
47 47 self.generic = generic
48 48 self.priority = priority
49 49 self._re = None
50 50 if generic:
51 51 self._re = re.compile(self.name)
52 52
53 53 class itemregister(dict):
54 54 """A specialized dictionary that can handle wild-card selection"""
55 55
56 56 def __init__(self):
57 57 super(itemregister, self).__init__()
58 58 self._generics = set()
59 59
60 60 def update(self, other):
61 61 super(itemregister, self).update(other)
62 62 self._generics.update(other._generics)
63 63
64 64 def __setitem__(self, key, item):
65 65 super(itemregister, self).__setitem__(key, item)
66 66 if item.generic:
67 67 self._generics.add(item)
68 68
69 69 def get(self, key):
70 70 baseitem = super(itemregister, self).get(key)
71 71 if baseitem is not None and not baseitem.generic:
72 72 return baseitem
73 73
74 74 # search for a matching generic item
75 75 generics = sorted(self._generics, key=(lambda x: (x.priority, x.name)))
76 76 for item in generics:
77 77 # we use 'match' instead of 'search' to make the matching simpler
78 78 # for people unfamiliar with regular expression. Having the match
79 79 # rooted to the start of the string will produce less surprising
80 80 # result for user writing simple regex for sub-attribute.
81 81 #
82 82 # For example using "color\..*" match produces an unsurprising
83 83 # result, while using search could suddenly match apparently
84 84 # unrelated configuration that happens to contains "color."
85 85 # anywhere. This is a tradeoff where we favor requiring ".*" on
86 86 # some match to avoid the need to prefix most pattern with "^".
87 87 # The "^" seems more error prone.
88 88 if item._re.match(key):
89 89 return item
90 90
91 91 return None
92 92
93 93 coreitems = {}
94 94
95 95 def _register(configtable, *args, **kwargs):
96 96 item = configitem(*args, **kwargs)
97 97 section = configtable.setdefault(item.section, itemregister())
98 98 if item.name in section:
99 99 msg = "duplicated config item registration for '%s.%s'"
100 100 raise error.ProgrammingError(msg % (item.section, item.name))
101 101 section[item.name] = item
102 102
103 103 # special value for case where the default is derived from other values
104 104 dynamicdefault = object()
105 105
106 106 # Registering actual config items
107 107
108 108 def getitemregister(configtable):
109 109 f = functools.partial(_register, configtable)
110 110 # export pseudo enum as configitem.*
111 111 f.dynamicdefault = dynamicdefault
112 112 return f
113 113
114 114 coreconfigitem = getitemregister(coreitems)
115 115
116 116 coreconfigitem('alias', '.*',
117 default=None,
117 default=dynamicdefault,
118 118 generic=True,
119 119 )
120 120 coreconfigitem('annotate', 'nodates',
121 121 default=False,
122 122 )
123 123 coreconfigitem('annotate', 'showfunc',
124 124 default=False,
125 125 )
126 126 coreconfigitem('annotate', 'unified',
127 127 default=None,
128 128 )
129 129 coreconfigitem('annotate', 'git',
130 130 default=False,
131 131 )
132 132 coreconfigitem('annotate', 'ignorews',
133 133 default=False,
134 134 )
135 135 coreconfigitem('annotate', 'ignorewsamount',
136 136 default=False,
137 137 )
138 138 coreconfigitem('annotate', 'ignoreblanklines',
139 139 default=False,
140 140 )
141 141 coreconfigitem('annotate', 'ignorewseol',
142 142 default=False,
143 143 )
144 144 coreconfigitem('annotate', 'nobinary',
145 145 default=False,
146 146 )
147 147 coreconfigitem('annotate', 'noprefix',
148 148 default=False,
149 149 )
150 150 coreconfigitem('auth', 'cookiefile',
151 151 default=None,
152 152 )
153 153 # bookmarks.pushing: internal hack for discovery
154 154 coreconfigitem('bookmarks', 'pushing',
155 155 default=list,
156 156 )
157 157 # bundle.mainreporoot: internal hack for bundlerepo
158 158 coreconfigitem('bundle', 'mainreporoot',
159 159 default='',
160 160 )
161 161 # bundle.reorder: experimental config
162 162 coreconfigitem('bundle', 'reorder',
163 163 default='auto',
164 164 )
165 165 coreconfigitem('censor', 'policy',
166 166 default='abort',
167 167 )
168 168 coreconfigitem('chgserver', 'idletimeout',
169 169 default=3600,
170 170 )
171 171 coreconfigitem('chgserver', 'skiphash',
172 172 default=False,
173 173 )
174 174 coreconfigitem('cmdserver', 'log',
175 175 default=None,
176 176 )
177 177 coreconfigitem('color', '.*',
178 178 default=None,
179 179 generic=True,
180 180 )
181 181 coreconfigitem('color', 'mode',
182 182 default='auto',
183 183 )
184 184 coreconfigitem('color', 'pagermode',
185 185 default=dynamicdefault,
186 186 )
187 187 coreconfigitem('commands', 'show.aliasprefix',
188 188 default=list,
189 189 )
190 190 coreconfigitem('commands', 'status.relative',
191 191 default=False,
192 192 )
193 193 coreconfigitem('commands', 'status.skipstates',
194 194 default=[],
195 195 )
196 196 coreconfigitem('commands', 'status.verbose',
197 197 default=False,
198 198 )
199 199 coreconfigitem('commands', 'update.check',
200 200 default=None,
201 201 # Deprecated, remove after 4.4 release
202 202 alias=[('experimental', 'updatecheck')]
203 203 )
204 204 coreconfigitem('commands', 'update.requiredest',
205 205 default=False,
206 206 )
207 207 coreconfigitem('committemplate', '.*',
208 208 default=None,
209 209 generic=True,
210 210 )
211 211 coreconfigitem('convert', 'cvsps.cache',
212 212 default=True,
213 213 )
214 214 coreconfigitem('convert', 'cvsps.fuzz',
215 215 default=60,
216 216 )
217 217 coreconfigitem('convert', 'cvsps.logencoding',
218 218 default=None,
219 219 )
220 220 coreconfigitem('convert', 'cvsps.mergefrom',
221 221 default=None,
222 222 )
223 223 coreconfigitem('convert', 'cvsps.mergeto',
224 224 default=None,
225 225 )
226 226 coreconfigitem('convert', 'git.committeractions',
227 227 default=lambda: ['messagedifferent'],
228 228 )
229 229 coreconfigitem('convert', 'git.extrakeys',
230 230 default=list,
231 231 )
232 232 coreconfigitem('convert', 'git.findcopiesharder',
233 233 default=False,
234 234 )
235 235 coreconfigitem('convert', 'git.remoteprefix',
236 236 default='remote',
237 237 )
238 238 coreconfigitem('convert', 'git.renamelimit',
239 239 default=400,
240 240 )
241 241 coreconfigitem('convert', 'git.saverev',
242 242 default=True,
243 243 )
244 244 coreconfigitem('convert', 'git.similarity',
245 245 default=50,
246 246 )
247 247 coreconfigitem('convert', 'git.skipsubmodules',
248 248 default=False,
249 249 )
250 250 coreconfigitem('convert', 'hg.clonebranches',
251 251 default=False,
252 252 )
253 253 coreconfigitem('convert', 'hg.ignoreerrors',
254 254 default=False,
255 255 )
256 256 coreconfigitem('convert', 'hg.revs',
257 257 default=None,
258 258 )
259 259 coreconfigitem('convert', 'hg.saverev',
260 260 default=False,
261 261 )
262 262 coreconfigitem('convert', 'hg.sourcename',
263 263 default=None,
264 264 )
265 265 coreconfigitem('convert', 'hg.startrev',
266 266 default=None,
267 267 )
268 268 coreconfigitem('convert', 'hg.tagsbranch',
269 269 default='default',
270 270 )
271 271 coreconfigitem('convert', 'hg.usebranchnames',
272 272 default=True,
273 273 )
274 274 coreconfigitem('convert', 'ignoreancestorcheck',
275 275 default=False,
276 276 )
277 277 coreconfigitem('convert', 'localtimezone',
278 278 default=False,
279 279 )
280 280 coreconfigitem('convert', 'p4.encoding',
281 281 default=dynamicdefault,
282 282 )
283 283 coreconfigitem('convert', 'p4.startrev',
284 284 default=0,
285 285 )
286 286 coreconfigitem('convert', 'skiptags',
287 287 default=False,
288 288 )
289 289 coreconfigitem('convert', 'svn.debugsvnlog',
290 290 default=True,
291 291 )
292 292 coreconfigitem('convert', 'svn.trunk',
293 293 default=None,
294 294 )
295 295 coreconfigitem('convert', 'svn.tags',
296 296 default=None,
297 297 )
298 298 coreconfigitem('convert', 'svn.branches',
299 299 default=None,
300 300 )
301 301 coreconfigitem('convert', 'svn.startrev',
302 302 default=0,
303 303 )
304 304 coreconfigitem('debug', 'dirstate.delaywrite',
305 305 default=0,
306 306 )
307 307 coreconfigitem('defaults', '.*',
308 308 default=None,
309 309 generic=True,
310 310 )
311 311 coreconfigitem('devel', 'all-warnings',
312 312 default=False,
313 313 )
314 314 coreconfigitem('devel', 'bundle2.debug',
315 315 default=False,
316 316 )
317 317 coreconfigitem('devel', 'cache-vfs',
318 318 default=None,
319 319 )
320 320 coreconfigitem('devel', 'check-locks',
321 321 default=False,
322 322 )
323 323 coreconfigitem('devel', 'check-relroot',
324 324 default=False,
325 325 )
326 326 coreconfigitem('devel', 'default-date',
327 327 default=None,
328 328 )
329 329 coreconfigitem('devel', 'deprec-warn',
330 330 default=False,
331 331 )
332 332 coreconfigitem('devel', 'disableloaddefaultcerts',
333 333 default=False,
334 334 )
335 335 coreconfigitem('devel', 'warn-empty-changegroup',
336 336 default=False,
337 337 )
338 338 coreconfigitem('devel', 'legacy.exchange',
339 339 default=list,
340 340 )
341 341 coreconfigitem('devel', 'servercafile',
342 342 default='',
343 343 )
344 344 coreconfigitem('devel', 'serverexactprotocol',
345 345 default='',
346 346 )
347 347 coreconfigitem('devel', 'serverrequirecert',
348 348 default=False,
349 349 )
350 350 coreconfigitem('devel', 'strip-obsmarkers',
351 351 default=True,
352 352 )
353 353 coreconfigitem('devel', 'warn-config',
354 354 default=None,
355 355 )
356 356 coreconfigitem('devel', 'warn-config-default',
357 357 default=None,
358 358 )
359 359 coreconfigitem('devel', 'user.obsmarker',
360 360 default=None,
361 361 )
362 362 coreconfigitem('devel', 'warn-config-unknown',
363 363 default=None,
364 364 )
365 365 coreconfigitem('devel', 'debug.peer-request',
366 366 default=False,
367 367 )
368 368 coreconfigitem('diff', 'nodates',
369 369 default=False,
370 370 )
371 371 coreconfigitem('diff', 'showfunc',
372 372 default=False,
373 373 )
374 374 coreconfigitem('diff', 'unified',
375 375 default=None,
376 376 )
377 377 coreconfigitem('diff', 'git',
378 378 default=False,
379 379 )
380 380 coreconfigitem('diff', 'ignorews',
381 381 default=False,
382 382 )
383 383 coreconfigitem('diff', 'ignorewsamount',
384 384 default=False,
385 385 )
386 386 coreconfigitem('diff', 'ignoreblanklines',
387 387 default=False,
388 388 )
389 389 coreconfigitem('diff', 'ignorewseol',
390 390 default=False,
391 391 )
392 392 coreconfigitem('diff', 'nobinary',
393 393 default=False,
394 394 )
395 395 coreconfigitem('diff', 'noprefix',
396 396 default=False,
397 397 )
398 398 coreconfigitem('email', 'bcc',
399 399 default=None,
400 400 )
401 401 coreconfigitem('email', 'cc',
402 402 default=None,
403 403 )
404 404 coreconfigitem('email', 'charsets',
405 405 default=list,
406 406 )
407 407 coreconfigitem('email', 'from',
408 408 default=None,
409 409 )
410 410 coreconfigitem('email', 'method',
411 411 default='smtp',
412 412 )
413 413 coreconfigitem('email', 'reply-to',
414 414 default=None,
415 415 )
416 416 coreconfigitem('email', 'to',
417 417 default=None,
418 418 )
419 419 coreconfigitem('experimental', 'archivemetatemplate',
420 420 default=dynamicdefault,
421 421 )
422 422 coreconfigitem('experimental', 'bundle-phases',
423 423 default=False,
424 424 )
425 425 coreconfigitem('experimental', 'bundle2-advertise',
426 426 default=True,
427 427 )
428 428 coreconfigitem('experimental', 'bundle2-output-capture',
429 429 default=False,
430 430 )
431 431 coreconfigitem('experimental', 'bundle2.pushback',
432 432 default=False,
433 433 )
434 434 coreconfigitem('experimental', 'bundle2.stream',
435 435 default=False,
436 436 )
437 437 coreconfigitem('experimental', 'bundle2lazylocking',
438 438 default=False,
439 439 )
440 440 coreconfigitem('experimental', 'bundlecomplevel',
441 441 default=None,
442 442 )
443 443 coreconfigitem('experimental', 'changegroup3',
444 444 default=False,
445 445 )
446 446 coreconfigitem('experimental', 'clientcompressionengines',
447 447 default=list,
448 448 )
449 449 coreconfigitem('experimental', 'copytrace',
450 450 default='on',
451 451 )
452 452 coreconfigitem('experimental', 'copytrace.movecandidateslimit',
453 453 default=100,
454 454 )
455 455 coreconfigitem('experimental', 'copytrace.sourcecommitlimit',
456 456 default=100,
457 457 )
458 458 coreconfigitem('experimental', 'crecordtest',
459 459 default=None,
460 460 )
461 461 coreconfigitem('experimental', 'directaccess',
462 462 default=False,
463 463 )
464 464 coreconfigitem('experimental', 'directaccess.revnums',
465 465 default=False,
466 466 )
467 467 coreconfigitem('experimental', 'editortmpinhg',
468 468 default=False,
469 469 )
470 470 coreconfigitem('experimental', 'evolution',
471 471 default=list,
472 472 )
473 473 coreconfigitem('experimental', 'evolution.allowdivergence',
474 474 default=False,
475 475 alias=[('experimental', 'allowdivergence')]
476 476 )
477 477 coreconfigitem('experimental', 'evolution.allowunstable',
478 478 default=None,
479 479 )
480 480 coreconfigitem('experimental', 'evolution.createmarkers',
481 481 default=None,
482 482 )
483 483 coreconfigitem('experimental', 'evolution.effect-flags',
484 484 default=True,
485 485 alias=[('experimental', 'effect-flags')]
486 486 )
487 487 coreconfigitem('experimental', 'evolution.exchange',
488 488 default=None,
489 489 )
490 490 coreconfigitem('experimental', 'evolution.bundle-obsmarker',
491 491 default=False,
492 492 )
493 493 coreconfigitem('experimental', 'evolution.report-instabilities',
494 494 default=True,
495 495 )
496 496 coreconfigitem('experimental', 'evolution.track-operation',
497 497 default=True,
498 498 )
499 499 coreconfigitem('experimental', 'worddiff',
500 500 default=False,
501 501 )
502 502 coreconfigitem('experimental', 'maxdeltachainspan',
503 503 default=-1,
504 504 )
505 505 coreconfigitem('experimental', 'mergetempdirprefix',
506 506 default=None,
507 507 )
508 508 coreconfigitem('experimental', 'mmapindexthreshold',
509 509 default=None,
510 510 )
511 511 coreconfigitem('experimental', 'nonnormalparanoidcheck',
512 512 default=False,
513 513 )
514 514 coreconfigitem('experimental', 'exportableenviron',
515 515 default=list,
516 516 )
517 517 coreconfigitem('experimental', 'extendedheader.index',
518 518 default=None,
519 519 )
520 520 coreconfigitem('experimental', 'extendedheader.similarity',
521 521 default=False,
522 522 )
523 523 coreconfigitem('experimental', 'format.compression',
524 524 default='zlib',
525 525 )
526 526 coreconfigitem('experimental', 'graphshorten',
527 527 default=False,
528 528 )
529 529 coreconfigitem('experimental', 'graphstyle.parent',
530 530 default=dynamicdefault,
531 531 )
532 532 coreconfigitem('experimental', 'graphstyle.missing',
533 533 default=dynamicdefault,
534 534 )
535 535 coreconfigitem('experimental', 'graphstyle.grandparent',
536 536 default=dynamicdefault,
537 537 )
538 538 coreconfigitem('experimental', 'hook-track-tags',
539 539 default=False,
540 540 )
541 541 coreconfigitem('experimental', 'httppostargs',
542 542 default=False,
543 543 )
544 544 coreconfigitem('experimental', 'mergedriver',
545 545 default=None,
546 546 )
547 547 coreconfigitem('experimental', 'obsmarkers-exchange-debug',
548 548 default=False,
549 549 )
550 550 coreconfigitem('experimental', 'remotenames',
551 551 default=False,
552 552 )
553 553 coreconfigitem('experimental', 'revlogv2',
554 554 default=None,
555 555 )
556 556 coreconfigitem('experimental', 'single-head-per-branch',
557 557 default=False,
558 558 )
559 559 coreconfigitem('experimental', 'sshserver.support-v2',
560 560 default=False,
561 561 )
562 562 coreconfigitem('experimental', 'spacemovesdown',
563 563 default=False,
564 564 )
565 565 coreconfigitem('experimental', 'sparse-read',
566 566 default=False,
567 567 )
568 568 coreconfigitem('experimental', 'sparse-read.density-threshold',
569 569 default=0.25,
570 570 )
571 571 coreconfigitem('experimental', 'sparse-read.min-gap-size',
572 572 default='256K',
573 573 )
574 574 coreconfigitem('experimental', 'treemanifest',
575 575 default=False,
576 576 )
577 577 coreconfigitem('experimental', 'update.atomic-file',
578 578 default=False,
579 579 )
580 580 coreconfigitem('experimental', 'sshpeer.advertise-v2',
581 581 default=False,
582 582 )
583 583 coreconfigitem('experimental', 'web.apiserver',
584 584 default=False,
585 585 )
586 586 coreconfigitem('experimental', 'web.api.http-v2',
587 587 default=False,
588 588 )
589 589 coreconfigitem('experimental', 'web.api.debugreflect',
590 590 default=False,
591 591 )
592 592 coreconfigitem('experimental', 'xdiff',
593 593 default=False,
594 594 )
595 595 coreconfigitem('extensions', '.*',
596 596 default=None,
597 597 generic=True,
598 598 )
599 599 coreconfigitem('extdata', '.*',
600 600 default=None,
601 601 generic=True,
602 602 )
603 603 coreconfigitem('format', 'aggressivemergedeltas',
604 604 default=False,
605 605 )
606 606 coreconfigitem('format', 'chunkcachesize',
607 607 default=None,
608 608 )
609 609 coreconfigitem('format', 'dotencode',
610 610 default=True,
611 611 )
612 612 coreconfigitem('format', 'generaldelta',
613 613 default=False,
614 614 )
615 615 coreconfigitem('format', 'manifestcachesize',
616 616 default=None,
617 617 )
618 618 coreconfigitem('format', 'maxchainlen',
619 619 default=None,
620 620 )
621 621 coreconfigitem('format', 'obsstore-version',
622 622 default=None,
623 623 )
624 624 coreconfigitem('format', 'usefncache',
625 625 default=True,
626 626 )
627 627 coreconfigitem('format', 'usegeneraldelta',
628 628 default=True,
629 629 )
630 630 coreconfigitem('format', 'usestore',
631 631 default=True,
632 632 )
633 633 coreconfigitem('fsmonitor', 'warn_when_unused',
634 634 default=True,
635 635 )
636 636 coreconfigitem('fsmonitor', 'warn_update_file_count',
637 637 default=50000,
638 638 )
639 639 coreconfigitem('hooks', '.*',
640 640 default=dynamicdefault,
641 641 generic=True,
642 642 )
643 643 coreconfigitem('hgweb-paths', '.*',
644 644 default=list,
645 645 generic=True,
646 646 )
647 647 coreconfigitem('hostfingerprints', '.*',
648 648 default=list,
649 649 generic=True,
650 650 )
651 651 coreconfigitem('hostsecurity', 'ciphers',
652 652 default=None,
653 653 )
654 654 coreconfigitem('hostsecurity', 'disabletls10warning',
655 655 default=False,
656 656 )
657 657 coreconfigitem('hostsecurity', 'minimumprotocol',
658 658 default=dynamicdefault,
659 659 )
660 660 coreconfigitem('hostsecurity', '.*:minimumprotocol$',
661 661 default=dynamicdefault,
662 662 generic=True,
663 663 )
664 664 coreconfigitem('hostsecurity', '.*:ciphers$',
665 665 default=dynamicdefault,
666 666 generic=True,
667 667 )
668 668 coreconfigitem('hostsecurity', '.*:fingerprints$',
669 669 default=list,
670 670 generic=True,
671 671 )
672 672 coreconfigitem('hostsecurity', '.*:verifycertsfile$',
673 673 default=None,
674 674 generic=True,
675 675 )
676 676
677 677 coreconfigitem('http_proxy', 'always',
678 678 default=False,
679 679 )
680 680 coreconfigitem('http_proxy', 'host',
681 681 default=None,
682 682 )
683 683 coreconfigitem('http_proxy', 'no',
684 684 default=list,
685 685 )
686 686 coreconfigitem('http_proxy', 'passwd',
687 687 default=None,
688 688 )
689 689 coreconfigitem('http_proxy', 'user',
690 690 default=None,
691 691 )
692 692 coreconfigitem('logtoprocess', 'commandexception',
693 693 default=None,
694 694 )
695 695 coreconfigitem('logtoprocess', 'commandfinish',
696 696 default=None,
697 697 )
698 698 coreconfigitem('logtoprocess', 'command',
699 699 default=None,
700 700 )
701 701 coreconfigitem('logtoprocess', 'develwarn',
702 702 default=None,
703 703 )
704 704 coreconfigitem('logtoprocess', 'uiblocked',
705 705 default=None,
706 706 )
707 707 coreconfigitem('merge', 'checkunknown',
708 708 default='abort',
709 709 )
710 710 coreconfigitem('merge', 'checkignored',
711 711 default='abort',
712 712 )
713 713 coreconfigitem('experimental', 'merge.checkpathconflicts',
714 714 default=False,
715 715 )
716 716 coreconfigitem('merge', 'followcopies',
717 717 default=True,
718 718 )
719 719 coreconfigitem('merge', 'on-failure',
720 720 default='continue',
721 721 )
722 722 coreconfigitem('merge', 'preferancestor',
723 723 default=lambda: ['*'],
724 724 )
725 725 coreconfigitem('merge-tools', '.*',
726 726 default=None,
727 727 generic=True,
728 728 )
729 729 coreconfigitem('merge-tools', br'.*\.args$',
730 730 default="$local $base $other",
731 731 generic=True,
732 732 priority=-1,
733 733 )
734 734 coreconfigitem('merge-tools', br'.*\.binary$',
735 735 default=False,
736 736 generic=True,
737 737 priority=-1,
738 738 )
739 739 coreconfigitem('merge-tools', br'.*\.check$',
740 740 default=list,
741 741 generic=True,
742 742 priority=-1,
743 743 )
744 744 coreconfigitem('merge-tools', br'.*\.checkchanged$',
745 745 default=False,
746 746 generic=True,
747 747 priority=-1,
748 748 )
749 749 coreconfigitem('merge-tools', br'.*\.executable$',
750 750 default=dynamicdefault,
751 751 generic=True,
752 752 priority=-1,
753 753 )
754 754 coreconfigitem('merge-tools', br'.*\.fixeol$',
755 755 default=False,
756 756 generic=True,
757 757 priority=-1,
758 758 )
759 759 coreconfigitem('merge-tools', br'.*\.gui$',
760 760 default=False,
761 761 generic=True,
762 762 priority=-1,
763 763 )
764 764 coreconfigitem('merge-tools', br'.*\.mergemarkers$',
765 765 default='basic',
766 766 generic=True,
767 767 priority=-1,
768 768 )
769 769 coreconfigitem('merge-tools', br'.*\.mergemarkertemplate$',
770 770 default=dynamicdefault, # take from ui.mergemarkertemplate
771 771 generic=True,
772 772 priority=-1,
773 773 )
774 774 coreconfigitem('merge-tools', br'.*\.priority$',
775 775 default=0,
776 776 generic=True,
777 777 priority=-1,
778 778 )
779 779 coreconfigitem('merge-tools', br'.*\.premerge$',
780 780 default=dynamicdefault,
781 781 generic=True,
782 782 priority=-1,
783 783 )
784 784 coreconfigitem('merge-tools', br'.*\.symlink$',
785 785 default=False,
786 786 generic=True,
787 787 priority=-1,
788 788 )
789 789 coreconfigitem('pager', 'attend-.*',
790 790 default=dynamicdefault,
791 791 generic=True,
792 792 )
793 793 coreconfigitem('pager', 'ignore',
794 794 default=list,
795 795 )
796 796 coreconfigitem('pager', 'pager',
797 797 default=dynamicdefault,
798 798 )
799 799 coreconfigitem('patch', 'eol',
800 800 default='strict',
801 801 )
802 802 coreconfigitem('patch', 'fuzz',
803 803 default=2,
804 804 )
805 805 coreconfigitem('paths', 'default',
806 806 default=None,
807 807 )
808 808 coreconfigitem('paths', 'default-push',
809 809 default=None,
810 810 )
811 811 coreconfigitem('paths', '.*',
812 812 default=None,
813 813 generic=True,
814 814 )
815 815 coreconfigitem('phases', 'checksubrepos',
816 816 default='follow',
817 817 )
818 818 coreconfigitem('phases', 'new-commit',
819 819 default='draft',
820 820 )
821 821 coreconfigitem('phases', 'publish',
822 822 default=True,
823 823 )
824 824 coreconfigitem('profiling', 'enabled',
825 825 default=False,
826 826 )
827 827 coreconfigitem('profiling', 'format',
828 828 default='text',
829 829 )
830 830 coreconfigitem('profiling', 'freq',
831 831 default=1000,
832 832 )
833 833 coreconfigitem('profiling', 'limit',
834 834 default=30,
835 835 )
836 836 coreconfigitem('profiling', 'nested',
837 837 default=0,
838 838 )
839 839 coreconfigitem('profiling', 'output',
840 840 default=None,
841 841 )
842 842 coreconfigitem('profiling', 'showmax',
843 843 default=0.999,
844 844 )
845 845 coreconfigitem('profiling', 'showmin',
846 846 default=dynamicdefault,
847 847 )
848 848 coreconfigitem('profiling', 'sort',
849 849 default='inlinetime',
850 850 )
851 851 coreconfigitem('profiling', 'statformat',
852 852 default='hotpath',
853 853 )
854 854 coreconfigitem('profiling', 'type',
855 855 default='stat',
856 856 )
857 857 coreconfigitem('progress', 'assume-tty',
858 858 default=False,
859 859 )
860 860 coreconfigitem('progress', 'changedelay',
861 861 default=1,
862 862 )
863 863 coreconfigitem('progress', 'clear-complete',
864 864 default=True,
865 865 )
866 866 coreconfigitem('progress', 'debug',
867 867 default=False,
868 868 )
869 869 coreconfigitem('progress', 'delay',
870 870 default=3,
871 871 )
872 872 coreconfigitem('progress', 'disable',
873 873 default=False,
874 874 )
875 875 coreconfigitem('progress', 'estimateinterval',
876 876 default=60.0,
877 877 )
878 878 coreconfigitem('progress', 'format',
879 879 default=lambda: ['topic', 'bar', 'number', 'estimate'],
880 880 )
881 881 coreconfigitem('progress', 'refresh',
882 882 default=0.1,
883 883 )
884 884 coreconfigitem('progress', 'width',
885 885 default=dynamicdefault,
886 886 )
887 887 coreconfigitem('push', 'pushvars.server',
888 888 default=False,
889 889 )
890 890 coreconfigitem('server', 'bookmarks-pushkey-compat',
891 891 default=True,
892 892 )
893 893 coreconfigitem('server', 'bundle1',
894 894 default=True,
895 895 )
896 896 coreconfigitem('server', 'bundle1gd',
897 897 default=None,
898 898 )
899 899 coreconfigitem('server', 'bundle1.pull',
900 900 default=None,
901 901 )
902 902 coreconfigitem('server', 'bundle1gd.pull',
903 903 default=None,
904 904 )
905 905 coreconfigitem('server', 'bundle1.push',
906 906 default=None,
907 907 )
908 908 coreconfigitem('server', 'bundle1gd.push',
909 909 default=None,
910 910 )
911 911 coreconfigitem('server', 'compressionengines',
912 912 default=list,
913 913 )
914 914 coreconfigitem('server', 'concurrent-push-mode',
915 915 default='strict',
916 916 )
917 917 coreconfigitem('server', 'disablefullbundle',
918 918 default=False,
919 919 )
920 920 coreconfigitem('server', 'maxhttpheaderlen',
921 921 default=1024,
922 922 )
923 923 coreconfigitem('server', 'preferuncompressed',
924 924 default=False,
925 925 )
926 926 coreconfigitem('server', 'uncompressed',
927 927 default=True,
928 928 )
929 929 coreconfigitem('server', 'uncompressedallowsecret',
930 930 default=False,
931 931 )
932 932 coreconfigitem('server', 'validate',
933 933 default=False,
934 934 )
935 935 coreconfigitem('server', 'zliblevel',
936 936 default=-1,
937 937 )
938 938 coreconfigitem('share', 'pool',
939 939 default=None,
940 940 )
941 941 coreconfigitem('share', 'poolnaming',
942 942 default='identity',
943 943 )
944 944 coreconfigitem('smtp', 'host',
945 945 default=None,
946 946 )
947 947 coreconfigitem('smtp', 'local_hostname',
948 948 default=None,
949 949 )
950 950 coreconfigitem('smtp', 'password',
951 951 default=None,
952 952 )
953 953 coreconfigitem('smtp', 'port',
954 954 default=dynamicdefault,
955 955 )
956 956 coreconfigitem('smtp', 'tls',
957 957 default='none',
958 958 )
959 959 coreconfigitem('smtp', 'username',
960 960 default=None,
961 961 )
962 962 coreconfigitem('sparse', 'missingwarning',
963 963 default=True,
964 964 )
965 965 coreconfigitem('subrepos', 'allowed',
966 966 default=dynamicdefault, # to make backporting simpler
967 967 )
968 968 coreconfigitem('subrepos', 'hg:allowed',
969 969 default=dynamicdefault,
970 970 )
971 971 coreconfigitem('subrepos', 'git:allowed',
972 972 default=dynamicdefault,
973 973 )
974 974 coreconfigitem('subrepos', 'svn:allowed',
975 975 default=dynamicdefault,
976 976 )
977 977 coreconfigitem('templates', '.*',
978 978 default=None,
979 979 generic=True,
980 980 )
981 981 coreconfigitem('trusted', 'groups',
982 982 default=list,
983 983 )
984 984 coreconfigitem('trusted', 'users',
985 985 default=list,
986 986 )
987 987 coreconfigitem('ui', '_usedassubrepo',
988 988 default=False,
989 989 )
990 990 coreconfigitem('ui', 'allowemptycommit',
991 991 default=False,
992 992 )
993 993 coreconfigitem('ui', 'archivemeta',
994 994 default=True,
995 995 )
996 996 coreconfigitem('ui', 'askusername',
997 997 default=False,
998 998 )
999 999 coreconfigitem('ui', 'clonebundlefallback',
1000 1000 default=False,
1001 1001 )
1002 1002 coreconfigitem('ui', 'clonebundleprefers',
1003 1003 default=list,
1004 1004 )
1005 1005 coreconfigitem('ui', 'clonebundles',
1006 1006 default=True,
1007 1007 )
1008 1008 coreconfigitem('ui', 'color',
1009 1009 default='auto',
1010 1010 )
1011 1011 coreconfigitem('ui', 'commitsubrepos',
1012 1012 default=False,
1013 1013 )
1014 1014 coreconfigitem('ui', 'debug',
1015 1015 default=False,
1016 1016 )
1017 1017 coreconfigitem('ui', 'debugger',
1018 1018 default=None,
1019 1019 )
1020 1020 coreconfigitem('ui', 'editor',
1021 1021 default=dynamicdefault,
1022 1022 )
1023 1023 coreconfigitem('ui', 'fallbackencoding',
1024 1024 default=None,
1025 1025 )
1026 1026 coreconfigitem('ui', 'forcecwd',
1027 1027 default=None,
1028 1028 )
1029 1029 coreconfigitem('ui', 'forcemerge',
1030 1030 default=None,
1031 1031 )
1032 1032 coreconfigitem('ui', 'formatdebug',
1033 1033 default=False,
1034 1034 )
1035 1035 coreconfigitem('ui', 'formatjson',
1036 1036 default=False,
1037 1037 )
1038 1038 coreconfigitem('ui', 'formatted',
1039 1039 default=None,
1040 1040 )
1041 1041 coreconfigitem('ui', 'graphnodetemplate',
1042 1042 default=None,
1043 1043 )
1044 1044 coreconfigitem('ui', 'interactive',
1045 1045 default=None,
1046 1046 )
1047 1047 coreconfigitem('ui', 'interface',
1048 1048 default=None,
1049 1049 )
1050 1050 coreconfigitem('ui', 'interface.chunkselector',
1051 1051 default=None,
1052 1052 )
1053 1053 coreconfigitem('ui', 'logblockedtimes',
1054 1054 default=False,
1055 1055 )
1056 1056 coreconfigitem('ui', 'logtemplate',
1057 1057 default=None,
1058 1058 )
1059 1059 coreconfigitem('ui', 'merge',
1060 1060 default=None,
1061 1061 )
1062 1062 coreconfigitem('ui', 'mergemarkers',
1063 1063 default='basic',
1064 1064 )
1065 1065 coreconfigitem('ui', 'mergemarkertemplate',
1066 1066 default=('{node|short} '
1067 1067 '{ifeq(tags, "tip", "", '
1068 1068 'ifeq(tags, "", "", "{tags} "))}'
1069 1069 '{if(bookmarks, "{bookmarks} ")}'
1070 1070 '{ifeq(branch, "default", "", "{branch} ")}'
1071 1071 '- {author|user}: {desc|firstline}')
1072 1072 )
1073 1073 coreconfigitem('ui', 'nontty',
1074 1074 default=False,
1075 1075 )
1076 1076 coreconfigitem('ui', 'origbackuppath',
1077 1077 default=None,
1078 1078 )
1079 1079 coreconfigitem('ui', 'paginate',
1080 1080 default=True,
1081 1081 )
1082 1082 coreconfigitem('ui', 'patch',
1083 1083 default=None,
1084 1084 )
1085 1085 coreconfigitem('ui', 'portablefilenames',
1086 1086 default='warn',
1087 1087 )
1088 1088 coreconfigitem('ui', 'promptecho',
1089 1089 default=False,
1090 1090 )
1091 1091 coreconfigitem('ui', 'quiet',
1092 1092 default=False,
1093 1093 )
1094 1094 coreconfigitem('ui', 'quietbookmarkmove',
1095 1095 default=False,
1096 1096 )
1097 1097 coreconfigitem('ui', 'remotecmd',
1098 1098 default='hg',
1099 1099 )
1100 1100 coreconfigitem('ui', 'report_untrusted',
1101 1101 default=True,
1102 1102 )
1103 1103 coreconfigitem('ui', 'rollback',
1104 1104 default=True,
1105 1105 )
1106 1106 coreconfigitem('ui', 'slash',
1107 1107 default=False,
1108 1108 )
1109 1109 coreconfigitem('ui', 'ssh',
1110 1110 default='ssh',
1111 1111 )
1112 1112 coreconfigitem('ui', 'ssherrorhint',
1113 1113 default=None,
1114 1114 )
1115 1115 coreconfigitem('ui', 'statuscopies',
1116 1116 default=False,
1117 1117 )
1118 1118 coreconfigitem('ui', 'strict',
1119 1119 default=False,
1120 1120 )
1121 1121 coreconfigitem('ui', 'style',
1122 1122 default='',
1123 1123 )
1124 1124 coreconfigitem('ui', 'supportcontact',
1125 1125 default=None,
1126 1126 )
1127 1127 coreconfigitem('ui', 'textwidth',
1128 1128 default=78,
1129 1129 )
1130 1130 coreconfigitem('ui', 'timeout',
1131 1131 default='600',
1132 1132 )
1133 1133 coreconfigitem('ui', 'timeout.warn',
1134 1134 default=0,
1135 1135 )
1136 1136 coreconfigitem('ui', 'traceback',
1137 1137 default=False,
1138 1138 )
1139 1139 coreconfigitem('ui', 'tweakdefaults',
1140 1140 default=False,
1141 1141 )
1142 1142 coreconfigitem('ui', 'username',
1143 1143 alias=[('ui', 'user')]
1144 1144 )
1145 1145 coreconfigitem('ui', 'verbose',
1146 1146 default=False,
1147 1147 )
1148 1148 coreconfigitem('verify', 'skipflags',
1149 1149 default=None,
1150 1150 )
1151 1151 coreconfigitem('web', 'allowbz2',
1152 1152 default=False,
1153 1153 )
1154 1154 coreconfigitem('web', 'allowgz',
1155 1155 default=False,
1156 1156 )
1157 1157 coreconfigitem('web', 'allow-pull',
1158 1158 alias=[('web', 'allowpull')],
1159 1159 default=True,
1160 1160 )
1161 1161 coreconfigitem('web', 'allow-push',
1162 1162 alias=[('web', 'allow_push')],
1163 1163 default=list,
1164 1164 )
1165 1165 coreconfigitem('web', 'allowzip',
1166 1166 default=False,
1167 1167 )
1168 1168 coreconfigitem('web', 'archivesubrepos',
1169 1169 default=False,
1170 1170 )
1171 1171 coreconfigitem('web', 'cache',
1172 1172 default=True,
1173 1173 )
1174 1174 coreconfigitem('web', 'contact',
1175 1175 default=None,
1176 1176 )
1177 1177 coreconfigitem('web', 'deny_push',
1178 1178 default=list,
1179 1179 )
1180 1180 coreconfigitem('web', 'guessmime',
1181 1181 default=False,
1182 1182 )
1183 1183 coreconfigitem('web', 'hidden',
1184 1184 default=False,
1185 1185 )
1186 1186 coreconfigitem('web', 'labels',
1187 1187 default=list,
1188 1188 )
1189 1189 coreconfigitem('web', 'logoimg',
1190 1190 default='hglogo.png',
1191 1191 )
1192 1192 coreconfigitem('web', 'logourl',
1193 1193 default='https://mercurial-scm.org/',
1194 1194 )
1195 1195 coreconfigitem('web', 'accesslog',
1196 1196 default='-',
1197 1197 )
1198 1198 coreconfigitem('web', 'address',
1199 1199 default='',
1200 1200 )
1201 1201 coreconfigitem('web', 'allow_archive',
1202 1202 default=list,
1203 1203 )
1204 1204 coreconfigitem('web', 'allow_read',
1205 1205 default=list,
1206 1206 )
1207 1207 coreconfigitem('web', 'baseurl',
1208 1208 default=None,
1209 1209 )
1210 1210 coreconfigitem('web', 'cacerts',
1211 1211 default=None,
1212 1212 )
1213 1213 coreconfigitem('web', 'certificate',
1214 1214 default=None,
1215 1215 )
1216 1216 coreconfigitem('web', 'collapse',
1217 1217 default=False,
1218 1218 )
1219 1219 coreconfigitem('web', 'csp',
1220 1220 default=None,
1221 1221 )
1222 1222 coreconfigitem('web', 'deny_read',
1223 1223 default=list,
1224 1224 )
1225 1225 coreconfigitem('web', 'descend',
1226 1226 default=True,
1227 1227 )
1228 1228 coreconfigitem('web', 'description',
1229 1229 default="",
1230 1230 )
1231 1231 coreconfigitem('web', 'encoding',
1232 1232 default=lambda: encoding.encoding,
1233 1233 )
1234 1234 coreconfigitem('web', 'errorlog',
1235 1235 default='-',
1236 1236 )
1237 1237 coreconfigitem('web', 'ipv6',
1238 1238 default=False,
1239 1239 )
1240 1240 coreconfigitem('web', 'maxchanges',
1241 1241 default=10,
1242 1242 )
1243 1243 coreconfigitem('web', 'maxfiles',
1244 1244 default=10,
1245 1245 )
1246 1246 coreconfigitem('web', 'maxshortchanges',
1247 1247 default=60,
1248 1248 )
1249 1249 coreconfigitem('web', 'motd',
1250 1250 default='',
1251 1251 )
1252 1252 coreconfigitem('web', 'name',
1253 1253 default=dynamicdefault,
1254 1254 )
1255 1255 coreconfigitem('web', 'port',
1256 1256 default=8000,
1257 1257 )
1258 1258 coreconfigitem('web', 'prefix',
1259 1259 default='',
1260 1260 )
1261 1261 coreconfigitem('web', 'push_ssl',
1262 1262 default=True,
1263 1263 )
1264 1264 coreconfigitem('web', 'refreshinterval',
1265 1265 default=20,
1266 1266 )
1267 1267 coreconfigitem('web', 'server-header',
1268 1268 default=None,
1269 1269 )
1270 1270 coreconfigitem('web', 'staticurl',
1271 1271 default=None,
1272 1272 )
1273 1273 coreconfigitem('web', 'stripes',
1274 1274 default=1,
1275 1275 )
1276 1276 coreconfigitem('web', 'style',
1277 1277 default='paper',
1278 1278 )
1279 1279 coreconfigitem('web', 'templates',
1280 1280 default=None,
1281 1281 )
1282 1282 coreconfigitem('web', 'view',
1283 1283 default='served',
1284 1284 )
1285 1285 coreconfigitem('worker', 'backgroundclose',
1286 1286 default=dynamicdefault,
1287 1287 )
1288 1288 # Windows defaults to a limit of 512 open files. A buffer of 128
1289 1289 # should give us enough headway.
1290 1290 coreconfigitem('worker', 'backgroundclosemaxqueue',
1291 1291 default=384,
1292 1292 )
1293 1293 coreconfigitem('worker', 'backgroundcloseminfilecount',
1294 1294 default=2048,
1295 1295 )
1296 1296 coreconfigitem('worker', 'backgroundclosethreadcount',
1297 1297 default=4,
1298 1298 )
1299 1299 coreconfigitem('worker', 'enabled',
1300 1300 default=True,
1301 1301 )
1302 1302 coreconfigitem('worker', 'numcpus',
1303 1303 default=None,
1304 1304 )
1305 1305
1306 1306 # Rebase related configuration moved to core because other extension are doing
1307 1307 # strange things. For example, shelve import the extensions to reuse some bit
1308 1308 # without formally loading it.
1309 1309 coreconfigitem('commands', 'rebase.requiredest',
1310 1310 default=False,
1311 1311 )
1312 1312 coreconfigitem('experimental', 'rebaseskipobsolete',
1313 1313 default=True,
1314 1314 )
1315 1315 coreconfigitem('rebase', 'singletransaction',
1316 1316 default=False,
1317 1317 )
1318 1318 coreconfigitem('rebase', 'experimental.inmemory',
1319 1319 default=False,
1320 1320 )
@@ -1,1030 +1,1040 b''
1 1 # dispatch.py - command dispatching for mercurial
2 2 #
3 3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
4 4 #
5 5 # This software may be used and distributed according to the terms of the
6 6 # GNU General Public License version 2 or any later version.
7 7
8 8 from __future__ import absolute_import, print_function
9 9
10 10 import difflib
11 11 import errno
12 12 import getopt
13 13 import os
14 14 import pdb
15 15 import re
16 16 import signal
17 17 import sys
18 18 import time
19 19 import traceback
20 20
21 21
22 22 from .i18n import _
23 23
24 24 from . import (
25 25 cmdutil,
26 26 color,
27 27 commands,
28 28 demandimport,
29 29 encoding,
30 30 error,
31 31 extensions,
32 32 fancyopts,
33 33 help,
34 34 hg,
35 35 hook,
36 36 profiling,
37 37 pycompat,
38 38 registrar,
39 39 scmutil,
40 40 ui as uimod,
41 41 util,
42 42 )
43 43
44 44 from .utils import (
45 45 procutil,
46 46 stringutil,
47 47 )
48 48
49 49 unrecoverablewrite = registrar.command.unrecoverablewrite
50 50
51 51 class request(object):
52 52 def __init__(self, args, ui=None, repo=None, fin=None, fout=None,
53 53 ferr=None, prereposetups=None):
54 54 self.args = args
55 55 self.ui = ui
56 56 self.repo = repo
57 57
58 58 # input/output/error streams
59 59 self.fin = fin
60 60 self.fout = fout
61 61 self.ferr = ferr
62 62
63 63 # remember options pre-parsed by _earlyparseopts()
64 64 self.earlyoptions = {}
65 65
66 66 # reposetups which run before extensions, useful for chg to pre-fill
67 67 # low-level repo state (for example, changelog) before extensions.
68 68 self.prereposetups = prereposetups or []
69 69
70 70 def _runexithandlers(self):
71 71 exc = None
72 72 handlers = self.ui._exithandlers
73 73 try:
74 74 while handlers:
75 75 func, args, kwargs = handlers.pop()
76 76 try:
77 77 func(*args, **kwargs)
78 78 except: # re-raises below
79 79 if exc is None:
80 80 exc = sys.exc_info()[1]
81 81 self.ui.warn(('error in exit handlers:\n'))
82 82 self.ui.traceback(force=True)
83 83 finally:
84 84 if exc is not None:
85 85 raise exc
86 86
87 87 def run():
88 88 "run the command in sys.argv"
89 89 _initstdio()
90 90 req = request(pycompat.sysargv[1:])
91 91 err = None
92 92 try:
93 93 status = (dispatch(req) or 0)
94 94 except error.StdioError as e:
95 95 err = e
96 96 status = -1
97 97 if util.safehasattr(req.ui, 'fout'):
98 98 try:
99 99 req.ui.fout.flush()
100 100 except IOError as e:
101 101 err = e
102 102 status = -1
103 103 if util.safehasattr(req.ui, 'ferr'):
104 104 try:
105 105 if err is not None and err.errno != errno.EPIPE:
106 106 req.ui.ferr.write('abort: %s\n' %
107 107 encoding.strtolocal(err.strerror))
108 108 req.ui.ferr.flush()
109 109 # There's not much we can do about an I/O error here. So (possibly)
110 110 # change the status code and move on.
111 111 except IOError:
112 112 status = -1
113 113
114 114 _silencestdio()
115 115 sys.exit(status & 255)
116 116
117 117 if pycompat.ispy3:
118 118 def _initstdio():
119 119 pass
120 120
121 121 def _silencestdio():
122 122 for fp in (sys.stdout, sys.stderr):
123 123 # Check if the file is okay
124 124 try:
125 125 fp.flush()
126 126 continue
127 127 except IOError:
128 128 pass
129 129 # Otherwise mark it as closed to silence "Exception ignored in"
130 130 # message emitted by the interpreter finalizer. Be careful to
131 131 # not close procutil.stdout, which may be a fdopen-ed file object
132 132 # and its close() actually closes the underlying file descriptor.
133 133 try:
134 134 fp.close()
135 135 except IOError:
136 136 pass
137 137 else:
138 138 def _initstdio():
139 139 for fp in (sys.stdin, sys.stdout, sys.stderr):
140 140 procutil.setbinary(fp)
141 141
142 142 def _silencestdio():
143 143 pass
144 144
145 145 def _getsimilar(symbols, value):
146 146 sim = lambda x: difflib.SequenceMatcher(None, value, x).ratio()
147 147 # The cutoff for similarity here is pretty arbitrary. It should
148 148 # probably be investigated and tweaked.
149 149 return [s for s in symbols if sim(s) > 0.6]
150 150
151 151 def _reportsimilar(write, similar):
152 152 if len(similar) == 1:
153 153 write(_("(did you mean %s?)\n") % similar[0])
154 154 elif similar:
155 155 ss = ", ".join(sorted(similar))
156 156 write(_("(did you mean one of %s?)\n") % ss)
157 157
158 158 def _formatparse(write, inst):
159 159 similar = []
160 160 if isinstance(inst, error.UnknownIdentifier):
161 161 # make sure to check fileset first, as revset can invoke fileset
162 162 similar = _getsimilar(inst.symbols, inst.function)
163 163 if len(inst.args) > 1:
164 164 write(_("hg: parse error at %s: %s\n") %
165 165 (pycompat.bytestr(inst.args[1]), inst.args[0]))
166 166 if inst.args[0].startswith(' '):
167 167 write(_("unexpected leading whitespace\n"))
168 168 else:
169 169 write(_("hg: parse error: %s\n") % inst.args[0])
170 170 _reportsimilar(write, similar)
171 171 if inst.hint:
172 172 write(_("(%s)\n") % inst.hint)
173 173
174 174 def _formatargs(args):
175 175 return ' '.join(procutil.shellquote(a) for a in args)
176 176
177 177 def dispatch(req):
178 178 "run the command specified in req.args"
179 179 if req.ferr:
180 180 ferr = req.ferr
181 181 elif req.ui:
182 182 ferr = req.ui.ferr
183 183 else:
184 184 ferr = procutil.stderr
185 185
186 186 try:
187 187 if not req.ui:
188 188 req.ui = uimod.ui.load()
189 189 req.earlyoptions.update(_earlyparseopts(req.ui, req.args))
190 190 if req.earlyoptions['traceback']:
191 191 req.ui.setconfig('ui', 'traceback', 'on', '--traceback')
192 192
193 193 # set ui streams from the request
194 194 if req.fin:
195 195 req.ui.fin = req.fin
196 196 if req.fout:
197 197 req.ui.fout = req.fout
198 198 if req.ferr:
199 199 req.ui.ferr = req.ferr
200 200 except error.Abort as inst:
201 201 ferr.write(_("abort: %s\n") % inst)
202 202 if inst.hint:
203 203 ferr.write(_("(%s)\n") % inst.hint)
204 204 return -1
205 205 except error.ParseError as inst:
206 206 _formatparse(ferr.write, inst)
207 207 return -1
208 208
209 209 msg = _formatargs(req.args)
210 210 starttime = util.timer()
211 211 ret = None
212 212 try:
213 213 ret = _runcatch(req)
214 214 except error.ProgrammingError as inst:
215 215 req.ui.warn(_('** ProgrammingError: %s\n') % inst)
216 216 if inst.hint:
217 217 req.ui.warn(_('** (%s)\n') % inst.hint)
218 218 raise
219 219 except KeyboardInterrupt as inst:
220 220 try:
221 221 if isinstance(inst, error.SignalInterrupt):
222 222 msg = _("killed!\n")
223 223 else:
224 224 msg = _("interrupted!\n")
225 225 req.ui.warn(msg)
226 226 except error.SignalInterrupt:
227 227 # maybe pager would quit without consuming all the output, and
228 228 # SIGPIPE was raised. we cannot print anything in this case.
229 229 pass
230 230 except IOError as inst:
231 231 if inst.errno != errno.EPIPE:
232 232 raise
233 233 ret = -1
234 234 finally:
235 235 duration = util.timer() - starttime
236 236 req.ui.flush()
237 237 if req.ui.logblockedtimes:
238 238 req.ui._blockedtimes['command_duration'] = duration * 1000
239 239 req.ui.log('uiblocked', 'ui blocked ms',
240 240 **pycompat.strkwargs(req.ui._blockedtimes))
241 241 req.ui.log("commandfinish", "%s exited %d after %0.2f seconds\n",
242 242 msg, ret or 0, duration)
243 243 try:
244 244 req._runexithandlers()
245 245 except: # exiting, so no re-raises
246 246 ret = ret or -1
247 247 return ret
248 248
249 249 def _runcatch(req):
250 250 def catchterm(*args):
251 251 raise error.SignalInterrupt
252 252
253 253 ui = req.ui
254 254 try:
255 255 for name in 'SIGBREAK', 'SIGHUP', 'SIGTERM':
256 256 num = getattr(signal, name, None)
257 257 if num:
258 258 signal.signal(num, catchterm)
259 259 except ValueError:
260 260 pass # happens if called in a thread
261 261
262 262 def _runcatchfunc():
263 263 realcmd = None
264 264 try:
265 265 cmdargs = fancyopts.fancyopts(req.args[:], commands.globalopts, {})
266 266 cmd = cmdargs[0]
267 267 aliases, entry = cmdutil.findcmd(cmd, commands.table, False)
268 268 realcmd = aliases[0]
269 269 except (error.UnknownCommand, error.AmbiguousCommand,
270 270 IndexError, getopt.GetoptError):
271 271 # Don't handle this here. We know the command is
272 272 # invalid, but all we're worried about for now is that
273 273 # it's not a command that server operators expect to
274 274 # be safe to offer to users in a sandbox.
275 275 pass
276 276 if realcmd == 'serve' and '--stdio' in cmdargs:
277 277 # We want to constrain 'hg serve --stdio' instances pretty
278 278 # closely, as many shared-ssh access tools want to grant
279 279 # access to run *only* 'hg -R $repo serve --stdio'. We
280 280 # restrict to exactly that set of arguments, and prohibit
281 281 # any repo name that starts with '--' to prevent
282 282 # shenanigans wherein a user does something like pass
283 283 # --debugger or --config=ui.debugger=1 as a repo
284 284 # name. This used to actually run the debugger.
285 285 if (len(req.args) != 4 or
286 286 req.args[0] != '-R' or
287 287 req.args[1].startswith('--') or
288 288 req.args[2] != 'serve' or
289 289 req.args[3] != '--stdio'):
290 290 raise error.Abort(
291 291 _('potentially unsafe serve --stdio invocation: %r') %
292 292 (req.args,))
293 293
294 294 try:
295 295 debugger = 'pdb'
296 296 debugtrace = {
297 297 'pdb': pdb.set_trace
298 298 }
299 299 debugmortem = {
300 300 'pdb': pdb.post_mortem
301 301 }
302 302
303 303 # read --config before doing anything else
304 304 # (e.g. to change trust settings for reading .hg/hgrc)
305 305 cfgs = _parseconfig(req.ui, req.earlyoptions['config'])
306 306
307 307 if req.repo:
308 308 # copy configs that were passed on the cmdline (--config) to
309 309 # the repo ui
310 310 for sec, name, val in cfgs:
311 311 req.repo.ui.setconfig(sec, name, val, source='--config')
312 312
313 313 # developer config: ui.debugger
314 314 debugger = ui.config("ui", "debugger")
315 315 debugmod = pdb
316 316 if not debugger or ui.plain():
317 317 # if we are in HGPLAIN mode, then disable custom debugging
318 318 debugger = 'pdb'
319 319 elif req.earlyoptions['debugger']:
320 320 # This import can be slow for fancy debuggers, so only
321 321 # do it when absolutely necessary, i.e. when actual
322 322 # debugging has been requested
323 323 with demandimport.deactivated():
324 324 try:
325 325 debugmod = __import__(debugger)
326 326 except ImportError:
327 327 pass # Leave debugmod = pdb
328 328
329 329 debugtrace[debugger] = debugmod.set_trace
330 330 debugmortem[debugger] = debugmod.post_mortem
331 331
332 332 # enter the debugger before command execution
333 333 if req.earlyoptions['debugger']:
334 334 ui.warn(_("entering debugger - "
335 335 "type c to continue starting hg or h for help\n"))
336 336
337 337 if (debugger != 'pdb' and
338 338 debugtrace[debugger] == debugtrace['pdb']):
339 339 ui.warn(_("%s debugger specified "
340 340 "but its module was not found\n") % debugger)
341 341 with demandimport.deactivated():
342 342 debugtrace[debugger]()
343 343 try:
344 344 return _dispatch(req)
345 345 finally:
346 346 ui.flush()
347 347 except: # re-raises
348 348 # enter the debugger when we hit an exception
349 349 if req.earlyoptions['debugger']:
350 350 traceback.print_exc()
351 351 debugmortem[debugger](sys.exc_info()[2])
352 352 raise
353 353
354 354 return _callcatch(ui, _runcatchfunc)
355 355
356 356 def _callcatch(ui, func):
357 357 """like scmutil.callcatch but handles more high-level exceptions about
358 358 config parsing and commands. besides, use handlecommandexception to handle
359 359 uncaught exceptions.
360 360 """
361 361 try:
362 362 return scmutil.callcatch(ui, func)
363 363 except error.AmbiguousCommand as inst:
364 364 ui.warn(_("hg: command '%s' is ambiguous:\n %s\n") %
365 365 (inst.args[0], " ".join(inst.args[1])))
366 366 except error.CommandError as inst:
367 367 if inst.args[0]:
368 368 ui.pager('help')
369 369 msgbytes = pycompat.bytestr(inst.args[1])
370 370 ui.warn(_("hg %s: %s\n") % (inst.args[0], msgbytes))
371 371 commands.help_(ui, inst.args[0], full=False, command=True)
372 372 else:
373 373 ui.pager('help')
374 374 ui.warn(_("hg: %s\n") % inst.args[1])
375 375 commands.help_(ui, 'shortlist')
376 376 except error.ParseError as inst:
377 377 _formatparse(ui.warn, inst)
378 378 return -1
379 379 except error.UnknownCommand as inst:
380 380 nocmdmsg = _("hg: unknown command '%s'\n") % inst.args[0]
381 381 try:
382 382 # check if the command is in a disabled extension
383 383 # (but don't check for extensions themselves)
384 384 formatted = help.formattedhelp(ui, commands, inst.args[0],
385 385 unknowncmd=True)
386 386 ui.warn(nocmdmsg)
387 387 ui.write(formatted)
388 388 except (error.UnknownCommand, error.Abort):
389 389 suggested = False
390 390 if len(inst.args) == 2:
391 391 sim = _getsimilar(inst.args[1], inst.args[0])
392 392 if sim:
393 393 ui.warn(nocmdmsg)
394 394 _reportsimilar(ui.warn, sim)
395 395 suggested = True
396 396 if not suggested:
397 397 ui.pager('help')
398 398 ui.warn(nocmdmsg)
399 399 commands.help_(ui, 'shortlist')
400 400 except IOError:
401 401 raise
402 402 except KeyboardInterrupt:
403 403 raise
404 404 except: # probably re-raises
405 405 if not handlecommandexception(ui):
406 406 raise
407 407
408 408 return -1
409 409
410 410 def aliasargs(fn, givenargs):
411 411 args = []
412 412 # only care about alias 'args', ignore 'args' set by extensions.wrapfunction
413 413 if not util.safehasattr(fn, '_origfunc'):
414 414 args = getattr(fn, 'args', args)
415 415 if args:
416 416 cmd = ' '.join(map(procutil.shellquote, args))
417 417
418 418 nums = []
419 419 def replacer(m):
420 420 num = int(m.group(1)) - 1
421 421 nums.append(num)
422 422 if num < len(givenargs):
423 423 return givenargs[num]
424 424 raise error.Abort(_('too few arguments for command alias'))
425 425 cmd = re.sub(br'\$(\d+|\$)', replacer, cmd)
426 426 givenargs = [x for i, x in enumerate(givenargs)
427 427 if i not in nums]
428 428 args = pycompat.shlexsplit(cmd)
429 429 return args + givenargs
430 430
431 431 def aliasinterpolate(name, args, cmd):
432 432 '''interpolate args into cmd for shell aliases
433 433
434 434 This also handles $0, $@ and "$@".
435 435 '''
436 436 # util.interpolate can't deal with "$@" (with quotes) because it's only
437 437 # built to match prefix + patterns.
438 438 replacemap = dict(('$%d' % (i + 1), arg) for i, arg in enumerate(args))
439 439 replacemap['$0'] = name
440 440 replacemap['$$'] = '$'
441 441 replacemap['$@'] = ' '.join(args)
442 442 # Typical Unix shells interpolate "$@" (with quotes) as all the positional
443 443 # parameters, separated out into words. Emulate the same behavior here by
444 444 # quoting the arguments individually. POSIX shells will then typically
445 445 # tokenize each argument into exactly one word.
446 446 replacemap['"$@"'] = ' '.join(procutil.shellquote(arg) for arg in args)
447 447 # escape '\$' for regex
448 448 regex = '|'.join(replacemap.keys()).replace('$', br'\$')
449 449 r = re.compile(regex)
450 450 return r.sub(lambda x: replacemap[x.group()], cmd)
451 451
452 452 class cmdalias(object):
453 def __init__(self, name, definition, cmdtable, source):
453 def __init__(self, ui, name, definition, cmdtable, source):
454 454 self.name = self.cmd = name
455 455 self.cmdname = ''
456 456 self.definition = definition
457 457 self.fn = None
458 458 self.givenargs = []
459 459 self.opts = []
460 460 self.help = ''
461 461 self.badalias = None
462 462 self.unknowncmd = False
463 463 self.source = source
464 464
465 465 try:
466 466 aliases, entry = cmdutil.findcmd(self.name, cmdtable)
467 467 for alias, e in cmdtable.iteritems():
468 468 if e is entry:
469 469 self.cmd = alias
470 470 break
471 471 self.shadows = True
472 472 except error.UnknownCommand:
473 473 self.shadows = False
474 474
475 475 if not self.definition:
476 476 self.badalias = _("no definition for alias '%s'") % self.name
477 477 return
478 478
479 479 if self.definition.startswith('!'):
480 shdef = self.definition[1:]
480 481 self.shell = True
481 482 def fn(ui, *args):
482 483 env = {'HG_ARGS': ' '.join((self.name,) + args)}
483 484 def _checkvar(m):
484 485 if m.groups()[0] == '$':
485 486 return m.group()
486 487 elif int(m.groups()[0]) <= len(args):
487 488 return m.group()
488 489 else:
489 490 ui.debug("No argument found for substitution "
490 491 "of %i variable in alias '%s' definition.\n"
491 492 % (int(m.groups()[0]), self.name))
492 493 return ''
493 cmd = re.sub(br'\$(\d+|\$)', _checkvar, self.definition[1:])
494 cmd = re.sub(br'\$(\d+|\$)', _checkvar, shdef)
494 495 cmd = aliasinterpolate(self.name, args, cmd)
495 496 return ui.system(cmd, environ=env,
496 497 blockedtag='alias_%s' % self.name)
497 498 self.fn = fn
499 self._populatehelp(ui, name, shdef, self.fn)
498 500 return
499 501
500 502 try:
501 503 args = pycompat.shlexsplit(self.definition)
502 504 except ValueError as inst:
503 505 self.badalias = (_("error in definition for alias '%s': %s")
504 506 % (self.name, stringutil.forcebytestr(inst)))
505 507 return
506 508 earlyopts, args = _earlysplitopts(args)
507 509 if earlyopts:
508 510 self.badalias = (_("error in definition for alias '%s': %s may "
509 511 "only be given on the command line")
510 512 % (self.name, '/'.join(pycompat.ziplist(*earlyopts)
511 513 [0])))
512 514 return
513 515 self.cmdname = cmd = args.pop(0)
514 516 self.givenargs = args
515 517
516 518 try:
517 519 tableentry = cmdutil.findcmd(cmd, cmdtable, False)[1]
518 520 if len(tableentry) > 2:
519 self.fn, self.opts, self.help = tableentry
521 self.fn, self.opts, cmdhelp = tableentry
520 522 else:
521 523 self.fn, self.opts = tableentry
524 cmdhelp = None
522 525
523 if self.help.startswith("hg " + cmd):
524 # drop prefix in old-style help lines so hg shows the alias
525 self.help = self.help[4 + len(cmd):]
526 self.__doc__ = self.fn.__doc__
526 self._populatehelp(ui, name, cmd, self.fn, cmdhelp)
527 527
528 528 except error.UnknownCommand:
529 529 self.badalias = (_("alias '%s' resolves to unknown command '%s'")
530 530 % (self.name, cmd))
531 531 self.unknowncmd = True
532 532 except error.AmbiguousCommand:
533 533 self.badalias = (_("alias '%s' resolves to ambiguous command '%s'")
534 534 % (self.name, cmd))
535 535
536 def _populatehelp(self, ui, name, cmd, fn, defaulthelp=None):
537 self.help = ui.config('alias', '%s:help' % name, defaulthelp or '')
538 if self.help and self.help.startswith("hg " + cmd):
539 # drop prefix in old-style help lines so hg shows the alias
540 self.help = self.help[4 + len(cmd):]
541
542 self.__doc__ = ui.config('alias', '%s:doc' % name, fn.__doc__)
543
536 544 @property
537 545 def args(self):
538 546 args = pycompat.maplist(util.expandpath, self.givenargs)
539 547 return aliasargs(self.fn, args)
540 548
541 549 def __getattr__(self, name):
542 550 adefaults = {r'norepo': True, r'cmdtype': unrecoverablewrite,
543 551 r'optionalrepo': False, r'inferrepo': False}
544 552 if name not in adefaults:
545 553 raise AttributeError(name)
546 554 if self.badalias or util.safehasattr(self, 'shell'):
547 555 return adefaults[name]
548 556 return getattr(self.fn, name)
549 557
550 558 def __call__(self, ui, *args, **opts):
551 559 if self.badalias:
552 560 hint = None
553 561 if self.unknowncmd:
554 562 try:
555 563 # check if the command is in a disabled extension
556 564 cmd, ext = extensions.disabledcmd(ui, self.cmdname)[:2]
557 565 hint = _("'%s' is provided by '%s' extension") % (cmd, ext)
558 566 except error.UnknownCommand:
559 567 pass
560 568 raise error.Abort(self.badalias, hint=hint)
561 569 if self.shadows:
562 570 ui.debug("alias '%s' shadows command '%s'\n" %
563 571 (self.name, self.cmdname))
564 572
565 573 ui.log('commandalias', "alias '%s' expands to '%s'\n",
566 574 self.name, self.definition)
567 575 if util.safehasattr(self, 'shell'):
568 576 return self.fn(ui, *args, **opts)
569 577 else:
570 578 try:
571 579 return util.checksignature(self.fn)(ui, *args, **opts)
572 580 except error.SignatureError:
573 581 args = ' '.join([self.cmdname] + self.args)
574 582 ui.debug("alias '%s' expands to '%s'\n" % (self.name, args))
575 583 raise
576 584
577 585 class lazyaliasentry(object):
578 586 """like a typical command entry (func, opts, help), but is lazy"""
579 587
580 def __init__(self, name, definition, cmdtable, source):
588 def __init__(self, ui, name, definition, cmdtable, source):
589 self.ui = ui
581 590 self.name = name
582 591 self.definition = definition
583 592 self.cmdtable = cmdtable.copy()
584 593 self.source = source
585 594
586 595 @util.propertycache
587 596 def _aliasdef(self):
588 return cmdalias(self.name, self.definition, self.cmdtable, self.source)
597 return cmdalias(self.ui, self.name, self.definition, self.cmdtable,
598 self.source)
589 599
590 600 def __getitem__(self, n):
591 601 aliasdef = self._aliasdef
592 602 if n == 0:
593 603 return aliasdef
594 604 elif n == 1:
595 605 return aliasdef.opts
596 606 elif n == 2:
597 607 return aliasdef.help
598 608 else:
599 609 raise IndexError
600 610
601 611 def __iter__(self):
602 612 for i in range(3):
603 613 yield self[i]
604 614
605 615 def __len__(self):
606 616 return 3
607 617
608 618 def addaliases(ui, cmdtable):
609 619 # aliases are processed after extensions have been loaded, so they
610 620 # may use extension commands. Aliases can also use other alias definitions,
611 621 # but only if they have been defined prior to the current definition.
612 for alias, definition in ui.configitems('alias'):
622 for alias, definition in ui.configitems('alias', ignoresub=True):
613 623 try:
614 624 if cmdtable[alias].definition == definition:
615 625 continue
616 626 except (KeyError, AttributeError):
617 627 # definition might not exist or it might not be a cmdalias
618 628 pass
619 629
620 630 source = ui.configsource('alias', alias)
621 entry = lazyaliasentry(alias, definition, cmdtable, source)
631 entry = lazyaliasentry(ui, alias, definition, cmdtable, source)
622 632 cmdtable[alias] = entry
623 633
624 634 def _parse(ui, args):
625 635 options = {}
626 636 cmdoptions = {}
627 637
628 638 try:
629 639 args = fancyopts.fancyopts(args, commands.globalopts, options)
630 640 except getopt.GetoptError as inst:
631 641 raise error.CommandError(None, stringutil.forcebytestr(inst))
632 642
633 643 if args:
634 644 cmd, args = args[0], args[1:]
635 645 aliases, entry = cmdutil.findcmd(cmd, commands.table,
636 646 ui.configbool("ui", "strict"))
637 647 cmd = aliases[0]
638 648 args = aliasargs(entry[0], args)
639 649 defaults = ui.config("defaults", cmd)
640 650 if defaults:
641 651 args = pycompat.maplist(
642 652 util.expandpath, pycompat.shlexsplit(defaults)) + args
643 653 c = list(entry[1])
644 654 else:
645 655 cmd = None
646 656 c = []
647 657
648 658 # combine global options into local
649 659 for o in commands.globalopts:
650 660 c.append((o[0], o[1], options[o[1]], o[3]))
651 661
652 662 try:
653 663 args = fancyopts.fancyopts(args, c, cmdoptions, gnu=True)
654 664 except getopt.GetoptError as inst:
655 665 raise error.CommandError(cmd, stringutil.forcebytestr(inst))
656 666
657 667 # separate global options back out
658 668 for o in commands.globalopts:
659 669 n = o[1]
660 670 options[n] = cmdoptions[n]
661 671 del cmdoptions[n]
662 672
663 673 return (cmd, cmd and entry[0] or None, args, options, cmdoptions)
664 674
665 675 def _parseconfig(ui, config):
666 676 """parse the --config options from the command line"""
667 677 configs = []
668 678
669 679 for cfg in config:
670 680 try:
671 681 name, value = [cfgelem.strip()
672 682 for cfgelem in cfg.split('=', 1)]
673 683 section, name = name.split('.', 1)
674 684 if not section or not name:
675 685 raise IndexError
676 686 ui.setconfig(section, name, value, '--config')
677 687 configs.append((section, name, value))
678 688 except (IndexError, ValueError):
679 689 raise error.Abort(_('malformed --config option: %r '
680 690 '(use --config section.name=value)')
681 691 % pycompat.bytestr(cfg))
682 692
683 693 return configs
684 694
685 695 def _earlyparseopts(ui, args):
686 696 options = {}
687 697 fancyopts.fancyopts(args, commands.globalopts, options,
688 698 gnu=not ui.plain('strictflags'), early=True,
689 699 optaliases={'repository': ['repo']})
690 700 return options
691 701
692 702 def _earlysplitopts(args):
693 703 """Split args into a list of possible early options and remainder args"""
694 704 shortoptions = 'R:'
695 705 # TODO: perhaps 'debugger' should be included
696 706 longoptions = ['cwd=', 'repository=', 'repo=', 'config=']
697 707 return fancyopts.earlygetopt(args, shortoptions, longoptions,
698 708 gnu=True, keepsep=True)
699 709
700 710 def runcommand(lui, repo, cmd, fullargs, ui, options, d, cmdpats, cmdoptions):
701 711 # run pre-hook, and abort if it fails
702 712 hook.hook(lui, repo, "pre-%s" % cmd, True, args=" ".join(fullargs),
703 713 pats=cmdpats, opts=cmdoptions)
704 714 try:
705 715 ret = _runcommand(ui, options, cmd, d)
706 716 # run post-hook, passing command result
707 717 hook.hook(lui, repo, "post-%s" % cmd, False, args=" ".join(fullargs),
708 718 result=ret, pats=cmdpats, opts=cmdoptions)
709 719 except Exception:
710 720 # run failure hook and re-raise
711 721 hook.hook(lui, repo, "fail-%s" % cmd, False, args=" ".join(fullargs),
712 722 pats=cmdpats, opts=cmdoptions)
713 723 raise
714 724 return ret
715 725
716 726 def _getlocal(ui, rpath, wd=None):
717 727 """Return (path, local ui object) for the given target path.
718 728
719 729 Takes paths in [cwd]/.hg/hgrc into account."
720 730 """
721 731 if wd is None:
722 732 try:
723 733 wd = pycompat.getcwd()
724 734 except OSError as e:
725 735 raise error.Abort(_("error getting current working directory: %s") %
726 736 encoding.strtolocal(e.strerror))
727 737 path = cmdutil.findrepo(wd) or ""
728 738 if not path:
729 739 lui = ui
730 740 else:
731 741 lui = ui.copy()
732 742 lui.readconfig(os.path.join(path, ".hg", "hgrc"), path)
733 743
734 744 if rpath:
735 745 path = lui.expandpath(rpath)
736 746 lui = ui.copy()
737 747 lui.readconfig(os.path.join(path, ".hg", "hgrc"), path)
738 748
739 749 return path, lui
740 750
741 751 def _checkshellalias(lui, ui, args):
742 752 """Return the function to run the shell alias, if it is required"""
743 753 options = {}
744 754
745 755 try:
746 756 args = fancyopts.fancyopts(args, commands.globalopts, options)
747 757 except getopt.GetoptError:
748 758 return
749 759
750 760 if not args:
751 761 return
752 762
753 763 cmdtable = commands.table
754 764
755 765 cmd = args[0]
756 766 try:
757 767 strict = ui.configbool("ui", "strict")
758 768 aliases, entry = cmdutil.findcmd(cmd, cmdtable, strict)
759 769 except (error.AmbiguousCommand, error.UnknownCommand):
760 770 return
761 771
762 772 cmd = aliases[0]
763 773 fn = entry[0]
764 774
765 775 if cmd and util.safehasattr(fn, 'shell'):
766 776 # shell alias shouldn't receive early options which are consumed by hg
767 777 _earlyopts, args = _earlysplitopts(args)
768 778 d = lambda: fn(ui, *args[1:])
769 779 return lambda: runcommand(lui, None, cmd, args[:1], ui, options, d,
770 780 [], {})
771 781
772 782 def _dispatch(req):
773 783 args = req.args
774 784 ui = req.ui
775 785
776 786 # check for cwd
777 787 cwd = req.earlyoptions['cwd']
778 788 if cwd:
779 789 os.chdir(cwd)
780 790
781 791 rpath = req.earlyoptions['repository']
782 792 path, lui = _getlocal(ui, rpath)
783 793
784 794 uis = {ui, lui}
785 795
786 796 if req.repo:
787 797 uis.add(req.repo.ui)
788 798
789 799 if req.earlyoptions['profile']:
790 800 for ui_ in uis:
791 801 ui_.setconfig('profiling', 'enabled', 'true', '--profile')
792 802
793 803 profile = lui.configbool('profiling', 'enabled')
794 804 with profiling.profile(lui, enabled=profile) as profiler:
795 805 # Configure extensions in phases: uisetup, extsetup, cmdtable, and
796 806 # reposetup
797 807 extensions.loadall(lui)
798 808 # Propagate any changes to lui.__class__ by extensions
799 809 ui.__class__ = lui.__class__
800 810
801 811 # (uisetup and extsetup are handled in extensions.loadall)
802 812
803 813 # (reposetup is handled in hg.repository)
804 814
805 815 addaliases(lui, commands.table)
806 816
807 817 # All aliases and commands are completely defined, now.
808 818 # Check abbreviation/ambiguity of shell alias.
809 819 shellaliasfn = _checkshellalias(lui, ui, args)
810 820 if shellaliasfn:
811 821 return shellaliasfn()
812 822
813 823 # check for fallback encoding
814 824 fallback = lui.config('ui', 'fallbackencoding')
815 825 if fallback:
816 826 encoding.fallbackencoding = fallback
817 827
818 828 fullargs = args
819 829 cmd, func, args, options, cmdoptions = _parse(lui, args)
820 830
821 831 if options["config"] != req.earlyoptions["config"]:
822 832 raise error.Abort(_("option --config may not be abbreviated!"))
823 833 if options["cwd"] != req.earlyoptions["cwd"]:
824 834 raise error.Abort(_("option --cwd may not be abbreviated!"))
825 835 if options["repository"] != req.earlyoptions["repository"]:
826 836 raise error.Abort(_(
827 837 "option -R has to be separated from other options (e.g. not "
828 838 "-qR) and --repository may only be abbreviated as --repo!"))
829 839 if options["debugger"] != req.earlyoptions["debugger"]:
830 840 raise error.Abort(_("option --debugger may not be abbreviated!"))
831 841 # don't validate --profile/--traceback, which can be enabled from now
832 842
833 843 if options["encoding"]:
834 844 encoding.encoding = options["encoding"]
835 845 if options["encodingmode"]:
836 846 encoding.encodingmode = options["encodingmode"]
837 847 if options["time"]:
838 848 def get_times():
839 849 t = os.times()
840 850 if t[4] == 0.0:
841 851 # Windows leaves this as zero, so use time.clock()
842 852 t = (t[0], t[1], t[2], t[3], time.clock())
843 853 return t
844 854 s = get_times()
845 855 def print_time():
846 856 t = get_times()
847 857 ui.warn(
848 858 _("time: real %.3f secs (user %.3f+%.3f sys %.3f+%.3f)\n") %
849 859 (t[4]-s[4], t[0]-s[0], t[2]-s[2], t[1]-s[1], t[3]-s[3]))
850 860 ui.atexit(print_time)
851 861 if options["profile"]:
852 862 profiler.start()
853 863
854 864 if options['verbose'] or options['debug'] or options['quiet']:
855 865 for opt in ('verbose', 'debug', 'quiet'):
856 866 val = pycompat.bytestr(bool(options[opt]))
857 867 for ui_ in uis:
858 868 ui_.setconfig('ui', opt, val, '--' + opt)
859 869
860 870 if options['traceback']:
861 871 for ui_ in uis:
862 872 ui_.setconfig('ui', 'traceback', 'on', '--traceback')
863 873
864 874 if options['noninteractive']:
865 875 for ui_ in uis:
866 876 ui_.setconfig('ui', 'interactive', 'off', '-y')
867 877
868 878 if cmdoptions.get('insecure', False):
869 879 for ui_ in uis:
870 880 ui_.insecureconnections = True
871 881
872 882 # setup color handling before pager, because setting up pager
873 883 # might cause incorrect console information
874 884 coloropt = options['color']
875 885 for ui_ in uis:
876 886 if coloropt:
877 887 ui_.setconfig('ui', 'color', coloropt, '--color')
878 888 color.setup(ui_)
879 889
880 890 if stringutil.parsebool(options['pager']):
881 891 # ui.pager() expects 'internal-always-' prefix in this case
882 892 ui.pager('internal-always-' + cmd)
883 893 elif options['pager'] != 'auto':
884 894 for ui_ in uis:
885 895 ui_.disablepager()
886 896
887 897 if options['version']:
888 898 return commands.version_(ui)
889 899 if options['help']:
890 900 return commands.help_(ui, cmd, command=cmd is not None)
891 901 elif not cmd:
892 902 return commands.help_(ui, 'shortlist')
893 903
894 904 repo = None
895 905 cmdpats = args[:]
896 906 if not func.norepo:
897 907 # use the repo from the request only if we don't have -R
898 908 if not rpath and not cwd:
899 909 repo = req.repo
900 910
901 911 if repo:
902 912 # set the descriptors of the repo ui to those of ui
903 913 repo.ui.fin = ui.fin
904 914 repo.ui.fout = ui.fout
905 915 repo.ui.ferr = ui.ferr
906 916 else:
907 917 try:
908 918 repo = hg.repository(ui, path=path,
909 919 presetupfuncs=req.prereposetups)
910 920 if not repo.local():
911 921 raise error.Abort(_("repository '%s' is not local")
912 922 % path)
913 923 repo.ui.setconfig("bundle", "mainreporoot", repo.root,
914 924 'repo')
915 925 except error.RequirementError:
916 926 raise
917 927 except error.RepoError:
918 928 if rpath: # invalid -R path
919 929 raise
920 930 if not func.optionalrepo:
921 931 if func.inferrepo and args and not path:
922 932 # try to infer -R from command args
923 933 repos = pycompat.maplist(cmdutil.findrepo, args)
924 934 guess = repos[0]
925 935 if guess and repos.count(guess) == len(repos):
926 936 req.args = ['--repository', guess] + fullargs
927 937 req.earlyoptions['repository'] = guess
928 938 return _dispatch(req)
929 939 if not path:
930 940 raise error.RepoError(_("no repository found in"
931 941 " '%s' (.hg not found)")
932 942 % pycompat.getcwd())
933 943 raise
934 944 if repo:
935 945 ui = repo.ui
936 946 if options['hidden']:
937 947 repo = repo.unfiltered()
938 948 args.insert(0, repo)
939 949 elif rpath:
940 950 ui.warn(_("warning: --repository ignored\n"))
941 951
942 952 msg = _formatargs(fullargs)
943 953 ui.log("command", '%s\n', msg)
944 954 strcmdopt = pycompat.strkwargs(cmdoptions)
945 955 d = lambda: util.checksignature(func)(ui, *args, **strcmdopt)
946 956 try:
947 957 return runcommand(lui, repo, cmd, fullargs, ui, options, d,
948 958 cmdpats, cmdoptions)
949 959 finally:
950 960 if repo and repo != req.repo:
951 961 repo.close()
952 962
953 963 def _runcommand(ui, options, cmd, cmdfunc):
954 964 """Run a command function, possibly with profiling enabled."""
955 965 try:
956 966 return cmdfunc()
957 967 except error.SignatureError:
958 968 raise error.CommandError(cmd, _('invalid arguments'))
959 969
960 970 def _exceptionwarning(ui):
961 971 """Produce a warning message for the current active exception"""
962 972
963 973 # For compatibility checking, we discard the portion of the hg
964 974 # version after the + on the assumption that if a "normal
965 975 # user" is running a build with a + in it the packager
966 976 # probably built from fairly close to a tag and anyone with a
967 977 # 'make local' copy of hg (where the version number can be out
968 978 # of date) will be clueful enough to notice the implausible
969 979 # version number and try updating.
970 980 ct = util.versiontuple(n=2)
971 981 worst = None, ct, ''
972 982 if ui.config('ui', 'supportcontact') is None:
973 983 for name, mod in extensions.extensions():
974 984 # 'testedwith' should be bytes, but not all extensions are ported
975 985 # to py3 and we don't want UnicodeException because of that.
976 986 testedwith = stringutil.forcebytestr(getattr(mod, 'testedwith', ''))
977 987 report = getattr(mod, 'buglink', _('the extension author.'))
978 988 if not testedwith.strip():
979 989 # We found an untested extension. It's likely the culprit.
980 990 worst = name, 'unknown', report
981 991 break
982 992
983 993 # Never blame on extensions bundled with Mercurial.
984 994 if extensions.ismoduleinternal(mod):
985 995 continue
986 996
987 997 tested = [util.versiontuple(t, 2) for t in testedwith.split()]
988 998 if ct in tested:
989 999 continue
990 1000
991 1001 lower = [t for t in tested if t < ct]
992 1002 nearest = max(lower or tested)
993 1003 if worst[0] is None or nearest < worst[1]:
994 1004 worst = name, nearest, report
995 1005 if worst[0] is not None:
996 1006 name, testedwith, report = worst
997 1007 if not isinstance(testedwith, (bytes, str)):
998 1008 testedwith = '.'.join([stringutil.forcebytestr(c)
999 1009 for c in testedwith])
1000 1010 warning = (_('** Unknown exception encountered with '
1001 1011 'possibly-broken third-party extension %s\n'
1002 1012 '** which supports versions %s of Mercurial.\n'
1003 1013 '** Please disable %s and try your action again.\n'
1004 1014 '** If that fixes the bug please report it to %s\n')
1005 1015 % (name, testedwith, name, report))
1006 1016 else:
1007 1017 bugtracker = ui.config('ui', 'supportcontact')
1008 1018 if bugtracker is None:
1009 1019 bugtracker = _("https://mercurial-scm.org/wiki/BugTracker")
1010 1020 warning = (_("** unknown exception encountered, "
1011 1021 "please report by visiting\n** ") + bugtracker + '\n')
1012 1022 sysversion = pycompat.sysbytes(sys.version).replace('\n', '')
1013 1023 warning += ((_("** Python %s\n") % sysversion) +
1014 1024 (_("** Mercurial Distributed SCM (version %s)\n") %
1015 1025 util.version()) +
1016 1026 (_("** Extensions loaded: %s\n") %
1017 1027 ", ".join([x[0] for x in extensions.extensions()])))
1018 1028 return warning
1019 1029
1020 1030 def handlecommandexception(ui):
1021 1031 """Produce a warning message for broken commands
1022 1032
1023 1033 Called when handling an exception; the exception is reraised if
1024 1034 this function returns False, ignored otherwise.
1025 1035 """
1026 1036 warning = _exceptionwarning(ui)
1027 1037 ui.log("commandexception", "%s\n%s\n", warning,
1028 1038 pycompat.sysbytes(traceback.format_exc()))
1029 1039 ui.warn(warning)
1030 1040 return False # re-raise the exception
@@ -1,689 +1,689 b''
1 1 # help.py - help data for mercurial
2 2 #
3 3 # Copyright 2006 Matt Mackall <mpm@selenic.com>
4 4 #
5 5 # This software may be used and distributed according to the terms of the
6 6 # GNU General Public License version 2 or any later version.
7 7
8 8 from __future__ import absolute_import
9 9
10 10 import itertools
11 11 import os
12 12 import textwrap
13 13
14 14 from .i18n import (
15 15 _,
16 16 gettext,
17 17 )
18 18 from . import (
19 19 cmdutil,
20 20 encoding,
21 21 error,
22 22 extensions,
23 23 fancyopts,
24 24 filemerge,
25 25 fileset,
26 26 minirst,
27 27 pycompat,
28 28 revset,
29 29 templatefilters,
30 30 templatefuncs,
31 31 templatekw,
32 32 util,
33 33 )
34 34 from .hgweb import (
35 35 webcommands,
36 36 )
37 37
38 38 _exclkeywords = {
39 39 "(ADVANCED)",
40 40 "(DEPRECATED)",
41 41 "(EXPERIMENTAL)",
42 42 # i18n: "(ADVANCED)" is a keyword, must be translated consistently
43 43 _("(ADVANCED)"),
44 44 # i18n: "(DEPRECATED)" is a keyword, must be translated consistently
45 45 _("(DEPRECATED)"),
46 46 # i18n: "(EXPERIMENTAL)" is a keyword, must be translated consistently
47 47 _("(EXPERIMENTAL)"),
48 48 }
49 49
50 50 def listexts(header, exts, indent=1, showdeprecated=False):
51 51 '''return a text listing of the given extensions'''
52 52 rst = []
53 53 if exts:
54 54 for name, desc in sorted(exts.iteritems()):
55 55 if not showdeprecated and any(w in desc for w in _exclkeywords):
56 56 continue
57 57 rst.append('%s:%s: %s\n' % (' ' * indent, name, desc))
58 58 if rst:
59 59 rst.insert(0, '\n%s\n\n' % header)
60 60 return rst
61 61
62 62 def extshelp(ui):
63 63 rst = loaddoc('extensions')(ui).splitlines(True)
64 64 rst.extend(listexts(
65 65 _('enabled extensions:'), extensions.enabled(), showdeprecated=True))
66 66 rst.extend(listexts(_('disabled extensions:'), extensions.disabled(),
67 67 showdeprecated=ui.verbose))
68 68 doc = ''.join(rst)
69 69 return doc
70 70
71 71 def optrst(header, options, verbose):
72 72 data = []
73 73 multioccur = False
74 74 for option in options:
75 75 if len(option) == 5:
76 76 shortopt, longopt, default, desc, optlabel = option
77 77 else:
78 78 shortopt, longopt, default, desc = option
79 79 optlabel = _("VALUE") # default label
80 80
81 81 if not verbose and any(w in desc for w in _exclkeywords):
82 82 continue
83 83
84 84 so = ''
85 85 if shortopt:
86 86 so = '-' + shortopt
87 87 lo = '--' + longopt
88 88
89 89 if isinstance(default, fancyopts.customopt):
90 90 default = default.getdefaultvalue()
91 91 if default and not callable(default):
92 92 # default is of unknown type, and in Python 2 we abused
93 93 # the %s-shows-repr property to handle integers etc. To
94 94 # match that behavior on Python 3, we do str(default) and
95 95 # then convert it to bytes.
96 96 desc += _(" (default: %s)") % pycompat.bytestr(default)
97 97
98 98 if isinstance(default, list):
99 99 lo += " %s [+]" % optlabel
100 100 multioccur = True
101 101 elif (default is not None) and not isinstance(default, bool):
102 102 lo += " %s" % optlabel
103 103
104 104 data.append((so, lo, desc))
105 105
106 106 if multioccur:
107 107 header += (_(" ([+] can be repeated)"))
108 108
109 109 rst = ['\n%s:\n\n' % header]
110 110 rst.extend(minirst.maketable(data, 1))
111 111
112 112 return ''.join(rst)
113 113
114 114 def indicateomitted(rst, omitted, notomitted=None):
115 115 rst.append('\n\n.. container:: omitted\n\n %s\n\n' % omitted)
116 116 if notomitted:
117 117 rst.append('\n\n.. container:: notomitted\n\n %s\n\n' % notomitted)
118 118
119 119 def filtercmd(ui, cmd, kw, doc):
120 120 if not ui.debugflag and cmd.startswith("debug") and kw != "debug":
121 121 return True
122 122 if not ui.verbose and doc and any(w in doc for w in _exclkeywords):
123 123 return True
124 124 return False
125 125
126 126 def topicmatch(ui, commands, kw):
127 127 """Return help topics matching kw.
128 128
129 129 Returns {'section': [(name, summary), ...], ...} where section is
130 130 one of topics, commands, extensions, or extensioncommands.
131 131 """
132 132 kw = encoding.lower(kw)
133 133 def lowercontains(container):
134 134 return kw in encoding.lower(container) # translated in helptable
135 135 results = {'topics': [],
136 136 'commands': [],
137 137 'extensions': [],
138 138 'extensioncommands': [],
139 139 }
140 140 for names, header, doc in helptable:
141 141 # Old extensions may use a str as doc.
142 142 if (sum(map(lowercontains, names))
143 143 or lowercontains(header)
144 144 or (callable(doc) and lowercontains(doc(ui)))):
145 145 results['topics'].append((names[0], header))
146 146 for cmd, entry in commands.table.iteritems():
147 147 if len(entry) == 3:
148 148 summary = entry[2]
149 149 else:
150 150 summary = ''
151 151 # translate docs *before* searching there
152 152 docs = _(pycompat.getdoc(entry[0])) or ''
153 153 if kw in cmd or lowercontains(summary) or lowercontains(docs):
154 154 doclines = docs.splitlines()
155 155 if doclines:
156 156 summary = doclines[0]
157 157 cmdname = cmdutil.parsealiases(cmd)[0]
158 158 if filtercmd(ui, cmdname, kw, docs):
159 159 continue
160 160 results['commands'].append((cmdname, summary))
161 161 for name, docs in itertools.chain(
162 162 extensions.enabled(False).iteritems(),
163 163 extensions.disabled().iteritems()):
164 164 if not docs:
165 165 continue
166 166 name = name.rpartition('.')[-1]
167 167 if lowercontains(name) or lowercontains(docs):
168 168 # extension docs are already translated
169 169 results['extensions'].append((name, docs.splitlines()[0]))
170 170 try:
171 171 mod = extensions.load(ui, name, '')
172 172 except ImportError:
173 173 # debug message would be printed in extensions.load()
174 174 continue
175 175 for cmd, entry in getattr(mod, 'cmdtable', {}).iteritems():
176 176 if kw in cmd or (len(entry) > 2 and lowercontains(entry[2])):
177 177 cmdname = cmdutil.parsealiases(cmd)[0]
178 178 cmddoc = pycompat.getdoc(entry[0])
179 179 if cmddoc:
180 180 cmddoc = gettext(cmddoc).splitlines()[0]
181 181 else:
182 182 cmddoc = _('(no help text available)')
183 183 if filtercmd(ui, cmdname, kw, cmddoc):
184 184 continue
185 185 results['extensioncommands'].append((cmdname, cmddoc))
186 186 return results
187 187
188 188 def loaddoc(topic, subdir=None):
189 189 """Return a delayed loader for help/topic.txt."""
190 190
191 191 def loader(ui):
192 192 docdir = os.path.join(util.datapath, 'help')
193 193 if subdir:
194 194 docdir = os.path.join(docdir, subdir)
195 195 path = os.path.join(docdir, topic + ".txt")
196 196 doc = gettext(util.readfile(path))
197 197 for rewriter in helphooks.get(topic, []):
198 198 doc = rewriter(ui, topic, doc)
199 199 return doc
200 200
201 201 return loader
202 202
203 203 internalstable = sorted([
204 204 (['bundle2'], _('Bundle2'),
205 205 loaddoc('bundle2', subdir='internals')),
206 206 (['bundles'], _('Bundles'),
207 207 loaddoc('bundles', subdir='internals')),
208 208 (['censor'], _('Censor'),
209 209 loaddoc('censor', subdir='internals')),
210 210 (['changegroups'], _('Changegroups'),
211 211 loaddoc('changegroups', subdir='internals')),
212 212 (['config'], _('Config Registrar'),
213 213 loaddoc('config', subdir='internals')),
214 214 (['requirements'], _('Repository Requirements'),
215 215 loaddoc('requirements', subdir='internals')),
216 216 (['revlogs'], _('Revision Logs'),
217 217 loaddoc('revlogs', subdir='internals')),
218 218 (['wireprotocol'], _('Wire Protocol'),
219 219 loaddoc('wireprotocol', subdir='internals')),
220 220 ])
221 221
222 222 def internalshelp(ui):
223 223 """Generate the index for the "internals" topic."""
224 224 lines = ['To access a subtopic, use "hg help internals.{subtopic-name}"\n',
225 225 '\n']
226 226 for names, header, doc in internalstable:
227 227 lines.append(' :%s: %s\n' % (names[0], header))
228 228
229 229 return ''.join(lines)
230 230
231 231 helptable = sorted([
232 232 (['bundlespec'], _("Bundle File Formats"), loaddoc('bundlespec')),
233 233 (['color'], _("Colorizing Outputs"), loaddoc('color')),
234 234 (["config", "hgrc"], _("Configuration Files"), loaddoc('config')),
235 235 (["dates"], _("Date Formats"), loaddoc('dates')),
236 236 (["flags"], _("Command-line flags"), loaddoc('flags')),
237 237 (["patterns"], _("File Name Patterns"), loaddoc('patterns')),
238 238 (['environment', 'env'], _('Environment Variables'),
239 239 loaddoc('environment')),
240 240 (['revisions', 'revs', 'revsets', 'revset', 'multirevs', 'mrevs'],
241 241 _('Specifying Revisions'), loaddoc('revisions')),
242 242 (['filesets', 'fileset'], _("Specifying File Sets"), loaddoc('filesets')),
243 243 (['diffs'], _('Diff Formats'), loaddoc('diffs')),
244 244 (['merge-tools', 'mergetools', 'mergetool'], _('Merge Tools'),
245 245 loaddoc('merge-tools')),
246 246 (['templating', 'templates', 'template', 'style'], _('Template Usage'),
247 247 loaddoc('templates')),
248 248 (['urls'], _('URL Paths'), loaddoc('urls')),
249 249 (["extensions"], _("Using Additional Features"), extshelp),
250 250 (["subrepos", "subrepo"], _("Subrepositories"), loaddoc('subrepos')),
251 251 (["hgweb"], _("Configuring hgweb"), loaddoc('hgweb')),
252 252 (["glossary"], _("Glossary"), loaddoc('glossary')),
253 253 (["hgignore", "ignore"], _("Syntax for Mercurial Ignore Files"),
254 254 loaddoc('hgignore')),
255 255 (["phases"], _("Working with Phases"), loaddoc('phases')),
256 256 (['scripting'], _('Using Mercurial from scripts and automation'),
257 257 loaddoc('scripting')),
258 258 (['internals'], _("Technical implementation topics"),
259 259 internalshelp),
260 260 (['pager'], _("Pager Support"), loaddoc('pager')),
261 261 ])
262 262
263 263 # Maps topics with sub-topics to a list of their sub-topics.
264 264 subtopics = {
265 265 'internals': internalstable,
266 266 }
267 267
268 268 # Map topics to lists of callable taking the current topic help and
269 269 # returning the updated version
270 270 helphooks = {}
271 271
272 272 def addtopichook(topic, rewriter):
273 273 helphooks.setdefault(topic, []).append(rewriter)
274 274
275 275 def makeitemsdoc(ui, topic, doc, marker, items, dedent=False):
276 276 """Extract docstring from the items key to function mapping, build a
277 277 single documentation block and use it to overwrite the marker in doc.
278 278 """
279 279 entries = []
280 280 for name in sorted(items):
281 281 text = (pycompat.getdoc(items[name]) or '').rstrip()
282 282 if (not text
283 283 or not ui.verbose and any(w in text for w in _exclkeywords)):
284 284 continue
285 285 text = gettext(text)
286 286 if dedent:
287 287 # Abuse latin1 to use textwrap.dedent() on bytes.
288 288 text = textwrap.dedent(text.decode('latin1')).encode('latin1')
289 289 lines = text.splitlines()
290 290 doclines = [(lines[0])]
291 291 for l in lines[1:]:
292 292 # Stop once we find some Python doctest
293 293 if l.strip().startswith('>>>'):
294 294 break
295 295 if dedent:
296 296 doclines.append(l.rstrip())
297 297 else:
298 298 doclines.append(' ' + l.strip())
299 299 entries.append('\n'.join(doclines))
300 300 entries = '\n\n'.join(entries)
301 301 return doc.replace(marker, entries)
302 302
303 303 def addtopicsymbols(topic, marker, symbols, dedent=False):
304 304 def add(ui, topic, doc):
305 305 return makeitemsdoc(ui, topic, doc, marker, symbols, dedent=dedent)
306 306 addtopichook(topic, add)
307 307
308 308 addtopicsymbols('bundlespec', '.. bundlecompressionmarker',
309 309 util.bundlecompressiontopics())
310 310 addtopicsymbols('filesets', '.. predicatesmarker', fileset.symbols)
311 311 addtopicsymbols('merge-tools', '.. internaltoolsmarker',
312 312 filemerge.internalsdoc)
313 313 addtopicsymbols('revisions', '.. predicatesmarker', revset.symbols)
314 314 addtopicsymbols('templates', '.. keywordsmarker', templatekw.keywords)
315 315 addtopicsymbols('templates', '.. filtersmarker', templatefilters.filters)
316 316 addtopicsymbols('templates', '.. functionsmarker', templatefuncs.funcs)
317 317 addtopicsymbols('hgweb', '.. webcommandsmarker', webcommands.commands,
318 318 dedent=True)
319 319
320 320 def help_(ui, commands, name, unknowncmd=False, full=True, subtopic=None,
321 321 **opts):
322 322 '''
323 323 Generate the help for 'name' as unformatted restructured text. If
324 324 'name' is None, describe the commands available.
325 325 '''
326 326
327 327 opts = pycompat.byteskwargs(opts)
328 328
329 329 def helpcmd(name, subtopic=None):
330 330 try:
331 331 aliases, entry = cmdutil.findcmd(name, commands.table,
332 332 strict=unknowncmd)
333 333 except error.AmbiguousCommand as inst:
334 334 # py3k fix: except vars can't be used outside the scope of the
335 335 # except block, nor can be used inside a lambda. python issue4617
336 336 prefix = inst.args[0]
337 337 select = lambda c: cmdutil.parsealiases(c)[0].startswith(prefix)
338 338 rst = helplist(select)
339 339 return rst
340 340
341 341 rst = []
342 342
343 343 # check if it's an invalid alias and display its error if it is
344 344 if getattr(entry[0], 'badalias', None):
345 345 rst.append(entry[0].badalias + '\n')
346 346 if entry[0].unknowncmd:
347 347 try:
348 348 rst.extend(helpextcmd(entry[0].cmdname))
349 349 except error.UnknownCommand:
350 350 pass
351 351 return rst
352 352
353 353 # synopsis
354 354 if len(entry) > 2:
355 355 if entry[2].startswith('hg'):
356 356 rst.append("%s\n" % entry[2])
357 357 else:
358 358 rst.append('hg %s %s\n' % (aliases[0], entry[2]))
359 359 else:
360 360 rst.append('hg %s\n' % aliases[0])
361 361 # aliases
362 362 if full and not ui.quiet and len(aliases) > 1:
363 363 rst.append(_("\naliases: %s\n") % ', '.join(aliases[1:]))
364 364 rst.append('\n')
365 365
366 366 # description
367 367 doc = gettext(pycompat.getdoc(entry[0]))
368 368 if not doc:
369 369 doc = _("(no help text available)")
370 370 if util.safehasattr(entry[0], 'definition'): # aliased command
371 371 source = entry[0].source
372 372 if entry[0].definition.startswith('!'): # shell alias
373 doc = (_('shell alias for::\n\n %s\n\ndefined by: %s\n') %
374 (entry[0].definition[1:], source))
373 doc = (_('shell alias for: %s\n\n%s\n\ndefined by: %s\n') %
374 (entry[0].definition[1:], doc, source))
375 375 else:
376 376 doc = (_('alias for: hg %s\n\n%s\n\ndefined by: %s\n') %
377 377 (entry[0].definition, doc, source))
378 378 doc = doc.splitlines(True)
379 379 if ui.quiet or not full:
380 380 rst.append(doc[0])
381 381 else:
382 382 rst.extend(doc)
383 383 rst.append('\n')
384 384
385 385 # check if this command shadows a non-trivial (multi-line)
386 386 # extension help text
387 387 try:
388 388 mod = extensions.find(name)
389 389 doc = gettext(pycompat.getdoc(mod)) or ''
390 390 if '\n' in doc.strip():
391 391 msg = _("(use 'hg help -e %s' to show help for "
392 392 "the %s extension)") % (name, name)
393 393 rst.append('\n%s\n' % msg)
394 394 except KeyError:
395 395 pass
396 396
397 397 # options
398 398 if not ui.quiet and entry[1]:
399 399 rst.append(optrst(_("options"), entry[1], ui.verbose))
400 400
401 401 if ui.verbose:
402 402 rst.append(optrst(_("global options"),
403 403 commands.globalopts, ui.verbose))
404 404
405 405 if not ui.verbose:
406 406 if not full:
407 407 rst.append(_("\n(use 'hg %s -h' to show more help)\n")
408 408 % name)
409 409 elif not ui.quiet:
410 410 rst.append(_('\n(some details hidden, use --verbose '
411 411 'to show complete help)'))
412 412
413 413 return rst
414 414
415 415
416 416 def helplist(select=None, **opts):
417 417 # list of commands
418 418 if name == "shortlist":
419 419 header = _('basic commands:\n\n')
420 420 elif name == "debug":
421 421 header = _('debug commands (internal and unsupported):\n\n')
422 422 else:
423 423 header = _('list of commands:\n\n')
424 424
425 425 h = {}
426 426 cmds = {}
427 427 for c, e in commands.table.iteritems():
428 428 fs = cmdutil.parsealiases(c)
429 429 f = fs[0]
430 430 p = ''
431 431 if c.startswith("^"):
432 432 p = '^'
433 433 if select and not select(p + f):
434 434 continue
435 435 if (not select and name != 'shortlist' and
436 436 e[0].__module__ != commands.__name__):
437 437 continue
438 438 if name == "shortlist" and not p:
439 439 continue
440 440 doc = pycompat.getdoc(e[0])
441 441 if filtercmd(ui, f, name, doc):
442 442 continue
443 443 doc = gettext(doc)
444 444 if not doc:
445 445 doc = _("(no help text available)")
446 446 h[f] = doc.splitlines()[0].rstrip()
447 447 cmds[f] = '|'.join(fs)
448 448
449 449 rst = []
450 450 if not h:
451 451 if not ui.quiet:
452 452 rst.append(_('no commands defined\n'))
453 453 return rst
454 454
455 455 if not ui.quiet:
456 456 rst.append(header)
457 457 fns = sorted(h)
458 458 for f in fns:
459 459 if ui.verbose:
460 460 commacmds = cmds[f].replace("|",", ")
461 461 rst.append(" :%s: %s\n" % (commacmds, h[f]))
462 462 else:
463 463 rst.append(' :%s: %s\n' % (f, h[f]))
464 464
465 465 ex = opts.get
466 466 anyopts = (ex(r'keyword') or not (ex(r'command') or ex(r'extension')))
467 467 if not name and anyopts:
468 468 exts = listexts(_('enabled extensions:'), extensions.enabled())
469 469 if exts:
470 470 rst.append('\n')
471 471 rst.extend(exts)
472 472
473 473 rst.append(_("\nadditional help topics:\n\n"))
474 474 topics = []
475 475 for names, header, doc in helptable:
476 476 topics.append((names[0], header))
477 477 for t, desc in topics:
478 478 rst.append(" :%s: %s\n" % (t, desc))
479 479
480 480 if ui.quiet:
481 481 pass
482 482 elif ui.verbose:
483 483 rst.append('\n%s\n' % optrst(_("global options"),
484 484 commands.globalopts, ui.verbose))
485 485 if name == 'shortlist':
486 486 rst.append(_("\n(use 'hg help' for the full list "
487 487 "of commands)\n"))
488 488 else:
489 489 if name == 'shortlist':
490 490 rst.append(_("\n(use 'hg help' for the full list of commands "
491 491 "or 'hg -v' for details)\n"))
492 492 elif name and not full:
493 493 rst.append(_("\n(use 'hg help %s' to show the full help "
494 494 "text)\n") % name)
495 495 elif name and cmds and name in cmds.keys():
496 496 rst.append(_("\n(use 'hg help -v -e %s' to show built-in "
497 497 "aliases and global options)\n") % name)
498 498 else:
499 499 rst.append(_("\n(use 'hg help -v%s' to show built-in aliases "
500 500 "and global options)\n")
501 501 % (name and " " + name or ""))
502 502 return rst
503 503
504 504 def helptopic(name, subtopic=None):
505 505 # Look for sub-topic entry first.
506 506 header, doc = None, None
507 507 if subtopic and name in subtopics:
508 508 for names, header, doc in subtopics[name]:
509 509 if subtopic in names:
510 510 break
511 511
512 512 if not header:
513 513 for names, header, doc in helptable:
514 514 if name in names:
515 515 break
516 516 else:
517 517 raise error.UnknownCommand(name)
518 518
519 519 rst = [minirst.section(header)]
520 520
521 521 # description
522 522 if not doc:
523 523 rst.append(" %s\n" % _("(no help text available)"))
524 524 if callable(doc):
525 525 rst += [" %s\n" % l for l in doc(ui).splitlines()]
526 526
527 527 if not ui.verbose:
528 528 omitted = _('(some details hidden, use --verbose'
529 529 ' to show complete help)')
530 530 indicateomitted(rst, omitted)
531 531
532 532 try:
533 533 cmdutil.findcmd(name, commands.table)
534 534 rst.append(_("\nuse 'hg help -c %s' to see help for "
535 535 "the %s command\n") % (name, name))
536 536 except error.UnknownCommand:
537 537 pass
538 538 return rst
539 539
540 540 def helpext(name, subtopic=None):
541 541 try:
542 542 mod = extensions.find(name)
543 543 doc = gettext(pycompat.getdoc(mod)) or _('no help text available')
544 544 except KeyError:
545 545 mod = None
546 546 doc = extensions.disabledext(name)
547 547 if not doc:
548 548 raise error.UnknownCommand(name)
549 549
550 550 if '\n' not in doc:
551 551 head, tail = doc, ""
552 552 else:
553 553 head, tail = doc.split('\n', 1)
554 554 rst = [_('%s extension - %s\n\n') % (name.rpartition('.')[-1], head)]
555 555 if tail:
556 556 rst.extend(tail.splitlines(True))
557 557 rst.append('\n')
558 558
559 559 if not ui.verbose:
560 560 omitted = _('(some details hidden, use --verbose'
561 561 ' to show complete help)')
562 562 indicateomitted(rst, omitted)
563 563
564 564 if mod:
565 565 try:
566 566 ct = mod.cmdtable
567 567 except AttributeError:
568 568 ct = {}
569 569 modcmds = set([c.partition('|')[0] for c in ct])
570 570 rst.extend(helplist(modcmds.__contains__))
571 571 else:
572 572 rst.append(_("(use 'hg help extensions' for information on enabling"
573 573 " extensions)\n"))
574 574 return rst
575 575
576 576 def helpextcmd(name, subtopic=None):
577 577 cmd, ext, mod = extensions.disabledcmd(ui, name,
578 578 ui.configbool('ui', 'strict'))
579 579 doc = gettext(pycompat.getdoc(mod)).splitlines()[0]
580 580
581 581 rst = listexts(_("'%s' is provided by the following "
582 582 "extension:") % cmd, {ext: doc}, indent=4,
583 583 showdeprecated=True)
584 584 rst.append('\n')
585 585 rst.append(_("(use 'hg help extensions' for information on enabling "
586 586 "extensions)\n"))
587 587 return rst
588 588
589 589
590 590 rst = []
591 591 kw = opts.get('keyword')
592 592 if kw or name is None and any(opts[o] for o in opts):
593 593 matches = topicmatch(ui, commands, name or '')
594 594 helpareas = []
595 595 if opts.get('extension'):
596 596 helpareas += [('extensions', _('Extensions'))]
597 597 if opts.get('command'):
598 598 helpareas += [('commands', _('Commands'))]
599 599 if not helpareas:
600 600 helpareas = [('topics', _('Topics')),
601 601 ('commands', _('Commands')),
602 602 ('extensions', _('Extensions')),
603 603 ('extensioncommands', _('Extension Commands'))]
604 604 for t, title in helpareas:
605 605 if matches[t]:
606 606 rst.append('%s:\n\n' % title)
607 607 rst.extend(minirst.maketable(sorted(matches[t]), 1))
608 608 rst.append('\n')
609 609 if not rst:
610 610 msg = _('no matches')
611 611 hint = _("try 'hg help' for a list of topics")
612 612 raise error.Abort(msg, hint=hint)
613 613 elif name and name != 'shortlist':
614 614 queries = []
615 615 if unknowncmd:
616 616 queries += [helpextcmd]
617 617 if opts.get('extension'):
618 618 queries += [helpext]
619 619 if opts.get('command'):
620 620 queries += [helpcmd]
621 621 if not queries:
622 622 queries = (helptopic, helpcmd, helpext, helpextcmd)
623 623 for f in queries:
624 624 try:
625 625 rst = f(name, subtopic)
626 626 break
627 627 except error.UnknownCommand:
628 628 pass
629 629 else:
630 630 if unknowncmd:
631 631 raise error.UnknownCommand(name)
632 632 else:
633 633 msg = _('no such help topic: %s') % name
634 634 hint = _("try 'hg help --keyword %s'") % name
635 635 raise error.Abort(msg, hint=hint)
636 636 else:
637 637 # program name
638 638 if not ui.quiet:
639 639 rst = [_("Mercurial Distributed SCM\n"), '\n']
640 640 rst.extend(helplist(None, **pycompat.strkwargs(opts)))
641 641
642 642 return ''.join(rst)
643 643
644 644 def formattedhelp(ui, commands, name, keep=None, unknowncmd=False, full=True,
645 645 **opts):
646 646 """get help for a given topic (as a dotted name) as rendered rst
647 647
648 648 Either returns the rendered help text or raises an exception.
649 649 """
650 650 if keep is None:
651 651 keep = []
652 652 else:
653 653 keep = list(keep) # make a copy so we can mutate this later
654 654 fullname = name
655 655 section = None
656 656 subtopic = None
657 657 if name and '.' in name:
658 658 name, remaining = name.split('.', 1)
659 659 remaining = encoding.lower(remaining)
660 660 if '.' in remaining:
661 661 subtopic, section = remaining.split('.', 1)
662 662 else:
663 663 if name in subtopics:
664 664 subtopic = remaining
665 665 else:
666 666 section = remaining
667 667 textwidth = ui.configint('ui', 'textwidth')
668 668 termwidth = ui.termwidth() - 2
669 669 if textwidth <= 0 or termwidth < textwidth:
670 670 textwidth = termwidth
671 671 text = help_(ui, commands, name,
672 672 subtopic=subtopic, unknowncmd=unknowncmd, full=full, **opts)
673 673
674 674 formatted, pruned = minirst.format(text, textwidth, keep=keep,
675 675 section=section)
676 676
677 677 # We could have been given a weird ".foo" section without a name
678 678 # to look for, or we could have simply failed to found "foo.bar"
679 679 # because bar isn't a section of foo
680 680 if section and not (formatted and name):
681 681 raise error.Abort(_("help section not found: %s") % fullname)
682 682
683 683 if 'verbose' in pruned:
684 684 keep.append('omitted')
685 685 else:
686 686 keep.append('notomitted')
687 687 formatted, pruned = minirst.format(text, textwidth, keep=keep,
688 688 section=section)
689 689 return formatted
@@ -1,1874 +1,1870 b''
1 1 # ui.py - user interface bits for mercurial
2 2 #
3 3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
4 4 #
5 5 # This software may be used and distributed according to the terms of the
6 6 # GNU General Public License version 2 or any later version.
7 7
8 8 from __future__ import absolute_import
9 9
10 10 import collections
11 11 import contextlib
12 12 import errno
13 13 import getpass
14 14 import inspect
15 15 import os
16 16 import re
17 17 import signal
18 18 import socket
19 19 import subprocess
20 20 import sys
21 21 import tempfile
22 22 import traceback
23 23
24 24 from .i18n import _
25 25 from .node import hex
26 26
27 27 from . import (
28 28 color,
29 29 config,
30 30 configitems,
31 31 encoding,
32 32 error,
33 33 formatter,
34 34 progress,
35 35 pycompat,
36 36 rcutil,
37 37 scmutil,
38 38 util,
39 39 )
40 40 from .utils import (
41 41 dateutil,
42 42 procutil,
43 43 stringutil,
44 44 )
45 45
46 46 urlreq = util.urlreq
47 47
48 48 # for use with str.translate(None, _keepalnum), to keep just alphanumerics
49 49 _keepalnum = ''.join(c for c in map(pycompat.bytechr, range(256))
50 50 if not c.isalnum())
51 51
52 52 # The config knobs that will be altered (if unset) by ui.tweakdefaults.
53 53 tweakrc = b"""
54 54 [ui]
55 55 # The rollback command is dangerous. As a rule, don't use it.
56 56 rollback = False
57 57 # Make `hg status` report copy information
58 58 statuscopies = yes
59 59 # Prefer curses UIs when available. Revert to plain-text with `text`.
60 60 interface = curses
61 61
62 62 [commands]
63 63 # Make `hg status` emit cwd-relative paths by default.
64 64 status.relative = yes
65 65 # Refuse to perform an `hg update` that would cause a file content merge
66 66 update.check = noconflict
67 67 # Show conflicts information in `hg status`
68 68 status.verbose = True
69 69 # Skip the bisect state in conflicts information in `hg status`
70 70 status.skipstates = bisect
71 71
72 72 [diff]
73 73 git = 1
74 74 showfunc = 1
75 75 """
76 76
77 77 samplehgrcs = {
78 78 'user':
79 79 b"""# example user config (see 'hg help config' for more info)
80 80 [ui]
81 81 # name and email, e.g.
82 82 # username = Jane Doe <jdoe@example.com>
83 83 username =
84 84
85 85 # We recommend enabling tweakdefaults to get slight improvements to
86 86 # the UI over time. Make sure to set HGPLAIN in the environment when
87 87 # writing scripts!
88 88 # tweakdefaults = True
89 89
90 90 # uncomment to disable color in command output
91 91 # (see 'hg help color' for details)
92 92 # color = never
93 93
94 94 # uncomment to disable command output pagination
95 95 # (see 'hg help pager' for details)
96 96 # paginate = never
97 97
98 98 [extensions]
99 99 # uncomment these lines to enable some popular extensions
100 100 # (see 'hg help extensions' for more info)
101 101 #
102 102 # churn =
103 103 """,
104 104
105 105 'cloned':
106 106 b"""# example repository config (see 'hg help config' for more info)
107 107 [paths]
108 108 default = %s
109 109
110 110 # path aliases to other clones of this repo in URLs or filesystem paths
111 111 # (see 'hg help config.paths' for more info)
112 112 #
113 113 # default:pushurl = ssh://jdoe@example.net/hg/jdoes-fork
114 114 # my-fork = ssh://jdoe@example.net/hg/jdoes-fork
115 115 # my-clone = /home/jdoe/jdoes-clone
116 116
117 117 [ui]
118 118 # name and email (local to this repository, optional), e.g.
119 119 # username = Jane Doe <jdoe@example.com>
120 120 """,
121 121
122 122 'local':
123 123 b"""# example repository config (see 'hg help config' for more info)
124 124 [paths]
125 125 # path aliases to other clones of this repo in URLs or filesystem paths
126 126 # (see 'hg help config.paths' for more info)
127 127 #
128 128 # default = http://example.com/hg/example-repo
129 129 # default:pushurl = ssh://jdoe@example.net/hg/jdoes-fork
130 130 # my-fork = ssh://jdoe@example.net/hg/jdoes-fork
131 131 # my-clone = /home/jdoe/jdoes-clone
132 132
133 133 [ui]
134 134 # name and email (local to this repository, optional), e.g.
135 135 # username = Jane Doe <jdoe@example.com>
136 136 """,
137 137
138 138 'global':
139 139 b"""# example system-wide hg config (see 'hg help config' for more info)
140 140
141 141 [ui]
142 142 # uncomment to disable color in command output
143 143 # (see 'hg help color' for details)
144 144 # color = never
145 145
146 146 # uncomment to disable command output pagination
147 147 # (see 'hg help pager' for details)
148 148 # paginate = never
149 149
150 150 [extensions]
151 151 # uncomment these lines to enable some popular extensions
152 152 # (see 'hg help extensions' for more info)
153 153 #
154 154 # blackbox =
155 155 # churn =
156 156 """,
157 157 }
158 158
159 159 def _maybestrurl(maybebytes):
160 160 return util.rapply(pycompat.strurl, maybebytes)
161 161
162 162 def _maybebytesurl(maybestr):
163 163 return util.rapply(pycompat.bytesurl, maybestr)
164 164
165 165 class httppasswordmgrdbproxy(object):
166 166 """Delays loading urllib2 until it's needed."""
167 167 def __init__(self):
168 168 self._mgr = None
169 169
170 170 def _get_mgr(self):
171 171 if self._mgr is None:
172 172 self._mgr = urlreq.httppasswordmgrwithdefaultrealm()
173 173 return self._mgr
174 174
175 175 def add_password(self, realm, uris, user, passwd):
176 176 return self._get_mgr().add_password(
177 177 _maybestrurl(realm), _maybestrurl(uris),
178 178 _maybestrurl(user), _maybestrurl(passwd))
179 179
180 180 def find_user_password(self, realm, uri):
181 181 mgr = self._get_mgr()
182 182 return _maybebytesurl(mgr.find_user_password(_maybestrurl(realm),
183 183 _maybestrurl(uri)))
184 184
185 185 def _catchterm(*args):
186 186 raise error.SignalInterrupt
187 187
188 188 # unique object used to detect no default value has been provided when
189 189 # retrieving configuration value.
190 190 _unset = object()
191 191
192 192 # _reqexithandlers: callbacks run at the end of a request
193 193 _reqexithandlers = []
194 194
195 195 class ui(object):
196 196 def __init__(self, src=None):
197 197 """Create a fresh new ui object if no src given
198 198
199 199 Use uimod.ui.load() to create a ui which knows global and user configs.
200 200 In most cases, you should use ui.copy() to create a copy of an existing
201 201 ui object.
202 202 """
203 203 # _buffers: used for temporary capture of output
204 204 self._buffers = []
205 205 # 3-tuple describing how each buffer in the stack behaves.
206 206 # Values are (capture stderr, capture subprocesses, apply labels).
207 207 self._bufferstates = []
208 208 # When a buffer is active, defines whether we are expanding labels.
209 209 # This exists to prevent an extra list lookup.
210 210 self._bufferapplylabels = None
211 211 self.quiet = self.verbose = self.debugflag = self.tracebackflag = False
212 212 self._reportuntrusted = True
213 213 self._knownconfig = configitems.coreitems
214 214 self._ocfg = config.config() # overlay
215 215 self._tcfg = config.config() # trusted
216 216 self._ucfg = config.config() # untrusted
217 217 self._trustusers = set()
218 218 self._trustgroups = set()
219 219 self.callhooks = True
220 220 # Insecure server connections requested.
221 221 self.insecureconnections = False
222 222 # Blocked time
223 223 self.logblockedtimes = False
224 224 # color mode: see mercurial/color.py for possible value
225 225 self._colormode = None
226 226 self._terminfoparams = {}
227 227 self._styles = {}
228 228
229 229 if src:
230 230 self.fout = src.fout
231 231 self.ferr = src.ferr
232 232 self.fin = src.fin
233 233 self.pageractive = src.pageractive
234 234 self._disablepager = src._disablepager
235 235 self._tweaked = src._tweaked
236 236
237 237 self._tcfg = src._tcfg.copy()
238 238 self._ucfg = src._ucfg.copy()
239 239 self._ocfg = src._ocfg.copy()
240 240 self._trustusers = src._trustusers.copy()
241 241 self._trustgroups = src._trustgroups.copy()
242 242 self.environ = src.environ
243 243 self.callhooks = src.callhooks
244 244 self.insecureconnections = src.insecureconnections
245 245 self._colormode = src._colormode
246 246 self._terminfoparams = src._terminfoparams.copy()
247 247 self._styles = src._styles.copy()
248 248
249 249 self.fixconfig()
250 250
251 251 self.httppasswordmgrdb = src.httppasswordmgrdb
252 252 self._blockedtimes = src._blockedtimes
253 253 else:
254 254 self.fout = procutil.stdout
255 255 self.ferr = procutil.stderr
256 256 self.fin = procutil.stdin
257 257 self.pageractive = False
258 258 self._disablepager = False
259 259 self._tweaked = False
260 260
261 261 # shared read-only environment
262 262 self.environ = encoding.environ
263 263
264 264 self.httppasswordmgrdb = httppasswordmgrdbproxy()
265 265 self._blockedtimes = collections.defaultdict(int)
266 266
267 267 allowed = self.configlist('experimental', 'exportableenviron')
268 268 if '*' in allowed:
269 269 self._exportableenviron = self.environ
270 270 else:
271 271 self._exportableenviron = {}
272 272 for k in allowed:
273 273 if k in self.environ:
274 274 self._exportableenviron[k] = self.environ[k]
275 275
276 276 @classmethod
277 277 def load(cls):
278 278 """Create a ui and load global and user configs"""
279 279 u = cls()
280 280 # we always trust global config files and environment variables
281 281 for t, f in rcutil.rccomponents():
282 282 if t == 'path':
283 283 u.readconfig(f, trust=True)
284 284 elif t == 'items':
285 285 sections = set()
286 286 for section, name, value, source in f:
287 287 # do not set u._ocfg
288 288 # XXX clean this up once immutable config object is a thing
289 289 u._tcfg.set(section, name, value, source)
290 290 u._ucfg.set(section, name, value, source)
291 291 sections.add(section)
292 292 for section in sections:
293 293 u.fixconfig(section=section)
294 294 else:
295 295 raise error.ProgrammingError('unknown rctype: %s' % t)
296 296 u._maybetweakdefaults()
297 297 return u
298 298
299 299 def _maybetweakdefaults(self):
300 300 if not self.configbool('ui', 'tweakdefaults'):
301 301 return
302 302 if self._tweaked or self.plain('tweakdefaults'):
303 303 return
304 304
305 305 # Note: it is SUPER IMPORTANT that you set self._tweaked to
306 306 # True *before* any calls to setconfig(), otherwise you'll get
307 307 # infinite recursion between setconfig and this method.
308 308 #
309 309 # TODO: We should extract an inner method in setconfig() to
310 310 # avoid this weirdness.
311 311 self._tweaked = True
312 312 tmpcfg = config.config()
313 313 tmpcfg.parse('<tweakdefaults>', tweakrc)
314 314 for section in tmpcfg:
315 315 for name, value in tmpcfg.items(section):
316 316 if not self.hasconfig(section, name):
317 317 self.setconfig(section, name, value, "<tweakdefaults>")
318 318
319 319 def copy(self):
320 320 return self.__class__(self)
321 321
322 322 def resetstate(self):
323 323 """Clear internal state that shouldn't persist across commands"""
324 324 if self._progbar:
325 325 self._progbar.resetstate() # reset last-print time of progress bar
326 326 self.httppasswordmgrdb = httppasswordmgrdbproxy()
327 327
328 328 @contextlib.contextmanager
329 329 def timeblockedsection(self, key):
330 330 # this is open-coded below - search for timeblockedsection to find them
331 331 starttime = util.timer()
332 332 try:
333 333 yield
334 334 finally:
335 335 self._blockedtimes[key + '_blocked'] += \
336 336 (util.timer() - starttime) * 1000
337 337
338 338 def formatter(self, topic, opts):
339 339 return formatter.formatter(self, self, topic, opts)
340 340
341 341 def _trusted(self, fp, f):
342 342 st = util.fstat(fp)
343 343 if util.isowner(st):
344 344 return True
345 345
346 346 tusers, tgroups = self._trustusers, self._trustgroups
347 347 if '*' in tusers or '*' in tgroups:
348 348 return True
349 349
350 350 user = util.username(st.st_uid)
351 351 group = util.groupname(st.st_gid)
352 352 if user in tusers or group in tgroups or user == util.username():
353 353 return True
354 354
355 355 if self._reportuntrusted:
356 356 self.warn(_('not trusting file %s from untrusted '
357 357 'user %s, group %s\n') % (f, user, group))
358 358 return False
359 359
360 360 def readconfig(self, filename, root=None, trust=False,
361 361 sections=None, remap=None):
362 362 try:
363 363 fp = open(filename, u'rb')
364 364 except IOError:
365 365 if not sections: # ignore unless we were looking for something
366 366 return
367 367 raise
368 368
369 369 cfg = config.config()
370 370 trusted = sections or trust or self._trusted(fp, filename)
371 371
372 372 try:
373 373 cfg.read(filename, fp, sections=sections, remap=remap)
374 374 fp.close()
375 375 except error.ConfigError as inst:
376 376 if trusted:
377 377 raise
378 378 self.warn(_("ignored: %s\n") % stringutil.forcebytestr(inst))
379 379
380 380 if self.plain():
381 381 for k in ('debug', 'fallbackencoding', 'quiet', 'slash',
382 382 'logtemplate', 'statuscopies', 'style',
383 383 'traceback', 'verbose'):
384 384 if k in cfg['ui']:
385 385 del cfg['ui'][k]
386 386 for k, v in cfg.items('defaults'):
387 387 del cfg['defaults'][k]
388 388 for k, v in cfg.items('commands'):
389 389 del cfg['commands'][k]
390 390 # Don't remove aliases from the configuration if in the exceptionlist
391 391 if self.plain('alias'):
392 392 for k, v in cfg.items('alias'):
393 393 del cfg['alias'][k]
394 394 if self.plain('revsetalias'):
395 395 for k, v in cfg.items('revsetalias'):
396 396 del cfg['revsetalias'][k]
397 397 if self.plain('templatealias'):
398 398 for k, v in cfg.items('templatealias'):
399 399 del cfg['templatealias'][k]
400 400
401 401 if trusted:
402 402 self._tcfg.update(cfg)
403 403 self._tcfg.update(self._ocfg)
404 404 self._ucfg.update(cfg)
405 405 self._ucfg.update(self._ocfg)
406 406
407 407 if root is None:
408 408 root = os.path.expanduser('~')
409 409 self.fixconfig(root=root)
410 410
411 411 def fixconfig(self, root=None, section=None):
412 412 if section in (None, 'paths'):
413 413 # expand vars and ~
414 414 # translate paths relative to root (or home) into absolute paths
415 415 root = root or pycompat.getcwd()
416 416 for c in self._tcfg, self._ucfg, self._ocfg:
417 417 for n, p in c.items('paths'):
418 418 # Ignore sub-options.
419 419 if ':' in n:
420 420 continue
421 421 if not p:
422 422 continue
423 423 if '%%' in p:
424 424 s = self.configsource('paths', n) or 'none'
425 425 self.warn(_("(deprecated '%%' in path %s=%s from %s)\n")
426 426 % (n, p, s))
427 427 p = p.replace('%%', '%')
428 428 p = util.expandpath(p)
429 429 if not util.hasscheme(p) and not os.path.isabs(p):
430 430 p = os.path.normpath(os.path.join(root, p))
431 431 c.set("paths", n, p)
432 432
433 433 if section in (None, 'ui'):
434 434 # update ui options
435 435 self.debugflag = self.configbool('ui', 'debug')
436 436 self.verbose = self.debugflag or self.configbool('ui', 'verbose')
437 437 self.quiet = not self.debugflag and self.configbool('ui', 'quiet')
438 438 if self.verbose and self.quiet:
439 439 self.quiet = self.verbose = False
440 440 self._reportuntrusted = self.debugflag or self.configbool("ui",
441 441 "report_untrusted")
442 442 self.tracebackflag = self.configbool('ui', 'traceback')
443 443 self.logblockedtimes = self.configbool('ui', 'logblockedtimes')
444 444
445 445 if section in (None, 'trusted'):
446 446 # update trust information
447 447 self._trustusers.update(self.configlist('trusted', 'users'))
448 448 self._trustgroups.update(self.configlist('trusted', 'groups'))
449 449
450 450 def backupconfig(self, section, item):
451 451 return (self._ocfg.backup(section, item),
452 452 self._tcfg.backup(section, item),
453 453 self._ucfg.backup(section, item),)
454 454 def restoreconfig(self, data):
455 455 self._ocfg.restore(data[0])
456 456 self._tcfg.restore(data[1])
457 457 self._ucfg.restore(data[2])
458 458
459 459 def setconfig(self, section, name, value, source=''):
460 460 for cfg in (self._ocfg, self._tcfg, self._ucfg):
461 461 cfg.set(section, name, value, source)
462 462 self.fixconfig(section=section)
463 463 self._maybetweakdefaults()
464 464
465 465 def _data(self, untrusted):
466 466 return untrusted and self._ucfg or self._tcfg
467 467
468 468 def configsource(self, section, name, untrusted=False):
469 469 return self._data(untrusted).source(section, name)
470 470
471 471 def config(self, section, name, default=_unset, untrusted=False):
472 472 """return the plain string version of a config"""
473 473 value = self._config(section, name, default=default,
474 474 untrusted=untrusted)
475 475 if value is _unset:
476 476 return None
477 477 return value
478 478
479 479 def _config(self, section, name, default=_unset, untrusted=False):
480 480 value = itemdefault = default
481 481 item = self._knownconfig.get(section, {}).get(name)
482 482 alternates = [(section, name)]
483 483
484 484 if item is not None:
485 485 alternates.extend(item.alias)
486 486 if callable(item.default):
487 487 itemdefault = item.default()
488 488 else:
489 489 itemdefault = item.default
490 490 else:
491 491 msg = ("accessing unregistered config item: '%s.%s'")
492 492 msg %= (section, name)
493 493 self.develwarn(msg, 2, 'warn-config-unknown')
494 494
495 495 if default is _unset:
496 496 if item is None:
497 497 value = default
498 498 elif item.default is configitems.dynamicdefault:
499 499 value = None
500 500 msg = "config item requires an explicit default value: '%s.%s'"
501 501 msg %= (section, name)
502 502 self.develwarn(msg, 2, 'warn-config-default')
503 503 else:
504 504 value = itemdefault
505 505 elif (item is not None
506 506 and item.default is not configitems.dynamicdefault
507 507 and default != itemdefault):
508 508 msg = ("specifying a mismatched default value for a registered "
509 509 "config item: '%s.%s' '%s'")
510 510 msg %= (section, name, pycompat.bytestr(default))
511 511 self.develwarn(msg, 2, 'warn-config-default')
512 512
513 513 for s, n in alternates:
514 514 candidate = self._data(untrusted).get(s, n, None)
515 515 if candidate is not None:
516 516 value = candidate
517 517 section = s
518 518 name = n
519 519 break
520 520
521 521 if self.debugflag and not untrusted and self._reportuntrusted:
522 522 for s, n in alternates:
523 523 uvalue = self._ucfg.get(s, n)
524 524 if uvalue is not None and uvalue != value:
525 525 self.debug("ignoring untrusted configuration option "
526 526 "%s.%s = %s\n" % (s, n, uvalue))
527 527 return value
528 528
529 529 def configsuboptions(self, section, name, default=_unset, untrusted=False):
530 530 """Get a config option and all sub-options.
531 531
532 532 Some config options have sub-options that are declared with the
533 533 format "key:opt = value". This method is used to return the main
534 534 option and all its declared sub-options.
535 535
536 536 Returns a 2-tuple of ``(option, sub-options)``, where `sub-options``
537 537 is a dict of defined sub-options where keys and values are strings.
538 538 """
539 539 main = self.config(section, name, default, untrusted=untrusted)
540 540 data = self._data(untrusted)
541 541 sub = {}
542 542 prefix = '%s:' % name
543 543 for k, v in data.items(section):
544 544 if k.startswith(prefix):
545 545 sub[k[len(prefix):]] = v
546 546
547 547 if self.debugflag and not untrusted and self._reportuntrusted:
548 548 for k, v in sub.items():
549 549 uvalue = self._ucfg.get(section, '%s:%s' % (name, k))
550 550 if uvalue is not None and uvalue != v:
551 551 self.debug('ignoring untrusted configuration option '
552 552 '%s:%s.%s = %s\n' % (section, name, k, uvalue))
553 553
554 554 return main, sub
555 555
556 556 def configpath(self, section, name, default=_unset, untrusted=False):
557 557 'get a path config item, expanded relative to repo root or config file'
558 558 v = self.config(section, name, default, untrusted)
559 559 if v is None:
560 560 return None
561 561 if not os.path.isabs(v) or "://" not in v:
562 562 src = self.configsource(section, name, untrusted)
563 563 if ':' in src:
564 564 base = os.path.dirname(src.rsplit(':')[0])
565 565 v = os.path.join(base, os.path.expanduser(v))
566 566 return v
567 567
568 568 def configbool(self, section, name, default=_unset, untrusted=False):
569 569 """parse a configuration element as a boolean
570 570
571 571 >>> u = ui(); s = b'foo'
572 572 >>> u.setconfig(s, b'true', b'yes')
573 573 >>> u.configbool(s, b'true')
574 574 True
575 575 >>> u.setconfig(s, b'false', b'no')
576 576 >>> u.configbool(s, b'false')
577 577 False
578 578 >>> u.configbool(s, b'unknown')
579 579 False
580 580 >>> u.configbool(s, b'unknown', True)
581 581 True
582 582 >>> u.setconfig(s, b'invalid', b'somevalue')
583 583 >>> u.configbool(s, b'invalid')
584 584 Traceback (most recent call last):
585 585 ...
586 586 ConfigError: foo.invalid is not a boolean ('somevalue')
587 587 """
588 588
589 589 v = self._config(section, name, default, untrusted=untrusted)
590 590 if v is None:
591 591 return v
592 592 if v is _unset:
593 593 if default is _unset:
594 594 return False
595 595 return default
596 596 if isinstance(v, bool):
597 597 return v
598 598 b = stringutil.parsebool(v)
599 599 if b is None:
600 600 raise error.ConfigError(_("%s.%s is not a boolean ('%s')")
601 601 % (section, name, v))
602 602 return b
603 603
604 604 def configwith(self, convert, section, name, default=_unset,
605 605 desc=None, untrusted=False):
606 606 """parse a configuration element with a conversion function
607 607
608 608 >>> u = ui(); s = b'foo'
609 609 >>> u.setconfig(s, b'float1', b'42')
610 610 >>> u.configwith(float, s, b'float1')
611 611 42.0
612 612 >>> u.setconfig(s, b'float2', b'-4.25')
613 613 >>> u.configwith(float, s, b'float2')
614 614 -4.25
615 615 >>> u.configwith(float, s, b'unknown', 7)
616 616 7.0
617 617 >>> u.setconfig(s, b'invalid', b'somevalue')
618 618 >>> u.configwith(float, s, b'invalid')
619 619 Traceback (most recent call last):
620 620 ...
621 621 ConfigError: foo.invalid is not a valid float ('somevalue')
622 622 >>> u.configwith(float, s, b'invalid', desc=b'womble')
623 623 Traceback (most recent call last):
624 624 ...
625 625 ConfigError: foo.invalid is not a valid womble ('somevalue')
626 626 """
627 627
628 628 v = self.config(section, name, default, untrusted)
629 629 if v is None:
630 630 return v # do not attempt to convert None
631 631 try:
632 632 return convert(v)
633 633 except (ValueError, error.ParseError):
634 634 if desc is None:
635 635 desc = pycompat.sysbytes(convert.__name__)
636 636 raise error.ConfigError(_("%s.%s is not a valid %s ('%s')")
637 637 % (section, name, desc, v))
638 638
639 639 def configint(self, section, name, default=_unset, untrusted=False):
640 640 """parse a configuration element as an integer
641 641
642 642 >>> u = ui(); s = b'foo'
643 643 >>> u.setconfig(s, b'int1', b'42')
644 644 >>> u.configint(s, b'int1')
645 645 42
646 646 >>> u.setconfig(s, b'int2', b'-42')
647 647 >>> u.configint(s, b'int2')
648 648 -42
649 649 >>> u.configint(s, b'unknown', 7)
650 650 7
651 651 >>> u.setconfig(s, b'invalid', b'somevalue')
652 652 >>> u.configint(s, b'invalid')
653 653 Traceback (most recent call last):
654 654 ...
655 655 ConfigError: foo.invalid is not a valid integer ('somevalue')
656 656 """
657 657
658 658 return self.configwith(int, section, name, default, 'integer',
659 659 untrusted)
660 660
661 661 def configbytes(self, section, name, default=_unset, untrusted=False):
662 662 """parse a configuration element as a quantity in bytes
663 663
664 664 Units can be specified as b (bytes), k or kb (kilobytes), m or
665 665 mb (megabytes), g or gb (gigabytes).
666 666
667 667 >>> u = ui(); s = b'foo'
668 668 >>> u.setconfig(s, b'val1', b'42')
669 669 >>> u.configbytes(s, b'val1')
670 670 42
671 671 >>> u.setconfig(s, b'val2', b'42.5 kb')
672 672 >>> u.configbytes(s, b'val2')
673 673 43520
674 674 >>> u.configbytes(s, b'unknown', b'7 MB')
675 675 7340032
676 676 >>> u.setconfig(s, b'invalid', b'somevalue')
677 677 >>> u.configbytes(s, b'invalid')
678 678 Traceback (most recent call last):
679 679 ...
680 680 ConfigError: foo.invalid is not a byte quantity ('somevalue')
681 681 """
682 682
683 683 value = self._config(section, name, default, untrusted)
684 684 if value is _unset:
685 685 if default is _unset:
686 686 default = 0
687 687 value = default
688 688 if not isinstance(value, bytes):
689 689 return value
690 690 try:
691 691 return util.sizetoint(value)
692 692 except error.ParseError:
693 693 raise error.ConfigError(_("%s.%s is not a byte quantity ('%s')")
694 694 % (section, name, value))
695 695
696 696 def configlist(self, section, name, default=_unset, untrusted=False):
697 697 """parse a configuration element as a list of comma/space separated
698 698 strings
699 699
700 700 >>> u = ui(); s = b'foo'
701 701 >>> u.setconfig(s, b'list1', b'this,is "a small" ,test')
702 702 >>> u.configlist(s, b'list1')
703 703 ['this', 'is', 'a small', 'test']
704 704 >>> u.setconfig(s, b'list2', b'this, is "a small" , test ')
705 705 >>> u.configlist(s, b'list2')
706 706 ['this', 'is', 'a small', 'test']
707 707 """
708 708 # default is not always a list
709 709 v = self.configwith(config.parselist, section, name, default,
710 710 'list', untrusted)
711 711 if isinstance(v, bytes):
712 712 return config.parselist(v)
713 713 elif v is None:
714 714 return []
715 715 return v
716 716
717 717 def configdate(self, section, name, default=_unset, untrusted=False):
718 718 """parse a configuration element as a tuple of ints
719 719
720 720 >>> u = ui(); s = b'foo'
721 721 >>> u.setconfig(s, b'date', b'0 0')
722 722 >>> u.configdate(s, b'date')
723 723 (0, 0)
724 724 """
725 725 if self.config(section, name, default, untrusted):
726 726 return self.configwith(dateutil.parsedate, section, name, default,
727 727 'date', untrusted)
728 728 if default is _unset:
729 729 return None
730 730 return default
731 731
732 732 def hasconfig(self, section, name, untrusted=False):
733 733 return self._data(untrusted).hasitem(section, name)
734 734
735 735 def has_section(self, section, untrusted=False):
736 736 '''tell whether section exists in config.'''
737 737 return section in self._data(untrusted)
738 738
739 739 def configitems(self, section, untrusted=False, ignoresub=False):
740 740 items = self._data(untrusted).items(section)
741 741 if ignoresub:
742 newitems = {}
743 for k, v in items:
744 if ':' not in k:
745 newitems[k] = v
746 items = list(newitems.iteritems())
742 items = [i for i in items if ':' not in i[0]]
747 743 if self.debugflag and not untrusted and self._reportuntrusted:
748 744 for k, v in self._ucfg.items(section):
749 745 if self._tcfg.get(section, k) != v:
750 746 self.debug("ignoring untrusted configuration option "
751 747 "%s.%s = %s\n" % (section, k, v))
752 748 return items
753 749
754 750 def walkconfig(self, untrusted=False):
755 751 cfg = self._data(untrusted)
756 752 for section in cfg.sections():
757 753 for name, value in self.configitems(section, untrusted):
758 754 yield section, name, value
759 755
760 756 def plain(self, feature=None):
761 757 '''is plain mode active?
762 758
763 759 Plain mode means that all configuration variables which affect
764 760 the behavior and output of Mercurial should be
765 761 ignored. Additionally, the output should be stable,
766 762 reproducible and suitable for use in scripts or applications.
767 763
768 764 The only way to trigger plain mode is by setting either the
769 765 `HGPLAIN' or `HGPLAINEXCEPT' environment variables.
770 766
771 767 The return value can either be
772 768 - False if HGPLAIN is not set, or feature is in HGPLAINEXCEPT
773 769 - False if feature is disabled by default and not included in HGPLAIN
774 770 - True otherwise
775 771 '''
776 772 if ('HGPLAIN' not in encoding.environ and
777 773 'HGPLAINEXCEPT' not in encoding.environ):
778 774 return False
779 775 exceptions = encoding.environ.get('HGPLAINEXCEPT',
780 776 '').strip().split(',')
781 777 # TODO: add support for HGPLAIN=+feature,-feature syntax
782 778 if '+strictflags' not in encoding.environ.get('HGPLAIN', '').split(','):
783 779 exceptions.append('strictflags')
784 780 if feature and exceptions:
785 781 return feature not in exceptions
786 782 return True
787 783
788 784 def username(self, acceptempty=False):
789 785 """Return default username to be used in commits.
790 786
791 787 Searched in this order: $HGUSER, [ui] section of hgrcs, $EMAIL
792 788 and stop searching if one of these is set.
793 789 If not found and acceptempty is True, returns None.
794 790 If not found and ui.askusername is True, ask the user, else use
795 791 ($LOGNAME or $USER or $LNAME or $USERNAME) + "@full.hostname".
796 792 If no username could be found, raise an Abort error.
797 793 """
798 794 user = encoding.environ.get("HGUSER")
799 795 if user is None:
800 796 user = self.config("ui", "username")
801 797 if user is not None:
802 798 user = os.path.expandvars(user)
803 799 if user is None:
804 800 user = encoding.environ.get("EMAIL")
805 801 if user is None and acceptempty:
806 802 return user
807 803 if user is None and self.configbool("ui", "askusername"):
808 804 user = self.prompt(_("enter a commit username:"), default=None)
809 805 if user is None and not self.interactive():
810 806 try:
811 807 user = '%s@%s' % (procutil.getuser(),
812 808 encoding.strtolocal(socket.getfqdn()))
813 809 self.warn(_("no username found, using '%s' instead\n") % user)
814 810 except KeyError:
815 811 pass
816 812 if not user:
817 813 raise error.Abort(_('no username supplied'),
818 814 hint=_("use 'hg config --edit' "
819 815 'to set your username'))
820 816 if "\n" in user:
821 817 raise error.Abort(_("username %r contains a newline\n")
822 818 % pycompat.bytestr(user))
823 819 return user
824 820
825 821 def shortuser(self, user):
826 822 """Return a short representation of a user name or email address."""
827 823 if not self.verbose:
828 824 user = stringutil.shortuser(user)
829 825 return user
830 826
831 827 def expandpath(self, loc, default=None):
832 828 """Return repository location relative to cwd or from [paths]"""
833 829 try:
834 830 p = self.paths.getpath(loc)
835 831 if p:
836 832 return p.rawloc
837 833 except error.RepoError:
838 834 pass
839 835
840 836 if default:
841 837 try:
842 838 p = self.paths.getpath(default)
843 839 if p:
844 840 return p.rawloc
845 841 except error.RepoError:
846 842 pass
847 843
848 844 return loc
849 845
850 846 @util.propertycache
851 847 def paths(self):
852 848 return paths(self)
853 849
854 850 def pushbuffer(self, error=False, subproc=False, labeled=False):
855 851 """install a buffer to capture standard output of the ui object
856 852
857 853 If error is True, the error output will be captured too.
858 854
859 855 If subproc is True, output from subprocesses (typically hooks) will be
860 856 captured too.
861 857
862 858 If labeled is True, any labels associated with buffered
863 859 output will be handled. By default, this has no effect
864 860 on the output returned, but extensions and GUI tools may
865 861 handle this argument and returned styled output. If output
866 862 is being buffered so it can be captured and parsed or
867 863 processed, labeled should not be set to True.
868 864 """
869 865 self._buffers.append([])
870 866 self._bufferstates.append((error, subproc, labeled))
871 867 self._bufferapplylabels = labeled
872 868
873 869 def popbuffer(self):
874 870 '''pop the last buffer and return the buffered output'''
875 871 self._bufferstates.pop()
876 872 if self._bufferstates:
877 873 self._bufferapplylabels = self._bufferstates[-1][2]
878 874 else:
879 875 self._bufferapplylabels = None
880 876
881 877 return "".join(self._buffers.pop())
882 878
883 879 def canwritewithoutlabels(self):
884 880 '''check if write skips the label'''
885 881 if self._buffers and not self._bufferapplylabels:
886 882 return True
887 883 return self._colormode is None
888 884
889 885 def canbatchlabeledwrites(self):
890 886 '''check if write calls with labels are batchable'''
891 887 # Windows color printing is special, see ``write``.
892 888 return self._colormode != 'win32'
893 889
894 890 def write(self, *args, **opts):
895 891 '''write args to output
896 892
897 893 By default, this method simply writes to the buffer or stdout.
898 894 Color mode can be set on the UI class to have the output decorated
899 895 with color modifier before being written to stdout.
900 896
901 897 The color used is controlled by an optional keyword argument, "label".
902 898 This should be a string containing label names separated by space.
903 899 Label names take the form of "topic.type". For example, ui.debug()
904 900 issues a label of "ui.debug".
905 901
906 902 When labeling output for a specific command, a label of
907 903 "cmdname.type" is recommended. For example, status issues
908 904 a label of "status.modified" for modified files.
909 905 '''
910 906 if self._buffers:
911 907 if self._bufferapplylabels:
912 908 label = opts.get(r'label', '')
913 909 self._buffers[-1].extend(self.label(a, label) for a in args)
914 910 else:
915 911 self._buffers[-1].extend(args)
916 912 else:
917 913 self._writenobuf(*args, **opts)
918 914
919 915 def _writenobuf(self, *args, **opts):
920 916 if self._colormode == 'win32':
921 917 # windows color printing is its own can of crab, defer to
922 918 # the color module and that is it.
923 919 color.win32print(self, self._write, *args, **opts)
924 920 else:
925 921 msgs = args
926 922 if self._colormode is not None:
927 923 label = opts.get(r'label', '')
928 924 msgs = [self.label(a, label) for a in args]
929 925 self._write(*msgs, **opts)
930 926
931 927 def _write(self, *msgs, **opts):
932 928 self._progclear()
933 929 # opencode timeblockedsection because this is a critical path
934 930 starttime = util.timer()
935 931 try:
936 932 self.fout.write(''.join(msgs))
937 933 except IOError as err:
938 934 raise error.StdioError(err)
939 935 finally:
940 936 self._blockedtimes['stdio_blocked'] += \
941 937 (util.timer() - starttime) * 1000
942 938
943 939 def write_err(self, *args, **opts):
944 940 self._progclear()
945 941 if self._bufferstates and self._bufferstates[-1][0]:
946 942 self.write(*args, **opts)
947 943 elif self._colormode == 'win32':
948 944 # windows color printing is its own can of crab, defer to
949 945 # the color module and that is it.
950 946 color.win32print(self, self._write_err, *args, **opts)
951 947 else:
952 948 msgs = args
953 949 if self._colormode is not None:
954 950 label = opts.get(r'label', '')
955 951 msgs = [self.label(a, label) for a in args]
956 952 self._write_err(*msgs, **opts)
957 953
958 954 def _write_err(self, *msgs, **opts):
959 955 try:
960 956 with self.timeblockedsection('stdio'):
961 957 if not getattr(self.fout, 'closed', False):
962 958 self.fout.flush()
963 959 for a in msgs:
964 960 self.ferr.write(a)
965 961 # stderr may be buffered under win32 when redirected to files,
966 962 # including stdout.
967 963 if not getattr(self.ferr, 'closed', False):
968 964 self.ferr.flush()
969 965 except IOError as inst:
970 966 if inst.errno not in (errno.EPIPE, errno.EIO, errno.EBADF):
971 967 raise error.StdioError(inst)
972 968
973 969 def flush(self):
974 970 # opencode timeblockedsection because this is a critical path
975 971 starttime = util.timer()
976 972 try:
977 973 try:
978 974 self.fout.flush()
979 975 except IOError as err:
980 976 if err.errno not in (errno.EPIPE, errno.EIO, errno.EBADF):
981 977 raise error.StdioError(err)
982 978 finally:
983 979 try:
984 980 self.ferr.flush()
985 981 except IOError as err:
986 982 if err.errno not in (errno.EPIPE, errno.EIO, errno.EBADF):
987 983 raise error.StdioError(err)
988 984 finally:
989 985 self._blockedtimes['stdio_blocked'] += \
990 986 (util.timer() - starttime) * 1000
991 987
992 988 def _isatty(self, fh):
993 989 if self.configbool('ui', 'nontty'):
994 990 return False
995 991 return procutil.isatty(fh)
996 992
997 993 def disablepager(self):
998 994 self._disablepager = True
999 995
1000 996 def pager(self, command):
1001 997 """Start a pager for subsequent command output.
1002 998
1003 999 Commands which produce a long stream of output should call
1004 1000 this function to activate the user's preferred pagination
1005 1001 mechanism (which may be no pager). Calling this function
1006 1002 precludes any future use of interactive functionality, such as
1007 1003 prompting the user or activating curses.
1008 1004
1009 1005 Args:
1010 1006 command: The full, non-aliased name of the command. That is, "log"
1011 1007 not "history, "summary" not "summ", etc.
1012 1008 """
1013 1009 if (self._disablepager
1014 1010 or self.pageractive):
1015 1011 # how pager should do is already determined
1016 1012 return
1017 1013
1018 1014 if not command.startswith('internal-always-') and (
1019 1015 # explicit --pager=on (= 'internal-always-' prefix) should
1020 1016 # take precedence over disabling factors below
1021 1017 command in self.configlist('pager', 'ignore')
1022 1018 or not self.configbool('ui', 'paginate')
1023 1019 or not self.configbool('pager', 'attend-' + command, True)
1024 1020 # TODO: if we want to allow HGPLAINEXCEPT=pager,
1025 1021 # formatted() will need some adjustment.
1026 1022 or not self.formatted()
1027 1023 or self.plain()
1028 1024 or self._buffers
1029 1025 # TODO: expose debugger-enabled on the UI object
1030 1026 or '--debugger' in pycompat.sysargv):
1031 1027 # We only want to paginate if the ui appears to be
1032 1028 # interactive, the user didn't say HGPLAIN or
1033 1029 # HGPLAINEXCEPT=pager, and the user didn't specify --debug.
1034 1030 return
1035 1031
1036 1032 pagercmd = self.config('pager', 'pager', rcutil.fallbackpager)
1037 1033 if not pagercmd:
1038 1034 return
1039 1035
1040 1036 pagerenv = {}
1041 1037 for name, value in rcutil.defaultpagerenv().items():
1042 1038 if name not in encoding.environ:
1043 1039 pagerenv[name] = value
1044 1040
1045 1041 self.debug('starting pager for command %r\n' % command)
1046 1042 self.flush()
1047 1043
1048 1044 wasformatted = self.formatted()
1049 1045 if util.safehasattr(signal, "SIGPIPE"):
1050 1046 signal.signal(signal.SIGPIPE, _catchterm)
1051 1047 if self._runpager(pagercmd, pagerenv):
1052 1048 self.pageractive = True
1053 1049 # Preserve the formatted-ness of the UI. This is important
1054 1050 # because we mess with stdout, which might confuse
1055 1051 # auto-detection of things being formatted.
1056 1052 self.setconfig('ui', 'formatted', wasformatted, 'pager')
1057 1053 self.setconfig('ui', 'interactive', False, 'pager')
1058 1054
1059 1055 # If pagermode differs from color.mode, reconfigure color now that
1060 1056 # pageractive is set.
1061 1057 cm = self._colormode
1062 1058 if cm != self.config('color', 'pagermode', cm):
1063 1059 color.setup(self)
1064 1060 else:
1065 1061 # If the pager can't be spawned in dispatch when --pager=on is
1066 1062 # given, don't try again when the command runs, to avoid a duplicate
1067 1063 # warning about a missing pager command.
1068 1064 self.disablepager()
1069 1065
1070 1066 def _runpager(self, command, env=None):
1071 1067 """Actually start the pager and set up file descriptors.
1072 1068
1073 1069 This is separate in part so that extensions (like chg) can
1074 1070 override how a pager is invoked.
1075 1071 """
1076 1072 if command == 'cat':
1077 1073 # Save ourselves some work.
1078 1074 return False
1079 1075 # If the command doesn't contain any of these characters, we
1080 1076 # assume it's a binary and exec it directly. This means for
1081 1077 # simple pager command configurations, we can degrade
1082 1078 # gracefully and tell the user about their broken pager.
1083 1079 shell = any(c in command for c in "|&;<>()$`\\\"' \t\n*?[#~=%")
1084 1080
1085 1081 if pycompat.iswindows and not shell:
1086 1082 # Window's built-in `more` cannot be invoked with shell=False, but
1087 1083 # its `more.com` can. Hide this implementation detail from the
1088 1084 # user so we can also get sane bad PAGER behavior. MSYS has
1089 1085 # `more.exe`, so do a cmd.exe style resolution of the executable to
1090 1086 # determine which one to use.
1091 1087 fullcmd = procutil.findexe(command)
1092 1088 if not fullcmd:
1093 1089 self.warn(_("missing pager command '%s', skipping pager\n")
1094 1090 % command)
1095 1091 return False
1096 1092
1097 1093 command = fullcmd
1098 1094
1099 1095 try:
1100 1096 pager = subprocess.Popen(
1101 1097 command, shell=shell, bufsize=-1,
1102 1098 close_fds=procutil.closefds, stdin=subprocess.PIPE,
1103 1099 stdout=procutil.stdout, stderr=procutil.stderr,
1104 1100 env=procutil.shellenviron(env))
1105 1101 except OSError as e:
1106 1102 if e.errno == errno.ENOENT and not shell:
1107 1103 self.warn(_("missing pager command '%s', skipping pager\n")
1108 1104 % command)
1109 1105 return False
1110 1106 raise
1111 1107
1112 1108 # back up original file descriptors
1113 1109 stdoutfd = os.dup(procutil.stdout.fileno())
1114 1110 stderrfd = os.dup(procutil.stderr.fileno())
1115 1111
1116 1112 os.dup2(pager.stdin.fileno(), procutil.stdout.fileno())
1117 1113 if self._isatty(procutil.stderr):
1118 1114 os.dup2(pager.stdin.fileno(), procutil.stderr.fileno())
1119 1115
1120 1116 @self.atexit
1121 1117 def killpager():
1122 1118 if util.safehasattr(signal, "SIGINT"):
1123 1119 signal.signal(signal.SIGINT, signal.SIG_IGN)
1124 1120 # restore original fds, closing pager.stdin copies in the process
1125 1121 os.dup2(stdoutfd, procutil.stdout.fileno())
1126 1122 os.dup2(stderrfd, procutil.stderr.fileno())
1127 1123 pager.stdin.close()
1128 1124 pager.wait()
1129 1125
1130 1126 return True
1131 1127
1132 1128 @property
1133 1129 def _exithandlers(self):
1134 1130 return _reqexithandlers
1135 1131
1136 1132 def atexit(self, func, *args, **kwargs):
1137 1133 '''register a function to run after dispatching a request
1138 1134
1139 1135 Handlers do not stay registered across request boundaries.'''
1140 1136 self._exithandlers.append((func, args, kwargs))
1141 1137 return func
1142 1138
1143 1139 def interface(self, feature):
1144 1140 """what interface to use for interactive console features?
1145 1141
1146 1142 The interface is controlled by the value of `ui.interface` but also by
1147 1143 the value of feature-specific configuration. For example:
1148 1144
1149 1145 ui.interface.histedit = text
1150 1146 ui.interface.chunkselector = curses
1151 1147
1152 1148 Here the features are "histedit" and "chunkselector".
1153 1149
1154 1150 The configuration above means that the default interfaces for commands
1155 1151 is curses, the interface for histedit is text and the interface for
1156 1152 selecting chunk is crecord (the best curses interface available).
1157 1153
1158 1154 Consider the following example:
1159 1155 ui.interface = curses
1160 1156 ui.interface.histedit = text
1161 1157
1162 1158 Then histedit will use the text interface and chunkselector will use
1163 1159 the default curses interface (crecord at the moment).
1164 1160 """
1165 1161 alldefaults = frozenset(["text", "curses"])
1166 1162
1167 1163 featureinterfaces = {
1168 1164 "chunkselector": [
1169 1165 "text",
1170 1166 "curses",
1171 1167 ]
1172 1168 }
1173 1169
1174 1170 # Feature-specific interface
1175 1171 if feature not in featureinterfaces.keys():
1176 1172 # Programming error, not user error
1177 1173 raise ValueError("Unknown feature requested %s" % feature)
1178 1174
1179 1175 availableinterfaces = frozenset(featureinterfaces[feature])
1180 1176 if alldefaults > availableinterfaces:
1181 1177 # Programming error, not user error. We need a use case to
1182 1178 # define the right thing to do here.
1183 1179 raise ValueError(
1184 1180 "Feature %s does not handle all default interfaces" %
1185 1181 feature)
1186 1182
1187 1183 if self.plain():
1188 1184 return "text"
1189 1185
1190 1186 # Default interface for all the features
1191 1187 defaultinterface = "text"
1192 1188 i = self.config("ui", "interface")
1193 1189 if i in alldefaults:
1194 1190 defaultinterface = i
1195 1191
1196 1192 choseninterface = defaultinterface
1197 1193 f = self.config("ui", "interface.%s" % feature)
1198 1194 if f in availableinterfaces:
1199 1195 choseninterface = f
1200 1196
1201 1197 if i is not None and defaultinterface != i:
1202 1198 if f is not None:
1203 1199 self.warn(_("invalid value for ui.interface: %s\n") %
1204 1200 (i,))
1205 1201 else:
1206 1202 self.warn(_("invalid value for ui.interface: %s (using %s)\n") %
1207 1203 (i, choseninterface))
1208 1204 if f is not None and choseninterface != f:
1209 1205 self.warn(_("invalid value for ui.interface.%s: %s (using %s)\n") %
1210 1206 (feature, f, choseninterface))
1211 1207
1212 1208 return choseninterface
1213 1209
1214 1210 def interactive(self):
1215 1211 '''is interactive input allowed?
1216 1212
1217 1213 An interactive session is a session where input can be reasonably read
1218 1214 from `sys.stdin'. If this function returns false, any attempt to read
1219 1215 from stdin should fail with an error, unless a sensible default has been
1220 1216 specified.
1221 1217
1222 1218 Interactiveness is triggered by the value of the `ui.interactive'
1223 1219 configuration variable or - if it is unset - when `sys.stdin' points
1224 1220 to a terminal device.
1225 1221
1226 1222 This function refers to input only; for output, see `ui.formatted()'.
1227 1223 '''
1228 1224 i = self.configbool("ui", "interactive")
1229 1225 if i is None:
1230 1226 # some environments replace stdin without implementing isatty
1231 1227 # usually those are non-interactive
1232 1228 return self._isatty(self.fin)
1233 1229
1234 1230 return i
1235 1231
1236 1232 def termwidth(self):
1237 1233 '''how wide is the terminal in columns?
1238 1234 '''
1239 1235 if 'COLUMNS' in encoding.environ:
1240 1236 try:
1241 1237 return int(encoding.environ['COLUMNS'])
1242 1238 except ValueError:
1243 1239 pass
1244 1240 return scmutil.termsize(self)[0]
1245 1241
1246 1242 def formatted(self):
1247 1243 '''should formatted output be used?
1248 1244
1249 1245 It is often desirable to format the output to suite the output medium.
1250 1246 Examples of this are truncating long lines or colorizing messages.
1251 1247 However, this is not often not desirable when piping output into other
1252 1248 utilities, e.g. `grep'.
1253 1249
1254 1250 Formatted output is triggered by the value of the `ui.formatted'
1255 1251 configuration variable or - if it is unset - when `sys.stdout' points
1256 1252 to a terminal device. Please note that `ui.formatted' should be
1257 1253 considered an implementation detail; it is not intended for use outside
1258 1254 Mercurial or its extensions.
1259 1255
1260 1256 This function refers to output only; for input, see `ui.interactive()'.
1261 1257 This function always returns false when in plain mode, see `ui.plain()'.
1262 1258 '''
1263 1259 if self.plain():
1264 1260 return False
1265 1261
1266 1262 i = self.configbool("ui", "formatted")
1267 1263 if i is None:
1268 1264 # some environments replace stdout without implementing isatty
1269 1265 # usually those are non-interactive
1270 1266 return self._isatty(self.fout)
1271 1267
1272 1268 return i
1273 1269
1274 1270 def _readline(self):
1275 1271 # Replacing stdin/stdout temporarily is a hard problem on Python 3
1276 1272 # because they have to be text streams with *no buffering*. Instead,
1277 1273 # we use rawinput() only if call_readline() will be invoked by
1278 1274 # PyOS_Readline(), so no I/O will be made at Python layer.
1279 1275 usereadline = (self._isatty(self.fin) and self._isatty(self.fout)
1280 1276 and procutil.isstdin(self.fin)
1281 1277 and procutil.isstdout(self.fout))
1282 1278 if usereadline:
1283 1279 try:
1284 1280 # magically add command line editing support, where
1285 1281 # available
1286 1282 import readline
1287 1283 # force demandimport to really load the module
1288 1284 readline.read_history_file
1289 1285 # windows sometimes raises something other than ImportError
1290 1286 except Exception:
1291 1287 usereadline = False
1292 1288
1293 1289 # prompt ' ' must exist; otherwise readline may delete entire line
1294 1290 # - http://bugs.python.org/issue12833
1295 1291 with self.timeblockedsection('stdio'):
1296 1292 if usereadline:
1297 1293 line = encoding.strtolocal(pycompat.rawinput(r' '))
1298 1294 # When stdin is in binary mode on Windows, it can cause
1299 1295 # raw_input() to emit an extra trailing carriage return
1300 1296 if pycompat.oslinesep == b'\r\n' and line.endswith(b'\r'):
1301 1297 line = line[:-1]
1302 1298 else:
1303 1299 self.fout.write(b' ')
1304 1300 self.fout.flush()
1305 1301 line = self.fin.readline()
1306 1302 if not line:
1307 1303 raise EOFError
1308 1304 line = line.rstrip(pycompat.oslinesep)
1309 1305
1310 1306 return line
1311 1307
1312 1308 def prompt(self, msg, default="y"):
1313 1309 """Prompt user with msg, read response.
1314 1310 If ui is not interactive, the default is returned.
1315 1311 """
1316 1312 if not self.interactive():
1317 1313 self.write(msg, ' ', default or '', "\n")
1318 1314 return default
1319 1315 self._writenobuf(msg, label='ui.prompt')
1320 1316 self.flush()
1321 1317 try:
1322 1318 r = self._readline()
1323 1319 if not r:
1324 1320 r = default
1325 1321 if self.configbool('ui', 'promptecho'):
1326 1322 self.write(r, "\n")
1327 1323 return r
1328 1324 except EOFError:
1329 1325 raise error.ResponseExpected()
1330 1326
1331 1327 @staticmethod
1332 1328 def extractchoices(prompt):
1333 1329 """Extract prompt message and list of choices from specified prompt.
1334 1330
1335 1331 This returns tuple "(message, choices)", and "choices" is the
1336 1332 list of tuple "(response character, text without &)".
1337 1333
1338 1334 >>> ui.extractchoices(b"awake? $$ &Yes $$ &No")
1339 1335 ('awake? ', [('y', 'Yes'), ('n', 'No')])
1340 1336 >>> ui.extractchoices(b"line\\nbreak? $$ &Yes $$ &No")
1341 1337 ('line\\nbreak? ', [('y', 'Yes'), ('n', 'No')])
1342 1338 >>> ui.extractchoices(b"want lots of $$money$$?$$Ye&s$$N&o")
1343 1339 ('want lots of $$money$$?', [('s', 'Yes'), ('o', 'No')])
1344 1340 """
1345 1341
1346 1342 # Sadly, the prompt string may have been built with a filename
1347 1343 # containing "$$" so let's try to find the first valid-looking
1348 1344 # prompt to start parsing. Sadly, we also can't rely on
1349 1345 # choices containing spaces, ASCII, or basically anything
1350 1346 # except an ampersand followed by a character.
1351 1347 m = re.match(br'(?s)(.+?)\$\$([^\$]*&[^ \$].*)', prompt)
1352 1348 msg = m.group(1)
1353 1349 choices = [p.strip(' ') for p in m.group(2).split('$$')]
1354 1350 def choicetuple(s):
1355 1351 ampidx = s.index('&')
1356 1352 return s[ampidx + 1:ampidx + 2].lower(), s.replace('&', '', 1)
1357 1353 return (msg, [choicetuple(s) for s in choices])
1358 1354
1359 1355 def promptchoice(self, prompt, default=0):
1360 1356 """Prompt user with a message, read response, and ensure it matches
1361 1357 one of the provided choices. The prompt is formatted as follows:
1362 1358
1363 1359 "would you like fries with that (Yn)? $$ &Yes $$ &No"
1364 1360
1365 1361 The index of the choice is returned. Responses are case
1366 1362 insensitive. If ui is not interactive, the default is
1367 1363 returned.
1368 1364 """
1369 1365
1370 1366 msg, choices = self.extractchoices(prompt)
1371 1367 resps = [r for r, t in choices]
1372 1368 while True:
1373 1369 r = self.prompt(msg, resps[default])
1374 1370 if r.lower() in resps:
1375 1371 return resps.index(r.lower())
1376 1372 self.write(_("unrecognized response\n"))
1377 1373
1378 1374 def getpass(self, prompt=None, default=None):
1379 1375 if not self.interactive():
1380 1376 return default
1381 1377 try:
1382 1378 self.write_err(self.label(prompt or _('password: '), 'ui.prompt'))
1383 1379 # disable getpass() only if explicitly specified. it's still valid
1384 1380 # to interact with tty even if fin is not a tty.
1385 1381 with self.timeblockedsection('stdio'):
1386 1382 if self.configbool('ui', 'nontty'):
1387 1383 l = self.fin.readline()
1388 1384 if not l:
1389 1385 raise EOFError
1390 1386 return l.rstrip('\n')
1391 1387 else:
1392 1388 return getpass.getpass('')
1393 1389 except EOFError:
1394 1390 raise error.ResponseExpected()
1395 1391 def status(self, *msg, **opts):
1396 1392 '''write status message to output (if ui.quiet is False)
1397 1393
1398 1394 This adds an output label of "ui.status".
1399 1395 '''
1400 1396 if not self.quiet:
1401 1397 opts[r'label'] = opts.get(r'label', '') + ' ui.status'
1402 1398 self.write(*msg, **opts)
1403 1399 def warn(self, *msg, **opts):
1404 1400 '''write warning message to output (stderr)
1405 1401
1406 1402 This adds an output label of "ui.warning".
1407 1403 '''
1408 1404 opts[r'label'] = opts.get(r'label', '') + ' ui.warning'
1409 1405 self.write_err(*msg, **opts)
1410 1406 def note(self, *msg, **opts):
1411 1407 '''write note to output (if ui.verbose is True)
1412 1408
1413 1409 This adds an output label of "ui.note".
1414 1410 '''
1415 1411 if self.verbose:
1416 1412 opts[r'label'] = opts.get(r'label', '') + ' ui.note'
1417 1413 self.write(*msg, **opts)
1418 1414 def debug(self, *msg, **opts):
1419 1415 '''write debug message to output (if ui.debugflag is True)
1420 1416
1421 1417 This adds an output label of "ui.debug".
1422 1418 '''
1423 1419 if self.debugflag:
1424 1420 opts[r'label'] = opts.get(r'label', '') + ' ui.debug'
1425 1421 self.write(*msg, **opts)
1426 1422
1427 1423 def edit(self, text, user, extra=None, editform=None, pending=None,
1428 1424 repopath=None, action=None):
1429 1425 if action is None:
1430 1426 self.develwarn('action is None but will soon be a required '
1431 1427 'parameter to ui.edit()')
1432 1428 extra_defaults = {
1433 1429 'prefix': 'editor',
1434 1430 'suffix': '.txt',
1435 1431 }
1436 1432 if extra is not None:
1437 1433 if extra.get('suffix') is not None:
1438 1434 self.develwarn('extra.suffix is not None but will soon be '
1439 1435 'ignored by ui.edit()')
1440 1436 extra_defaults.update(extra)
1441 1437 extra = extra_defaults
1442 1438
1443 1439 if action == 'diff':
1444 1440 suffix = '.diff'
1445 1441 elif action:
1446 1442 suffix = '.%s.hg.txt' % action
1447 1443 else:
1448 1444 suffix = extra['suffix']
1449 1445
1450 1446 rdir = None
1451 1447 if self.configbool('experimental', 'editortmpinhg'):
1452 1448 rdir = repopath
1453 1449 (fd, name) = tempfile.mkstemp(prefix='hg-' + extra['prefix'] + '-',
1454 1450 suffix=suffix,
1455 1451 dir=rdir)
1456 1452 try:
1457 1453 f = os.fdopen(fd, r'wb')
1458 1454 f.write(util.tonativeeol(text))
1459 1455 f.close()
1460 1456
1461 1457 environ = {'HGUSER': user}
1462 1458 if 'transplant_source' in extra:
1463 1459 environ.update({'HGREVISION': hex(extra['transplant_source'])})
1464 1460 for label in ('intermediate-source', 'source', 'rebase_source'):
1465 1461 if label in extra:
1466 1462 environ.update({'HGREVISION': extra[label]})
1467 1463 break
1468 1464 if editform:
1469 1465 environ.update({'HGEDITFORM': editform})
1470 1466 if pending:
1471 1467 environ.update({'HG_PENDING': pending})
1472 1468
1473 1469 editor = self.geteditor()
1474 1470
1475 1471 self.system("%s \"%s\"" % (editor, name),
1476 1472 environ=environ,
1477 1473 onerr=error.Abort, errprefix=_("edit failed"),
1478 1474 blockedtag='editor')
1479 1475
1480 1476 f = open(name, r'rb')
1481 1477 t = util.fromnativeeol(f.read())
1482 1478 f.close()
1483 1479 finally:
1484 1480 os.unlink(name)
1485 1481
1486 1482 return t
1487 1483
1488 1484 def system(self, cmd, environ=None, cwd=None, onerr=None, errprefix=None,
1489 1485 blockedtag=None):
1490 1486 '''execute shell command with appropriate output stream. command
1491 1487 output will be redirected if fout is not stdout.
1492 1488
1493 1489 if command fails and onerr is None, return status, else raise onerr
1494 1490 object as exception.
1495 1491 '''
1496 1492 if blockedtag is None:
1497 1493 # Long cmds tend to be because of an absolute path on cmd. Keep
1498 1494 # the tail end instead
1499 1495 cmdsuffix = cmd.translate(None, _keepalnum)[-85:]
1500 1496 blockedtag = 'unknown_system_' + cmdsuffix
1501 1497 out = self.fout
1502 1498 if any(s[1] for s in self._bufferstates):
1503 1499 out = self
1504 1500 with self.timeblockedsection(blockedtag):
1505 1501 rc = self._runsystem(cmd, environ=environ, cwd=cwd, out=out)
1506 1502 if rc and onerr:
1507 1503 errmsg = '%s %s' % (os.path.basename(cmd.split(None, 1)[0]),
1508 1504 procutil.explainexit(rc)[0])
1509 1505 if errprefix:
1510 1506 errmsg = '%s: %s' % (errprefix, errmsg)
1511 1507 raise onerr(errmsg)
1512 1508 return rc
1513 1509
1514 1510 def _runsystem(self, cmd, environ, cwd, out):
1515 1511 """actually execute the given shell command (can be overridden by
1516 1512 extensions like chg)"""
1517 1513 return procutil.system(cmd, environ=environ, cwd=cwd, out=out)
1518 1514
1519 1515 def traceback(self, exc=None, force=False):
1520 1516 '''print exception traceback if traceback printing enabled or forced.
1521 1517 only to call in exception handler. returns true if traceback
1522 1518 printed.'''
1523 1519 if self.tracebackflag or force:
1524 1520 if exc is None:
1525 1521 exc = sys.exc_info()
1526 1522 cause = getattr(exc[1], 'cause', None)
1527 1523
1528 1524 if cause is not None:
1529 1525 causetb = traceback.format_tb(cause[2])
1530 1526 exctb = traceback.format_tb(exc[2])
1531 1527 exconly = traceback.format_exception_only(cause[0], cause[1])
1532 1528
1533 1529 # exclude frame where 'exc' was chained and rethrown from exctb
1534 1530 self.write_err('Traceback (most recent call last):\n',
1535 1531 ''.join(exctb[:-1]),
1536 1532 ''.join(causetb),
1537 1533 ''.join(exconly))
1538 1534 else:
1539 1535 output = traceback.format_exception(exc[0], exc[1], exc[2])
1540 1536 self.write_err(encoding.strtolocal(r''.join(output)))
1541 1537 return self.tracebackflag or force
1542 1538
1543 1539 def geteditor(self):
1544 1540 '''return editor to use'''
1545 1541 if pycompat.sysplatform == 'plan9':
1546 1542 # vi is the MIPS instruction simulator on Plan 9. We
1547 1543 # instead default to E to plumb commit messages to
1548 1544 # avoid confusion.
1549 1545 editor = 'E'
1550 1546 else:
1551 1547 editor = 'vi'
1552 1548 return (encoding.environ.get("HGEDITOR") or
1553 1549 self.config("ui", "editor", editor))
1554 1550
1555 1551 @util.propertycache
1556 1552 def _progbar(self):
1557 1553 """setup the progbar singleton to the ui object"""
1558 1554 if (self.quiet or self.debugflag
1559 1555 or self.configbool('progress', 'disable')
1560 1556 or not progress.shouldprint(self)):
1561 1557 return None
1562 1558 return getprogbar(self)
1563 1559
1564 1560 def _progclear(self):
1565 1561 """clear progress bar output if any. use it before any output"""
1566 1562 if not haveprogbar(): # nothing loaded yet
1567 1563 return
1568 1564 if self._progbar is not None and self._progbar.printed:
1569 1565 self._progbar.clear()
1570 1566
1571 1567 def progress(self, topic, pos, item="", unit="", total=None):
1572 1568 '''show a progress message
1573 1569
1574 1570 By default a textual progress bar will be displayed if an operation
1575 1571 takes too long. 'topic' is the current operation, 'item' is a
1576 1572 non-numeric marker of the current position (i.e. the currently
1577 1573 in-process file), 'pos' is the current numeric position (i.e.
1578 1574 revision, bytes, etc.), unit is a corresponding unit label,
1579 1575 and total is the highest expected pos.
1580 1576
1581 1577 Multiple nested topics may be active at a time.
1582 1578
1583 1579 All topics should be marked closed by setting pos to None at
1584 1580 termination.
1585 1581 '''
1586 1582 if self._progbar is not None:
1587 1583 self._progbar.progress(topic, pos, item=item, unit=unit,
1588 1584 total=total)
1589 1585 if pos is None or not self.configbool('progress', 'debug'):
1590 1586 return
1591 1587
1592 1588 if unit:
1593 1589 unit = ' ' + unit
1594 1590 if item:
1595 1591 item = ' ' + item
1596 1592
1597 1593 if total:
1598 1594 pct = 100.0 * pos / total
1599 1595 self.debug('%s:%s %d/%d%s (%4.2f%%)\n'
1600 1596 % (topic, item, pos, total, unit, pct))
1601 1597 else:
1602 1598 self.debug('%s:%s %d%s\n' % (topic, item, pos, unit))
1603 1599
1604 1600 def log(self, service, *msg, **opts):
1605 1601 '''hook for logging facility extensions
1606 1602
1607 1603 service should be a readily-identifiable subsystem, which will
1608 1604 allow filtering.
1609 1605
1610 1606 *msg should be a newline-terminated format string to log, and
1611 1607 then any values to %-format into that format string.
1612 1608
1613 1609 **opts currently has no defined meanings.
1614 1610 '''
1615 1611
1616 1612 def label(self, msg, label):
1617 1613 '''style msg based on supplied label
1618 1614
1619 1615 If some color mode is enabled, this will add the necessary control
1620 1616 characters to apply such color. In addition, 'debug' color mode adds
1621 1617 markup showing which label affects a piece of text.
1622 1618
1623 1619 ui.write(s, 'label') is equivalent to
1624 1620 ui.write(ui.label(s, 'label')).
1625 1621 '''
1626 1622 if self._colormode is not None:
1627 1623 return color.colorlabel(self, msg, label)
1628 1624 return msg
1629 1625
1630 1626 def develwarn(self, msg, stacklevel=1, config=None):
1631 1627 """issue a developer warning message
1632 1628
1633 1629 Use 'stacklevel' to report the offender some layers further up in the
1634 1630 stack.
1635 1631 """
1636 1632 if not self.configbool('devel', 'all-warnings'):
1637 1633 if config is None or not self.configbool('devel', config):
1638 1634 return
1639 1635 msg = 'devel-warn: ' + msg
1640 1636 stacklevel += 1 # get in develwarn
1641 1637 if self.tracebackflag:
1642 1638 util.debugstacktrace(msg, stacklevel, self.ferr, self.fout)
1643 1639 self.log('develwarn', '%s at:\n%s' %
1644 1640 (msg, ''.join(util.getstackframes(stacklevel))))
1645 1641 else:
1646 1642 curframe = inspect.currentframe()
1647 1643 calframe = inspect.getouterframes(curframe, 2)
1648 1644 fname, lineno, fmsg = calframe[stacklevel][1:4]
1649 1645 fname, fmsg = pycompat.sysbytes(fname), pycompat.sysbytes(fmsg)
1650 1646 self.write_err('%s at: %s:%d (%s)\n'
1651 1647 % (msg, fname, lineno, fmsg))
1652 1648 self.log('develwarn', '%s at: %s:%d (%s)\n',
1653 1649 msg, fname, lineno, fmsg)
1654 1650 curframe = calframe = None # avoid cycles
1655 1651
1656 1652 def deprecwarn(self, msg, version, stacklevel=2):
1657 1653 """issue a deprecation warning
1658 1654
1659 1655 - msg: message explaining what is deprecated and how to upgrade,
1660 1656 - version: last version where the API will be supported,
1661 1657 """
1662 1658 if not (self.configbool('devel', 'all-warnings')
1663 1659 or self.configbool('devel', 'deprec-warn')):
1664 1660 return
1665 1661 msg += ("\n(compatibility will be dropped after Mercurial-%s,"
1666 1662 " update your code.)") % version
1667 1663 self.develwarn(msg, stacklevel=stacklevel, config='deprec-warn')
1668 1664
1669 1665 def exportableenviron(self):
1670 1666 """The environment variables that are safe to export, e.g. through
1671 1667 hgweb.
1672 1668 """
1673 1669 return self._exportableenviron
1674 1670
1675 1671 @contextlib.contextmanager
1676 1672 def configoverride(self, overrides, source=""):
1677 1673 """Context manager for temporary config overrides
1678 1674 `overrides` must be a dict of the following structure:
1679 1675 {(section, name) : value}"""
1680 1676 backups = {}
1681 1677 try:
1682 1678 for (section, name), value in overrides.items():
1683 1679 backups[(section, name)] = self.backupconfig(section, name)
1684 1680 self.setconfig(section, name, value, source)
1685 1681 yield
1686 1682 finally:
1687 1683 for __, backup in backups.items():
1688 1684 self.restoreconfig(backup)
1689 1685 # just restoring ui.quiet config to the previous value is not enough
1690 1686 # as it does not update ui.quiet class member
1691 1687 if ('ui', 'quiet') in overrides:
1692 1688 self.fixconfig(section='ui')
1693 1689
1694 1690 class paths(dict):
1695 1691 """Represents a collection of paths and their configs.
1696 1692
1697 1693 Data is initially derived from ui instances and the config files they have
1698 1694 loaded.
1699 1695 """
1700 1696 def __init__(self, ui):
1701 1697 dict.__init__(self)
1702 1698
1703 1699 for name, loc in ui.configitems('paths', ignoresub=True):
1704 1700 # No location is the same as not existing.
1705 1701 if not loc:
1706 1702 continue
1707 1703 loc, sub = ui.configsuboptions('paths', name)
1708 1704 self[name] = path(ui, name, rawloc=loc, suboptions=sub)
1709 1705
1710 1706 def getpath(self, name, default=None):
1711 1707 """Return a ``path`` from a string, falling back to default.
1712 1708
1713 1709 ``name`` can be a named path or locations. Locations are filesystem
1714 1710 paths or URIs.
1715 1711
1716 1712 Returns None if ``name`` is not a registered path, a URI, or a local
1717 1713 path to a repo.
1718 1714 """
1719 1715 # Only fall back to default if no path was requested.
1720 1716 if name is None:
1721 1717 if not default:
1722 1718 default = ()
1723 1719 elif not isinstance(default, (tuple, list)):
1724 1720 default = (default,)
1725 1721 for k in default:
1726 1722 try:
1727 1723 return self[k]
1728 1724 except KeyError:
1729 1725 continue
1730 1726 return None
1731 1727
1732 1728 # Most likely empty string.
1733 1729 # This may need to raise in the future.
1734 1730 if not name:
1735 1731 return None
1736 1732
1737 1733 try:
1738 1734 return self[name]
1739 1735 except KeyError:
1740 1736 # Try to resolve as a local path or URI.
1741 1737 try:
1742 1738 # We don't pass sub-options in, so no need to pass ui instance.
1743 1739 return path(None, None, rawloc=name)
1744 1740 except ValueError:
1745 1741 raise error.RepoError(_('repository %s does not exist') %
1746 1742 name)
1747 1743
1748 1744 _pathsuboptions = {}
1749 1745
1750 1746 def pathsuboption(option, attr):
1751 1747 """Decorator used to declare a path sub-option.
1752 1748
1753 1749 Arguments are the sub-option name and the attribute it should set on
1754 1750 ``path`` instances.
1755 1751
1756 1752 The decorated function will receive as arguments a ``ui`` instance,
1757 1753 ``path`` instance, and the string value of this option from the config.
1758 1754 The function should return the value that will be set on the ``path``
1759 1755 instance.
1760 1756
1761 1757 This decorator can be used to perform additional verification of
1762 1758 sub-options and to change the type of sub-options.
1763 1759 """
1764 1760 def register(func):
1765 1761 _pathsuboptions[option] = (attr, func)
1766 1762 return func
1767 1763 return register
1768 1764
1769 1765 @pathsuboption('pushurl', 'pushloc')
1770 1766 def pushurlpathoption(ui, path, value):
1771 1767 u = util.url(value)
1772 1768 # Actually require a URL.
1773 1769 if not u.scheme:
1774 1770 ui.warn(_('(paths.%s:pushurl not a URL; ignoring)\n') % path.name)
1775 1771 return None
1776 1772
1777 1773 # Don't support the #foo syntax in the push URL to declare branch to
1778 1774 # push.
1779 1775 if u.fragment:
1780 1776 ui.warn(_('("#fragment" in paths.%s:pushurl not supported; '
1781 1777 'ignoring)\n') % path.name)
1782 1778 u.fragment = None
1783 1779
1784 1780 return bytes(u)
1785 1781
1786 1782 @pathsuboption('pushrev', 'pushrev')
1787 1783 def pushrevpathoption(ui, path, value):
1788 1784 return value
1789 1785
1790 1786 class path(object):
1791 1787 """Represents an individual path and its configuration."""
1792 1788
1793 1789 def __init__(self, ui, name, rawloc=None, suboptions=None):
1794 1790 """Construct a path from its config options.
1795 1791
1796 1792 ``ui`` is the ``ui`` instance the path is coming from.
1797 1793 ``name`` is the symbolic name of the path.
1798 1794 ``rawloc`` is the raw location, as defined in the config.
1799 1795 ``pushloc`` is the raw locations pushes should be made to.
1800 1796
1801 1797 If ``name`` is not defined, we require that the location be a) a local
1802 1798 filesystem path with a .hg directory or b) a URL. If not,
1803 1799 ``ValueError`` is raised.
1804 1800 """
1805 1801 if not rawloc:
1806 1802 raise ValueError('rawloc must be defined')
1807 1803
1808 1804 # Locations may define branches via syntax <base>#<branch>.
1809 1805 u = util.url(rawloc)
1810 1806 branch = None
1811 1807 if u.fragment:
1812 1808 branch = u.fragment
1813 1809 u.fragment = None
1814 1810
1815 1811 self.url = u
1816 1812 self.branch = branch
1817 1813
1818 1814 self.name = name
1819 1815 self.rawloc = rawloc
1820 1816 self.loc = '%s' % u
1821 1817
1822 1818 # When given a raw location but not a symbolic name, validate the
1823 1819 # location is valid.
1824 1820 if not name and not u.scheme and not self._isvalidlocalpath(self.loc):
1825 1821 raise ValueError('location is not a URL or path to a local '
1826 1822 'repo: %s' % rawloc)
1827 1823
1828 1824 suboptions = suboptions or {}
1829 1825
1830 1826 # Now process the sub-options. If a sub-option is registered, its
1831 1827 # attribute will always be present. The value will be None if there
1832 1828 # was no valid sub-option.
1833 1829 for suboption, (attr, func) in _pathsuboptions.iteritems():
1834 1830 if suboption not in suboptions:
1835 1831 setattr(self, attr, None)
1836 1832 continue
1837 1833
1838 1834 value = func(ui, self, suboptions[suboption])
1839 1835 setattr(self, attr, value)
1840 1836
1841 1837 def _isvalidlocalpath(self, path):
1842 1838 """Returns True if the given path is a potentially valid repository.
1843 1839 This is its own function so that extensions can change the definition of
1844 1840 'valid' in this case (like when pulling from a git repo into a hg
1845 1841 one)."""
1846 1842 return os.path.isdir(os.path.join(path, '.hg'))
1847 1843
1848 1844 @property
1849 1845 def suboptions(self):
1850 1846 """Return sub-options and their values for this path.
1851 1847
1852 1848 This is intended to be used for presentation purposes.
1853 1849 """
1854 1850 d = {}
1855 1851 for subopt, (attr, _func) in _pathsuboptions.iteritems():
1856 1852 value = getattr(self, attr)
1857 1853 if value is not None:
1858 1854 d[subopt] = value
1859 1855 return d
1860 1856
1861 1857 # we instantiate one globally shared progress bar to avoid
1862 1858 # competing progress bars when multiple UI objects get created
1863 1859 _progresssingleton = None
1864 1860
1865 1861 def getprogbar(ui):
1866 1862 global _progresssingleton
1867 1863 if _progresssingleton is None:
1868 1864 # passing 'ui' object to the singleton is fishy,
1869 1865 # this is how the extension used to work but feel free to rework it.
1870 1866 _progresssingleton = progress.progbar(ui)
1871 1867 return _progresssingleton
1872 1868
1873 1869 def haveprogbar():
1874 1870 return _progresssingleton is not None
@@ -1,596 +1,763 b''
1 1 $ HGFOO=BAR; export HGFOO
2 2 $ cat >> $HGRCPATH <<EOF
3 3 > [alias]
4 4 > # should clobber ci but not commit (issue2993)
5 5 > ci = version
6 6 > myinit = init
7 > myinit:doc = This is my documented alias for init.
8 > myinit:help = [OPTIONS] [BLA] [BLE]
7 9 > mycommit = commit
10 > mycommit:doc = This is my alias with only doc.
8 11 > optionalrepo = showconfig alias.myinit
9 12 > cleanstatus = status -c
13 > cleanstatus:help = [ONLYHELPHERE]
10 14 > unknown = bargle
11 15 > ambiguous = s
12 16 > recursive = recursive
13 17 > disabled = email
14 18 > nodefinition =
15 19 > noclosingquotation = '
16 20 > no--cwd = status --cwd elsewhere
17 21 > no-R = status -R elsewhere
18 22 > no--repo = status --repo elsewhere
19 23 > no--repository = status --repository elsewhere
20 24 > no--config = status --config a.config=1
21 25 > mylog = log
22 26 > lognull = log -r null
27 > lognull:doc = Logs the null rev
28 > lognull:help = foo bar baz
23 29 > shortlog = log --template '{rev} {node|short} | {date|isodate}\n'
24 30 > positional = log --template '{\$2} {\$1} | {date|isodate}\n'
25 31 > dln = lognull --debug
32 > recursivedoc = dln
33 > recursivedoc:doc = Logs the null rev in debug mode
26 34 > nousage = rollback
27 35 > put = export -r 0 -o "\$FOO/%R.diff"
28 36 > blank = !printf '\n'
29 37 > self = !printf '\$0\n'
30 38 > echoall = !printf '\$@\n'
31 39 > echo1 = !printf '\$1\n'
32 40 > echo2 = !printf '\$2\n'
33 41 > echo13 = !printf '\$1 \$3\n'
34 42 > echotokens = !printf "%s\n" "\$@"
35 43 > count = !hg log -r "\$@" --template=. | wc -c | sed -e 's/ //g'
36 44 > mcount = !hg log \$@ --template=. | wc -c | sed -e 's/ //g'
37 45 > rt = root
38 46 > tglog = log -G --template "{rev}:{node|short}: '{desc}' {branches}\n"
39 47 > idalias = id
40 48 > idaliaslong = id
41 49 > idaliasshell = !echo test
42 50 > parentsshell1 = !echo one
43 51 > parentsshell2 = !echo two
44 52 > escaped1 = !printf 'test\$\$test\n'
45 53 > escaped2 = !sh -c 'echo "HGFOO is \$\$HGFOO"'
46 54 > escaped3 = !sh -c 'echo "\$1 is \$\$\$1"'
47 55 > escaped4 = !printf '\$\$0 \$\$@\n'
48 56 > exit1 = !sh -c 'exit 1'
49 57 >
50 58 > [defaults]
51 59 > mylog = -q
52 60 > lognull = -q
53 61 > log = -v
54 62 > EOF
55 63
56
57 64 basic
58 65
59 66 $ hg myinit alias
60 67
68 help
69
70 $ hg help -c | grep myinit
71 myinit This is my documented alias for init.
72 $ hg help -c | grep mycommit
73 mycommit This is my alias with only doc.
74 $ hg help -c | grep cleanstatus
75 cleanstatus show changed files in the working directory
76 $ hg help -c | grep lognull
77 lognull Logs the null rev
78 $ hg help -c | grep dln
79 dln Logs the null rev
80 $ hg help -c | grep recursivedoc
81 recursivedoc Logs the null rev in debug mode
82 $ hg help myinit
83 hg myinit [OPTIONS] [BLA] [BLE]
84
85 alias for: hg init
86
87 This is my documented alias for init.
88
89 defined by: * (glob)
90 */* (glob) (?)
91 */* (glob) (?)
92 */* (glob) (?)
93
94 options:
95
96 -e --ssh CMD specify ssh command to use
97 --remotecmd CMD specify hg command to run on the remote side
98 --insecure do not verify server certificate (ignoring web.cacerts
99 config)
100
101 (some details hidden, use --verbose to show complete help)
102
103 $ hg help mycommit
104 hg mycommit [OPTION]... [FILE]...
105
106 alias for: hg commit
107
108 This is my alias with only doc.
109
110 defined by: * (glob)
111 */* (glob) (?)
112 */* (glob) (?)
113 */* (glob) (?)
114
115 options ([+] can be repeated):
116
117 -A --addremove mark new/missing files as added/removed before
118 committing
119 --close-branch mark a branch head as closed
120 --amend amend the parent of the working directory
121 -s --secret use the secret phase for committing
122 -e --edit invoke editor on commit messages
123 -i --interactive use interactive mode
124 -I --include PATTERN [+] include names matching the given patterns
125 -X --exclude PATTERN [+] exclude names matching the given patterns
126 -m --message TEXT use text as commit message
127 -l --logfile FILE read commit message from file
128 -d --date DATE record the specified date as commit date
129 -u --user USER record the specified user as committer
130 -S --subrepos recurse into subrepositories
131
132 (some details hidden, use --verbose to show complete help)
133
134 $ hg help cleanstatus
135 hg cleanstatus [ONLYHELPHERE]
136
137 alias for: hg status -c
138
139 show changed files in the working directory
140
141 Show status of files in the repository. If names are given, only files
142 that match are shown. Files that are clean or ignored or the source of a
143 copy/move operation, are not listed unless -c/--clean, -i/--ignored,
144 -C/--copies or -A/--all are given. Unless options described with "show
145 only ..." are given, the options -mardu are used.
146
147 Option -q/--quiet hides untracked (unknown and ignored) files unless
148 explicitly requested with -u/--unknown or -i/--ignored.
149
150 Note:
151 'hg status' may appear to disagree with diff if permissions have
152 changed or a merge has occurred. The standard diff format does not
153 report permission changes and diff only reports changes relative to one
154 merge parent.
155
156 If one revision is given, it is used as the base revision. If two
157 revisions are given, the differences between them are shown. The --change
158 option can also be used as a shortcut to list the changed files of a
159 revision from its first parent.
160
161 The codes used to show the status of files are:
162
163 M = modified
164 A = added
165 R = removed
166 C = clean
167 ! = missing (deleted by non-hg command, but still tracked)
168 ? = not tracked
169 I = ignored
170 = origin of the previous file (with --copies)
171
172 Returns 0 on success.
173
174 defined by: * (glob)
175 */* (glob) (?)
176 */* (glob) (?)
177 */* (glob) (?)
178
179 options ([+] can be repeated):
180
181 -A --all show status of all files
182 -m --modified show only modified files
183 -a --added show only added files
184 -r --removed show only removed files
185 -d --deleted show only deleted (but tracked) files
186 -c --clean show only files without changes
187 -u --unknown show only unknown (not tracked) files
188 -i --ignored show only ignored files
189 -n --no-status hide status prefix
190 -C --copies show source of copied files
191 -0 --print0 end filenames with NUL, for use with xargs
192 --rev REV [+] show difference from revision
193 --change REV list the changed files of a revision
194 -I --include PATTERN [+] include names matching the given patterns
195 -X --exclude PATTERN [+] exclude names matching the given patterns
196 -S --subrepos recurse into subrepositories
197
198 (some details hidden, use --verbose to show complete help)
199
200 $ hg help recursivedoc | head -n 5
201 hg recursivedoc foo bar baz
202
203 alias for: hg dln
204
205 Logs the null rev in debug mode
61 206
62 207 unknown
63 208
64 209 $ hg unknown
65 210 abort: alias 'unknown' resolves to unknown command 'bargle'
66 211 [255]
67 212 $ hg help unknown
68 213 alias 'unknown' resolves to unknown command 'bargle'
69 214
70 215
71 216 ambiguous
72 217
73 218 $ hg ambiguous
74 219 abort: alias 'ambiguous' resolves to ambiguous command 's'
75 220 [255]
76 221 $ hg help ambiguous
77 222 alias 'ambiguous' resolves to ambiguous command 's'
78 223
79 224
80 225 recursive
81 226
82 227 $ hg recursive
83 228 abort: alias 'recursive' resolves to unknown command 'recursive'
84 229 [255]
85 230 $ hg help recursive
86 231 alias 'recursive' resolves to unknown command 'recursive'
87 232
88 233
89 234 disabled
90 235
91 236 $ hg disabled
92 237 abort: alias 'disabled' resolves to unknown command 'email'
93 238 ('email' is provided by 'patchbomb' extension)
94 239 [255]
95 240 $ hg help disabled
96 241 alias 'disabled' resolves to unknown command 'email'
97 242
98 243 'email' is provided by the following extension:
99 244
100 245 patchbomb command to send changesets as (a series of) patch emails
101 246
102 247 (use 'hg help extensions' for information on enabling extensions)
103 248
104 249
105 250 no definition
106 251
107 252 $ hg nodef
108 253 abort: no definition for alias 'nodefinition'
109 254 [255]
110 255 $ hg help nodef
111 256 no definition for alias 'nodefinition'
112 257
113 258
114 259 no closing quotation
115 260
116 261 $ hg noclosing
117 262 abort: error in definition for alias 'noclosingquotation': No closing quotation
118 263 [255]
119 264 $ hg help noclosing
120 265 error in definition for alias 'noclosingquotation': No closing quotation
121 266
122 267 "--" in alias definition should be preserved
123 268
124 269 $ hg --config alias.dash='cat --' -R alias dash -r0
125 270 abort: -r0 not under root '$TESTTMP/alias'
126 271 (consider using '--cwd alias')
127 272 [255]
128 273
129 274 invalid options
130 275
131 276 $ hg no--cwd
132 277 abort: error in definition for alias 'no--cwd': --cwd may only be given on the command line
133 278 [255]
134 279 $ hg help no--cwd
135 280 error in definition for alias 'no--cwd': --cwd may only be given on the
136 281 command line
137 282 $ hg no-R
138 283 abort: error in definition for alias 'no-R': -R may only be given on the command line
139 284 [255]
140 285 $ hg help no-R
141 286 error in definition for alias 'no-R': -R may only be given on the command line
142 287 $ hg no--repo
143 288 abort: error in definition for alias 'no--repo': --repo may only be given on the command line
144 289 [255]
145 290 $ hg help no--repo
146 291 error in definition for alias 'no--repo': --repo may only be given on the
147 292 command line
148 293 $ hg no--repository
149 294 abort: error in definition for alias 'no--repository': --repository may only be given on the command line
150 295 [255]
151 296 $ hg help no--repository
152 297 error in definition for alias 'no--repository': --repository may only be given
153 298 on the command line
154 299 $ hg no--config
155 300 abort: error in definition for alias 'no--config': --config may only be given on the command line
156 301 [255]
157 302 $ hg no --config alias.no='--repo elsewhere --cwd elsewhere status'
158 303 abort: error in definition for alias 'no': --repo/--cwd may only be given on the command line
159 304 [255]
160 305 $ hg no --config alias.no='--repo elsewhere'
161 306 abort: error in definition for alias 'no': --repo may only be given on the command line
162 307 [255]
163 308
164 309 optional repository
165 310
166 311 #if no-outer-repo
167 312 $ hg optionalrepo
168 313 init
169 314 #endif
170 315 $ cd alias
171 316 $ cat > .hg/hgrc <<EOF
172 317 > [alias]
173 318 > myinit = init -q
174 319 > EOF
175 320 $ hg optionalrepo
176 321 init -q
177 322
178 323 no usage
179 324
180 325 $ hg nousage
181 326 no rollback information available
182 327 [1]
183 328
184 329 $ echo foo > foo
185 330 $ hg commit -Amfoo
186 331 adding foo
187 332
188 333 infer repository
189 334
190 335 $ cd ..
191 336
192 337 #if no-outer-repo
193 338 $ hg shortlog alias/foo
194 339 0 e63c23eaa88a | 1970-01-01 00:00 +0000
195 340 #endif
196 341
197 342 $ cd alias
198 343
199 344 with opts
200 345
201 346 $ hg cleanst
202 347 C foo
203 348
204 349
205 350 with opts and whitespace
206 351
207 352 $ hg shortlog
208 353 0 e63c23eaa88a | 1970-01-01 00:00 +0000
209 354
210 355 positional arguments
211 356
212 357 $ hg positional
213 358 abort: too few arguments for command alias
214 359 [255]
215 360 $ hg positional a
216 361 abort: too few arguments for command alias
217 362 [255]
218 363 $ hg positional 'node|short' rev
219 364 0 e63c23eaa88a | 1970-01-01 00:00 +0000
220 365
221 366 interaction with defaults
222 367
223 368 $ hg mylog
224 369 0:e63c23eaa88a
225 370 $ hg lognull
226 371 -1:000000000000
227 372
228 373
229 374 properly recursive
230 375
231 376 $ hg dln
232 377 changeset: -1:0000000000000000000000000000000000000000
233 378 phase: public
234 379 parent: -1:0000000000000000000000000000000000000000
235 380 parent: -1:0000000000000000000000000000000000000000
236 381 manifest: -1:0000000000000000000000000000000000000000
237 382 user:
238 383 date: Thu Jan 01 00:00:00 1970 +0000
239 384 extra: branch=default
240 385
241 386
242 387
243 388 path expanding
244 389
245 390 $ FOO=`pwd` hg put
246 391 $ cat 0.diff
247 392 # HG changeset patch
248 393 # User test
249 394 # Date 0 0
250 395 # Thu Jan 01 00:00:00 1970 +0000
251 396 # Node ID e63c23eaa88ae77967edcf4ea194d31167c478b0
252 397 # Parent 0000000000000000000000000000000000000000
253 398 foo
254 399
255 400 diff -r 000000000000 -r e63c23eaa88a foo
256 401 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
257 402 +++ b/foo Thu Jan 01 00:00:00 1970 +0000
258 403 @@ -0,0 +1,1 @@
259 404 +foo
260 405
261 406
262 407 simple shell aliases
263 408
264 409 $ hg blank
265 410
266 411 $ hg blank foo
267 412
268 413 $ hg self
269 414 self
270 415 $ hg echoall
271 416
272 417 $ hg echoall foo
273 418 foo
274 419 $ hg echoall 'test $2' foo
275 420 test $2 foo
276 421 $ hg echoall 'test $@' foo '$@'
277 422 test $@ foo $@
278 423 $ hg echoall 'test "$@"' foo '"$@"'
279 424 test "$@" foo "$@"
280 425 $ hg echo1 foo bar baz
281 426 foo
282 427 $ hg echo2 foo bar baz
283 428 bar
284 429 $ hg echo13 foo bar baz test
285 430 foo baz
286 431 $ hg echo2 foo
287 432
288 433 $ hg echotokens
289 434
290 435 $ hg echotokens foo 'bar $1 baz'
291 436 foo
292 437 bar $1 baz
293 438 $ hg echotokens 'test $2' foo
294 439 test $2
295 440 foo
296 441 $ hg echotokens 'test $@' foo '$@'
297 442 test $@
298 443 foo
299 444 $@
300 445 $ hg echotokens 'test "$@"' foo '"$@"'
301 446 test "$@"
302 447 foo
303 448 "$@"
304 449 $ echo bar > bar
305 450 $ hg commit -qA -m bar
306 451 $ hg count .
307 452 1
308 453 $ hg count 'branch(default)'
309 454 2
310 455 $ hg mcount -r '"branch(default)"'
311 456 2
312 457
313 458 $ hg tglog
314 459 @ 1:042423737847: 'bar'
315 460 |
316 461 o 0:e63c23eaa88a: 'foo'
317 462
318 463
319 464
320 465 shadowing
321 466
322 467 $ hg i
323 468 hg: command 'i' is ambiguous:
324 469 idalias idaliaslong idaliasshell identify import incoming init
325 470 [255]
326 471 $ hg id
327 472 042423737847 tip
328 473 $ hg ida
329 474 hg: command 'ida' is ambiguous:
330 475 idalias idaliaslong idaliasshell
331 476 [255]
332 477 $ hg idalias
333 478 042423737847 tip
334 479 $ hg idaliasl
335 480 042423737847 tip
336 481 $ hg idaliass
337 482 test
338 483 $ hg parentsshell
339 484 hg: command 'parentsshell' is ambiguous:
340 485 parentsshell1 parentsshell2
341 486 [255]
342 487 $ hg parentsshell1
343 488 one
344 489 $ hg parentsshell2
345 490 two
346 491
347 492
348 493 shell aliases with global options
349 494
350 495 $ hg init sub
351 496 $ cd sub
352 497 $ hg count 'branch(default)'
353 498 abort: unknown revision 'default'!
354 499 0
355 500 $ hg -v count 'branch(default)'
356 501 abort: unknown revision 'default'!
357 502 0
358 503 $ hg -R .. count 'branch(default)'
359 504 abort: unknown revision 'default'!
360 505 0
361 506 $ hg --cwd .. count 'branch(default)'
362 507 2
363 508 $ hg echoall --cwd ..
364 509
365 510
366 511 "--" passed to shell alias should be preserved
367 512
368 513 $ hg --config alias.printf='!printf "$@"' printf '%s %s %s\n' -- --cwd ..
369 514 -- --cwd ..
370 515
371 516 repo specific shell aliases
372 517
373 518 $ cat >> .hg/hgrc <<EOF
374 519 > [alias]
375 520 > subalias = !echo sub
376 521 > EOF
377 522 $ cat >> ../.hg/hgrc <<EOF
378 523 > [alias]
379 524 > mainalias = !echo main
380 525 > EOF
381 526
382 527
383 528 shell alias defined in current repo
384 529
385 530 $ hg subalias
386 531 sub
387 532 $ hg --cwd .. subalias > /dev/null
388 533 hg: unknown command 'subalias'
389 534 (did you mean idalias?)
390 535 [255]
391 536 $ hg -R .. subalias > /dev/null
392 537 hg: unknown command 'subalias'
393 538 (did you mean idalias?)
394 539 [255]
395 540
396 541
397 542 shell alias defined in other repo
398 543
399 544 $ hg mainalias > /dev/null
400 545 hg: unknown command 'mainalias'
401 546 (did you mean idalias?)
402 547 [255]
403 548 $ hg -R .. mainalias
404 549 main
405 550 $ hg --cwd .. mainalias
406 551 main
407 552
408 553 typos get useful suggestions
409 554 $ hg --cwd .. manalias
410 555 hg: unknown command 'manalias'
411 556 (did you mean one of idalias, mainalias, manifest?)
412 557 [255]
413 558
414 559 shell aliases with escaped $ chars
415 560
416 561 $ hg escaped1
417 562 test$test
418 563 $ hg escaped2
419 564 HGFOO is BAR
420 565 $ hg escaped3 HGFOO
421 566 HGFOO is BAR
422 567 $ hg escaped4 test
423 568 $0 $@
424 569
425 570 abbreviated name, which matches against both shell alias and the
426 571 command provided extension, should be aborted.
427 572
428 573 $ cat >> .hg/hgrc <<EOF
429 574 > [extensions]
430 575 > hgext.rebase =
431 576 > EOF
432 577 #if windows
433 578 $ cat >> .hg/hgrc <<EOF
434 579 > [alias]
435 580 > rebate = !echo this is %HG_ARGS%
436 581 > EOF
437 582 #else
438 583 $ cat >> .hg/hgrc <<EOF
439 584 > [alias]
440 585 > rebate = !echo this is \$HG_ARGS
441 586 > EOF
442 587 #endif
588 $ cat >> .hg/hgrc <<EOF
589 > rebate:doc = This is my alias which just prints something.
590 > rebate:help = [MYARGS]
591 > EOF
443 592 $ hg reba
444 593 hg: command 'reba' is ambiguous:
445 594 rebase rebate
446 595 [255]
447 596 $ hg rebat
448 597 this is rebate
449 598 $ hg rebat --foo-bar
450 599 this is rebate --foo-bar
451 600
601 help for a shell alias
602
603 $ hg help -c | grep rebate
604 rebate This is my alias which just prints something.
605 $ hg help rebate
606 hg rebate [MYARGS]
607
608 shell alias for: echo this is $HG_ARGS
609
610 This is my alias which just prints something.
611
612 defined by:* (glob)
613 */* (glob) (?)
614 */* (glob) (?)
615 */* (glob) (?)
616
617 (some details hidden, use --verbose to show complete help)
618
452 619 invalid arguments
453 620
454 621 $ hg rt foo
455 622 hg rt: invalid arguments
456 623 hg rt
457 624
458 625 alias for: hg root
459 626
460 627 (use 'hg rt -h' to show more help)
461 628 [255]
462 629
463 630 invalid global arguments for normal commands, aliases, and shell aliases
464 631
465 632 $ hg --invalid root
466 633 hg: option --invalid not recognized
467 634 Mercurial Distributed SCM
468 635
469 636 basic commands:
470 637
471 638 add add the specified files on the next commit
472 639 annotate show changeset information by line for each file
473 640 clone make a copy of an existing repository
474 641 commit commit the specified files or all outstanding changes
475 642 diff diff repository (or selected files)
476 643 export dump the header and diffs for one or more changesets
477 644 forget forget the specified files on the next commit
478 645 init create a new repository in the given directory
479 646 log show revision history of entire repository or files
480 647 merge merge another revision into working directory
481 648 pull pull changes from the specified source
482 649 push push changes to the specified destination
483 650 remove remove the specified files on the next commit
484 651 serve start stand-alone webserver
485 652 status show changed files in the working directory
486 653 summary summarize working directory state
487 654 update update working directory (or switch revisions)
488 655
489 656 (use 'hg help' for the full list of commands or 'hg -v' for details)
490 657 [255]
491 658 $ hg --invalid mylog
492 659 hg: option --invalid not recognized
493 660 Mercurial Distributed SCM
494 661
495 662 basic commands:
496 663
497 664 add add the specified files on the next commit
498 665 annotate show changeset information by line for each file
499 666 clone make a copy of an existing repository
500 667 commit commit the specified files or all outstanding changes
501 668 diff diff repository (or selected files)
502 669 export dump the header and diffs for one or more changesets
503 670 forget forget the specified files on the next commit
504 671 init create a new repository in the given directory
505 672 log show revision history of entire repository or files
506 673 merge merge another revision into working directory
507 674 pull pull changes from the specified source
508 675 push push changes to the specified destination
509 676 remove remove the specified files on the next commit
510 677 serve start stand-alone webserver
511 678 status show changed files in the working directory
512 679 summary summarize working directory state
513 680 update update working directory (or switch revisions)
514 681
515 682 (use 'hg help' for the full list of commands or 'hg -v' for details)
516 683 [255]
517 684 $ hg --invalid blank
518 685 hg: option --invalid not recognized
519 686 Mercurial Distributed SCM
520 687
521 688 basic commands:
522 689
523 690 add add the specified files on the next commit
524 691 annotate show changeset information by line for each file
525 692 clone make a copy of an existing repository
526 693 commit commit the specified files or all outstanding changes
527 694 diff diff repository (or selected files)
528 695 export dump the header and diffs for one or more changesets
529 696 forget forget the specified files on the next commit
530 697 init create a new repository in the given directory
531 698 log show revision history of entire repository or files
532 699 merge merge another revision into working directory
533 700 pull pull changes from the specified source
534 701 push push changes to the specified destination
535 702 remove remove the specified files on the next commit
536 703 serve start stand-alone webserver
537 704 status show changed files in the working directory
538 705 summary summarize working directory state
539 706 update update working directory (or switch revisions)
540 707
541 708 (use 'hg help' for the full list of commands or 'hg -v' for details)
542 709 [255]
543 710
544 711 environment variable changes in alias commands
545 712
546 713 $ cat > $TESTTMP/expandalias.py <<EOF
547 714 > import os
548 715 > from mercurial import cmdutil, commands, registrar
549 716 > cmdtable = {}
550 717 > command = registrar.command(cmdtable)
551 718 > @command(b'expandalias')
552 719 > def expandalias(ui, repo, name):
553 720 > alias = cmdutil.findcmd(name, commands.table)[1][0]
554 721 > ui.write(b'%s args: %s\n' % (name, b' '.join(alias.args)))
555 722 > os.environ['COUNT'] = '2'
556 723 > ui.write(b'%s args: %s (with COUNT=2)\n' % (name, b' '.join(alias.args)))
557 724 > EOF
558 725
559 726 $ cat >> $HGRCPATH <<'EOF'
560 727 > [extensions]
561 728 > expandalias = $TESTTMP/expandalias.py
562 729 > [alias]
563 730 > showcount = log -T "$COUNT" -r .
564 731 > EOF
565 732
566 733 $ COUNT=1 hg expandalias showcount
567 734 showcount args: -T 1 -r .
568 735 showcount args: -T 2 -r . (with COUNT=2)
569 736
570 737 This should show id:
571 738
572 739 $ hg --config alias.log='id' log
573 740 000000000000 tip
574 741
575 742 This shouldn't:
576 743
577 744 $ hg --config alias.log='id' history
578 745
579 746 $ cd ../..
580 747
581 748 return code of command and shell aliases:
582 749
583 750 $ hg mycommit -R alias
584 751 nothing changed
585 752 [1]
586 753 $ hg exit1
587 754 [1]
588 755
589 756 #if no-outer-repo
590 757 $ hg root
591 758 abort: no repository found in '$TESTTMP' (.hg not found)!
592 759 [255]
593 760 $ hg --config alias.hgroot='!hg root' hgroot
594 761 abort: no repository found in '$TESTTMP' (.hg not found)!
595 762 [255]
596 763 #endif
@@ -1,3494 +1,3494 b''
1 1 Short help:
2 2
3 3 $ hg
4 4 Mercurial Distributed SCM
5 5
6 6 basic commands:
7 7
8 8 add add the specified files on the next commit
9 9 annotate show changeset information by line for each file
10 10 clone make a copy of an existing repository
11 11 commit commit the specified files or all outstanding changes
12 12 diff diff repository (or selected files)
13 13 export dump the header and diffs for one or more changesets
14 14 forget forget the specified files on the next commit
15 15 init create a new repository in the given directory
16 16 log show revision history of entire repository or files
17 17 merge merge another revision into working directory
18 18 pull pull changes from the specified source
19 19 push push changes to the specified destination
20 20 remove remove the specified files on the next commit
21 21 serve start stand-alone webserver
22 22 status show changed files in the working directory
23 23 summary summarize working directory state
24 24 update update working directory (or switch revisions)
25 25
26 26 (use 'hg help' for the full list of commands or 'hg -v' for details)
27 27
28 28 $ hg -q
29 29 add add the specified files on the next commit
30 30 annotate show changeset information by line for each file
31 31 clone make a copy of an existing repository
32 32 commit commit the specified files or all outstanding changes
33 33 diff diff repository (or selected files)
34 34 export dump the header and diffs for one or more changesets
35 35 forget forget the specified files on the next commit
36 36 init create a new repository in the given directory
37 37 log show revision history of entire repository or files
38 38 merge merge another revision into working directory
39 39 pull pull changes from the specified source
40 40 push push changes to the specified destination
41 41 remove remove the specified files on the next commit
42 42 serve start stand-alone webserver
43 43 status show changed files in the working directory
44 44 summary summarize working directory state
45 45 update update working directory (or switch revisions)
46 46
47 47 $ hg help
48 48 Mercurial Distributed SCM
49 49
50 50 list of commands:
51 51
52 52 add add the specified files on the next commit
53 53 addremove add all new files, delete all missing files
54 54 annotate show changeset information by line for each file
55 55 archive create an unversioned archive of a repository revision
56 56 backout reverse effect of earlier changeset
57 57 bisect subdivision search of changesets
58 58 bookmarks create a new bookmark or list existing bookmarks
59 59 branch set or show the current branch name
60 60 branches list repository named branches
61 61 bundle create a bundle file
62 62 cat output the current or given revision of files
63 63 clone make a copy of an existing repository
64 64 commit commit the specified files or all outstanding changes
65 65 config show combined config settings from all hgrc files
66 66 copy mark files as copied for the next commit
67 67 diff diff repository (or selected files)
68 68 export dump the header and diffs for one or more changesets
69 69 files list tracked files
70 70 forget forget the specified files on the next commit
71 71 graft copy changes from other branches onto the current branch
72 72 grep search revision history for a pattern in specified files
73 73 heads show branch heads
74 74 help show help for a given topic or a help overview
75 75 identify identify the working directory or specified revision
76 76 import import an ordered set of patches
77 77 incoming show new changesets found in source
78 78 init create a new repository in the given directory
79 79 log show revision history of entire repository or files
80 80 manifest output the current or given revision of the project manifest
81 81 merge merge another revision into working directory
82 82 outgoing show changesets not found in the destination
83 83 paths show aliases for remote repositories
84 84 phase set or show the current phase name
85 85 pull pull changes from the specified source
86 86 push push changes to the specified destination
87 87 recover roll back an interrupted transaction
88 88 remove remove the specified files on the next commit
89 89 rename rename files; equivalent of copy + remove
90 90 resolve redo merges or set/view the merge status of files
91 91 revert restore files to their checkout state
92 92 root print the root (top) of the current working directory
93 93 serve start stand-alone webserver
94 94 status show changed files in the working directory
95 95 summary summarize working directory state
96 96 tag add one or more tags for the current or given revision
97 97 tags list repository tags
98 98 unbundle apply one or more bundle files
99 99 update update working directory (or switch revisions)
100 100 verify verify the integrity of the repository
101 101 version output version and copyright information
102 102
103 103 additional help topics:
104 104
105 105 bundlespec Bundle File Formats
106 106 color Colorizing Outputs
107 107 config Configuration Files
108 108 dates Date Formats
109 109 diffs Diff Formats
110 110 environment Environment Variables
111 111 extensions Using Additional Features
112 112 filesets Specifying File Sets
113 113 flags Command-line flags
114 114 glossary Glossary
115 115 hgignore Syntax for Mercurial Ignore Files
116 116 hgweb Configuring hgweb
117 117 internals Technical implementation topics
118 118 merge-tools Merge Tools
119 119 pager Pager Support
120 120 patterns File Name Patterns
121 121 phases Working with Phases
122 122 revisions Specifying Revisions
123 123 scripting Using Mercurial from scripts and automation
124 124 subrepos Subrepositories
125 125 templating Template Usage
126 126 urls URL Paths
127 127
128 128 (use 'hg help -v' to show built-in aliases and global options)
129 129
130 130 $ hg -q help
131 131 add add the specified files on the next commit
132 132 addremove add all new files, delete all missing files
133 133 annotate show changeset information by line for each file
134 134 archive create an unversioned archive of a repository revision
135 135 backout reverse effect of earlier changeset
136 136 bisect subdivision search of changesets
137 137 bookmarks create a new bookmark or list existing bookmarks
138 138 branch set or show the current branch name
139 139 branches list repository named branches
140 140 bundle create a bundle file
141 141 cat output the current or given revision of files
142 142 clone make a copy of an existing repository
143 143 commit commit the specified files or all outstanding changes
144 144 config show combined config settings from all hgrc files
145 145 copy mark files as copied for the next commit
146 146 diff diff repository (or selected files)
147 147 export dump the header and diffs for one or more changesets
148 148 files list tracked files
149 149 forget forget the specified files on the next commit
150 150 graft copy changes from other branches onto the current branch
151 151 grep search revision history for a pattern in specified files
152 152 heads show branch heads
153 153 help show help for a given topic or a help overview
154 154 identify identify the working directory or specified revision
155 155 import import an ordered set of patches
156 156 incoming show new changesets found in source
157 157 init create a new repository in the given directory
158 158 log show revision history of entire repository or files
159 159 manifest output the current or given revision of the project manifest
160 160 merge merge another revision into working directory
161 161 outgoing show changesets not found in the destination
162 162 paths show aliases for remote repositories
163 163 phase set or show the current phase name
164 164 pull pull changes from the specified source
165 165 push push changes to the specified destination
166 166 recover roll back an interrupted transaction
167 167 remove remove the specified files on the next commit
168 168 rename rename files; equivalent of copy + remove
169 169 resolve redo merges or set/view the merge status of files
170 170 revert restore files to their checkout state
171 171 root print the root (top) of the current working directory
172 172 serve start stand-alone webserver
173 173 status show changed files in the working directory
174 174 summary summarize working directory state
175 175 tag add one or more tags for the current or given revision
176 176 tags list repository tags
177 177 unbundle apply one or more bundle files
178 178 update update working directory (or switch revisions)
179 179 verify verify the integrity of the repository
180 180 version output version and copyright information
181 181
182 182 additional help topics:
183 183
184 184 bundlespec Bundle File Formats
185 185 color Colorizing Outputs
186 186 config Configuration Files
187 187 dates Date Formats
188 188 diffs Diff Formats
189 189 environment Environment Variables
190 190 extensions Using Additional Features
191 191 filesets Specifying File Sets
192 192 flags Command-line flags
193 193 glossary Glossary
194 194 hgignore Syntax for Mercurial Ignore Files
195 195 hgweb Configuring hgweb
196 196 internals Technical implementation topics
197 197 merge-tools Merge Tools
198 198 pager Pager Support
199 199 patterns File Name Patterns
200 200 phases Working with Phases
201 201 revisions Specifying Revisions
202 202 scripting Using Mercurial from scripts and automation
203 203 subrepos Subrepositories
204 204 templating Template Usage
205 205 urls URL Paths
206 206
207 207 Test extension help:
208 208 $ hg help extensions --config extensions.rebase= --config extensions.children=
209 209 Using Additional Features
210 210 """""""""""""""""""""""""
211 211
212 212 Mercurial has the ability to add new features through the use of
213 213 extensions. Extensions may add new commands, add options to existing
214 214 commands, change the default behavior of commands, or implement hooks.
215 215
216 216 To enable the "foo" extension, either shipped with Mercurial or in the
217 217 Python search path, create an entry for it in your configuration file,
218 218 like this:
219 219
220 220 [extensions]
221 221 foo =
222 222
223 223 You may also specify the full path to an extension:
224 224
225 225 [extensions]
226 226 myfeature = ~/.hgext/myfeature.py
227 227
228 228 See 'hg help config' for more information on configuration files.
229 229
230 230 Extensions are not loaded by default for a variety of reasons: they can
231 231 increase startup overhead; they may be meant for advanced usage only; they
232 232 may provide potentially dangerous abilities (such as letting you destroy
233 233 or modify history); they might not be ready for prime time; or they may
234 234 alter some usual behaviors of stock Mercurial. It is thus up to the user
235 235 to activate extensions as needed.
236 236
237 237 To explicitly disable an extension enabled in a configuration file of
238 238 broader scope, prepend its path with !:
239 239
240 240 [extensions]
241 241 # disabling extension bar residing in /path/to/extension/bar.py
242 242 bar = !/path/to/extension/bar.py
243 243 # ditto, but no path was supplied for extension baz
244 244 baz = !
245 245
246 246 enabled extensions:
247 247
248 248 children command to display child changesets (DEPRECATED)
249 249 rebase command to move sets of revisions to a different ancestor
250 250
251 251 disabled extensions:
252 252
253 253 acl hooks for controlling repository access
254 254 blackbox log repository events to a blackbox for debugging
255 255 bugzilla hooks for integrating with the Bugzilla bug tracker
256 256 censor erase file content at a given revision
257 257 churn command to display statistics about repository history
258 258 clonebundles advertise pre-generated bundles to seed clones
259 259 convert import revisions from foreign VCS repositories into
260 260 Mercurial
261 261 eol automatically manage newlines in repository files
262 262 extdiff command to allow external programs to compare revisions
263 263 factotum http authentication with factotum
264 264 githelp try mapping git commands to Mercurial commands
265 265 gpg commands to sign and verify changesets
266 266 hgk browse the repository in a graphical way
267 267 highlight syntax highlighting for hgweb (requires Pygments)
268 268 histedit interactive history editing
269 269 keyword expand keywords in tracked files
270 270 largefiles track large binary files
271 271 mq manage a stack of patches
272 272 notify hooks for sending email push notifications
273 273 patchbomb command to send changesets as (a series of) patch emails
274 274 purge command to delete untracked files from the working
275 275 directory
276 276 relink recreates hardlinks between repository clones
277 277 remotenames showing remotebookmarks and remotebranches in UI
278 278 schemes extend schemes with shortcuts to repository swarms
279 279 share share a common history between several working directories
280 280 shelve save and restore changes to the working directory
281 281 strip strip changesets and their descendants from history
282 282 transplant command to transplant changesets from another branch
283 283 win32mbcs allow the use of MBCS paths with problematic encodings
284 284 zeroconf discover and advertise repositories on the local network
285 285
286 286 Verify that deprecated extensions are included if --verbose:
287 287
288 288 $ hg -v help extensions | grep children
289 289 children command to display child changesets (DEPRECATED)
290 290
291 291 Verify that extension keywords appear in help templates
292 292
293 293 $ hg help --config extensions.transplant= templating|grep transplant > /dev/null
294 294
295 295 Test short command list with verbose option
296 296
297 297 $ hg -v help shortlist
298 298 Mercurial Distributed SCM
299 299
300 300 basic commands:
301 301
302 302 add add the specified files on the next commit
303 303 annotate, blame
304 304 show changeset information by line for each file
305 305 clone make a copy of an existing repository
306 306 commit, ci commit the specified files or all outstanding changes
307 307 diff diff repository (or selected files)
308 308 export dump the header and diffs for one or more changesets
309 309 forget forget the specified files on the next commit
310 310 init create a new repository in the given directory
311 311 log, history show revision history of entire repository or files
312 312 merge merge another revision into working directory
313 313 pull pull changes from the specified source
314 314 push push changes to the specified destination
315 315 remove, rm remove the specified files on the next commit
316 316 serve start stand-alone webserver
317 317 status, st show changed files in the working directory
318 318 summary, sum summarize working directory state
319 319 update, up, checkout, co
320 320 update working directory (or switch revisions)
321 321
322 322 global options ([+] can be repeated):
323 323
324 324 -R --repository REPO repository root directory or name of overlay bundle
325 325 file
326 326 --cwd DIR change working directory
327 327 -y --noninteractive do not prompt, automatically pick the first choice for
328 328 all prompts
329 329 -q --quiet suppress output
330 330 -v --verbose enable additional output
331 331 --color TYPE when to colorize (boolean, always, auto, never, or
332 332 debug)
333 333 --config CONFIG [+] set/override config option (use 'section.name=value')
334 334 --debug enable debugging output
335 335 --debugger start debugger
336 336 --encoding ENCODE set the charset encoding (default: ascii)
337 337 --encodingmode MODE set the charset encoding mode (default: strict)
338 338 --traceback always print a traceback on exception
339 339 --time time how long the command takes
340 340 --profile print command execution profile
341 341 --version output version information and exit
342 342 -h --help display help and exit
343 343 --hidden consider hidden changesets
344 344 --pager TYPE when to paginate (boolean, always, auto, or never)
345 345 (default: auto)
346 346
347 347 (use 'hg help' for the full list of commands)
348 348
349 349 $ hg add -h
350 350 hg add [OPTION]... [FILE]...
351 351
352 352 add the specified files on the next commit
353 353
354 354 Schedule files to be version controlled and added to the repository.
355 355
356 356 The files will be added to the repository at the next commit. To undo an
357 357 add before that, see 'hg forget'.
358 358
359 359 If no names are given, add all files to the repository (except files
360 360 matching ".hgignore").
361 361
362 362 Returns 0 if all files are successfully added.
363 363
364 364 options ([+] can be repeated):
365 365
366 366 -I --include PATTERN [+] include names matching the given patterns
367 367 -X --exclude PATTERN [+] exclude names matching the given patterns
368 368 -S --subrepos recurse into subrepositories
369 369 -n --dry-run do not perform actions, just print output
370 370
371 371 (some details hidden, use --verbose to show complete help)
372 372
373 373 Verbose help for add
374 374
375 375 $ hg add -hv
376 376 hg add [OPTION]... [FILE]...
377 377
378 378 add the specified files on the next commit
379 379
380 380 Schedule files to be version controlled and added to the repository.
381 381
382 382 The files will be added to the repository at the next commit. To undo an
383 383 add before that, see 'hg forget'.
384 384
385 385 If no names are given, add all files to the repository (except files
386 386 matching ".hgignore").
387 387
388 388 Examples:
389 389
390 390 - New (unknown) files are added automatically by 'hg add':
391 391
392 392 $ ls
393 393 foo.c
394 394 $ hg status
395 395 ? foo.c
396 396 $ hg add
397 397 adding foo.c
398 398 $ hg status
399 399 A foo.c
400 400
401 401 - Specific files to be added can be specified:
402 402
403 403 $ ls
404 404 bar.c foo.c
405 405 $ hg status
406 406 ? bar.c
407 407 ? foo.c
408 408 $ hg add bar.c
409 409 $ hg status
410 410 A bar.c
411 411 ? foo.c
412 412
413 413 Returns 0 if all files are successfully added.
414 414
415 415 options ([+] can be repeated):
416 416
417 417 -I --include PATTERN [+] include names matching the given patterns
418 418 -X --exclude PATTERN [+] exclude names matching the given patterns
419 419 -S --subrepos recurse into subrepositories
420 420 -n --dry-run do not perform actions, just print output
421 421
422 422 global options ([+] can be repeated):
423 423
424 424 -R --repository REPO repository root directory or name of overlay bundle
425 425 file
426 426 --cwd DIR change working directory
427 427 -y --noninteractive do not prompt, automatically pick the first choice for
428 428 all prompts
429 429 -q --quiet suppress output
430 430 -v --verbose enable additional output
431 431 --color TYPE when to colorize (boolean, always, auto, never, or
432 432 debug)
433 433 --config CONFIG [+] set/override config option (use 'section.name=value')
434 434 --debug enable debugging output
435 435 --debugger start debugger
436 436 --encoding ENCODE set the charset encoding (default: ascii)
437 437 --encodingmode MODE set the charset encoding mode (default: strict)
438 438 --traceback always print a traceback on exception
439 439 --time time how long the command takes
440 440 --profile print command execution profile
441 441 --version output version information and exit
442 442 -h --help display help and exit
443 443 --hidden consider hidden changesets
444 444 --pager TYPE when to paginate (boolean, always, auto, or never)
445 445 (default: auto)
446 446
447 447 Test the textwidth config option
448 448
449 449 $ hg root -h --config ui.textwidth=50
450 450 hg root
451 451
452 452 print the root (top) of the current working
453 453 directory
454 454
455 455 Print the root directory of the current
456 456 repository.
457 457
458 458 Returns 0 on success.
459 459
460 460 (some details hidden, use --verbose to show
461 461 complete help)
462 462
463 463 Test help option with version option
464 464
465 465 $ hg add -h --version
466 466 Mercurial Distributed SCM (version *) (glob)
467 467 (see https://mercurial-scm.org for more information)
468 468
469 469 Copyright (C) 2005-* Matt Mackall and others (glob)
470 470 This is free software; see the source for copying conditions. There is NO
471 471 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
472 472
473 473 $ hg add --skjdfks
474 474 hg add: option --skjdfks not recognized
475 475 hg add [OPTION]... [FILE]...
476 476
477 477 add the specified files on the next commit
478 478
479 479 options ([+] can be repeated):
480 480
481 481 -I --include PATTERN [+] include names matching the given patterns
482 482 -X --exclude PATTERN [+] exclude names matching the given patterns
483 483 -S --subrepos recurse into subrepositories
484 484 -n --dry-run do not perform actions, just print output
485 485
486 486 (use 'hg add -h' to show more help)
487 487 [255]
488 488
489 489 Test ambiguous command help
490 490
491 491 $ hg help ad
492 492 list of commands:
493 493
494 494 add add the specified files on the next commit
495 495 addremove add all new files, delete all missing files
496 496
497 497 (use 'hg help -v ad' to show built-in aliases and global options)
498 498
499 499 Test command without options
500 500
501 501 $ hg help verify
502 502 hg verify
503 503
504 504 verify the integrity of the repository
505 505
506 506 Verify the integrity of the current repository.
507 507
508 508 This will perform an extensive check of the repository's integrity,
509 509 validating the hashes and checksums of each entry in the changelog,
510 510 manifest, and tracked files, as well as the integrity of their crosslinks
511 511 and indices.
512 512
513 513 Please see https://mercurial-scm.org/wiki/RepositoryCorruption for more
514 514 information about recovery from corruption of the repository.
515 515
516 516 Returns 0 on success, 1 if errors are encountered.
517 517
518 518 (some details hidden, use --verbose to show complete help)
519 519
520 520 $ hg help diff
521 521 hg diff [OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...
522 522
523 523 diff repository (or selected files)
524 524
525 525 Show differences between revisions for the specified files.
526 526
527 527 Differences between files are shown using the unified diff format.
528 528
529 529 Note:
530 530 'hg diff' may generate unexpected results for merges, as it will
531 531 default to comparing against the working directory's first parent
532 532 changeset if no revisions are specified.
533 533
534 534 When two revision arguments are given, then changes are shown between
535 535 those revisions. If only one revision is specified then that revision is
536 536 compared to the working directory, and, when no revisions are specified,
537 537 the working directory files are compared to its first parent.
538 538
539 539 Alternatively you can specify -c/--change with a revision to see the
540 540 changes in that changeset relative to its first parent.
541 541
542 542 Without the -a/--text option, diff will avoid generating diffs of files it
543 543 detects as binary. With -a, diff will generate a diff anyway, probably
544 544 with undesirable results.
545 545
546 546 Use the -g/--git option to generate diffs in the git extended diff format.
547 547 For more information, read 'hg help diffs'.
548 548
549 549 Returns 0 on success.
550 550
551 551 options ([+] can be repeated):
552 552
553 553 -r --rev REV [+] revision
554 554 -c --change REV change made by revision
555 555 -a --text treat all files as text
556 556 -g --git use git extended diff format
557 557 --binary generate binary diffs in git mode (default)
558 558 --nodates omit dates from diff headers
559 559 --noprefix omit a/ and b/ prefixes from filenames
560 560 -p --show-function show which function each change is in
561 561 --reverse produce a diff that undoes the changes
562 562 -w --ignore-all-space ignore white space when comparing lines
563 563 -b --ignore-space-change ignore changes in the amount of white space
564 564 -B --ignore-blank-lines ignore changes whose lines are all blank
565 565 -Z --ignore-space-at-eol ignore changes in whitespace at EOL
566 566 -U --unified NUM number of lines of context to show
567 567 --stat output diffstat-style summary of changes
568 568 --root DIR produce diffs relative to subdirectory
569 569 -I --include PATTERN [+] include names matching the given patterns
570 570 -X --exclude PATTERN [+] exclude names matching the given patterns
571 571 -S --subrepos recurse into subrepositories
572 572
573 573 (some details hidden, use --verbose to show complete help)
574 574
575 575 $ hg help status
576 576 hg status [OPTION]... [FILE]...
577 577
578 578 aliases: st
579 579
580 580 show changed files in the working directory
581 581
582 582 Show status of files in the repository. If names are given, only files
583 583 that match are shown. Files that are clean or ignored or the source of a
584 584 copy/move operation, are not listed unless -c/--clean, -i/--ignored,
585 585 -C/--copies or -A/--all are given. Unless options described with "show
586 586 only ..." are given, the options -mardu are used.
587 587
588 588 Option -q/--quiet hides untracked (unknown and ignored) files unless
589 589 explicitly requested with -u/--unknown or -i/--ignored.
590 590
591 591 Note:
592 592 'hg status' may appear to disagree with diff if permissions have
593 593 changed or a merge has occurred. The standard diff format does not
594 594 report permission changes and diff only reports changes relative to one
595 595 merge parent.
596 596
597 597 If one revision is given, it is used as the base revision. If two
598 598 revisions are given, the differences between them are shown. The --change
599 599 option can also be used as a shortcut to list the changed files of a
600 600 revision from its first parent.
601 601
602 602 The codes used to show the status of files are:
603 603
604 604 M = modified
605 605 A = added
606 606 R = removed
607 607 C = clean
608 608 ! = missing (deleted by non-hg command, but still tracked)
609 609 ? = not tracked
610 610 I = ignored
611 611 = origin of the previous file (with --copies)
612 612
613 613 Returns 0 on success.
614 614
615 615 options ([+] can be repeated):
616 616
617 617 -A --all show status of all files
618 618 -m --modified show only modified files
619 619 -a --added show only added files
620 620 -r --removed show only removed files
621 621 -d --deleted show only deleted (but tracked) files
622 622 -c --clean show only files without changes
623 623 -u --unknown show only unknown (not tracked) files
624 624 -i --ignored show only ignored files
625 625 -n --no-status hide status prefix
626 626 -C --copies show source of copied files
627 627 -0 --print0 end filenames with NUL, for use with xargs
628 628 --rev REV [+] show difference from revision
629 629 --change REV list the changed files of a revision
630 630 -I --include PATTERN [+] include names matching the given patterns
631 631 -X --exclude PATTERN [+] exclude names matching the given patterns
632 632 -S --subrepos recurse into subrepositories
633 633
634 634 (some details hidden, use --verbose to show complete help)
635 635
636 636 $ hg -q help status
637 637 hg status [OPTION]... [FILE]...
638 638
639 639 show changed files in the working directory
640 640
641 641 $ hg help foo
642 642 abort: no such help topic: foo
643 643 (try 'hg help --keyword foo')
644 644 [255]
645 645
646 646 $ hg skjdfks
647 647 hg: unknown command 'skjdfks'
648 648 Mercurial Distributed SCM
649 649
650 650 basic commands:
651 651
652 652 add add the specified files on the next commit
653 653 annotate show changeset information by line for each file
654 654 clone make a copy of an existing repository
655 655 commit commit the specified files or all outstanding changes
656 656 diff diff repository (or selected files)
657 657 export dump the header and diffs for one or more changesets
658 658 forget forget the specified files on the next commit
659 659 init create a new repository in the given directory
660 660 log show revision history of entire repository or files
661 661 merge merge another revision into working directory
662 662 pull pull changes from the specified source
663 663 push push changes to the specified destination
664 664 remove remove the specified files on the next commit
665 665 serve start stand-alone webserver
666 666 status show changed files in the working directory
667 667 summary summarize working directory state
668 668 update update working directory (or switch revisions)
669 669
670 670 (use 'hg help' for the full list of commands or 'hg -v' for details)
671 671 [255]
672 672
673 673 Typoed command gives suggestion
674 674 $ hg puls
675 675 hg: unknown command 'puls'
676 676 (did you mean one of pull, push?)
677 677 [255]
678 678
679 679 Not enabled extension gets suggested
680 680
681 681 $ hg rebase
682 682 hg: unknown command 'rebase'
683 683 'rebase' is provided by the following extension:
684 684
685 685 rebase command to move sets of revisions to a different ancestor
686 686
687 687 (use 'hg help extensions' for information on enabling extensions)
688 688 [255]
689 689
690 690 Disabled extension gets suggested
691 691 $ hg --config extensions.rebase=! rebase
692 692 hg: unknown command 'rebase'
693 693 'rebase' is provided by the following extension:
694 694
695 695 rebase command to move sets of revisions to a different ancestor
696 696
697 697 (use 'hg help extensions' for information on enabling extensions)
698 698 [255]
699 699
700 700 Make sure that we don't run afoul of the help system thinking that
701 701 this is a section and erroring out weirdly.
702 702
703 703 $ hg .log
704 704 hg: unknown command '.log'
705 705 (did you mean log?)
706 706 [255]
707 707
708 708 $ hg log.
709 709 hg: unknown command 'log.'
710 710 (did you mean log?)
711 711 [255]
712 712 $ hg pu.lh
713 713 hg: unknown command 'pu.lh'
714 714 (did you mean one of pull, push?)
715 715 [255]
716 716
717 717 $ cat > helpext.py <<EOF
718 718 > import os
719 719 > from mercurial import commands, fancyopts, registrar
720 720 >
721 721 > def func(arg):
722 722 > return '%sfoo' % arg
723 723 > class customopt(fancyopts.customopt):
724 724 > def newstate(self, oldstate, newparam, abort):
725 725 > return '%sbar' % oldstate
726 726 > cmdtable = {}
727 727 > command = registrar.command(cmdtable)
728 728 >
729 729 > @command(b'nohelp',
730 730 > [(b'', b'longdesc', 3, b'x'*67),
731 731 > (b'n', b'', None, b'normal desc'),
732 732 > (b'', b'newline', b'', b'line1\nline2'),
733 733 > (b'', b'callableopt', func, b'adds foo'),
734 734 > (b'', b'customopt', customopt(''), b'adds bar'),
735 735 > (b'', b'customopt-withdefault', customopt('foo'), b'adds bar')],
736 736 > b'hg nohelp',
737 737 > norepo=True)
738 738 > @command(b'debugoptADV', [(b'', b'aopt', None, b'option is (ADVANCED)')])
739 739 > @command(b'debugoptDEP', [(b'', b'dopt', None, b'option is (DEPRECATED)')])
740 740 > @command(b'debugoptEXP', [(b'', b'eopt', None, b'option is (EXPERIMENTAL)')])
741 741 > def nohelp(ui, *args, **kwargs):
742 742 > pass
743 743 >
744 744 > def uisetup(ui):
745 745 > ui.setconfig(b'alias', b'shellalias', b'!echo hi', b'helpext')
746 746 > ui.setconfig(b'alias', b'hgalias', b'summary', b'helpext')
747 747 >
748 748 > EOF
749 749 $ echo '[extensions]' >> $HGRCPATH
750 750 $ echo "helpext = `pwd`/helpext.py" >> $HGRCPATH
751 751
752 752 Test for aliases
753 753
754 754 $ hg help hgalias
755 755 hg hgalias [--remote]
756 756
757 757 alias for: hg summary
758 758
759 759 summarize working directory state
760 760
761 761 This generates a brief summary of the working directory state, including
762 762 parents, branch, commit status, phase and available updates.
763 763
764 764 With the --remote option, this will check the default paths for incoming
765 765 and outgoing changes. This can be time-consuming.
766 766
767 767 Returns 0 on success.
768 768
769 769 defined by: helpext
770 770
771 771 options:
772 772
773 773 --remote check for push and pull
774 774
775 775 (some details hidden, use --verbose to show complete help)
776 776
777 777 $ hg help shellalias
778 778 hg shellalias
779 779
780 shell alias for:
781
782 echo hi
780 shell alias for: echo hi
781
782 (no help text available)
783 783
784 784 defined by: helpext
785 785
786 786 (some details hidden, use --verbose to show complete help)
787 787
788 788 Test command with no help text
789 789
790 790 $ hg help nohelp
791 791 hg nohelp
792 792
793 793 (no help text available)
794 794
795 795 options:
796 796
797 797 --longdesc VALUE
798 798 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
799 799 xxxxxxxxxxxxxxxxxxxxxxx (default: 3)
800 800 -n -- normal desc
801 801 --newline VALUE line1 line2
802 802 --callableopt VALUE adds foo
803 803 --customopt VALUE adds bar
804 804 --customopt-withdefault VALUE adds bar (default: foo)
805 805
806 806 (some details hidden, use --verbose to show complete help)
807 807
808 808 $ hg help -k nohelp
809 809 Commands:
810 810
811 811 nohelp hg nohelp
812 812
813 813 Extension Commands:
814 814
815 815 nohelp (no help text available)
816 816
817 817 Test that default list of commands omits extension commands
818 818
819 819 $ hg help
820 820 Mercurial Distributed SCM
821 821
822 822 list of commands:
823 823
824 824 add add the specified files on the next commit
825 825 addremove add all new files, delete all missing files
826 826 annotate show changeset information by line for each file
827 827 archive create an unversioned archive of a repository revision
828 828 backout reverse effect of earlier changeset
829 829 bisect subdivision search of changesets
830 830 bookmarks create a new bookmark or list existing bookmarks
831 831 branch set or show the current branch name
832 832 branches list repository named branches
833 833 bundle create a bundle file
834 834 cat output the current or given revision of files
835 835 clone make a copy of an existing repository
836 836 commit commit the specified files or all outstanding changes
837 837 config show combined config settings from all hgrc files
838 838 copy mark files as copied for the next commit
839 839 diff diff repository (or selected files)
840 840 export dump the header and diffs for one or more changesets
841 841 files list tracked files
842 842 forget forget the specified files on the next commit
843 843 graft copy changes from other branches onto the current branch
844 844 grep search revision history for a pattern in specified files
845 845 heads show branch heads
846 846 help show help for a given topic or a help overview
847 847 identify identify the working directory or specified revision
848 848 import import an ordered set of patches
849 849 incoming show new changesets found in source
850 850 init create a new repository in the given directory
851 851 log show revision history of entire repository or files
852 852 manifest output the current or given revision of the project manifest
853 853 merge merge another revision into working directory
854 854 outgoing show changesets not found in the destination
855 855 paths show aliases for remote repositories
856 856 phase set or show the current phase name
857 857 pull pull changes from the specified source
858 858 push push changes to the specified destination
859 859 recover roll back an interrupted transaction
860 860 remove remove the specified files on the next commit
861 861 rename rename files; equivalent of copy + remove
862 862 resolve redo merges or set/view the merge status of files
863 863 revert restore files to their checkout state
864 864 root print the root (top) of the current working directory
865 865 serve start stand-alone webserver
866 866 status show changed files in the working directory
867 867 summary summarize working directory state
868 868 tag add one or more tags for the current or given revision
869 869 tags list repository tags
870 870 unbundle apply one or more bundle files
871 871 update update working directory (or switch revisions)
872 872 verify verify the integrity of the repository
873 873 version output version and copyright information
874 874
875 875 enabled extensions:
876 876
877 877 helpext (no help text available)
878 878
879 879 additional help topics:
880 880
881 881 bundlespec Bundle File Formats
882 882 color Colorizing Outputs
883 883 config Configuration Files
884 884 dates Date Formats
885 885 diffs Diff Formats
886 886 environment Environment Variables
887 887 extensions Using Additional Features
888 888 filesets Specifying File Sets
889 889 flags Command-line flags
890 890 glossary Glossary
891 891 hgignore Syntax for Mercurial Ignore Files
892 892 hgweb Configuring hgweb
893 893 internals Technical implementation topics
894 894 merge-tools Merge Tools
895 895 pager Pager Support
896 896 patterns File Name Patterns
897 897 phases Working with Phases
898 898 revisions Specifying Revisions
899 899 scripting Using Mercurial from scripts and automation
900 900 subrepos Subrepositories
901 901 templating Template Usage
902 902 urls URL Paths
903 903
904 904 (use 'hg help -v' to show built-in aliases and global options)
905 905
906 906
907 907 Test list of internal help commands
908 908
909 909 $ hg help debug
910 910 debug commands (internal and unsupported):
911 911
912 912 debugancestor
913 913 find the ancestor revision of two revisions in a given index
914 914 debugapplystreamclonebundle
915 915 apply a stream clone bundle file
916 916 debugbuilddag
917 917 builds a repo with a given DAG from scratch in the current
918 918 empty repo
919 919 debugbundle lists the contents of a bundle
920 920 debugcapabilities
921 921 lists the capabilities of a remote peer
922 922 debugcheckstate
923 923 validate the correctness of the current dirstate
924 924 debugcolor show available color, effects or style
925 925 debugcommands
926 926 list all available commands and options
927 927 debugcomplete
928 928 returns the completion list associated with the given command
929 929 debugcreatestreamclonebundle
930 930 create a stream clone bundle file
931 931 debugdag format the changelog or an index DAG as a concise textual
932 932 description
933 933 debugdata dump the contents of a data file revision
934 934 debugdate parse and display a date
935 935 debugdeltachain
936 936 dump information about delta chains in a revlog
937 937 debugdirstate
938 938 show the contents of the current dirstate
939 939 debugdiscovery
940 940 runs the changeset discovery protocol in isolation
941 941 debugdownload
942 942 download a resource using Mercurial logic and config
943 943 debugextensions
944 944 show information about active extensions
945 945 debugfileset parse and apply a fileset specification
946 946 debugformat display format information about the current repository
947 947 debugfsinfo show information detected about current filesystem
948 948 debuggetbundle
949 949 retrieves a bundle from a repo
950 950 debugignore display the combined ignore pattern and information about
951 951 ignored files
952 952 debugindex dump the contents of an index file
953 953 debugindexdot
954 954 dump an index DAG as a graphviz dot file
955 955 debuginstall test Mercurial installation
956 956 debugknown test whether node ids are known to a repo
957 957 debuglocks show or modify state of locks
958 958 debugmergestate
959 959 print merge state
960 960 debugnamecomplete
961 961 complete "names" - tags, open branch names, bookmark names
962 962 debugobsolete
963 963 create arbitrary obsolete marker
964 964 debugoptADV (no help text available)
965 965 debugoptDEP (no help text available)
966 966 debugoptEXP (no help text available)
967 967 debugpathcomplete
968 968 complete part or all of a tracked path
969 969 debugpeer establish a connection to a peer repository
970 970 debugpickmergetool
971 971 examine which merge tool is chosen for specified file
972 972 debugpushkey access the pushkey key/value protocol
973 973 debugpvec (no help text available)
974 974 debugrebuilddirstate
975 975 rebuild the dirstate as it would look like for the given
976 976 revision
977 977 debugrebuildfncache
978 978 rebuild the fncache file
979 979 debugrename dump rename information
980 980 debugrevlog show data and statistics about a revlog
981 981 debugrevspec parse and apply a revision specification
982 982 debugserve run a server with advanced settings
983 983 debugsetparents
984 984 manually set the parents of the current working directory
985 985 debugssl test a secure connection to a server
986 986 debugsub (no help text available)
987 987 debugsuccessorssets
988 988 show set of successors for revision
989 989 debugtemplate
990 990 parse and apply a template
991 991 debuguigetpass
992 992 show prompt to type password
993 993 debuguiprompt
994 994 show plain prompt
995 995 debugupdatecaches
996 996 warm all known caches in the repository
997 997 debugupgraderepo
998 998 upgrade a repository to use different features
999 999 debugwalk show how files match on given patterns
1000 1000 debugwhyunstable
1001 1001 explain instabilities of a changeset
1002 1002 debugwireargs
1003 1003 (no help text available)
1004 1004 debugwireproto
1005 1005 send wire protocol commands to a server
1006 1006
1007 1007 (use 'hg help -v debug' to show built-in aliases and global options)
1008 1008
1009 1009 internals topic renders index of available sub-topics
1010 1010
1011 1011 $ hg help internals
1012 1012 Technical implementation topics
1013 1013 """""""""""""""""""""""""""""""
1014 1014
1015 1015 To access a subtopic, use "hg help internals.{subtopic-name}"
1016 1016
1017 1017 bundle2 Bundle2
1018 1018 bundles Bundles
1019 1019 censor Censor
1020 1020 changegroups Changegroups
1021 1021 config Config Registrar
1022 1022 requirements Repository Requirements
1023 1023 revlogs Revision Logs
1024 1024 wireprotocol Wire Protocol
1025 1025
1026 1026 sub-topics can be accessed
1027 1027
1028 1028 $ hg help internals.changegroups
1029 1029 Changegroups
1030 1030 """"""""""""
1031 1031
1032 1032 Changegroups are representations of repository revlog data, specifically
1033 1033 the changelog data, root/flat manifest data, treemanifest data, and
1034 1034 filelogs.
1035 1035
1036 1036 There are 3 versions of changegroups: "1", "2", and "3". From a high-
1037 1037 level, versions "1" and "2" are almost exactly the same, with the only
1038 1038 difference being an additional item in the *delta header*. Version "3"
1039 1039 adds support for revlog flags in the *delta header* and optionally
1040 1040 exchanging treemanifests (enabled by setting an option on the
1041 1041 "changegroup" part in the bundle2).
1042 1042
1043 1043 Changegroups when not exchanging treemanifests consist of 3 logical
1044 1044 segments:
1045 1045
1046 1046 +---------------------------------+
1047 1047 | | | |
1048 1048 | changeset | manifest | filelogs |
1049 1049 | | | |
1050 1050 | | | |
1051 1051 +---------------------------------+
1052 1052
1053 1053 When exchanging treemanifests, there are 4 logical segments:
1054 1054
1055 1055 +-------------------------------------------------+
1056 1056 | | | | |
1057 1057 | changeset | root | treemanifests | filelogs |
1058 1058 | | manifest | | |
1059 1059 | | | | |
1060 1060 +-------------------------------------------------+
1061 1061
1062 1062 The principle building block of each segment is a *chunk*. A *chunk* is a
1063 1063 framed piece of data:
1064 1064
1065 1065 +---------------------------------------+
1066 1066 | | |
1067 1067 | length | data |
1068 1068 | (4 bytes) | (<length - 4> bytes) |
1069 1069 | | |
1070 1070 +---------------------------------------+
1071 1071
1072 1072 All integers are big-endian signed integers. Each chunk starts with a
1073 1073 32-bit integer indicating the length of the entire chunk (including the
1074 1074 length field itself).
1075 1075
1076 1076 There is a special case chunk that has a value of 0 for the length
1077 1077 ("0x00000000"). We call this an *empty chunk*.
1078 1078
1079 1079 Delta Groups
1080 1080 ============
1081 1081
1082 1082 A *delta group* expresses the content of a revlog as a series of deltas,
1083 1083 or patches against previous revisions.
1084 1084
1085 1085 Delta groups consist of 0 or more *chunks* followed by the *empty chunk*
1086 1086 to signal the end of the delta group:
1087 1087
1088 1088 +------------------------------------------------------------------------+
1089 1089 | | | | | |
1090 1090 | chunk0 length | chunk0 data | chunk1 length | chunk1 data | 0x0 |
1091 1091 | (4 bytes) | (various) | (4 bytes) | (various) | (4 bytes) |
1092 1092 | | | | | |
1093 1093 +------------------------------------------------------------------------+
1094 1094
1095 1095 Each *chunk*'s data consists of the following:
1096 1096
1097 1097 +---------------------------------------+
1098 1098 | | |
1099 1099 | delta header | delta data |
1100 1100 | (various by version) | (various) |
1101 1101 | | |
1102 1102 +---------------------------------------+
1103 1103
1104 1104 The *delta data* is a series of *delta*s that describe a diff from an
1105 1105 existing entry (either that the recipient already has, or previously
1106 1106 specified in the bundle/changegroup).
1107 1107
1108 1108 The *delta header* is different between versions "1", "2", and "3" of the
1109 1109 changegroup format.
1110 1110
1111 1111 Version 1 (headerlen=80):
1112 1112
1113 1113 +------------------------------------------------------+
1114 1114 | | | | |
1115 1115 | node | p1 node | p2 node | link node |
1116 1116 | (20 bytes) | (20 bytes) | (20 bytes) | (20 bytes) |
1117 1117 | | | | |
1118 1118 +------------------------------------------------------+
1119 1119
1120 1120 Version 2 (headerlen=100):
1121 1121
1122 1122 +------------------------------------------------------------------+
1123 1123 | | | | | |
1124 1124 | node | p1 node | p2 node | base node | link node |
1125 1125 | (20 bytes) | (20 bytes) | (20 bytes) | (20 bytes) | (20 bytes) |
1126 1126 | | | | | |
1127 1127 +------------------------------------------------------------------+
1128 1128
1129 1129 Version 3 (headerlen=102):
1130 1130
1131 1131 +------------------------------------------------------------------------------+
1132 1132 | | | | | | |
1133 1133 | node | p1 node | p2 node | base node | link node | flags |
1134 1134 | (20 bytes) | (20 bytes) | (20 bytes) | (20 bytes) | (20 bytes) | (2 bytes) |
1135 1135 | | | | | | |
1136 1136 +------------------------------------------------------------------------------+
1137 1137
1138 1138 The *delta data* consists of "chunklen - 4 - headerlen" bytes, which
1139 1139 contain a series of *delta*s, densely packed (no separators). These deltas
1140 1140 describe a diff from an existing entry (either that the recipient already
1141 1141 has, or previously specified in the bundle/changegroup). The format is
1142 1142 described more fully in "hg help internals.bdiff", but briefly:
1143 1143
1144 1144 +---------------------------------------------------------------+
1145 1145 | | | | |
1146 1146 | start offset | end offset | new length | content |
1147 1147 | (4 bytes) | (4 bytes) | (4 bytes) | (<new length> bytes) |
1148 1148 | | | | |
1149 1149 +---------------------------------------------------------------+
1150 1150
1151 1151 Please note that the length field in the delta data does *not* include
1152 1152 itself.
1153 1153
1154 1154 In version 1, the delta is always applied against the previous node from
1155 1155 the changegroup or the first parent if this is the first entry in the
1156 1156 changegroup.
1157 1157
1158 1158 In version 2 and up, the delta base node is encoded in the entry in the
1159 1159 changegroup. This allows the delta to be expressed against any parent,
1160 1160 which can result in smaller deltas and more efficient encoding of data.
1161 1161
1162 1162 Changeset Segment
1163 1163 =================
1164 1164
1165 1165 The *changeset segment* consists of a single *delta group* holding
1166 1166 changelog data. The *empty chunk* at the end of the *delta group* denotes
1167 1167 the boundary to the *manifest segment*.
1168 1168
1169 1169 Manifest Segment
1170 1170 ================
1171 1171
1172 1172 The *manifest segment* consists of a single *delta group* holding manifest
1173 1173 data. If treemanifests are in use, it contains only the manifest for the
1174 1174 root directory of the repository. Otherwise, it contains the entire
1175 1175 manifest data. The *empty chunk* at the end of the *delta group* denotes
1176 1176 the boundary to the next segment (either the *treemanifests segment* or
1177 1177 the *filelogs segment*, depending on version and the request options).
1178 1178
1179 1179 Treemanifests Segment
1180 1180 ---------------------
1181 1181
1182 1182 The *treemanifests segment* only exists in changegroup version "3", and
1183 1183 only if the 'treemanifest' param is part of the bundle2 changegroup part
1184 1184 (it is not possible to use changegroup version 3 outside of bundle2).
1185 1185 Aside from the filenames in the *treemanifests segment* containing a
1186 1186 trailing "/" character, it behaves identically to the *filelogs segment*
1187 1187 (see below). The final sub-segment is followed by an *empty chunk*
1188 1188 (logically, a sub-segment with filename size 0). This denotes the boundary
1189 1189 to the *filelogs segment*.
1190 1190
1191 1191 Filelogs Segment
1192 1192 ================
1193 1193
1194 1194 The *filelogs segment* consists of multiple sub-segments, each
1195 1195 corresponding to an individual file whose data is being described:
1196 1196
1197 1197 +--------------------------------------------------+
1198 1198 | | | | | |
1199 1199 | filelog0 | filelog1 | filelog2 | ... | 0x0 |
1200 1200 | | | | | (4 bytes) |
1201 1201 | | | | | |
1202 1202 +--------------------------------------------------+
1203 1203
1204 1204 The final filelog sub-segment is followed by an *empty chunk* (logically,
1205 1205 a sub-segment with filename size 0). This denotes the end of the segment
1206 1206 and of the overall changegroup.
1207 1207
1208 1208 Each filelog sub-segment consists of the following:
1209 1209
1210 1210 +------------------------------------------------------+
1211 1211 | | | |
1212 1212 | filename length | filename | delta group |
1213 1213 | (4 bytes) | (<length - 4> bytes) | (various) |
1214 1214 | | | |
1215 1215 +------------------------------------------------------+
1216 1216
1217 1217 That is, a *chunk* consisting of the filename (not terminated or padded)
1218 1218 followed by N chunks constituting the *delta group* for this file. The
1219 1219 *empty chunk* at the end of each *delta group* denotes the boundary to the
1220 1220 next filelog sub-segment.
1221 1221
1222 1222 Test list of commands with command with no help text
1223 1223
1224 1224 $ hg help helpext
1225 1225 helpext extension - no help text available
1226 1226
1227 1227 list of commands:
1228 1228
1229 1229 nohelp (no help text available)
1230 1230
1231 1231 (use 'hg help -v helpext' to show built-in aliases and global options)
1232 1232
1233 1233
1234 1234 test advanced, deprecated and experimental options are hidden in command help
1235 1235 $ hg help debugoptADV
1236 1236 hg debugoptADV
1237 1237
1238 1238 (no help text available)
1239 1239
1240 1240 options:
1241 1241
1242 1242 (some details hidden, use --verbose to show complete help)
1243 1243 $ hg help debugoptDEP
1244 1244 hg debugoptDEP
1245 1245
1246 1246 (no help text available)
1247 1247
1248 1248 options:
1249 1249
1250 1250 (some details hidden, use --verbose to show complete help)
1251 1251
1252 1252 $ hg help debugoptEXP
1253 1253 hg debugoptEXP
1254 1254
1255 1255 (no help text available)
1256 1256
1257 1257 options:
1258 1258
1259 1259 (some details hidden, use --verbose to show complete help)
1260 1260
1261 1261 test advanced, deprecated and experimental options are shown with -v
1262 1262 $ hg help -v debugoptADV | grep aopt
1263 1263 --aopt option is (ADVANCED)
1264 1264 $ hg help -v debugoptDEP | grep dopt
1265 1265 --dopt option is (DEPRECATED)
1266 1266 $ hg help -v debugoptEXP | grep eopt
1267 1267 --eopt option is (EXPERIMENTAL)
1268 1268
1269 1269 #if gettext
1270 1270 test deprecated option is hidden with translation with untranslated description
1271 1271 (use many globy for not failing on changed transaction)
1272 1272 $ LANGUAGE=sv hg help debugoptDEP
1273 1273 hg debugoptDEP
1274 1274
1275 1275 (*) (glob)
1276 1276
1277 1277 options:
1278 1278
1279 1279 (some details hidden, use --verbose to show complete help)
1280 1280 #endif
1281 1281
1282 1282 Test commands that collide with topics (issue4240)
1283 1283
1284 1284 $ hg config -hq
1285 1285 hg config [-u] [NAME]...
1286 1286
1287 1287 show combined config settings from all hgrc files
1288 1288 $ hg showconfig -hq
1289 1289 hg config [-u] [NAME]...
1290 1290
1291 1291 show combined config settings from all hgrc files
1292 1292
1293 1293 Test a help topic
1294 1294
1295 1295 $ hg help dates
1296 1296 Date Formats
1297 1297 """"""""""""
1298 1298
1299 1299 Some commands allow the user to specify a date, e.g.:
1300 1300
1301 1301 - backout, commit, import, tag: Specify the commit date.
1302 1302 - log, revert, update: Select revision(s) by date.
1303 1303
1304 1304 Many date formats are valid. Here are some examples:
1305 1305
1306 1306 - "Wed Dec 6 13:18:29 2006" (local timezone assumed)
1307 1307 - "Dec 6 13:18 -0600" (year assumed, time offset provided)
1308 1308 - "Dec 6 13:18 UTC" (UTC and GMT are aliases for +0000)
1309 1309 - "Dec 6" (midnight)
1310 1310 - "13:18" (today assumed)
1311 1311 - "3:39" (3:39AM assumed)
1312 1312 - "3:39pm" (15:39)
1313 1313 - "2006-12-06 13:18:29" (ISO 8601 format)
1314 1314 - "2006-12-6 13:18"
1315 1315 - "2006-12-6"
1316 1316 - "12-6"
1317 1317 - "12/6"
1318 1318 - "12/6/6" (Dec 6 2006)
1319 1319 - "today" (midnight)
1320 1320 - "yesterday" (midnight)
1321 1321 - "now" - right now
1322 1322
1323 1323 Lastly, there is Mercurial's internal format:
1324 1324
1325 1325 - "1165411109 0" (Wed Dec 6 13:18:29 2006 UTC)
1326 1326
1327 1327 This is the internal representation format for dates. The first number is
1328 1328 the number of seconds since the epoch (1970-01-01 00:00 UTC). The second
1329 1329 is the offset of the local timezone, in seconds west of UTC (negative if
1330 1330 the timezone is east of UTC).
1331 1331
1332 1332 The log command also accepts date ranges:
1333 1333
1334 1334 - "<DATE" - at or before a given date/time
1335 1335 - ">DATE" - on or after a given date/time
1336 1336 - "DATE to DATE" - a date range, inclusive
1337 1337 - "-DAYS" - within a given number of days of today
1338 1338
1339 1339 Test repeated config section name
1340 1340
1341 1341 $ hg help config.host
1342 1342 "http_proxy.host"
1343 1343 Host name and (optional) port of the proxy server, for example
1344 1344 "myproxy:8000".
1345 1345
1346 1346 "smtp.host"
1347 1347 Host name of mail server, e.g. "mail.example.com".
1348 1348
1349 1349 Unrelated trailing paragraphs shouldn't be included
1350 1350
1351 1351 $ hg help config.extramsg | grep '^$'
1352 1352
1353 1353
1354 1354 Test capitalized section name
1355 1355
1356 1356 $ hg help scripting.HGPLAIN > /dev/null
1357 1357
1358 1358 Help subsection:
1359 1359
1360 1360 $ hg help config.charsets |grep "Email example:" > /dev/null
1361 1361 [1]
1362 1362
1363 1363 Show nested definitions
1364 1364 ("profiling.type"[break]"ls"[break]"stat"[break])
1365 1365
1366 1366 $ hg help config.type | egrep '^$'|wc -l
1367 1367 \s*3 (re)
1368 1368
1369 1369 Separate sections from subsections
1370 1370
1371 1371 $ hg help config.format | egrep '^ ("|-)|^\s*$' | uniq
1372 1372 "format"
1373 1373 --------
1374 1374
1375 1375 "usegeneraldelta"
1376 1376
1377 1377 "dotencode"
1378 1378
1379 1379 "usefncache"
1380 1380
1381 1381 "usestore"
1382 1382
1383 1383 "profiling"
1384 1384 -----------
1385 1385
1386 1386 "format"
1387 1387
1388 1388 "progress"
1389 1389 ----------
1390 1390
1391 1391 "format"
1392 1392
1393 1393
1394 1394 Last item in help config.*:
1395 1395
1396 1396 $ hg help config.`hg help config|grep '^ "'| \
1397 1397 > tail -1|sed 's![ "]*!!g'`| \
1398 1398 > grep 'hg help -c config' > /dev/null
1399 1399 [1]
1400 1400
1401 1401 note to use help -c for general hg help config:
1402 1402
1403 1403 $ hg help config |grep 'hg help -c config' > /dev/null
1404 1404
1405 1405 Test templating help
1406 1406
1407 1407 $ hg help templating | egrep '(desc|diffstat|firstline|nonempty) '
1408 1408 desc String. The text of the changeset description.
1409 1409 diffstat String. Statistics of changes with the following format:
1410 1410 firstline Any text. Returns the first line of text.
1411 1411 nonempty Any text. Returns '(none)' if the string is empty.
1412 1412
1413 1413 Test deprecated items
1414 1414
1415 1415 $ hg help -v templating | grep currentbookmark
1416 1416 currentbookmark
1417 1417 $ hg help templating | (grep currentbookmark || true)
1418 1418
1419 1419 Test help hooks
1420 1420
1421 1421 $ cat > helphook1.py <<EOF
1422 1422 > from mercurial import help
1423 1423 >
1424 1424 > def rewrite(ui, topic, doc):
1425 1425 > return doc + '\nhelphook1\n'
1426 1426 >
1427 1427 > def extsetup(ui):
1428 1428 > help.addtopichook('revisions', rewrite)
1429 1429 > EOF
1430 1430 $ cat > helphook2.py <<EOF
1431 1431 > from mercurial import help
1432 1432 >
1433 1433 > def rewrite(ui, topic, doc):
1434 1434 > return doc + '\nhelphook2\n'
1435 1435 >
1436 1436 > def extsetup(ui):
1437 1437 > help.addtopichook('revisions', rewrite)
1438 1438 > EOF
1439 1439 $ echo '[extensions]' >> $HGRCPATH
1440 1440 $ echo "helphook1 = `pwd`/helphook1.py" >> $HGRCPATH
1441 1441 $ echo "helphook2 = `pwd`/helphook2.py" >> $HGRCPATH
1442 1442 $ hg help revsets | grep helphook
1443 1443 helphook1
1444 1444 helphook2
1445 1445
1446 1446 help -c should only show debug --debug
1447 1447
1448 1448 $ hg help -c --debug|egrep debug|wc -l|egrep '^\s*0\s*$'
1449 1449 [1]
1450 1450
1451 1451 help -c should only show deprecated for -v
1452 1452
1453 1453 $ hg help -c -v|egrep DEPRECATED|wc -l|egrep '^\s*0\s*$'
1454 1454 [1]
1455 1455
1456 1456 Test -s / --system
1457 1457
1458 1458 $ hg help config.files -s windows |grep 'etc/mercurial' | \
1459 1459 > wc -l | sed -e 's/ //g'
1460 1460 0
1461 1461 $ hg help config.files --system unix | grep 'USER' | \
1462 1462 > wc -l | sed -e 's/ //g'
1463 1463 0
1464 1464
1465 1465 Test -e / -c / -k combinations
1466 1466
1467 1467 $ hg help -c|egrep '^[A-Z].*:|^ debug'
1468 1468 Commands:
1469 1469 $ hg help -e|egrep '^[A-Z].*:|^ debug'
1470 1470 Extensions:
1471 1471 $ hg help -k|egrep '^[A-Z].*:|^ debug'
1472 1472 Topics:
1473 1473 Commands:
1474 1474 Extensions:
1475 1475 Extension Commands:
1476 1476 $ hg help -c schemes
1477 1477 abort: no such help topic: schemes
1478 1478 (try 'hg help --keyword schemes')
1479 1479 [255]
1480 1480 $ hg help -e schemes |head -1
1481 1481 schemes extension - extend schemes with shortcuts to repository swarms
1482 1482 $ hg help -c -k dates |egrep '^(Topics|Extensions|Commands):'
1483 1483 Commands:
1484 1484 $ hg help -e -k a |egrep '^(Topics|Extensions|Commands):'
1485 1485 Extensions:
1486 1486 $ hg help -e -c -k date |egrep '^(Topics|Extensions|Commands):'
1487 1487 Extensions:
1488 1488 Commands:
1489 1489 $ hg help -c commit > /dev/null
1490 1490 $ hg help -e -c commit > /dev/null
1491 1491 $ hg help -e commit > /dev/null
1492 1492 abort: no such help topic: commit
1493 1493 (try 'hg help --keyword commit')
1494 1494 [255]
1495 1495
1496 1496 Test keyword search help
1497 1497
1498 1498 $ cat > prefixedname.py <<EOF
1499 1499 > '''matched against word "clone"
1500 1500 > '''
1501 1501 > EOF
1502 1502 $ echo '[extensions]' >> $HGRCPATH
1503 1503 $ echo "dot.dot.prefixedname = `pwd`/prefixedname.py" >> $HGRCPATH
1504 1504 $ hg help -k clone
1505 1505 Topics:
1506 1506
1507 1507 config Configuration Files
1508 1508 extensions Using Additional Features
1509 1509 glossary Glossary
1510 1510 phases Working with Phases
1511 1511 subrepos Subrepositories
1512 1512 urls URL Paths
1513 1513
1514 1514 Commands:
1515 1515
1516 1516 bookmarks create a new bookmark or list existing bookmarks
1517 1517 clone make a copy of an existing repository
1518 1518 paths show aliases for remote repositories
1519 1519 update update working directory (or switch revisions)
1520 1520
1521 1521 Extensions:
1522 1522
1523 1523 clonebundles advertise pre-generated bundles to seed clones
1524 1524 narrow create clones which fetch history data for subset of files
1525 1525 (EXPERIMENTAL)
1526 1526 prefixedname matched against word "clone"
1527 1527 relink recreates hardlinks between repository clones
1528 1528
1529 1529 Extension Commands:
1530 1530
1531 1531 qclone clone main and patch repository at same time
1532 1532
1533 1533 Test unfound topic
1534 1534
1535 1535 $ hg help nonexistingtopicthatwillneverexisteverever
1536 1536 abort: no such help topic: nonexistingtopicthatwillneverexisteverever
1537 1537 (try 'hg help --keyword nonexistingtopicthatwillneverexisteverever')
1538 1538 [255]
1539 1539
1540 1540 Test unfound keyword
1541 1541
1542 1542 $ hg help --keyword nonexistingwordthatwillneverexisteverever
1543 1543 abort: no matches
1544 1544 (try 'hg help' for a list of topics)
1545 1545 [255]
1546 1546
1547 1547 Test omit indicating for help
1548 1548
1549 1549 $ cat > addverboseitems.py <<EOF
1550 1550 > '''extension to test omit indicating.
1551 1551 >
1552 1552 > This paragraph is never omitted (for extension)
1553 1553 >
1554 1554 > .. container:: verbose
1555 1555 >
1556 1556 > This paragraph is omitted,
1557 1557 > if :hg:\`help\` is invoked without \`\`-v\`\` (for extension)
1558 1558 >
1559 1559 > This paragraph is never omitted, too (for extension)
1560 1560 > '''
1561 1561 > from __future__ import absolute_import
1562 1562 > from mercurial import commands, help
1563 1563 > testtopic = """This paragraph is never omitted (for topic).
1564 1564 >
1565 1565 > .. container:: verbose
1566 1566 >
1567 1567 > This paragraph is omitted,
1568 1568 > if :hg:\`help\` is invoked without \`\`-v\`\` (for topic)
1569 1569 >
1570 1570 > This paragraph is never omitted, too (for topic)
1571 1571 > """
1572 1572 > def extsetup(ui):
1573 1573 > help.helptable.append((["topic-containing-verbose"],
1574 1574 > "This is the topic to test omit indicating.",
1575 1575 > lambda ui: testtopic))
1576 1576 > EOF
1577 1577 $ echo '[extensions]' >> $HGRCPATH
1578 1578 $ echo "addverboseitems = `pwd`/addverboseitems.py" >> $HGRCPATH
1579 1579 $ hg help addverboseitems
1580 1580 addverboseitems extension - extension to test omit indicating.
1581 1581
1582 1582 This paragraph is never omitted (for extension)
1583 1583
1584 1584 This paragraph is never omitted, too (for extension)
1585 1585
1586 1586 (some details hidden, use --verbose to show complete help)
1587 1587
1588 1588 no commands defined
1589 1589 $ hg help -v addverboseitems
1590 1590 addverboseitems extension - extension to test omit indicating.
1591 1591
1592 1592 This paragraph is never omitted (for extension)
1593 1593
1594 1594 This paragraph is omitted, if 'hg help' is invoked without "-v" (for
1595 1595 extension)
1596 1596
1597 1597 This paragraph is never omitted, too (for extension)
1598 1598
1599 1599 no commands defined
1600 1600 $ hg help topic-containing-verbose
1601 1601 This is the topic to test omit indicating.
1602 1602 """"""""""""""""""""""""""""""""""""""""""
1603 1603
1604 1604 This paragraph is never omitted (for topic).
1605 1605
1606 1606 This paragraph is never omitted, too (for topic)
1607 1607
1608 1608 (some details hidden, use --verbose to show complete help)
1609 1609 $ hg help -v topic-containing-verbose
1610 1610 This is the topic to test omit indicating.
1611 1611 """"""""""""""""""""""""""""""""""""""""""
1612 1612
1613 1613 This paragraph is never omitted (for topic).
1614 1614
1615 1615 This paragraph is omitted, if 'hg help' is invoked without "-v" (for
1616 1616 topic)
1617 1617
1618 1618 This paragraph is never omitted, too (for topic)
1619 1619
1620 1620 Test section lookup
1621 1621
1622 1622 $ hg help revset.merge
1623 1623 "merge()"
1624 1624 Changeset is a merge changeset.
1625 1625
1626 1626 $ hg help glossary.dag
1627 1627 DAG
1628 1628 The repository of changesets of a distributed version control system
1629 1629 (DVCS) can be described as a directed acyclic graph (DAG), consisting
1630 1630 of nodes and edges, where nodes correspond to changesets and edges
1631 1631 imply a parent -> child relation. This graph can be visualized by
1632 1632 graphical tools such as 'hg log --graph'. In Mercurial, the DAG is
1633 1633 limited by the requirement for children to have at most two parents.
1634 1634
1635 1635
1636 1636 $ hg help hgrc.paths
1637 1637 "paths"
1638 1638 -------
1639 1639
1640 1640 Assigns symbolic names and behavior to repositories.
1641 1641
1642 1642 Options are symbolic names defining the URL or directory that is the
1643 1643 location of the repository. Example:
1644 1644
1645 1645 [paths]
1646 1646 my_server = https://example.com/my_repo
1647 1647 local_path = /home/me/repo
1648 1648
1649 1649 These symbolic names can be used from the command line. To pull from
1650 1650 "my_server": 'hg pull my_server'. To push to "local_path": 'hg push
1651 1651 local_path'.
1652 1652
1653 1653 Options containing colons (":") denote sub-options that can influence
1654 1654 behavior for that specific path. Example:
1655 1655
1656 1656 [paths]
1657 1657 my_server = https://example.com/my_path
1658 1658 my_server:pushurl = ssh://example.com/my_path
1659 1659
1660 1660 The following sub-options can be defined:
1661 1661
1662 1662 "pushurl"
1663 1663 The URL to use for push operations. If not defined, the location
1664 1664 defined by the path's main entry is used.
1665 1665
1666 1666 "pushrev"
1667 1667 A revset defining which revisions to push by default.
1668 1668
1669 1669 When 'hg push' is executed without a "-r" argument, the revset defined
1670 1670 by this sub-option is evaluated to determine what to push.
1671 1671
1672 1672 For example, a value of "." will push the working directory's revision
1673 1673 by default.
1674 1674
1675 1675 Revsets specifying bookmarks will not result in the bookmark being
1676 1676 pushed.
1677 1677
1678 1678 The following special named paths exist:
1679 1679
1680 1680 "default"
1681 1681 The URL or directory to use when no source or remote is specified.
1682 1682
1683 1683 'hg clone' will automatically define this path to the location the
1684 1684 repository was cloned from.
1685 1685
1686 1686 "default-push"
1687 1687 (deprecated) The URL or directory for the default 'hg push' location.
1688 1688 "default:pushurl" should be used instead.
1689 1689
1690 1690 $ hg help glossary.mcguffin
1691 1691 abort: help section not found: glossary.mcguffin
1692 1692 [255]
1693 1693
1694 1694 $ hg help glossary.mc.guffin
1695 1695 abort: help section not found: glossary.mc.guffin
1696 1696 [255]
1697 1697
1698 1698 $ hg help template.files
1699 1699 files List of strings. All files modified, added, or removed by
1700 1700 this changeset.
1701 1701 files(pattern)
1702 1702 All files of the current changeset matching the pattern. See
1703 1703 'hg help patterns'.
1704 1704
1705 1705 Test section lookup by translated message
1706 1706
1707 1707 str.lower() instead of encoding.lower(str) on translated message might
1708 1708 make message meaningless, because some encoding uses 0x41(A) - 0x5a(Z)
1709 1709 as the second or later byte of multi-byte character.
1710 1710
1711 1711 For example, "\x8bL\x98^" (translation of "record" in ja_JP.cp932)
1712 1712 contains 0x4c (L). str.lower() replaces 0x4c(L) by 0x6c(l) and this
1713 1713 replacement makes message meaningless.
1714 1714
1715 1715 This tests that section lookup by translated string isn't broken by
1716 1716 such str.lower().
1717 1717
1718 1718 $ $PYTHON <<EOF
1719 1719 > def escape(s):
1720 1720 > return ''.join('\u%x' % ord(uc) for uc in s.decode('cp932'))
1721 1721 > # translation of "record" in ja_JP.cp932
1722 1722 > upper = "\x8bL\x98^"
1723 1723 > # str.lower()-ed section name should be treated as different one
1724 1724 > lower = "\x8bl\x98^"
1725 1725 > with open('ambiguous.py', 'w') as fp:
1726 1726 > fp.write("""# ambiguous section names in ja_JP.cp932
1727 1727 > u'''summary of extension
1728 1728 >
1729 1729 > %s
1730 1730 > ----
1731 1731 >
1732 1732 > Upper name should show only this message
1733 1733 >
1734 1734 > %s
1735 1735 > ----
1736 1736 >
1737 1737 > Lower name should show only this message
1738 1738 >
1739 1739 > subsequent section
1740 1740 > ------------------
1741 1741 >
1742 1742 > This should be hidden at 'hg help ambiguous' with section name.
1743 1743 > '''
1744 1744 > """ % (escape(upper), escape(lower)))
1745 1745 > EOF
1746 1746
1747 1747 $ cat >> $HGRCPATH <<EOF
1748 1748 > [extensions]
1749 1749 > ambiguous = ./ambiguous.py
1750 1750 > EOF
1751 1751
1752 1752 $ $PYTHON <<EOF | sh
1753 1753 > upper = "\x8bL\x98^"
1754 1754 > print("hg --encoding cp932 help -e ambiguous.%s" % upper)
1755 1755 > EOF
1756 1756 \x8bL\x98^ (esc)
1757 1757 ----
1758 1758
1759 1759 Upper name should show only this message
1760 1760
1761 1761
1762 1762 $ $PYTHON <<EOF | sh
1763 1763 > lower = "\x8bl\x98^"
1764 1764 > print("hg --encoding cp932 help -e ambiguous.%s" % lower)
1765 1765 > EOF
1766 1766 \x8bl\x98^ (esc)
1767 1767 ----
1768 1768
1769 1769 Lower name should show only this message
1770 1770
1771 1771
1772 1772 $ cat >> $HGRCPATH <<EOF
1773 1773 > [extensions]
1774 1774 > ambiguous = !
1775 1775 > EOF
1776 1776
1777 1777 Show help content of disabled extensions
1778 1778
1779 1779 $ cat >> $HGRCPATH <<EOF
1780 1780 > [extensions]
1781 1781 > ambiguous = !./ambiguous.py
1782 1782 > EOF
1783 1783 $ hg help -e ambiguous
1784 1784 ambiguous extension - (no help text available)
1785 1785
1786 1786 (use 'hg help extensions' for information on enabling extensions)
1787 1787
1788 1788 Test dynamic list of merge tools only shows up once
1789 1789 $ hg help merge-tools
1790 1790 Merge Tools
1791 1791 """""""""""
1792 1792
1793 1793 To merge files Mercurial uses merge tools.
1794 1794
1795 1795 A merge tool combines two different versions of a file into a merged file.
1796 1796 Merge tools are given the two files and the greatest common ancestor of
1797 1797 the two file versions, so they can determine the changes made on both
1798 1798 branches.
1799 1799
1800 1800 Merge tools are used both for 'hg resolve', 'hg merge', 'hg update', 'hg
1801 1801 backout' and in several extensions.
1802 1802
1803 1803 Usually, the merge tool tries to automatically reconcile the files by
1804 1804 combining all non-overlapping changes that occurred separately in the two
1805 1805 different evolutions of the same initial base file. Furthermore, some
1806 1806 interactive merge programs make it easier to manually resolve conflicting
1807 1807 merges, either in a graphical way, or by inserting some conflict markers.
1808 1808 Mercurial does not include any interactive merge programs but relies on
1809 1809 external tools for that.
1810 1810
1811 1811 Available merge tools
1812 1812 =====================
1813 1813
1814 1814 External merge tools and their properties are configured in the merge-
1815 1815 tools configuration section - see hgrc(5) - but they can often just be
1816 1816 named by their executable.
1817 1817
1818 1818 A merge tool is generally usable if its executable can be found on the
1819 1819 system and if it can handle the merge. The executable is found if it is an
1820 1820 absolute or relative executable path or the name of an application in the
1821 1821 executable search path. The tool is assumed to be able to handle the merge
1822 1822 if it can handle symlinks if the file is a symlink, if it can handle
1823 1823 binary files if the file is binary, and if a GUI is available if the tool
1824 1824 requires a GUI.
1825 1825
1826 1826 There are some internal merge tools which can be used. The internal merge
1827 1827 tools are:
1828 1828
1829 1829 ":dump"
1830 1830 Creates three versions of the files to merge, containing the contents of
1831 1831 local, other and base. These files can then be used to perform a merge
1832 1832 manually. If the file to be merged is named "a.txt", these files will
1833 1833 accordingly be named "a.txt.local", "a.txt.other" and "a.txt.base" and
1834 1834 they will be placed in the same directory as "a.txt".
1835 1835
1836 1836 This implies premerge. Therefore, files aren't dumped, if premerge runs
1837 1837 successfully. Use :forcedump to forcibly write files out.
1838 1838
1839 1839 ":fail"
1840 1840 Rather than attempting to merge files that were modified on both
1841 1841 branches, it marks them as unresolved. The resolve command must be used
1842 1842 to resolve these conflicts.
1843 1843
1844 1844 ":forcedump"
1845 1845 Creates three versions of the files as same as :dump, but omits
1846 1846 premerge.
1847 1847
1848 1848 ":local"
1849 1849 Uses the local 'p1()' version of files as the merged version.
1850 1850
1851 1851 ":merge"
1852 1852 Uses the internal non-interactive simple merge algorithm for merging
1853 1853 files. It will fail if there are any conflicts and leave markers in the
1854 1854 partially merged file. Markers will have two sections, one for each side
1855 1855 of merge.
1856 1856
1857 1857 ":merge-local"
1858 1858 Like :merge, but resolve all conflicts non-interactively in favor of the
1859 1859 local 'p1()' changes.
1860 1860
1861 1861 ":merge-other"
1862 1862 Like :merge, but resolve all conflicts non-interactively in favor of the
1863 1863 other 'p2()' changes.
1864 1864
1865 1865 ":merge3"
1866 1866 Uses the internal non-interactive simple merge algorithm for merging
1867 1867 files. It will fail if there are any conflicts and leave markers in the
1868 1868 partially merged file. Marker will have three sections, one from each
1869 1869 side of the merge and one for the base content.
1870 1870
1871 1871 ":other"
1872 1872 Uses the other 'p2()' version of files as the merged version.
1873 1873
1874 1874 ":prompt"
1875 1875 Asks the user which of the local 'p1()' or the other 'p2()' version to
1876 1876 keep as the merged version.
1877 1877
1878 1878 ":tagmerge"
1879 1879 Uses the internal tag merge algorithm (experimental).
1880 1880
1881 1881 ":union"
1882 1882 Uses the internal non-interactive simple merge algorithm for merging
1883 1883 files. It will use both left and right sides for conflict regions. No
1884 1884 markers are inserted.
1885 1885
1886 1886 Internal tools are always available and do not require a GUI but will by
1887 1887 default not handle symlinks or binary files.
1888 1888
1889 1889 Choosing a merge tool
1890 1890 =====================
1891 1891
1892 1892 Mercurial uses these rules when deciding which merge tool to use:
1893 1893
1894 1894 1. If a tool has been specified with the --tool option to merge or
1895 1895 resolve, it is used. If it is the name of a tool in the merge-tools
1896 1896 configuration, its configuration is used. Otherwise the specified tool
1897 1897 must be executable by the shell.
1898 1898 2. If the "HGMERGE" environment variable is present, its value is used and
1899 1899 must be executable by the shell.
1900 1900 3. If the filename of the file to be merged matches any of the patterns in
1901 1901 the merge-patterns configuration section, the first usable merge tool
1902 1902 corresponding to a matching pattern is used. Here, binary capabilities
1903 1903 of the merge tool are not considered.
1904 1904 4. If ui.merge is set it will be considered next. If the value is not the
1905 1905 name of a configured tool, the specified value is used and must be
1906 1906 executable by the shell. Otherwise the named tool is used if it is
1907 1907 usable.
1908 1908 5. If any usable merge tools are present in the merge-tools configuration
1909 1909 section, the one with the highest priority is used.
1910 1910 6. If a program named "hgmerge" can be found on the system, it is used -
1911 1911 but it will by default not be used for symlinks and binary files.
1912 1912 7. If the file to be merged is not binary and is not a symlink, then
1913 1913 internal ":merge" is used.
1914 1914 8. Otherwise, ":prompt" is used.
1915 1915
1916 1916 Note:
1917 1917 After selecting a merge program, Mercurial will by default attempt to
1918 1918 merge the files using a simple merge algorithm first. Only if it
1919 1919 doesn't succeed because of conflicting changes will Mercurial actually
1920 1920 execute the merge program. Whether to use the simple merge algorithm
1921 1921 first can be controlled by the premerge setting of the merge tool.
1922 1922 Premerge is enabled by default unless the file is binary or a symlink.
1923 1923
1924 1924 See the merge-tools and ui sections of hgrc(5) for details on the
1925 1925 configuration of merge tools.
1926 1926
1927 1927 Compression engines listed in `hg help bundlespec`
1928 1928
1929 1929 $ hg help bundlespec | grep gzip
1930 1930 "v1" bundles can only use the "gzip", "bzip2", and "none" compression
1931 1931 An algorithm that produces smaller bundles than "gzip".
1932 1932 This engine will likely produce smaller bundles than "gzip" but will be
1933 1933 "gzip"
1934 1934 better compression than "gzip". It also frequently yields better (?)
1935 1935
1936 1936 Test usage of section marks in help documents
1937 1937
1938 1938 $ cd "$TESTDIR"/../doc
1939 1939 $ $PYTHON check-seclevel.py
1940 1940 $ cd $TESTTMP
1941 1941
1942 1942 #if serve
1943 1943
1944 1944 Test the help pages in hgweb.
1945 1945
1946 1946 Dish up an empty repo; serve it cold.
1947 1947
1948 1948 $ hg init "$TESTTMP/test"
1949 1949 $ hg serve -R "$TESTTMP/test" -n test -p $HGPORT -d --pid-file=hg.pid
1950 1950 $ cat hg.pid >> $DAEMON_PIDS
1951 1951
1952 1952 $ get-with-headers.py $LOCALIP:$HGPORT "help"
1953 1953 200 Script output follows
1954 1954
1955 1955 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
1956 1956 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
1957 1957 <head>
1958 1958 <link rel="icon" href="/static/hgicon.png" type="image/png" />
1959 1959 <meta name="robots" content="index, nofollow" />
1960 1960 <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
1961 1961 <script type="text/javascript" src="/static/mercurial.js"></script>
1962 1962
1963 1963 <title>Help: Index</title>
1964 1964 </head>
1965 1965 <body>
1966 1966
1967 1967 <div class="container">
1968 1968 <div class="menu">
1969 1969 <div class="logo">
1970 1970 <a href="https://mercurial-scm.org/">
1971 1971 <img src="/static/hglogo.png" alt="mercurial" /></a>
1972 1972 </div>
1973 1973 <ul>
1974 1974 <li><a href="/shortlog">log</a></li>
1975 1975 <li><a href="/graph">graph</a></li>
1976 1976 <li><a href="/tags">tags</a></li>
1977 1977 <li><a href="/bookmarks">bookmarks</a></li>
1978 1978 <li><a href="/branches">branches</a></li>
1979 1979 </ul>
1980 1980 <ul>
1981 1981 <li class="active">help</li>
1982 1982 </ul>
1983 1983 </div>
1984 1984
1985 1985 <div class="main">
1986 1986 <h2 class="breadcrumb"><a href="/">Mercurial</a> </h2>
1987 1987
1988 1988 <form class="search" action="/log">
1989 1989
1990 1990 <p><input name="rev" id="search1" type="text" size="30" value="" /></p>
1991 1991 <div id="hint">Find changesets by keywords (author, files, the commit message), revision
1992 1992 number or hash, or <a href="/help/revsets">revset expression</a>.</div>
1993 1993 </form>
1994 1994 <table class="bigtable">
1995 1995 <tr><td colspan="2"><h2><a name="topics" href="#topics">Topics</a></h2></td></tr>
1996 1996
1997 1997 <tr><td>
1998 1998 <a href="/help/bundlespec">
1999 1999 bundlespec
2000 2000 </a>
2001 2001 </td><td>
2002 2002 Bundle File Formats
2003 2003 </td></tr>
2004 2004 <tr><td>
2005 2005 <a href="/help/color">
2006 2006 color
2007 2007 </a>
2008 2008 </td><td>
2009 2009 Colorizing Outputs
2010 2010 </td></tr>
2011 2011 <tr><td>
2012 2012 <a href="/help/config">
2013 2013 config
2014 2014 </a>
2015 2015 </td><td>
2016 2016 Configuration Files
2017 2017 </td></tr>
2018 2018 <tr><td>
2019 2019 <a href="/help/dates">
2020 2020 dates
2021 2021 </a>
2022 2022 </td><td>
2023 2023 Date Formats
2024 2024 </td></tr>
2025 2025 <tr><td>
2026 2026 <a href="/help/diffs">
2027 2027 diffs
2028 2028 </a>
2029 2029 </td><td>
2030 2030 Diff Formats
2031 2031 </td></tr>
2032 2032 <tr><td>
2033 2033 <a href="/help/environment">
2034 2034 environment
2035 2035 </a>
2036 2036 </td><td>
2037 2037 Environment Variables
2038 2038 </td></tr>
2039 2039 <tr><td>
2040 2040 <a href="/help/extensions">
2041 2041 extensions
2042 2042 </a>
2043 2043 </td><td>
2044 2044 Using Additional Features
2045 2045 </td></tr>
2046 2046 <tr><td>
2047 2047 <a href="/help/filesets">
2048 2048 filesets
2049 2049 </a>
2050 2050 </td><td>
2051 2051 Specifying File Sets
2052 2052 </td></tr>
2053 2053 <tr><td>
2054 2054 <a href="/help/flags">
2055 2055 flags
2056 2056 </a>
2057 2057 </td><td>
2058 2058 Command-line flags
2059 2059 </td></tr>
2060 2060 <tr><td>
2061 2061 <a href="/help/glossary">
2062 2062 glossary
2063 2063 </a>
2064 2064 </td><td>
2065 2065 Glossary
2066 2066 </td></tr>
2067 2067 <tr><td>
2068 2068 <a href="/help/hgignore">
2069 2069 hgignore
2070 2070 </a>
2071 2071 </td><td>
2072 2072 Syntax for Mercurial Ignore Files
2073 2073 </td></tr>
2074 2074 <tr><td>
2075 2075 <a href="/help/hgweb">
2076 2076 hgweb
2077 2077 </a>
2078 2078 </td><td>
2079 2079 Configuring hgweb
2080 2080 </td></tr>
2081 2081 <tr><td>
2082 2082 <a href="/help/internals">
2083 2083 internals
2084 2084 </a>
2085 2085 </td><td>
2086 2086 Technical implementation topics
2087 2087 </td></tr>
2088 2088 <tr><td>
2089 2089 <a href="/help/merge-tools">
2090 2090 merge-tools
2091 2091 </a>
2092 2092 </td><td>
2093 2093 Merge Tools
2094 2094 </td></tr>
2095 2095 <tr><td>
2096 2096 <a href="/help/pager">
2097 2097 pager
2098 2098 </a>
2099 2099 </td><td>
2100 2100 Pager Support
2101 2101 </td></tr>
2102 2102 <tr><td>
2103 2103 <a href="/help/patterns">
2104 2104 patterns
2105 2105 </a>
2106 2106 </td><td>
2107 2107 File Name Patterns
2108 2108 </td></tr>
2109 2109 <tr><td>
2110 2110 <a href="/help/phases">
2111 2111 phases
2112 2112 </a>
2113 2113 </td><td>
2114 2114 Working with Phases
2115 2115 </td></tr>
2116 2116 <tr><td>
2117 2117 <a href="/help/revisions">
2118 2118 revisions
2119 2119 </a>
2120 2120 </td><td>
2121 2121 Specifying Revisions
2122 2122 </td></tr>
2123 2123 <tr><td>
2124 2124 <a href="/help/scripting">
2125 2125 scripting
2126 2126 </a>
2127 2127 </td><td>
2128 2128 Using Mercurial from scripts and automation
2129 2129 </td></tr>
2130 2130 <tr><td>
2131 2131 <a href="/help/subrepos">
2132 2132 subrepos
2133 2133 </a>
2134 2134 </td><td>
2135 2135 Subrepositories
2136 2136 </td></tr>
2137 2137 <tr><td>
2138 2138 <a href="/help/templating">
2139 2139 templating
2140 2140 </a>
2141 2141 </td><td>
2142 2142 Template Usage
2143 2143 </td></tr>
2144 2144 <tr><td>
2145 2145 <a href="/help/urls">
2146 2146 urls
2147 2147 </a>
2148 2148 </td><td>
2149 2149 URL Paths
2150 2150 </td></tr>
2151 2151 <tr><td>
2152 2152 <a href="/help/topic-containing-verbose">
2153 2153 topic-containing-verbose
2154 2154 </a>
2155 2155 </td><td>
2156 2156 This is the topic to test omit indicating.
2157 2157 </td></tr>
2158 2158
2159 2159
2160 2160 <tr><td colspan="2"><h2><a name="main" href="#main">Main Commands</a></h2></td></tr>
2161 2161
2162 2162 <tr><td>
2163 2163 <a href="/help/add">
2164 2164 add
2165 2165 </a>
2166 2166 </td><td>
2167 2167 add the specified files on the next commit
2168 2168 </td></tr>
2169 2169 <tr><td>
2170 2170 <a href="/help/annotate">
2171 2171 annotate
2172 2172 </a>
2173 2173 </td><td>
2174 2174 show changeset information by line for each file
2175 2175 </td></tr>
2176 2176 <tr><td>
2177 2177 <a href="/help/clone">
2178 2178 clone
2179 2179 </a>
2180 2180 </td><td>
2181 2181 make a copy of an existing repository
2182 2182 </td></tr>
2183 2183 <tr><td>
2184 2184 <a href="/help/commit">
2185 2185 commit
2186 2186 </a>
2187 2187 </td><td>
2188 2188 commit the specified files or all outstanding changes
2189 2189 </td></tr>
2190 2190 <tr><td>
2191 2191 <a href="/help/diff">
2192 2192 diff
2193 2193 </a>
2194 2194 </td><td>
2195 2195 diff repository (or selected files)
2196 2196 </td></tr>
2197 2197 <tr><td>
2198 2198 <a href="/help/export">
2199 2199 export
2200 2200 </a>
2201 2201 </td><td>
2202 2202 dump the header and diffs for one or more changesets
2203 2203 </td></tr>
2204 2204 <tr><td>
2205 2205 <a href="/help/forget">
2206 2206 forget
2207 2207 </a>
2208 2208 </td><td>
2209 2209 forget the specified files on the next commit
2210 2210 </td></tr>
2211 2211 <tr><td>
2212 2212 <a href="/help/init">
2213 2213 init
2214 2214 </a>
2215 2215 </td><td>
2216 2216 create a new repository in the given directory
2217 2217 </td></tr>
2218 2218 <tr><td>
2219 2219 <a href="/help/log">
2220 2220 log
2221 2221 </a>
2222 2222 </td><td>
2223 2223 show revision history of entire repository or files
2224 2224 </td></tr>
2225 2225 <tr><td>
2226 2226 <a href="/help/merge">
2227 2227 merge
2228 2228 </a>
2229 2229 </td><td>
2230 2230 merge another revision into working directory
2231 2231 </td></tr>
2232 2232 <tr><td>
2233 2233 <a href="/help/pull">
2234 2234 pull
2235 2235 </a>
2236 2236 </td><td>
2237 2237 pull changes from the specified source
2238 2238 </td></tr>
2239 2239 <tr><td>
2240 2240 <a href="/help/push">
2241 2241 push
2242 2242 </a>
2243 2243 </td><td>
2244 2244 push changes to the specified destination
2245 2245 </td></tr>
2246 2246 <tr><td>
2247 2247 <a href="/help/remove">
2248 2248 remove
2249 2249 </a>
2250 2250 </td><td>
2251 2251 remove the specified files on the next commit
2252 2252 </td></tr>
2253 2253 <tr><td>
2254 2254 <a href="/help/serve">
2255 2255 serve
2256 2256 </a>
2257 2257 </td><td>
2258 2258 start stand-alone webserver
2259 2259 </td></tr>
2260 2260 <tr><td>
2261 2261 <a href="/help/status">
2262 2262 status
2263 2263 </a>
2264 2264 </td><td>
2265 2265 show changed files in the working directory
2266 2266 </td></tr>
2267 2267 <tr><td>
2268 2268 <a href="/help/summary">
2269 2269 summary
2270 2270 </a>
2271 2271 </td><td>
2272 2272 summarize working directory state
2273 2273 </td></tr>
2274 2274 <tr><td>
2275 2275 <a href="/help/update">
2276 2276 update
2277 2277 </a>
2278 2278 </td><td>
2279 2279 update working directory (or switch revisions)
2280 2280 </td></tr>
2281 2281
2282 2282
2283 2283
2284 2284 <tr><td colspan="2"><h2><a name="other" href="#other">Other Commands</a></h2></td></tr>
2285 2285
2286 2286 <tr><td>
2287 2287 <a href="/help/addremove">
2288 2288 addremove
2289 2289 </a>
2290 2290 </td><td>
2291 2291 add all new files, delete all missing files
2292 2292 </td></tr>
2293 2293 <tr><td>
2294 2294 <a href="/help/archive">
2295 2295 archive
2296 2296 </a>
2297 2297 </td><td>
2298 2298 create an unversioned archive of a repository revision
2299 2299 </td></tr>
2300 2300 <tr><td>
2301 2301 <a href="/help/backout">
2302 2302 backout
2303 2303 </a>
2304 2304 </td><td>
2305 2305 reverse effect of earlier changeset
2306 2306 </td></tr>
2307 2307 <tr><td>
2308 2308 <a href="/help/bisect">
2309 2309 bisect
2310 2310 </a>
2311 2311 </td><td>
2312 2312 subdivision search of changesets
2313 2313 </td></tr>
2314 2314 <tr><td>
2315 2315 <a href="/help/bookmarks">
2316 2316 bookmarks
2317 2317 </a>
2318 2318 </td><td>
2319 2319 create a new bookmark or list existing bookmarks
2320 2320 </td></tr>
2321 2321 <tr><td>
2322 2322 <a href="/help/branch">
2323 2323 branch
2324 2324 </a>
2325 2325 </td><td>
2326 2326 set or show the current branch name
2327 2327 </td></tr>
2328 2328 <tr><td>
2329 2329 <a href="/help/branches">
2330 2330 branches
2331 2331 </a>
2332 2332 </td><td>
2333 2333 list repository named branches
2334 2334 </td></tr>
2335 2335 <tr><td>
2336 2336 <a href="/help/bundle">
2337 2337 bundle
2338 2338 </a>
2339 2339 </td><td>
2340 2340 create a bundle file
2341 2341 </td></tr>
2342 2342 <tr><td>
2343 2343 <a href="/help/cat">
2344 2344 cat
2345 2345 </a>
2346 2346 </td><td>
2347 2347 output the current or given revision of files
2348 2348 </td></tr>
2349 2349 <tr><td>
2350 2350 <a href="/help/config">
2351 2351 config
2352 2352 </a>
2353 2353 </td><td>
2354 2354 show combined config settings from all hgrc files
2355 2355 </td></tr>
2356 2356 <tr><td>
2357 2357 <a href="/help/copy">
2358 2358 copy
2359 2359 </a>
2360 2360 </td><td>
2361 2361 mark files as copied for the next commit
2362 2362 </td></tr>
2363 2363 <tr><td>
2364 2364 <a href="/help/files">
2365 2365 files
2366 2366 </a>
2367 2367 </td><td>
2368 2368 list tracked files
2369 2369 </td></tr>
2370 2370 <tr><td>
2371 2371 <a href="/help/graft">
2372 2372 graft
2373 2373 </a>
2374 2374 </td><td>
2375 2375 copy changes from other branches onto the current branch
2376 2376 </td></tr>
2377 2377 <tr><td>
2378 2378 <a href="/help/grep">
2379 2379 grep
2380 2380 </a>
2381 2381 </td><td>
2382 2382 search revision history for a pattern in specified files
2383 2383 </td></tr>
2384 2384 <tr><td>
2385 2385 <a href="/help/heads">
2386 2386 heads
2387 2387 </a>
2388 2388 </td><td>
2389 2389 show branch heads
2390 2390 </td></tr>
2391 2391 <tr><td>
2392 2392 <a href="/help/help">
2393 2393 help
2394 2394 </a>
2395 2395 </td><td>
2396 2396 show help for a given topic or a help overview
2397 2397 </td></tr>
2398 2398 <tr><td>
2399 2399 <a href="/help/hgalias">
2400 2400 hgalias
2401 2401 </a>
2402 2402 </td><td>
2403 2403 summarize working directory state
2404 2404 </td></tr>
2405 2405 <tr><td>
2406 2406 <a href="/help/identify">
2407 2407 identify
2408 2408 </a>
2409 2409 </td><td>
2410 2410 identify the working directory or specified revision
2411 2411 </td></tr>
2412 2412 <tr><td>
2413 2413 <a href="/help/import">
2414 2414 import
2415 2415 </a>
2416 2416 </td><td>
2417 2417 import an ordered set of patches
2418 2418 </td></tr>
2419 2419 <tr><td>
2420 2420 <a href="/help/incoming">
2421 2421 incoming
2422 2422 </a>
2423 2423 </td><td>
2424 2424 show new changesets found in source
2425 2425 </td></tr>
2426 2426 <tr><td>
2427 2427 <a href="/help/manifest">
2428 2428 manifest
2429 2429 </a>
2430 2430 </td><td>
2431 2431 output the current or given revision of the project manifest
2432 2432 </td></tr>
2433 2433 <tr><td>
2434 2434 <a href="/help/nohelp">
2435 2435 nohelp
2436 2436 </a>
2437 2437 </td><td>
2438 2438 (no help text available)
2439 2439 </td></tr>
2440 2440 <tr><td>
2441 2441 <a href="/help/outgoing">
2442 2442 outgoing
2443 2443 </a>
2444 2444 </td><td>
2445 2445 show changesets not found in the destination
2446 2446 </td></tr>
2447 2447 <tr><td>
2448 2448 <a href="/help/paths">
2449 2449 paths
2450 2450 </a>
2451 2451 </td><td>
2452 2452 show aliases for remote repositories
2453 2453 </td></tr>
2454 2454 <tr><td>
2455 2455 <a href="/help/phase">
2456 2456 phase
2457 2457 </a>
2458 2458 </td><td>
2459 2459 set or show the current phase name
2460 2460 </td></tr>
2461 2461 <tr><td>
2462 2462 <a href="/help/recover">
2463 2463 recover
2464 2464 </a>
2465 2465 </td><td>
2466 2466 roll back an interrupted transaction
2467 2467 </td></tr>
2468 2468 <tr><td>
2469 2469 <a href="/help/rename">
2470 2470 rename
2471 2471 </a>
2472 2472 </td><td>
2473 2473 rename files; equivalent of copy + remove
2474 2474 </td></tr>
2475 2475 <tr><td>
2476 2476 <a href="/help/resolve">
2477 2477 resolve
2478 2478 </a>
2479 2479 </td><td>
2480 2480 redo merges or set/view the merge status of files
2481 2481 </td></tr>
2482 2482 <tr><td>
2483 2483 <a href="/help/revert">
2484 2484 revert
2485 2485 </a>
2486 2486 </td><td>
2487 2487 restore files to their checkout state
2488 2488 </td></tr>
2489 2489 <tr><td>
2490 2490 <a href="/help/root">
2491 2491 root
2492 2492 </a>
2493 2493 </td><td>
2494 2494 print the root (top) of the current working directory
2495 2495 </td></tr>
2496 2496 <tr><td>
2497 2497 <a href="/help/shellalias">
2498 2498 shellalias
2499 2499 </a>
2500 2500 </td><td>
2501 2501 (no help text available)
2502 2502 </td></tr>
2503 2503 <tr><td>
2504 2504 <a href="/help/tag">
2505 2505 tag
2506 2506 </a>
2507 2507 </td><td>
2508 2508 add one or more tags for the current or given revision
2509 2509 </td></tr>
2510 2510 <tr><td>
2511 2511 <a href="/help/tags">
2512 2512 tags
2513 2513 </a>
2514 2514 </td><td>
2515 2515 list repository tags
2516 2516 </td></tr>
2517 2517 <tr><td>
2518 2518 <a href="/help/unbundle">
2519 2519 unbundle
2520 2520 </a>
2521 2521 </td><td>
2522 2522 apply one or more bundle files
2523 2523 </td></tr>
2524 2524 <tr><td>
2525 2525 <a href="/help/verify">
2526 2526 verify
2527 2527 </a>
2528 2528 </td><td>
2529 2529 verify the integrity of the repository
2530 2530 </td></tr>
2531 2531 <tr><td>
2532 2532 <a href="/help/version">
2533 2533 version
2534 2534 </a>
2535 2535 </td><td>
2536 2536 output version and copyright information
2537 2537 </td></tr>
2538 2538
2539 2539
2540 2540 </table>
2541 2541 </div>
2542 2542 </div>
2543 2543
2544 2544
2545 2545
2546 2546 </body>
2547 2547 </html>
2548 2548
2549 2549
2550 2550 $ get-with-headers.py $LOCALIP:$HGPORT "help/add"
2551 2551 200 Script output follows
2552 2552
2553 2553 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
2554 2554 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
2555 2555 <head>
2556 2556 <link rel="icon" href="/static/hgicon.png" type="image/png" />
2557 2557 <meta name="robots" content="index, nofollow" />
2558 2558 <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
2559 2559 <script type="text/javascript" src="/static/mercurial.js"></script>
2560 2560
2561 2561 <title>Help: add</title>
2562 2562 </head>
2563 2563 <body>
2564 2564
2565 2565 <div class="container">
2566 2566 <div class="menu">
2567 2567 <div class="logo">
2568 2568 <a href="https://mercurial-scm.org/">
2569 2569 <img src="/static/hglogo.png" alt="mercurial" /></a>
2570 2570 </div>
2571 2571 <ul>
2572 2572 <li><a href="/shortlog">log</a></li>
2573 2573 <li><a href="/graph">graph</a></li>
2574 2574 <li><a href="/tags">tags</a></li>
2575 2575 <li><a href="/bookmarks">bookmarks</a></li>
2576 2576 <li><a href="/branches">branches</a></li>
2577 2577 </ul>
2578 2578 <ul>
2579 2579 <li class="active"><a href="/help">help</a></li>
2580 2580 </ul>
2581 2581 </div>
2582 2582
2583 2583 <div class="main">
2584 2584 <h2 class="breadcrumb"><a href="/">Mercurial</a> </h2>
2585 2585 <h3>Help: add</h3>
2586 2586
2587 2587 <form class="search" action="/log">
2588 2588
2589 2589 <p><input name="rev" id="search1" type="text" size="30" value="" /></p>
2590 2590 <div id="hint">Find changesets by keywords (author, files, the commit message), revision
2591 2591 number or hash, or <a href="/help/revsets">revset expression</a>.</div>
2592 2592 </form>
2593 2593 <div id="doc">
2594 2594 <p>
2595 2595 hg add [OPTION]... [FILE]...
2596 2596 </p>
2597 2597 <p>
2598 2598 add the specified files on the next commit
2599 2599 </p>
2600 2600 <p>
2601 2601 Schedule files to be version controlled and added to the
2602 2602 repository.
2603 2603 </p>
2604 2604 <p>
2605 2605 The files will be added to the repository at the next commit. To
2606 2606 undo an add before that, see 'hg forget'.
2607 2607 </p>
2608 2608 <p>
2609 2609 If no names are given, add all files to the repository (except
2610 2610 files matching &quot;.hgignore&quot;).
2611 2611 </p>
2612 2612 <p>
2613 2613 Examples:
2614 2614 </p>
2615 2615 <ul>
2616 2616 <li> New (unknown) files are added automatically by 'hg add':
2617 2617 <pre>
2618 2618 \$ ls (re)
2619 2619 foo.c
2620 2620 \$ hg status (re)
2621 2621 ? foo.c
2622 2622 \$ hg add (re)
2623 2623 adding foo.c
2624 2624 \$ hg status (re)
2625 2625 A foo.c
2626 2626 </pre>
2627 2627 <li> Specific files to be added can be specified:
2628 2628 <pre>
2629 2629 \$ ls (re)
2630 2630 bar.c foo.c
2631 2631 \$ hg status (re)
2632 2632 ? bar.c
2633 2633 ? foo.c
2634 2634 \$ hg add bar.c (re)
2635 2635 \$ hg status (re)
2636 2636 A bar.c
2637 2637 ? foo.c
2638 2638 </pre>
2639 2639 </ul>
2640 2640 <p>
2641 2641 Returns 0 if all files are successfully added.
2642 2642 </p>
2643 2643 <p>
2644 2644 options ([+] can be repeated):
2645 2645 </p>
2646 2646 <table>
2647 2647 <tr><td>-I</td>
2648 2648 <td>--include PATTERN [+]</td>
2649 2649 <td>include names matching the given patterns</td></tr>
2650 2650 <tr><td>-X</td>
2651 2651 <td>--exclude PATTERN [+]</td>
2652 2652 <td>exclude names matching the given patterns</td></tr>
2653 2653 <tr><td>-S</td>
2654 2654 <td>--subrepos</td>
2655 2655 <td>recurse into subrepositories</td></tr>
2656 2656 <tr><td>-n</td>
2657 2657 <td>--dry-run</td>
2658 2658 <td>do not perform actions, just print output</td></tr>
2659 2659 </table>
2660 2660 <p>
2661 2661 global options ([+] can be repeated):
2662 2662 </p>
2663 2663 <table>
2664 2664 <tr><td>-R</td>
2665 2665 <td>--repository REPO</td>
2666 2666 <td>repository root directory or name of overlay bundle file</td></tr>
2667 2667 <tr><td></td>
2668 2668 <td>--cwd DIR</td>
2669 2669 <td>change working directory</td></tr>
2670 2670 <tr><td>-y</td>
2671 2671 <td>--noninteractive</td>
2672 2672 <td>do not prompt, automatically pick the first choice for all prompts</td></tr>
2673 2673 <tr><td>-q</td>
2674 2674 <td>--quiet</td>
2675 2675 <td>suppress output</td></tr>
2676 2676 <tr><td>-v</td>
2677 2677 <td>--verbose</td>
2678 2678 <td>enable additional output</td></tr>
2679 2679 <tr><td></td>
2680 2680 <td>--color TYPE</td>
2681 2681 <td>when to colorize (boolean, always, auto, never, or debug)</td></tr>
2682 2682 <tr><td></td>
2683 2683 <td>--config CONFIG [+]</td>
2684 2684 <td>set/override config option (use 'section.name=value')</td></tr>
2685 2685 <tr><td></td>
2686 2686 <td>--debug</td>
2687 2687 <td>enable debugging output</td></tr>
2688 2688 <tr><td></td>
2689 2689 <td>--debugger</td>
2690 2690 <td>start debugger</td></tr>
2691 2691 <tr><td></td>
2692 2692 <td>--encoding ENCODE</td>
2693 2693 <td>set the charset encoding (default: ascii)</td></tr>
2694 2694 <tr><td></td>
2695 2695 <td>--encodingmode MODE</td>
2696 2696 <td>set the charset encoding mode (default: strict)</td></tr>
2697 2697 <tr><td></td>
2698 2698 <td>--traceback</td>
2699 2699 <td>always print a traceback on exception</td></tr>
2700 2700 <tr><td></td>
2701 2701 <td>--time</td>
2702 2702 <td>time how long the command takes</td></tr>
2703 2703 <tr><td></td>
2704 2704 <td>--profile</td>
2705 2705 <td>print command execution profile</td></tr>
2706 2706 <tr><td></td>
2707 2707 <td>--version</td>
2708 2708 <td>output version information and exit</td></tr>
2709 2709 <tr><td>-h</td>
2710 2710 <td>--help</td>
2711 2711 <td>display help and exit</td></tr>
2712 2712 <tr><td></td>
2713 2713 <td>--hidden</td>
2714 2714 <td>consider hidden changesets</td></tr>
2715 2715 <tr><td></td>
2716 2716 <td>--pager TYPE</td>
2717 2717 <td>when to paginate (boolean, always, auto, or never) (default: auto)</td></tr>
2718 2718 </table>
2719 2719
2720 2720 </div>
2721 2721 </div>
2722 2722 </div>
2723 2723
2724 2724
2725 2725
2726 2726 </body>
2727 2727 </html>
2728 2728
2729 2729
2730 2730 $ get-with-headers.py $LOCALIP:$HGPORT "help/remove"
2731 2731 200 Script output follows
2732 2732
2733 2733 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
2734 2734 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
2735 2735 <head>
2736 2736 <link rel="icon" href="/static/hgicon.png" type="image/png" />
2737 2737 <meta name="robots" content="index, nofollow" />
2738 2738 <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
2739 2739 <script type="text/javascript" src="/static/mercurial.js"></script>
2740 2740
2741 2741 <title>Help: remove</title>
2742 2742 </head>
2743 2743 <body>
2744 2744
2745 2745 <div class="container">
2746 2746 <div class="menu">
2747 2747 <div class="logo">
2748 2748 <a href="https://mercurial-scm.org/">
2749 2749 <img src="/static/hglogo.png" alt="mercurial" /></a>
2750 2750 </div>
2751 2751 <ul>
2752 2752 <li><a href="/shortlog">log</a></li>
2753 2753 <li><a href="/graph">graph</a></li>
2754 2754 <li><a href="/tags">tags</a></li>
2755 2755 <li><a href="/bookmarks">bookmarks</a></li>
2756 2756 <li><a href="/branches">branches</a></li>
2757 2757 </ul>
2758 2758 <ul>
2759 2759 <li class="active"><a href="/help">help</a></li>
2760 2760 </ul>
2761 2761 </div>
2762 2762
2763 2763 <div class="main">
2764 2764 <h2 class="breadcrumb"><a href="/">Mercurial</a> </h2>
2765 2765 <h3>Help: remove</h3>
2766 2766
2767 2767 <form class="search" action="/log">
2768 2768
2769 2769 <p><input name="rev" id="search1" type="text" size="30" value="" /></p>
2770 2770 <div id="hint">Find changesets by keywords (author, files, the commit message), revision
2771 2771 number or hash, or <a href="/help/revsets">revset expression</a>.</div>
2772 2772 </form>
2773 2773 <div id="doc">
2774 2774 <p>
2775 2775 hg remove [OPTION]... FILE...
2776 2776 </p>
2777 2777 <p>
2778 2778 aliases: rm
2779 2779 </p>
2780 2780 <p>
2781 2781 remove the specified files on the next commit
2782 2782 </p>
2783 2783 <p>
2784 2784 Schedule the indicated files for removal from the current branch.
2785 2785 </p>
2786 2786 <p>
2787 2787 This command schedules the files to be removed at the next commit.
2788 2788 To undo a remove before that, see 'hg revert'. To undo added
2789 2789 files, see 'hg forget'.
2790 2790 </p>
2791 2791 <p>
2792 2792 -A/--after can be used to remove only files that have already
2793 2793 been deleted, -f/--force can be used to force deletion, and -Af
2794 2794 can be used to remove files from the next revision without
2795 2795 deleting them from the working directory.
2796 2796 </p>
2797 2797 <p>
2798 2798 The following table details the behavior of remove for different
2799 2799 file states (columns) and option combinations (rows). The file
2800 2800 states are Added [A], Clean [C], Modified [M] and Missing [!]
2801 2801 (as reported by 'hg status'). The actions are Warn, Remove
2802 2802 (from branch) and Delete (from disk):
2803 2803 </p>
2804 2804 <table>
2805 2805 <tr><td>opt/state</td>
2806 2806 <td>A</td>
2807 2807 <td>C</td>
2808 2808 <td>M</td>
2809 2809 <td>!</td></tr>
2810 2810 <tr><td>none</td>
2811 2811 <td>W</td>
2812 2812 <td>RD</td>
2813 2813 <td>W</td>
2814 2814 <td>R</td></tr>
2815 2815 <tr><td>-f</td>
2816 2816 <td>R</td>
2817 2817 <td>RD</td>
2818 2818 <td>RD</td>
2819 2819 <td>R</td></tr>
2820 2820 <tr><td>-A</td>
2821 2821 <td>W</td>
2822 2822 <td>W</td>
2823 2823 <td>W</td>
2824 2824 <td>R</td></tr>
2825 2825 <tr><td>-Af</td>
2826 2826 <td>R</td>
2827 2827 <td>R</td>
2828 2828 <td>R</td>
2829 2829 <td>R</td></tr>
2830 2830 </table>
2831 2831 <p>
2832 2832 <b>Note:</b>
2833 2833 </p>
2834 2834 <p>
2835 2835 'hg remove' never deletes files in Added [A] state from the
2836 2836 working directory, not even if &quot;--force&quot; is specified.
2837 2837 </p>
2838 2838 <p>
2839 2839 Returns 0 on success, 1 if any warnings encountered.
2840 2840 </p>
2841 2841 <p>
2842 2842 options ([+] can be repeated):
2843 2843 </p>
2844 2844 <table>
2845 2845 <tr><td>-A</td>
2846 2846 <td>--after</td>
2847 2847 <td>record delete for missing files</td></tr>
2848 2848 <tr><td>-f</td>
2849 2849 <td>--force</td>
2850 2850 <td>forget added files, delete modified files</td></tr>
2851 2851 <tr><td>-S</td>
2852 2852 <td>--subrepos</td>
2853 2853 <td>recurse into subrepositories</td></tr>
2854 2854 <tr><td>-I</td>
2855 2855 <td>--include PATTERN [+]</td>
2856 2856 <td>include names matching the given patterns</td></tr>
2857 2857 <tr><td>-X</td>
2858 2858 <td>--exclude PATTERN [+]</td>
2859 2859 <td>exclude names matching the given patterns</td></tr>
2860 2860 </table>
2861 2861 <p>
2862 2862 global options ([+] can be repeated):
2863 2863 </p>
2864 2864 <table>
2865 2865 <tr><td>-R</td>
2866 2866 <td>--repository REPO</td>
2867 2867 <td>repository root directory or name of overlay bundle file</td></tr>
2868 2868 <tr><td></td>
2869 2869 <td>--cwd DIR</td>
2870 2870 <td>change working directory</td></tr>
2871 2871 <tr><td>-y</td>
2872 2872 <td>--noninteractive</td>
2873 2873 <td>do not prompt, automatically pick the first choice for all prompts</td></tr>
2874 2874 <tr><td>-q</td>
2875 2875 <td>--quiet</td>
2876 2876 <td>suppress output</td></tr>
2877 2877 <tr><td>-v</td>
2878 2878 <td>--verbose</td>
2879 2879 <td>enable additional output</td></tr>
2880 2880 <tr><td></td>
2881 2881 <td>--color TYPE</td>
2882 2882 <td>when to colorize (boolean, always, auto, never, or debug)</td></tr>
2883 2883 <tr><td></td>
2884 2884 <td>--config CONFIG [+]</td>
2885 2885 <td>set/override config option (use 'section.name=value')</td></tr>
2886 2886 <tr><td></td>
2887 2887 <td>--debug</td>
2888 2888 <td>enable debugging output</td></tr>
2889 2889 <tr><td></td>
2890 2890 <td>--debugger</td>
2891 2891 <td>start debugger</td></tr>
2892 2892 <tr><td></td>
2893 2893 <td>--encoding ENCODE</td>
2894 2894 <td>set the charset encoding (default: ascii)</td></tr>
2895 2895 <tr><td></td>
2896 2896 <td>--encodingmode MODE</td>
2897 2897 <td>set the charset encoding mode (default: strict)</td></tr>
2898 2898 <tr><td></td>
2899 2899 <td>--traceback</td>
2900 2900 <td>always print a traceback on exception</td></tr>
2901 2901 <tr><td></td>
2902 2902 <td>--time</td>
2903 2903 <td>time how long the command takes</td></tr>
2904 2904 <tr><td></td>
2905 2905 <td>--profile</td>
2906 2906 <td>print command execution profile</td></tr>
2907 2907 <tr><td></td>
2908 2908 <td>--version</td>
2909 2909 <td>output version information and exit</td></tr>
2910 2910 <tr><td>-h</td>
2911 2911 <td>--help</td>
2912 2912 <td>display help and exit</td></tr>
2913 2913 <tr><td></td>
2914 2914 <td>--hidden</td>
2915 2915 <td>consider hidden changesets</td></tr>
2916 2916 <tr><td></td>
2917 2917 <td>--pager TYPE</td>
2918 2918 <td>when to paginate (boolean, always, auto, or never) (default: auto)</td></tr>
2919 2919 </table>
2920 2920
2921 2921 </div>
2922 2922 </div>
2923 2923 </div>
2924 2924
2925 2925
2926 2926
2927 2927 </body>
2928 2928 </html>
2929 2929
2930 2930
2931 2931 $ get-with-headers.py $LOCALIP:$HGPORT "help/dates"
2932 2932 200 Script output follows
2933 2933
2934 2934 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
2935 2935 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
2936 2936 <head>
2937 2937 <link rel="icon" href="/static/hgicon.png" type="image/png" />
2938 2938 <meta name="robots" content="index, nofollow" />
2939 2939 <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
2940 2940 <script type="text/javascript" src="/static/mercurial.js"></script>
2941 2941
2942 2942 <title>Help: dates</title>
2943 2943 </head>
2944 2944 <body>
2945 2945
2946 2946 <div class="container">
2947 2947 <div class="menu">
2948 2948 <div class="logo">
2949 2949 <a href="https://mercurial-scm.org/">
2950 2950 <img src="/static/hglogo.png" alt="mercurial" /></a>
2951 2951 </div>
2952 2952 <ul>
2953 2953 <li><a href="/shortlog">log</a></li>
2954 2954 <li><a href="/graph">graph</a></li>
2955 2955 <li><a href="/tags">tags</a></li>
2956 2956 <li><a href="/bookmarks">bookmarks</a></li>
2957 2957 <li><a href="/branches">branches</a></li>
2958 2958 </ul>
2959 2959 <ul>
2960 2960 <li class="active"><a href="/help">help</a></li>
2961 2961 </ul>
2962 2962 </div>
2963 2963
2964 2964 <div class="main">
2965 2965 <h2 class="breadcrumb"><a href="/">Mercurial</a> </h2>
2966 2966 <h3>Help: dates</h3>
2967 2967
2968 2968 <form class="search" action="/log">
2969 2969
2970 2970 <p><input name="rev" id="search1" type="text" size="30" value="" /></p>
2971 2971 <div id="hint">Find changesets by keywords (author, files, the commit message), revision
2972 2972 number or hash, or <a href="/help/revsets">revset expression</a>.</div>
2973 2973 </form>
2974 2974 <div id="doc">
2975 2975 <h1>Date Formats</h1>
2976 2976 <p>
2977 2977 Some commands allow the user to specify a date, e.g.:
2978 2978 </p>
2979 2979 <ul>
2980 2980 <li> backout, commit, import, tag: Specify the commit date.
2981 2981 <li> log, revert, update: Select revision(s) by date.
2982 2982 </ul>
2983 2983 <p>
2984 2984 Many date formats are valid. Here are some examples:
2985 2985 </p>
2986 2986 <ul>
2987 2987 <li> &quot;Wed Dec 6 13:18:29 2006&quot; (local timezone assumed)
2988 2988 <li> &quot;Dec 6 13:18 -0600&quot; (year assumed, time offset provided)
2989 2989 <li> &quot;Dec 6 13:18 UTC&quot; (UTC and GMT are aliases for +0000)
2990 2990 <li> &quot;Dec 6&quot; (midnight)
2991 2991 <li> &quot;13:18&quot; (today assumed)
2992 2992 <li> &quot;3:39&quot; (3:39AM assumed)
2993 2993 <li> &quot;3:39pm&quot; (15:39)
2994 2994 <li> &quot;2006-12-06 13:18:29&quot; (ISO 8601 format)
2995 2995 <li> &quot;2006-12-6 13:18&quot;
2996 2996 <li> &quot;2006-12-6&quot;
2997 2997 <li> &quot;12-6&quot;
2998 2998 <li> &quot;12/6&quot;
2999 2999 <li> &quot;12/6/6&quot; (Dec 6 2006)
3000 3000 <li> &quot;today&quot; (midnight)
3001 3001 <li> &quot;yesterday&quot; (midnight)
3002 3002 <li> &quot;now&quot; - right now
3003 3003 </ul>
3004 3004 <p>
3005 3005 Lastly, there is Mercurial's internal format:
3006 3006 </p>
3007 3007 <ul>
3008 3008 <li> &quot;1165411109 0&quot; (Wed Dec 6 13:18:29 2006 UTC)
3009 3009 </ul>
3010 3010 <p>
3011 3011 This is the internal representation format for dates. The first number
3012 3012 is the number of seconds since the epoch (1970-01-01 00:00 UTC). The
3013 3013 second is the offset of the local timezone, in seconds west of UTC
3014 3014 (negative if the timezone is east of UTC).
3015 3015 </p>
3016 3016 <p>
3017 3017 The log command also accepts date ranges:
3018 3018 </p>
3019 3019 <ul>
3020 3020 <li> &quot;&lt;DATE&quot; - at or before a given date/time
3021 3021 <li> &quot;&gt;DATE&quot; - on or after a given date/time
3022 3022 <li> &quot;DATE to DATE&quot; - a date range, inclusive
3023 3023 <li> &quot;-DAYS&quot; - within a given number of days of today
3024 3024 </ul>
3025 3025
3026 3026 </div>
3027 3027 </div>
3028 3028 </div>
3029 3029
3030 3030
3031 3031
3032 3032 </body>
3033 3033 </html>
3034 3034
3035 3035
3036 3036 Sub-topic indexes rendered properly
3037 3037
3038 3038 $ get-with-headers.py $LOCALIP:$HGPORT "help/internals"
3039 3039 200 Script output follows
3040 3040
3041 3041 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
3042 3042 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
3043 3043 <head>
3044 3044 <link rel="icon" href="/static/hgicon.png" type="image/png" />
3045 3045 <meta name="robots" content="index, nofollow" />
3046 3046 <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
3047 3047 <script type="text/javascript" src="/static/mercurial.js"></script>
3048 3048
3049 3049 <title>Help: internals</title>
3050 3050 </head>
3051 3051 <body>
3052 3052
3053 3053 <div class="container">
3054 3054 <div class="menu">
3055 3055 <div class="logo">
3056 3056 <a href="https://mercurial-scm.org/">
3057 3057 <img src="/static/hglogo.png" alt="mercurial" /></a>
3058 3058 </div>
3059 3059 <ul>
3060 3060 <li><a href="/shortlog">log</a></li>
3061 3061 <li><a href="/graph">graph</a></li>
3062 3062 <li><a href="/tags">tags</a></li>
3063 3063 <li><a href="/bookmarks">bookmarks</a></li>
3064 3064 <li><a href="/branches">branches</a></li>
3065 3065 </ul>
3066 3066 <ul>
3067 3067 <li><a href="/help">help</a></li>
3068 3068 </ul>
3069 3069 </div>
3070 3070
3071 3071 <div class="main">
3072 3072 <h2 class="breadcrumb"><a href="/">Mercurial</a> </h2>
3073 3073
3074 3074 <form class="search" action="/log">
3075 3075
3076 3076 <p><input name="rev" id="search1" type="text" size="30" value="" /></p>
3077 3077 <div id="hint">Find changesets by keywords (author, files, the commit message), revision
3078 3078 number or hash, or <a href="/help/revsets">revset expression</a>.</div>
3079 3079 </form>
3080 3080 <table class="bigtable">
3081 3081 <tr><td colspan="2"><h2><a name="topics" href="#topics">Topics</a></h2></td></tr>
3082 3082
3083 3083 <tr><td>
3084 3084 <a href="/help/internals.bundle2">
3085 3085 bundle2
3086 3086 </a>
3087 3087 </td><td>
3088 3088 Bundle2
3089 3089 </td></tr>
3090 3090 <tr><td>
3091 3091 <a href="/help/internals.bundles">
3092 3092 bundles
3093 3093 </a>
3094 3094 </td><td>
3095 3095 Bundles
3096 3096 </td></tr>
3097 3097 <tr><td>
3098 3098 <a href="/help/internals.censor">
3099 3099 censor
3100 3100 </a>
3101 3101 </td><td>
3102 3102 Censor
3103 3103 </td></tr>
3104 3104 <tr><td>
3105 3105 <a href="/help/internals.changegroups">
3106 3106 changegroups
3107 3107 </a>
3108 3108 </td><td>
3109 3109 Changegroups
3110 3110 </td></tr>
3111 3111 <tr><td>
3112 3112 <a href="/help/internals.config">
3113 3113 config
3114 3114 </a>
3115 3115 </td><td>
3116 3116 Config Registrar
3117 3117 </td></tr>
3118 3118 <tr><td>
3119 3119 <a href="/help/internals.requirements">
3120 3120 requirements
3121 3121 </a>
3122 3122 </td><td>
3123 3123 Repository Requirements
3124 3124 </td></tr>
3125 3125 <tr><td>
3126 3126 <a href="/help/internals.revlogs">
3127 3127 revlogs
3128 3128 </a>
3129 3129 </td><td>
3130 3130 Revision Logs
3131 3131 </td></tr>
3132 3132 <tr><td>
3133 3133 <a href="/help/internals.wireprotocol">
3134 3134 wireprotocol
3135 3135 </a>
3136 3136 </td><td>
3137 3137 Wire Protocol
3138 3138 </td></tr>
3139 3139
3140 3140
3141 3141
3142 3142
3143 3143
3144 3144 </table>
3145 3145 </div>
3146 3146 </div>
3147 3147
3148 3148
3149 3149
3150 3150 </body>
3151 3151 </html>
3152 3152
3153 3153
3154 3154 Sub-topic topics rendered properly
3155 3155
3156 3156 $ get-with-headers.py $LOCALIP:$HGPORT "help/internals.changegroups"
3157 3157 200 Script output follows
3158 3158
3159 3159 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
3160 3160 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
3161 3161 <head>
3162 3162 <link rel="icon" href="/static/hgicon.png" type="image/png" />
3163 3163 <meta name="robots" content="index, nofollow" />
3164 3164 <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
3165 3165 <script type="text/javascript" src="/static/mercurial.js"></script>
3166 3166
3167 3167 <title>Help: internals.changegroups</title>
3168 3168 </head>
3169 3169 <body>
3170 3170
3171 3171 <div class="container">
3172 3172 <div class="menu">
3173 3173 <div class="logo">
3174 3174 <a href="https://mercurial-scm.org/">
3175 3175 <img src="/static/hglogo.png" alt="mercurial" /></a>
3176 3176 </div>
3177 3177 <ul>
3178 3178 <li><a href="/shortlog">log</a></li>
3179 3179 <li><a href="/graph">graph</a></li>
3180 3180 <li><a href="/tags">tags</a></li>
3181 3181 <li><a href="/bookmarks">bookmarks</a></li>
3182 3182 <li><a href="/branches">branches</a></li>
3183 3183 </ul>
3184 3184 <ul>
3185 3185 <li class="active"><a href="/help">help</a></li>
3186 3186 </ul>
3187 3187 </div>
3188 3188
3189 3189 <div class="main">
3190 3190 <h2 class="breadcrumb"><a href="/">Mercurial</a> </h2>
3191 3191 <h3>Help: internals.changegroups</h3>
3192 3192
3193 3193 <form class="search" action="/log">
3194 3194
3195 3195 <p><input name="rev" id="search1" type="text" size="30" value="" /></p>
3196 3196 <div id="hint">Find changesets by keywords (author, files, the commit message), revision
3197 3197 number or hash, or <a href="/help/revsets">revset expression</a>.</div>
3198 3198 </form>
3199 3199 <div id="doc">
3200 3200 <h1>Changegroups</h1>
3201 3201 <p>
3202 3202 Changegroups are representations of repository revlog data, specifically
3203 3203 the changelog data, root/flat manifest data, treemanifest data, and
3204 3204 filelogs.
3205 3205 </p>
3206 3206 <p>
3207 3207 There are 3 versions of changegroups: &quot;1&quot;, &quot;2&quot;, and &quot;3&quot;. From a
3208 3208 high-level, versions &quot;1&quot; and &quot;2&quot; are almost exactly the same, with the
3209 3209 only difference being an additional item in the *delta header*. Version
3210 3210 &quot;3&quot; adds support for revlog flags in the *delta header* and optionally
3211 3211 exchanging treemanifests (enabled by setting an option on the
3212 3212 &quot;changegroup&quot; part in the bundle2).
3213 3213 </p>
3214 3214 <p>
3215 3215 Changegroups when not exchanging treemanifests consist of 3 logical
3216 3216 segments:
3217 3217 </p>
3218 3218 <pre>
3219 3219 +---------------------------------+
3220 3220 | | | |
3221 3221 | changeset | manifest | filelogs |
3222 3222 | | | |
3223 3223 | | | |
3224 3224 +---------------------------------+
3225 3225 </pre>
3226 3226 <p>
3227 3227 When exchanging treemanifests, there are 4 logical segments:
3228 3228 </p>
3229 3229 <pre>
3230 3230 +-------------------------------------------------+
3231 3231 | | | | |
3232 3232 | changeset | root | treemanifests | filelogs |
3233 3233 | | manifest | | |
3234 3234 | | | | |
3235 3235 +-------------------------------------------------+
3236 3236 </pre>
3237 3237 <p>
3238 3238 The principle building block of each segment is a *chunk*. A *chunk*
3239 3239 is a framed piece of data:
3240 3240 </p>
3241 3241 <pre>
3242 3242 +---------------------------------------+
3243 3243 | | |
3244 3244 | length | data |
3245 3245 | (4 bytes) | (&lt;length - 4&gt; bytes) |
3246 3246 | | |
3247 3247 +---------------------------------------+
3248 3248 </pre>
3249 3249 <p>
3250 3250 All integers are big-endian signed integers. Each chunk starts with a 32-bit
3251 3251 integer indicating the length of the entire chunk (including the length field
3252 3252 itself).
3253 3253 </p>
3254 3254 <p>
3255 3255 There is a special case chunk that has a value of 0 for the length
3256 3256 (&quot;0x00000000&quot;). We call this an *empty chunk*.
3257 3257 </p>
3258 3258 <h2>Delta Groups</h2>
3259 3259 <p>
3260 3260 A *delta group* expresses the content of a revlog as a series of deltas,
3261 3261 or patches against previous revisions.
3262 3262 </p>
3263 3263 <p>
3264 3264 Delta groups consist of 0 or more *chunks* followed by the *empty chunk*
3265 3265 to signal the end of the delta group:
3266 3266 </p>
3267 3267 <pre>
3268 3268 +------------------------------------------------------------------------+
3269 3269 | | | | | |
3270 3270 | chunk0 length | chunk0 data | chunk1 length | chunk1 data | 0x0 |
3271 3271 | (4 bytes) | (various) | (4 bytes) | (various) | (4 bytes) |
3272 3272 | | | | | |
3273 3273 +------------------------------------------------------------------------+
3274 3274 </pre>
3275 3275 <p>
3276 3276 Each *chunk*'s data consists of the following:
3277 3277 </p>
3278 3278 <pre>
3279 3279 +---------------------------------------+
3280 3280 | | |
3281 3281 | delta header | delta data |
3282 3282 | (various by version) | (various) |
3283 3283 | | |
3284 3284 +---------------------------------------+
3285 3285 </pre>
3286 3286 <p>
3287 3287 The *delta data* is a series of *delta*s that describe a diff from an existing
3288 3288 entry (either that the recipient already has, or previously specified in the
3289 3289 bundle/changegroup).
3290 3290 </p>
3291 3291 <p>
3292 3292 The *delta header* is different between versions &quot;1&quot;, &quot;2&quot;, and
3293 3293 &quot;3&quot; of the changegroup format.
3294 3294 </p>
3295 3295 <p>
3296 3296 Version 1 (headerlen=80):
3297 3297 </p>
3298 3298 <pre>
3299 3299 +------------------------------------------------------+
3300 3300 | | | | |
3301 3301 | node | p1 node | p2 node | link node |
3302 3302 | (20 bytes) | (20 bytes) | (20 bytes) | (20 bytes) |
3303 3303 | | | | |
3304 3304 +------------------------------------------------------+
3305 3305 </pre>
3306 3306 <p>
3307 3307 Version 2 (headerlen=100):
3308 3308 </p>
3309 3309 <pre>
3310 3310 +------------------------------------------------------------------+
3311 3311 | | | | | |
3312 3312 | node | p1 node | p2 node | base node | link node |
3313 3313 | (20 bytes) | (20 bytes) | (20 bytes) | (20 bytes) | (20 bytes) |
3314 3314 | | | | | |
3315 3315 +------------------------------------------------------------------+
3316 3316 </pre>
3317 3317 <p>
3318 3318 Version 3 (headerlen=102):
3319 3319 </p>
3320 3320 <pre>
3321 3321 +------------------------------------------------------------------------------+
3322 3322 | | | | | | |
3323 3323 | node | p1 node | p2 node | base node | link node | flags |
3324 3324 | (20 bytes) | (20 bytes) | (20 bytes) | (20 bytes) | (20 bytes) | (2 bytes) |
3325 3325 | | | | | | |
3326 3326 +------------------------------------------------------------------------------+
3327 3327 </pre>
3328 3328 <p>
3329 3329 The *delta data* consists of &quot;chunklen - 4 - headerlen&quot; bytes, which contain a
3330 3330 series of *delta*s, densely packed (no separators). These deltas describe a diff
3331 3331 from an existing entry (either that the recipient already has, or previously
3332 3332 specified in the bundle/changegroup). The format is described more fully in
3333 3333 &quot;hg help internals.bdiff&quot;, but briefly:
3334 3334 </p>
3335 3335 <pre>
3336 3336 +---------------------------------------------------------------+
3337 3337 | | | | |
3338 3338 | start offset | end offset | new length | content |
3339 3339 | (4 bytes) | (4 bytes) | (4 bytes) | (&lt;new length&gt; bytes) |
3340 3340 | | | | |
3341 3341 +---------------------------------------------------------------+
3342 3342 </pre>
3343 3343 <p>
3344 3344 Please note that the length field in the delta data does *not* include itself.
3345 3345 </p>
3346 3346 <p>
3347 3347 In version 1, the delta is always applied against the previous node from
3348 3348 the changegroup or the first parent if this is the first entry in the
3349 3349 changegroup.
3350 3350 </p>
3351 3351 <p>
3352 3352 In version 2 and up, the delta base node is encoded in the entry in the
3353 3353 changegroup. This allows the delta to be expressed against any parent,
3354 3354 which can result in smaller deltas and more efficient encoding of data.
3355 3355 </p>
3356 3356 <h2>Changeset Segment</h2>
3357 3357 <p>
3358 3358 The *changeset segment* consists of a single *delta group* holding
3359 3359 changelog data. The *empty chunk* at the end of the *delta group* denotes
3360 3360 the boundary to the *manifest segment*.
3361 3361 </p>
3362 3362 <h2>Manifest Segment</h2>
3363 3363 <p>
3364 3364 The *manifest segment* consists of a single *delta group* holding manifest
3365 3365 data. If treemanifests are in use, it contains only the manifest for the
3366 3366 root directory of the repository. Otherwise, it contains the entire
3367 3367 manifest data. The *empty chunk* at the end of the *delta group* denotes
3368 3368 the boundary to the next segment (either the *treemanifests segment* or the
3369 3369 *filelogs segment*, depending on version and the request options).
3370 3370 </p>
3371 3371 <h3>Treemanifests Segment</h3>
3372 3372 <p>
3373 3373 The *treemanifests segment* only exists in changegroup version &quot;3&quot;, and
3374 3374 only if the 'treemanifest' param is part of the bundle2 changegroup part
3375 3375 (it is not possible to use changegroup version 3 outside of bundle2).
3376 3376 Aside from the filenames in the *treemanifests segment* containing a
3377 3377 trailing &quot;/&quot; character, it behaves identically to the *filelogs segment*
3378 3378 (see below). The final sub-segment is followed by an *empty chunk* (logically,
3379 3379 a sub-segment with filename size 0). This denotes the boundary to the
3380 3380 *filelogs segment*.
3381 3381 </p>
3382 3382 <h2>Filelogs Segment</h2>
3383 3383 <p>
3384 3384 The *filelogs segment* consists of multiple sub-segments, each
3385 3385 corresponding to an individual file whose data is being described:
3386 3386 </p>
3387 3387 <pre>
3388 3388 +--------------------------------------------------+
3389 3389 | | | | | |
3390 3390 | filelog0 | filelog1 | filelog2 | ... | 0x0 |
3391 3391 | | | | | (4 bytes) |
3392 3392 | | | | | |
3393 3393 +--------------------------------------------------+
3394 3394 </pre>
3395 3395 <p>
3396 3396 The final filelog sub-segment is followed by an *empty chunk* (logically,
3397 3397 a sub-segment with filename size 0). This denotes the end of the segment
3398 3398 and of the overall changegroup.
3399 3399 </p>
3400 3400 <p>
3401 3401 Each filelog sub-segment consists of the following:
3402 3402 </p>
3403 3403 <pre>
3404 3404 +------------------------------------------------------+
3405 3405 | | | |
3406 3406 | filename length | filename | delta group |
3407 3407 | (4 bytes) | (&lt;length - 4&gt; bytes) | (various) |
3408 3408 | | | |
3409 3409 +------------------------------------------------------+
3410 3410 </pre>
3411 3411 <p>
3412 3412 That is, a *chunk* consisting of the filename (not terminated or padded)
3413 3413 followed by N chunks constituting the *delta group* for this file. The
3414 3414 *empty chunk* at the end of each *delta group* denotes the boundary to the
3415 3415 next filelog sub-segment.
3416 3416 </p>
3417 3417
3418 3418 </div>
3419 3419 </div>
3420 3420 </div>
3421 3421
3422 3422
3423 3423
3424 3424 </body>
3425 3425 </html>
3426 3426
3427 3427
3428 3428 $ get-with-headers.py 127.0.0.1:$HGPORT "help/unknowntopic"
3429 3429 404 Not Found
3430 3430
3431 3431 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
3432 3432 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
3433 3433 <head>
3434 3434 <link rel="icon" href="/static/hgicon.png" type="image/png" />
3435 3435 <meta name="robots" content="index, nofollow" />
3436 3436 <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
3437 3437 <script type="text/javascript" src="/static/mercurial.js"></script>
3438 3438
3439 3439 <title>test: error</title>
3440 3440 </head>
3441 3441 <body>
3442 3442
3443 3443 <div class="container">
3444 3444 <div class="menu">
3445 3445 <div class="logo">
3446 3446 <a href="https://mercurial-scm.org/">
3447 3447 <img src="/static/hglogo.png" width=75 height=90 border=0 alt="mercurial" /></a>
3448 3448 </div>
3449 3449 <ul>
3450 3450 <li><a href="/shortlog">log</a></li>
3451 3451 <li><a href="/graph">graph</a></li>
3452 3452 <li><a href="/tags">tags</a></li>
3453 3453 <li><a href="/bookmarks">bookmarks</a></li>
3454 3454 <li><a href="/branches">branches</a></li>
3455 3455 </ul>
3456 3456 <ul>
3457 3457 <li><a href="/help">help</a></li>
3458 3458 </ul>
3459 3459 </div>
3460 3460
3461 3461 <div class="main">
3462 3462
3463 3463 <h2 class="breadcrumb"><a href="/">Mercurial</a> </h2>
3464 3464 <h3>error</h3>
3465 3465
3466 3466
3467 3467 <form class="search" action="/log">
3468 3468
3469 3469 <p><input name="rev" id="search1" type="text" size="30" value="" /></p>
3470 3470 <div id="hint">Find changesets by keywords (author, files, the commit message), revision
3471 3471 number or hash, or <a href="/help/revsets">revset expression</a>.</div>
3472 3472 </form>
3473 3473
3474 3474 <div class="description">
3475 3475 <p>
3476 3476 An error occurred while processing your request:
3477 3477 </p>
3478 3478 <p>
3479 3479 Not Found
3480 3480 </p>
3481 3481 </div>
3482 3482 </div>
3483 3483 </div>
3484 3484
3485 3485
3486 3486
3487 3487 </body>
3488 3488 </html>
3489 3489
3490 3490 [1]
3491 3491
3492 3492 $ killdaemons.py
3493 3493
3494 3494 #endif
General Comments 0
You need to be logged in to leave comments. Login now