##// END OF EJS Templates
help: suggest '-v -e' to get built-in aliases for extensions (issue4461)...
Chingis Dugarzhapov -
r23624:861ddedf default
parent child Browse files
Show More
@@ -1,501 +1,504 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 i18n import gettext, _
9 9 import itertools, os
10 10 import error
11 11 import extensions, revset, fileset, templatekw, templatefilters, filemerge
12 12 import encoding, util, minirst
13 13 import cmdutil
14 14
15 15 def listexts(header, exts, indent=1, showdeprecated=False):
16 16 '''return a text listing of the given extensions'''
17 17 rst = []
18 18 if exts:
19 19 rst.append('\n%s\n\n' % header)
20 20 for name, desc in sorted(exts.iteritems()):
21 21 if '(DEPRECATED)' in desc and not showdeprecated:
22 22 continue
23 23 rst.append('%s:%s: %s\n' % (' ' * indent, name, desc))
24 24 return rst
25 25
26 26 def extshelp():
27 27 rst = loaddoc('extensions')().splitlines(True)
28 28 rst.extend(listexts(
29 29 _('enabled extensions:'), extensions.enabled(), showdeprecated=True))
30 30 rst.extend(listexts(_('disabled extensions:'), extensions.disabled()))
31 31 doc = ''.join(rst)
32 32 return doc
33 33
34 34 def optrst(header, options, verbose):
35 35 data = []
36 36 multioccur = False
37 37 for option in options:
38 38 if len(option) == 5:
39 39 shortopt, longopt, default, desc, optlabel = option
40 40 else:
41 41 shortopt, longopt, default, desc = option
42 42 optlabel = _("VALUE") # default label
43 43
44 44 if not verbose and ("DEPRECATED" in desc or _("DEPRECATED") in desc):
45 45 continue
46 46
47 47 so = ''
48 48 if shortopt:
49 49 so = '-' + shortopt
50 50 lo = '--' + longopt
51 51 if default:
52 52 desc += _(" (default: %s)") % default
53 53
54 54 if isinstance(default, list):
55 55 lo += " %s [+]" % optlabel
56 56 multioccur = True
57 57 elif (default is not None) and not isinstance(default, bool):
58 58 lo += " %s" % optlabel
59 59
60 60 data.append((so, lo, desc))
61 61
62 62 if multioccur:
63 63 header += (_(" ([+] can be repeated)"))
64 64
65 65 rst = ['\n%s:\n\n' % header]
66 66 rst.extend(minirst.maketable(data, 1))
67 67
68 68 return ''.join(rst)
69 69
70 70 def indicateomitted(rst, omitted, notomitted=None):
71 71 rst.append('\n\n.. container:: omitted\n\n %s\n\n' % omitted)
72 72 if notomitted:
73 73 rst.append('\n\n.. container:: notomitted\n\n %s\n\n' % notomitted)
74 74
75 75 def topicmatch(kw):
76 76 """Return help topics matching kw.
77 77
78 78 Returns {'section': [(name, summary), ...], ...} where section is
79 79 one of topics, commands, extensions, or extensioncommands.
80 80 """
81 81 kw = encoding.lower(kw)
82 82 def lowercontains(container):
83 83 return kw in encoding.lower(container) # translated in helptable
84 84 results = {'topics': [],
85 85 'commands': [],
86 86 'extensions': [],
87 87 'extensioncommands': [],
88 88 }
89 89 for names, header, doc in helptable:
90 90 # Old extensions may use a str as doc.
91 91 if (sum(map(lowercontains, names))
92 92 or lowercontains(header)
93 93 or (callable(doc) and lowercontains(doc()))):
94 94 results['topics'].append((names[0], header))
95 95 import commands # avoid cycle
96 96 for cmd, entry in commands.table.iteritems():
97 97 if len(entry) == 3:
98 98 summary = entry[2]
99 99 else:
100 100 summary = ''
101 101 # translate docs *before* searching there
102 102 docs = _(getattr(entry[0], '__doc__', None)) or ''
103 103 if kw in cmd or lowercontains(summary) or lowercontains(docs):
104 104 doclines = docs.splitlines()
105 105 if doclines:
106 106 summary = doclines[0]
107 107 cmdname = cmd.split('|')[0].lstrip('^')
108 108 results['commands'].append((cmdname, summary))
109 109 for name, docs in itertools.chain(
110 110 extensions.enabled(False).iteritems(),
111 111 extensions.disabled().iteritems()):
112 112 # extensions.load ignores the UI argument
113 113 mod = extensions.load(None, name, '')
114 114 name = name.split('.')[-1]
115 115 if lowercontains(name) or lowercontains(docs):
116 116 # extension docs are already translated
117 117 results['extensions'].append((name, docs.splitlines()[0]))
118 118 for cmd, entry in getattr(mod, 'cmdtable', {}).iteritems():
119 119 if kw in cmd or (len(entry) > 2 and lowercontains(entry[2])):
120 120 cmdname = cmd.split('|')[0].lstrip('^')
121 121 if entry[0].__doc__:
122 122 cmddoc = gettext(entry[0].__doc__).splitlines()[0]
123 123 else:
124 124 cmddoc = _('(no help text available)')
125 125 results['extensioncommands'].append((cmdname, cmddoc))
126 126 return results
127 127
128 128 def loaddoc(topic):
129 129 """Return a delayed loader for help/topic.txt."""
130 130
131 131 def loader():
132 132 docdir = os.path.join(util.datapath, 'help')
133 133 path = os.path.join(docdir, topic + ".txt")
134 134 doc = gettext(util.readfile(path))
135 135 for rewriter in helphooks.get(topic, []):
136 136 doc = rewriter(topic, doc)
137 137 return doc
138 138
139 139 return loader
140 140
141 141 helptable = sorted([
142 142 (["config", "hgrc"], _("Configuration Files"), loaddoc('config')),
143 143 (["dates"], _("Date Formats"), loaddoc('dates')),
144 144 (["patterns"], _("File Name Patterns"), loaddoc('patterns')),
145 145 (['environment', 'env'], _('Environment Variables'),
146 146 loaddoc('environment')),
147 147 (['revisions', 'revs'], _('Specifying Single Revisions'),
148 148 loaddoc('revisions')),
149 149 (['multirevs', 'mrevs'], _('Specifying Multiple Revisions'),
150 150 loaddoc('multirevs')),
151 151 (['revsets', 'revset'], _("Specifying Revision Sets"), loaddoc('revsets')),
152 152 (['filesets', 'fileset'], _("Specifying File Sets"), loaddoc('filesets')),
153 153 (['diffs'], _('Diff Formats'), loaddoc('diffs')),
154 154 (['merge-tools', 'mergetools'], _('Merge Tools'), loaddoc('merge-tools')),
155 155 (['templating', 'templates', 'template', 'style'], _('Template Usage'),
156 156 loaddoc('templates')),
157 157 (['urls'], _('URL Paths'), loaddoc('urls')),
158 158 (["extensions"], _("Using Additional Features"), extshelp),
159 159 (["subrepos", "subrepo"], _("Subrepositories"), loaddoc('subrepos')),
160 160 (["hgweb"], _("Configuring hgweb"), loaddoc('hgweb')),
161 161 (["glossary"], _("Glossary"), loaddoc('glossary')),
162 162 (["hgignore", "ignore"], _("Syntax for Mercurial Ignore Files"),
163 163 loaddoc('hgignore')),
164 164 (["phases"], _("Working with Phases"), loaddoc('phases')),
165 165 ])
166 166
167 167 # Map topics to lists of callable taking the current topic help and
168 168 # returning the updated version
169 169 helphooks = {}
170 170
171 171 def addtopichook(topic, rewriter):
172 172 helphooks.setdefault(topic, []).append(rewriter)
173 173
174 174 def makeitemsdoc(topic, doc, marker, items):
175 175 """Extract docstring from the items key to function mapping, build a
176 176 .single documentation block and use it to overwrite the marker in doc
177 177 """
178 178 entries = []
179 179 for name in sorted(items):
180 180 text = (items[name].__doc__ or '').rstrip()
181 181 if not text:
182 182 continue
183 183 text = gettext(text)
184 184 lines = text.splitlines()
185 185 doclines = [(lines[0])]
186 186 for l in lines[1:]:
187 187 # Stop once we find some Python doctest
188 188 if l.strip().startswith('>>>'):
189 189 break
190 190 doclines.append(' ' + l.strip())
191 191 entries.append('\n'.join(doclines))
192 192 entries = '\n\n'.join(entries)
193 193 return doc.replace(marker, entries)
194 194
195 195 def addtopicsymbols(topic, marker, symbols):
196 196 def add(topic, doc):
197 197 return makeitemsdoc(topic, doc, marker, symbols)
198 198 addtopichook(topic, add)
199 199
200 200 addtopicsymbols('filesets', '.. predicatesmarker', fileset.symbols)
201 201 addtopicsymbols('merge-tools', '.. internaltoolsmarker', filemerge.internals)
202 202 addtopicsymbols('revsets', '.. predicatesmarker', revset.symbols)
203 203 addtopicsymbols('templates', '.. keywordsmarker', templatekw.dockeywords)
204 204 addtopicsymbols('templates', '.. filtersmarker', templatefilters.filters)
205 205
206 206 def help_(ui, name, unknowncmd=False, full=True, **opts):
207 207 '''
208 208 Generate the help for 'name' as unformatted restructured text. If
209 209 'name' is None, describe the commands available.
210 210 '''
211 211
212 212 import commands # avoid cycle
213 213
214 214 def helpcmd(name):
215 215 try:
216 216 aliases, entry = cmdutil.findcmd(name, commands.table,
217 217 strict=unknowncmd)
218 218 except error.AmbiguousCommand, inst:
219 219 # py3k fix: except vars can't be used outside the scope of the
220 220 # except block, nor can be used inside a lambda. python issue4617
221 221 prefix = inst.args[0]
222 222 select = lambda c: c.lstrip('^').startswith(prefix)
223 223 rst = helplist(select)
224 224 return rst
225 225
226 226 rst = []
227 227
228 228 # check if it's an invalid alias and display its error if it is
229 229 if getattr(entry[0], 'badalias', None):
230 230 rst.append(entry[0].badalias + '\n')
231 231 if entry[0].unknowncmd:
232 232 try:
233 233 rst.extend(helpextcmd(entry[0].cmdname))
234 234 except error.UnknownCommand:
235 235 pass
236 236 return rst
237 237
238 238 # synopsis
239 239 if len(entry) > 2:
240 240 if entry[2].startswith('hg'):
241 241 rst.append("%s\n" % entry[2])
242 242 else:
243 243 rst.append('hg %s %s\n' % (aliases[0], entry[2]))
244 244 else:
245 245 rst.append('hg %s\n' % aliases[0])
246 246 # aliases
247 247 if full and not ui.quiet and len(aliases) > 1:
248 248 rst.append(_("\naliases: %s\n") % ', '.join(aliases[1:]))
249 249 rst.append('\n')
250 250
251 251 # description
252 252 doc = gettext(entry[0].__doc__)
253 253 if not doc:
254 254 doc = _("(no help text available)")
255 255 if util.safehasattr(entry[0], 'definition'): # aliased command
256 256 if entry[0].definition.startswith('!'): # shell alias
257 257 doc = _('shell alias for::\n\n %s') % entry[0].definition[1:]
258 258 else:
259 259 doc = _('alias for: hg %s\n\n%s') % (entry[0].definition, doc)
260 260 doc = doc.splitlines(True)
261 261 if ui.quiet or not full:
262 262 rst.append(doc[0])
263 263 else:
264 264 rst.extend(doc)
265 265 rst.append('\n')
266 266
267 267 # check if this command shadows a non-trivial (multi-line)
268 268 # extension help text
269 269 try:
270 270 mod = extensions.find(name)
271 271 doc = gettext(mod.__doc__) or ''
272 272 if '\n' in doc.strip():
273 273 msg = _('(use "hg help -e %s" to show help for '
274 274 'the %s extension)') % (name, name)
275 275 rst.append('\n%s\n' % msg)
276 276 except KeyError:
277 277 pass
278 278
279 279 # options
280 280 if not ui.quiet and entry[1]:
281 281 rst.append(optrst(_("options"), entry[1], ui.verbose))
282 282
283 283 if ui.verbose:
284 284 rst.append(optrst(_("global options"),
285 285 commands.globalopts, ui.verbose))
286 286
287 287 if not ui.verbose:
288 288 if not full:
289 289 rst.append(_('\n(use "hg %s -h" to show more help)\n')
290 290 % name)
291 291 elif not ui.quiet:
292 292 rst.append(_('\n(some details hidden, use --verbose '
293 293 'to show complete help)'))
294 294
295 295 return rst
296 296
297 297
298 298 def helplist(select=None):
299 299 # list of commands
300 300 if name == "shortlist":
301 301 header = _('basic commands:\n\n')
302 302 elif name == "debug":
303 303 header = _('debug commands (internal and unsupported):\n\n')
304 304 else:
305 305 header = _('list of commands:\n\n')
306 306
307 307 h = {}
308 308 cmds = {}
309 309 for c, e in commands.table.iteritems():
310 310 f = c.split("|", 1)[0]
311 311 if select and not select(f):
312 312 continue
313 313 if (not select and name != 'shortlist' and
314 314 e[0].__module__ != commands.__name__):
315 315 continue
316 316 if name == "shortlist" and not f.startswith("^"):
317 317 continue
318 318 f = f.lstrip("^")
319 319 if not ui.debugflag and f.startswith("debug") and name != "debug":
320 320 continue
321 321 doc = e[0].__doc__
322 322 if doc and 'DEPRECATED' in doc and not ui.verbose:
323 323 continue
324 324 doc = gettext(doc)
325 325 if not doc:
326 326 doc = _("(no help text available)")
327 327 h[f] = doc.splitlines()[0].rstrip()
328 328 cmds[f] = c.lstrip("^")
329 329
330 330 rst = []
331 331 if not h:
332 332 if not ui.quiet:
333 333 rst.append(_('no commands defined\n'))
334 334 return rst
335 335
336 336 if not ui.quiet:
337 337 rst.append(header)
338 338 fns = sorted(h)
339 339 for f in fns:
340 340 if ui.verbose:
341 341 commacmds = cmds[f].replace("|",", ")
342 342 rst.append(" :%s: %s\n" % (commacmds, h[f]))
343 343 else:
344 344 rst.append(' :%s: %s\n' % (f, h[f]))
345 345
346 346 if not name:
347 347 exts = listexts(_('enabled extensions:'), extensions.enabled())
348 348 if exts:
349 349 rst.append('\n')
350 350 rst.extend(exts)
351 351
352 352 rst.append(_("\nadditional help topics:\n\n"))
353 353 topics = []
354 354 for names, header, doc in helptable:
355 355 topics.append((names[0], header))
356 356 for t, desc in topics:
357 357 rst.append(" :%s: %s\n" % (t, desc))
358 358
359 359 if ui.quiet:
360 360 pass
361 361 elif ui.verbose:
362 362 rst.append('\n%s\n' % optrst(_("global options"),
363 363 commands.globalopts, ui.verbose))
364 364 if name == 'shortlist':
365 365 rst.append(_('\n(use "hg help" for the full list '
366 366 'of commands)\n'))
367 367 else:
368 368 if name == 'shortlist':
369 369 rst.append(_('\n(use "hg help" for the full list of commands '
370 370 'or "hg -v" for details)\n'))
371 371 elif name and not full:
372 372 rst.append(_('\n(use "hg help %s" to show the full help '
373 373 'text)\n') % name)
374 elif name and cmds and name in cmds.keys():
375 rst.append(_('\n(use "hg help -v -e %s" to show built-in '
376 'aliases and global options)\n') % name)
374 377 else:
375 378 rst.append(_('\n(use "hg help -v%s" to show built-in aliases '
376 379 'and global options)\n')
377 380 % (name and " " + name or ""))
378 381 return rst
379 382
380 383 def helptopic(name):
381 384 for names, header, doc in helptable:
382 385 if name in names:
383 386 break
384 387 else:
385 388 raise error.UnknownCommand(name)
386 389
387 390 rst = [minirst.section(header)]
388 391
389 392 # description
390 393 if not doc:
391 394 rst.append(" %s\n" % _("(no help text available)"))
392 395 if callable(doc):
393 396 rst += [" %s\n" % l for l in doc().splitlines()]
394 397
395 398 if not ui.verbose:
396 399 omitted = _('(some details hidden, use --verbose'
397 400 ' to show complete help)')
398 401 indicateomitted(rst, omitted)
399 402
400 403 try:
401 404 cmdutil.findcmd(name, commands.table)
402 405 rst.append(_('\nuse "hg help -c %s" to see help for '
403 406 'the %s command\n') % (name, name))
404 407 except error.UnknownCommand:
405 408 pass
406 409 return rst
407 410
408 411 def helpext(name):
409 412 try:
410 413 mod = extensions.find(name)
411 414 doc = gettext(mod.__doc__) or _('no help text available')
412 415 except KeyError:
413 416 mod = None
414 417 doc = extensions.disabledext(name)
415 418 if not doc:
416 419 raise error.UnknownCommand(name)
417 420
418 421 if '\n' not in doc:
419 422 head, tail = doc, ""
420 423 else:
421 424 head, tail = doc.split('\n', 1)
422 425 rst = [_('%s extension - %s\n\n') % (name.split('.')[-1], head)]
423 426 if tail:
424 427 rst.extend(tail.splitlines(True))
425 428 rst.append('\n')
426 429
427 430 if not ui.verbose:
428 431 omitted = _('(some details hidden, use --verbose'
429 432 ' to show complete help)')
430 433 indicateomitted(rst, omitted)
431 434
432 435 if mod:
433 436 try:
434 437 ct = mod.cmdtable
435 438 except AttributeError:
436 439 ct = {}
437 440 modcmds = set([c.split('|', 1)[0] for c in ct])
438 441 rst.extend(helplist(modcmds.__contains__))
439 442 else:
440 443 rst.append(_('(use "hg help extensions" for information on enabling'
441 444 ' extensions)\n'))
442 445 return rst
443 446
444 447 def helpextcmd(name):
445 448 cmd, ext, mod = extensions.disabledcmd(ui, name,
446 449 ui.configbool('ui', 'strict'))
447 450 doc = gettext(mod.__doc__).splitlines()[0]
448 451
449 452 rst = listexts(_("'%s' is provided by the following "
450 453 "extension:") % cmd, {ext: doc}, indent=4)
451 454 rst.append('\n')
452 455 rst.append(_('(use "hg help extensions" for information on enabling '
453 456 'extensions)\n'))
454 457 return rst
455 458
456 459
457 460 rst = []
458 461 kw = opts.get('keyword')
459 462 if kw:
460 463 matches = topicmatch(kw)
461 464 for t, title in (('topics', _('Topics')),
462 465 ('commands', _('Commands')),
463 466 ('extensions', _('Extensions')),
464 467 ('extensioncommands', _('Extension Commands'))):
465 468 if matches[t]:
466 469 rst.append('%s:\n\n' % title)
467 470 rst.extend(minirst.maketable(sorted(matches[t]), 1))
468 471 rst.append('\n')
469 472 if not rst:
470 473 msg = _('no matches')
471 474 hint = _('try "hg help" for a list of topics')
472 475 raise util.Abort(msg, hint=hint)
473 476 elif name and name != 'shortlist':
474 477 if unknowncmd:
475 478 queries = (helpextcmd,)
476 479 elif opts.get('extension'):
477 480 queries = (helpext,)
478 481 elif opts.get('command'):
479 482 queries = (helpcmd,)
480 483 else:
481 484 queries = (helptopic, helpcmd, helpext, helpextcmd)
482 485 for f in queries:
483 486 try:
484 487 rst = f(name)
485 488 break
486 489 except error.UnknownCommand:
487 490 pass
488 491 else:
489 492 if unknowncmd:
490 493 raise error.UnknownCommand(name)
491 494 else:
492 495 msg = _('no such help topic: %s') % name
493 496 hint = _('try "hg help --keyword %s"') % name
494 497 raise util.Abort(msg, hint=hint)
495 498 else:
496 499 # program name
497 500 if not ui.quiet:
498 501 rst = [_("Mercurial Distributed SCM\n"), '\n']
499 502 rst.extend(helplist())
500 503
501 504 return ''.join(rst)
@@ -1,917 +1,1125 b''
1 1 Test basic extension support
2 2
3 3 $ cat > foobar.py <<EOF
4 4 > import os
5 5 > from mercurial import cmdutil, commands
6 6 > cmdtable = {}
7 7 > command = cmdutil.command(cmdtable)
8 8 > def uisetup(ui):
9 9 > ui.write("uisetup called\\n")
10 10 > def reposetup(ui, repo):
11 11 > ui.write("reposetup called for %s\\n" % os.path.basename(repo.root))
12 12 > ui.write("ui %s= repo.ui\\n" % (ui == repo.ui and "=" or "!"))
13 13 > @command('foo', [], 'hg foo')
14 14 > def foo(ui, *args, **kwargs):
15 15 > ui.write("Foo\\n")
16 16 > @command('bar', [], 'hg bar', norepo=True)
17 17 > def bar(ui, *args, **kwargs):
18 18 > ui.write("Bar\\n")
19 19 > EOF
20 20 $ abspath=`pwd`/foobar.py
21 21
22 22 $ mkdir barfoo
23 23 $ cp foobar.py barfoo/__init__.py
24 24 $ barfoopath=`pwd`/barfoo
25 25
26 26 $ hg init a
27 27 $ cd a
28 28 $ echo foo > file
29 29 $ hg add file
30 30 $ hg commit -m 'add file'
31 31
32 32 $ echo '[extensions]' >> $HGRCPATH
33 33 $ echo "foobar = $abspath" >> $HGRCPATH
34 34 $ hg foo
35 35 uisetup called
36 36 reposetup called for a
37 37 ui == repo.ui
38 38 Foo
39 39
40 40 $ cd ..
41 41 $ hg clone a b
42 42 uisetup called
43 43 reposetup called for a
44 44 ui == repo.ui
45 45 reposetup called for b
46 46 ui == repo.ui
47 47 updating to branch default
48 48 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
49 49
50 50 $ hg bar
51 51 uisetup called
52 52 Bar
53 53 $ echo 'foobar = !' >> $HGRCPATH
54 54
55 55 module/__init__.py-style
56 56
57 57 $ echo "barfoo = $barfoopath" >> $HGRCPATH
58 58 $ cd a
59 59 $ hg foo
60 60 uisetup called
61 61 reposetup called for a
62 62 ui == repo.ui
63 63 Foo
64 64 $ echo 'barfoo = !' >> $HGRCPATH
65 65
66 66 Check that extensions are loaded in phases:
67 67
68 68 $ cat > foo.py <<EOF
69 69 > import os
70 70 > name = os.path.basename(__file__).rsplit('.', 1)[0]
71 71 > print "1) %s imported" % name
72 72 > def uisetup(ui):
73 73 > print "2) %s uisetup" % name
74 74 > def extsetup():
75 75 > print "3) %s extsetup" % name
76 76 > def reposetup(ui, repo):
77 77 > print "4) %s reposetup" % name
78 78 > EOF
79 79
80 80 $ cp foo.py bar.py
81 81 $ echo 'foo = foo.py' >> $HGRCPATH
82 82 $ echo 'bar = bar.py' >> $HGRCPATH
83 83
84 84 Command with no output, we just want to see the extensions loaded:
85 85
86 86 $ hg paths
87 87 1) foo imported
88 88 1) bar imported
89 89 2) foo uisetup
90 90 2) bar uisetup
91 91 3) foo extsetup
92 92 3) bar extsetup
93 93 4) foo reposetup
94 94 4) bar reposetup
95 95
96 96 Check hgweb's load order:
97 97
98 98 $ cat > hgweb.cgi <<EOF
99 99 > #!/usr/bin/env python
100 100 > from mercurial import demandimport; demandimport.enable()
101 101 > from mercurial.hgweb import hgweb
102 102 > from mercurial.hgweb import wsgicgi
103 103 > application = hgweb('.', 'test repo')
104 104 > wsgicgi.launch(application)
105 105 > EOF
106 106
107 107 $ REQUEST_METHOD='GET' PATH_INFO='/' SCRIPT_NAME='' QUERY_STRING='' \
108 108 > SERVER_PORT='80' SERVER_NAME='localhost' python hgweb.cgi \
109 109 > | grep '^[0-9]) ' # ignores HTML output
110 110 1) foo imported
111 111 1) bar imported
112 112 2) foo uisetup
113 113 2) bar uisetup
114 114 3) foo extsetup
115 115 3) bar extsetup
116 116 4) foo reposetup
117 117 4) bar reposetup
118 118 4) foo reposetup
119 119 4) bar reposetup
120 120
121 121 $ echo 'foo = !' >> $HGRCPATH
122 122 $ echo 'bar = !' >> $HGRCPATH
123 123
124 124 Check "from __future__ import absolute_import" support for external libraries
125 125
126 126 #if windows
127 127 $ PATHSEP=";"
128 128 #else
129 129 $ PATHSEP=":"
130 130 #endif
131 131 $ export PATHSEP
132 132
133 133 $ mkdir $TESTTMP/libroot
134 134 $ echo "s = 'libroot/ambig.py'" > $TESTTMP/libroot/ambig.py
135 135 $ mkdir $TESTTMP/libroot/mod
136 136 $ touch $TESTTMP/libroot/mod/__init__.py
137 137 $ echo "s = 'libroot/mod/ambig.py'" > $TESTTMP/libroot/mod/ambig.py
138 138
139 139 #if absimport
140 140 $ cat > $TESTTMP/libroot/mod/ambigabs.py <<EOF
141 141 > from __future__ import absolute_import
142 142 > import ambig # should load "libroot/ambig.py"
143 143 > s = ambig.s
144 144 > EOF
145 145 $ cat > loadabs.py <<EOF
146 146 > import mod.ambigabs as ambigabs
147 147 > def extsetup():
148 148 > print 'ambigabs.s=%s' % ambigabs.s
149 149 > EOF
150 150 $ (PYTHONPATH=${PYTHONPATH}${PATHSEP}${TESTTMP}/libroot; hg --config extensions.loadabs=loadabs.py root)
151 151 ambigabs.s=libroot/ambig.py
152 152 $TESTTMP/a (glob)
153 153 #endif
154 154
155 155 #if no-py3k
156 156 $ cat > $TESTTMP/libroot/mod/ambigrel.py <<EOF
157 157 > import ambig # should load "libroot/mod/ambig.py"
158 158 > s = ambig.s
159 159 > EOF
160 160 $ cat > loadrel.py <<EOF
161 161 > import mod.ambigrel as ambigrel
162 162 > def extsetup():
163 163 > print 'ambigrel.s=%s' % ambigrel.s
164 164 > EOF
165 165 $ (PYTHONPATH=${PYTHONPATH}${PATHSEP}${TESTTMP}/libroot; hg --config extensions.loadrel=loadrel.py root)
166 166 ambigrel.s=libroot/mod/ambig.py
167 167 $TESTTMP/a (glob)
168 168 #endif
169 169
170 170 Check absolute/relative import of extension specific modules
171 171
172 172 $ mkdir $TESTTMP/extroot
173 173 $ cat > $TESTTMP/extroot/bar.py <<EOF
174 174 > s = 'this is extroot.bar'
175 175 > EOF
176 176 $ mkdir $TESTTMP/extroot/sub1
177 177 $ cat > $TESTTMP/extroot/sub1/__init__.py <<EOF
178 178 > s = 'this is extroot.sub1.__init__'
179 179 > EOF
180 180 $ cat > $TESTTMP/extroot/sub1/baz.py <<EOF
181 181 > s = 'this is extroot.sub1.baz'
182 182 > EOF
183 183 $ cat > $TESTTMP/extroot/__init__.py <<EOF
184 184 > s = 'this is extroot.__init__'
185 185 > import foo
186 186 > def extsetup(ui):
187 187 > ui.write('(extroot) ', foo.func(), '\n')
188 188 > EOF
189 189
190 190 $ cat > $TESTTMP/extroot/foo.py <<EOF
191 191 > # test absolute import
192 192 > buf = []
193 193 > def func():
194 194 > # "not locals" case
195 195 > import extroot.bar
196 196 > buf.append('import extroot.bar in func(): %s' % extroot.bar.s)
197 197 > return '\n(extroot) '.join(buf)
198 198 > # "fromlist == ('*',)" case
199 199 > from extroot.bar import *
200 200 > buf.append('from extroot.bar import *: %s' % s)
201 201 > # "not fromlist" and "if '.' in name" case
202 202 > import extroot.sub1.baz
203 203 > buf.append('import extroot.sub1.baz: %s' % extroot.sub1.baz.s)
204 204 > # "not fromlist" and NOT "if '.' in name" case
205 205 > import extroot
206 206 > buf.append('import extroot: %s' % extroot.s)
207 207 > # NOT "not fromlist" and NOT "level != -1" case
208 208 > from extroot.bar import s
209 209 > buf.append('from extroot.bar import s: %s' % s)
210 210 > EOF
211 211 $ hg --config extensions.extroot=$TESTTMP/extroot root
212 212 (extroot) from extroot.bar import *: this is extroot.bar
213 213 (extroot) import extroot.sub1.baz: this is extroot.sub1.baz
214 214 (extroot) import extroot: this is extroot.__init__
215 215 (extroot) from extroot.bar import s: this is extroot.bar
216 216 (extroot) import extroot.bar in func(): this is extroot.bar
217 217 $TESTTMP/a (glob)
218 218
219 219 #if no-py3k
220 220 $ rm "$TESTTMP"/extroot/foo.*
221 221 $ cat > $TESTTMP/extroot/foo.py <<EOF
222 222 > # test relative import
223 223 > buf = []
224 224 > def func():
225 225 > # "not locals" case
226 226 > import bar
227 227 > buf.append('import bar in func(): %s' % bar.s)
228 228 > return '\n(extroot) '.join(buf)
229 229 > # "fromlist == ('*',)" case
230 230 > from bar import *
231 231 > buf.append('from bar import *: %s' % s)
232 232 > # "not fromlist" and "if '.' in name" case
233 233 > import sub1.baz
234 234 > buf.append('import sub1.baz: %s' % sub1.baz.s)
235 235 > # "not fromlist" and NOT "if '.' in name" case
236 236 > import sub1
237 237 > buf.append('import sub1: %s' % sub1.s)
238 238 > # NOT "not fromlist" and NOT "level != -1" case
239 239 > from bar import s
240 240 > buf.append('from bar import s: %s' % s)
241 241 > EOF
242 242 $ hg --config extensions.extroot=$TESTTMP/extroot root
243 243 (extroot) from bar import *: this is extroot.bar
244 244 (extroot) import sub1.baz: this is extroot.sub1.baz
245 245 (extroot) import sub1: this is extroot.sub1.__init__
246 246 (extroot) from bar import s: this is extroot.bar
247 247 (extroot) import bar in func(): this is extroot.bar
248 248 $TESTTMP/a (glob)
249 249 #endif
250 250
251 251 $ cd ..
252 252
253 253 hide outer repo
254 254 $ hg init
255 255
256 256 $ cat > empty.py <<EOF
257 257 > '''empty cmdtable
258 258 > '''
259 259 > cmdtable = {}
260 260 > EOF
261 261 $ emptypath=`pwd`/empty.py
262 262 $ echo "empty = $emptypath" >> $HGRCPATH
263 263 $ hg help empty
264 264 empty extension - empty cmdtable
265 265
266 266 no commands defined
267 267
268 268
269 269 $ echo 'empty = !' >> $HGRCPATH
270 270
271 271 $ cat > debugextension.py <<EOF
272 272 > '''only debugcommands
273 273 > '''
274 274 > from mercurial import cmdutil
275 275 > cmdtable = {}
276 276 > command = cmdutil.command(cmdtable)
277 277 > @command('debugfoobar', [], 'hg debugfoobar')
278 278 > def debugfoobar(ui, repo, *args, **opts):
279 279 > "yet another debug command"
280 280 > pass
281 281 > @command('foo', [], 'hg foo')
282 282 > def foo(ui, repo, *args, **opts):
283 283 > """yet another foo command
284 284 > This command has been DEPRECATED since forever.
285 285 > """
286 286 > pass
287 287 > EOF
288 288 $ debugpath=`pwd`/debugextension.py
289 289 $ echo "debugextension = $debugpath" >> $HGRCPATH
290 290
291 291 $ hg help debugextension
292 292 debugextension extension - only debugcommands
293 293
294 294 no commands defined
295 295
296 296
297 297 $ hg --verbose help debugextension
298 298 debugextension extension - only debugcommands
299 299
300 300 list of commands:
301 301
302 302 foo yet another foo command
303 303
304 304 global options ([+] can be repeated):
305 305
306 306 -R --repository REPO repository root directory or name of overlay bundle
307 307 file
308 308 --cwd DIR change working directory
309 309 -y --noninteractive do not prompt, automatically pick the first choice for
310 310 all prompts
311 311 -q --quiet suppress output
312 312 -v --verbose enable additional output
313 313 --config CONFIG [+] set/override config option (use 'section.name=value')
314 314 --debug enable debugging output
315 315 --debugger start debugger
316 316 --encoding ENCODE set the charset encoding (default: ascii)
317 317 --encodingmode MODE set the charset encoding mode (default: strict)
318 318 --traceback always print a traceback on exception
319 319 --time time how long the command takes
320 320 --profile print command execution profile
321 321 --version output version information and exit
322 322 -h --help display help and exit
323 323 --hidden consider hidden changesets
324 324
325 325
326 326
327 327
328 328
329 329
330 330 $ hg --debug help debugextension
331 331 debugextension extension - only debugcommands
332 332
333 333 list of commands:
334 334
335 335 debugfoobar yet another debug command
336 336 foo yet another foo command
337 337
338 338 global options ([+] can be repeated):
339 339
340 340 -R --repository REPO repository root directory or name of overlay bundle
341 341 file
342 342 --cwd DIR change working directory
343 343 -y --noninteractive do not prompt, automatically pick the first choice for
344 344 all prompts
345 345 -q --quiet suppress output
346 346 -v --verbose enable additional output
347 347 --config CONFIG [+] set/override config option (use 'section.name=value')
348 348 --debug enable debugging output
349 349 --debugger start debugger
350 350 --encoding ENCODE set the charset encoding (default: ascii)
351 351 --encodingmode MODE set the charset encoding mode (default: strict)
352 352 --traceback always print a traceback on exception
353 353 --time time how long the command takes
354 354 --profile print command execution profile
355 355 --version output version information and exit
356 356 -h --help display help and exit
357 357 --hidden consider hidden changesets
358 358
359 359
360 360
361 361
362 362
363 363 $ echo 'debugextension = !' >> $HGRCPATH
364 364
365 365 Extension module help vs command help:
366 366
367 367 $ echo 'extdiff =' >> $HGRCPATH
368 368 $ hg help extdiff
369 369 hg extdiff [OPT]... [FILE]...
370 370
371 371 use external program to diff repository (or selected files)
372 372
373 373 Show differences between revisions for the specified files, using an
374 374 external program. The default program used is diff, with default options
375 375 "-Npru".
376 376
377 377 To select a different program, use the -p/--program option. The program
378 378 will be passed the names of two directories to compare. To pass additional
379 379 options to the program, use -o/--option. These will be passed before the
380 380 names of the directories to compare.
381 381
382 382 When two revision arguments are given, then changes are shown between
383 383 those revisions. If only one revision is specified then that revision is
384 384 compared to the working directory, and, when no revisions are specified,
385 385 the working directory files are compared to its parent.
386 386
387 387 (use "hg help -e extdiff" to show help for the extdiff extension)
388 388
389 389 options ([+] can be repeated):
390 390
391 391 -p --program CMD comparison program to run
392 392 -o --option OPT [+] pass option to comparison program
393 393 -r --rev REV [+] revision
394 394 -c --change REV change made by revision
395 395 -I --include PATTERN [+] include names matching the given patterns
396 396 -X --exclude PATTERN [+] exclude names matching the given patterns
397 397
398 398 (some details hidden, use --verbose to show complete help)
399 399
400 400
401 401
402 402
403 403
404 404
405 405
406 406
407 407
408 408
409 409 $ hg help --extension extdiff
410 410 extdiff extension - command to allow external programs to compare revisions
411 411
412 412 The extdiff Mercurial extension allows you to use external programs to compare
413 413 revisions, or revision with working directory. The external diff programs are
414 414 called with a configurable set of options and two non-option arguments: paths
415 415 to directories containing snapshots of files to compare.
416 416
417 417 The extdiff extension also allows you to configure new diff commands, so you
418 418 do not need to type "hg extdiff -p kdiff3" always.
419 419
420 420 [extdiff]
421 421 # add new command that runs GNU diff(1) in 'context diff' mode
422 422 cdiff = gdiff -Nprc5
423 423 ## or the old way:
424 424 #cmd.cdiff = gdiff
425 425 #opts.cdiff = -Nprc5
426 426
427 427 # add new command called meld, runs meld (no need to name twice). If
428 428 # the meld executable is not available, the meld tool in [merge-tools]
429 429 # will be used, if available
430 430 meld =
431 431
432 432 # add new command called vimdiff, runs gvimdiff with DirDiff plugin
433 433 # (see http://www.vim.org/scripts/script.php?script_id=102) Non
434 434 # English user, be sure to put "let g:DirDiffDynamicDiffText = 1" in
435 435 # your .vimrc
436 436 vimdiff = gvim -f "+next" \
437 437 "+execute 'DirDiff' fnameescape(argv(0)) fnameescape(argv(1))"
438 438
439 439 Tool arguments can include variables that are expanded at runtime:
440 440
441 441 $parent1, $plabel1 - filename, descriptive label of first parent
442 442 $child, $clabel - filename, descriptive label of child revision
443 443 $parent2, $plabel2 - filename, descriptive label of second parent
444 444 $root - repository root
445 445 $parent is an alias for $parent1.
446 446
447 447 The extdiff extension will look in your [diff-tools] and [merge-tools]
448 448 sections for diff tool arguments, when none are specified in [extdiff].
449 449
450 450 [extdiff]
451 451 kdiff3 =
452 452
453 453 [diff-tools]
454 454 kdiff3.diffargs=--L1 '$plabel1' --L2 '$clabel' $parent $child
455 455
456 456 You can use -I/-X and list of file or directory names like normal "hg diff"
457 457 command. The extdiff extension makes snapshots of only needed files, so
458 458 running the external diff program will actually be pretty fast (at least
459 459 faster than having to compare the entire tree).
460 460
461 461 list of commands:
462 462
463 463 extdiff use external program to diff repository (or selected files)
464 464
465 (use "hg help -v extdiff" to show built-in aliases and global options)
465 (use "hg help -v -e extdiff" to show built-in aliases and global options)
466 466
467 467
468 468
469 469
470 470
471 471
472 472
473 473
474 474
475 475
476 476
477 477
478 478
479 479
480 480
481 481
482 482 $ echo 'extdiff = !' >> $HGRCPATH
483 483
484 484 Test help topic with same name as extension
485 485
486 486 $ cat > multirevs.py <<EOF
487 487 > from mercurial import cmdutil, commands
488 488 > cmdtable = {}
489 489 > command = cmdutil.command(cmdtable)
490 490 > """multirevs extension
491 491 > Big multi-line module docstring."""
492 492 > @command('multirevs', [], 'ARG', norepo=True)
493 493 > def multirevs(ui, repo, arg, *args, **opts):
494 494 > """multirevs command"""
495 495 > pass
496 496 > EOF
497 497 $ echo "multirevs = multirevs.py" >> $HGRCPATH
498 498
499 499 $ hg help multirevs
500 500 Specifying Multiple Revisions
501 501 """""""""""""""""""""""""""""
502 502
503 503 When Mercurial accepts more than one revision, they may be specified
504 504 individually, or provided as a topologically continuous range, separated
505 505 by the ":" character.
506 506
507 507 The syntax of range notation is [BEGIN]:[END], where BEGIN and END are
508 508 revision identifiers. Both BEGIN and END are optional. If BEGIN is not
509 509 specified, it defaults to revision number 0. If END is not specified, it
510 510 defaults to the tip. The range ":" thus means "all revisions".
511 511
512 512 If BEGIN is greater than END, revisions are treated in reverse order.
513 513
514 514 A range acts as a closed interval. This means that a range of 3:5 gives 3,
515 515 4 and 5. Similarly, a range of 9:6 gives 9, 8, 7, and 6.
516 516
517 517 use "hg help -c multirevs" to see help for the multirevs command
518 518
519 519
520 520
521 521
522 522
523 523
524 524 $ hg help -c multirevs
525 525 hg multirevs ARG
526 526
527 527 multirevs command
528 528
529 529 (some details hidden, use --verbose to show complete help)
530 530
531 531
532 532
533 533 $ hg multirevs
534 534 hg multirevs: invalid arguments
535 535 hg multirevs ARG
536 536
537 537 multirevs command
538 538
539 539 (use "hg multirevs -h" to show more help)
540 540 [255]
541 541
542 542
543 543
544 544 $ echo "multirevs = !" >> $HGRCPATH
545 545
546 546 Issue811: Problem loading extensions twice (by site and by user)
547 547
548 548 $ debugpath=`pwd`/debugissue811.py
549 549 $ cat > debugissue811.py <<EOF
550 550 > '''show all loaded extensions
551 551 > '''
552 552 > from mercurial import cmdutil, commands, extensions
553 553 > cmdtable = {}
554 554 > command = cmdutil.command(cmdtable)
555 555 > @command('debugextensions', [], 'hg debugextensions', norepo=True)
556 556 > def debugextensions(ui):
557 557 > "yet another debug command"
558 558 > ui.write("%s\n" % '\n'.join([x for x, y in extensions.extensions()]))
559 559 > EOF
560 560 $ cat <<EOF >> $HGRCPATH
561 561 > debugissue811 = $debugpath
562 562 > mq =
563 563 > strip =
564 564 > hgext.mq =
565 565 > hgext/mq =
566 566 > EOF
567 567
568 568 Show extensions:
569 569 (note that mq force load strip, also checking it's not loaded twice)
570 570
571 571 $ hg debugextensions
572 572 debugissue811
573 573 strip
574 574 mq
575 575
576 For extensions, which name matches one of its commands, help
577 message should ask '-v -e' to get list of built-in aliases
578 along with extension help itself
579
580 $ mkdir $TESTTMP/d
581 $ cat > $TESTTMP/d/dodo.py <<EOF
582 > """
583 > This is an awesome 'dodo' extension. It does nothing and
584 > writes 'Foo foo'
585 > """
586 > from mercurial import cmdutil, commands
587 > cmdtable = {}
588 > command = cmdutil.command(cmdtable)
589 > @command('dodo', [], 'hg dodo')
590 > def dodo(ui, *args, **kwargs):
591 > """Does nothing"""
592 > ui.write("I do nothing. Yay\\n")
593 > @command('foofoo', [], 'hg foofoo')
594 > def foofoo(ui, *args, **kwargs):
595 > """Writes 'Foo foo'"""
596 > ui.write("Foo foo\\n")
597 > EOF
598 $ dodopath=$TESTTMP/d/dodo.py
599
600 $ echo "dodo = $dodopath" >> $HGRCPATH
601
602 Make sure that user is asked to enter '-v -e' to get list of built-in aliases
603 $ hg help -e dodo
604 dodo extension -
605
606 This is an awesome 'dodo' extension. It does nothing and writes 'Foo foo'
607
608 list of commands:
609
610 dodo Does nothing
611 foofoo Writes 'Foo foo'
612
613 (use "hg help -v -e dodo" to show built-in aliases and global options)
614
615 Make sure that '-v -e' prints list of built-in aliases along with
616 extension help itself
617 $ hg help -v -e dodo
618 dodo extension -
619
620 This is an awesome 'dodo' extension. It does nothing and writes 'Foo foo'
621
622 list of commands:
623
624 dodo Does nothing
625 foofoo Writes 'Foo foo'
626
627 global options ([+] can be repeated):
628
629 -R --repository REPO repository root directory or name of overlay bundle
630 file
631 --cwd DIR change working directory
632 -y --noninteractive do not prompt, automatically pick the first choice for
633 all prompts
634 -q --quiet suppress output
635 -v --verbose enable additional output
636 --config CONFIG [+] set/override config option (use 'section.name=value')
637 --debug enable debugging output
638 --debugger start debugger
639 --encoding ENCODE set the charset encoding (default: ascii)
640 --encodingmode MODE set the charset encoding mode (default: strict)
641 --traceback always print a traceback on exception
642 --time time how long the command takes
643 --profile print command execution profile
644 --version output version information and exit
645 -h --help display help and exit
646 --hidden consider hidden changesets
647
648 Make sure that single '-v' option shows help and built-ins only for 'dodo' command
649 $ hg help -v dodo
650 hg dodo
651
652 Does nothing
653
654 (use "hg help -e dodo" to show help for the dodo extension)
655
656 options:
657
658 --mq operate on patch repository
659
660 global options ([+] can be repeated):
661
662 -R --repository REPO repository root directory or name of overlay bundle
663 file
664 --cwd DIR change working directory
665 -y --noninteractive do not prompt, automatically pick the first choice for
666 all prompts
667 -q --quiet suppress output
668 -v --verbose enable additional output
669 --config CONFIG [+] set/override config option (use 'section.name=value')
670 --debug enable debugging output
671 --debugger start debugger
672 --encoding ENCODE set the charset encoding (default: ascii)
673 --encodingmode MODE set the charset encoding mode (default: strict)
674 --traceback always print a traceback on exception
675 --time time how long the command takes
676 --profile print command execution profile
677 --version output version information and exit
678 -h --help display help and exit
679 --hidden consider hidden changesets
680
681 In case when extension name doesn't match any of its commands,
682 help message should ask for '-v' to get list of built-in aliases
683 along with extension help
684 $ cat > $TESTTMP/d/dudu.py <<EOF
685 > """
686 > This is an awesome 'dudu' extension. It does something and
687 > also writes 'Beep beep'
688 > """
689 > from mercurial import cmdutil, commands
690 > cmdtable = {}
691 > command = cmdutil.command(cmdtable)
692 > @command('something', [], 'hg something')
693 > def something(ui, *args, **kwargs):
694 > """Does something"""
695 > ui.write("I do something. Yaaay\\n")
696 > @command('beep', [], 'hg beep')
697 > def beep(ui, *args, **kwargs):
698 > """Writes 'Beep beep'"""
699 > ui.write("Beep beep\\n")
700 > EOF
701 $ dudupath=$TESTTMP/d/dudu.py
702
703 $ echo "dudu = $dudupath" >> $HGRCPATH
704
705 $ hg help -e dudu
706 dudu extension -
707
708 This is an awesome 'dudu' extension. It does something and also writes 'Beep
709 beep'
710
711 list of commands:
712
713 beep Writes 'Beep beep'
714 something Does something
715
716 (use "hg help -v dudu" to show built-in aliases and global options)
717
718 In case when extension name doesn't match any of its commands,
719 help options '-v' and '-v -e' should be equivalent
720 $ hg help -v dudu
721 dudu extension -
722
723 This is an awesome 'dudu' extension. It does something and also writes 'Beep
724 beep'
725
726 list of commands:
727
728 beep Writes 'Beep beep'
729 something Does something
730
731 global options ([+] can be repeated):
732
733 -R --repository REPO repository root directory or name of overlay bundle
734 file
735 --cwd DIR change working directory
736 -y --noninteractive do not prompt, automatically pick the first choice for
737 all prompts
738 -q --quiet suppress output
739 -v --verbose enable additional output
740 --config CONFIG [+] set/override config option (use 'section.name=value')
741 --debug enable debugging output
742 --debugger start debugger
743 --encoding ENCODE set the charset encoding (default: ascii)
744 --encodingmode MODE set the charset encoding mode (default: strict)
745 --traceback always print a traceback on exception
746 --time time how long the command takes
747 --profile print command execution profile
748 --version output version information and exit
749 -h --help display help and exit
750 --hidden consider hidden changesets
751
752 $ hg help -v -e dudu
753 dudu extension -
754
755 This is an awesome 'dudu' extension. It does something and also writes 'Beep
756 beep'
757
758 list of commands:
759
760 beep Writes 'Beep beep'
761 something Does something
762
763 global options ([+] can be repeated):
764
765 -R --repository REPO repository root directory or name of overlay bundle
766 file
767 --cwd DIR change working directory
768 -y --noninteractive do not prompt, automatically pick the first choice for
769 all prompts
770 -q --quiet suppress output
771 -v --verbose enable additional output
772 --config CONFIG [+] set/override config option (use 'section.name=value')
773 --debug enable debugging output
774 --debugger start debugger
775 --encoding ENCODE set the charset encoding (default: ascii)
776 --encodingmode MODE set the charset encoding mode (default: strict)
777 --traceback always print a traceback on exception
778 --time time how long the command takes
779 --profile print command execution profile
780 --version output version information and exit
781 -h --help display help and exit
782 --hidden consider hidden changesets
783
576 784 Disabled extension commands:
577 785
578 786 $ ORGHGRCPATH=$HGRCPATH
579 787 $ HGRCPATH=
580 788 $ export HGRCPATH
581 789 $ hg help email
582 790 'email' is provided by the following extension:
583 791
584 792 patchbomb command to send changesets as (a series of) patch emails
585 793
586 794 (use "hg help extensions" for information on enabling extensions)
587 795
588 796
589 797 $ hg qdel
590 798 hg: unknown command 'qdel'
591 799 'qdelete' is provided by the following extension:
592 800
593 801 mq manage a stack of patches
594 802
595 803 (use "hg help extensions" for information on enabling extensions)
596 804 [255]
597 805
598 806
599 807 $ hg churn
600 808 hg: unknown command 'churn'
601 809 'churn' is provided by the following extension:
602 810
603 811 churn command to display statistics about repository history
604 812
605 813 (use "hg help extensions" for information on enabling extensions)
606 814 [255]
607 815
608 816
609 817
610 818 Disabled extensions:
611 819
612 820 $ hg help churn
613 821 churn extension - command to display statistics about repository history
614 822
615 823 (use "hg help extensions" for information on enabling extensions)
616 824
617 825 $ hg help patchbomb
618 826 patchbomb extension - command to send changesets as (a series of) patch emails
619 827
620 828 (use "hg help extensions" for information on enabling extensions)
621 829
622 830
623 831 Broken disabled extension and command:
624 832
625 833 $ mkdir hgext
626 834 $ echo > hgext/__init__.py
627 835 $ cat > hgext/broken.py <<EOF
628 836 > "broken extension'
629 837 > EOF
630 838 $ cat > path.py <<EOF
631 839 > import os, sys
632 840 > sys.path.insert(0, os.environ['HGEXTPATH'])
633 841 > EOF
634 842 $ HGEXTPATH=`pwd`
635 843 $ export HGEXTPATH
636 844
637 845 $ hg --config extensions.path=./path.py help broken
638 846 broken extension - (no help text available)
639 847
640 848 (use "hg help extensions" for information on enabling extensions)
641 849
642 850
643 851 $ cat > hgext/forest.py <<EOF
644 852 > cmdtable = None
645 853 > EOF
646 854 $ hg --config extensions.path=./path.py help foo > /dev/null
647 855 warning: error finding commands in $TESTTMP/hgext/forest.py (glob)
648 856 abort: no such help topic: foo
649 857 (try "hg help --keyword foo")
650 858 [255]
651 859
652 860 $ cat > throw.py <<EOF
653 861 > from mercurial import cmdutil, commands
654 862 > cmdtable = {}
655 863 > command = cmdutil.command(cmdtable)
656 864 > class Bogon(Exception): pass
657 865 > @command('throw', [], 'hg throw', norepo=True)
658 866 > def throw(ui, **opts):
659 867 > """throws an exception"""
660 868 > raise Bogon()
661 869 > EOF
662 870 No declared supported version, extension complains:
663 871 $ hg --config extensions.throw=throw.py throw 2>&1 | egrep '^\*\*'
664 872 ** Unknown exception encountered with possibly-broken third-party extension throw
665 873 ** which supports versions unknown of Mercurial.
666 874 ** Please disable throw and try your action again.
667 875 ** If that fixes the bug please report it to the extension author.
668 876 ** Python * (glob)
669 877 ** Mercurial Distributed SCM * (glob)
670 878 ** Extensions loaded: throw
671 879 empty declaration of supported version, extension complains:
672 880 $ echo "testedwith = ''" >> throw.py
673 881 $ hg --config extensions.throw=throw.py throw 2>&1 | egrep '^\*\*'
674 882 ** Unknown exception encountered with possibly-broken third-party extension throw
675 883 ** which supports versions unknown of Mercurial.
676 884 ** Please disable throw and try your action again.
677 885 ** If that fixes the bug please report it to the extension author.
678 886 ** Python * (glob)
679 887 ** Mercurial Distributed SCM (*) (glob)
680 888 ** Extensions loaded: throw
681 889 If the extension specifies a buglink, show that:
682 890 $ echo 'buglink = "http://example.com/bts"' >> throw.py
683 891 $ rm -f throw.pyc throw.pyo
684 892 $ hg --config extensions.throw=throw.py throw 2>&1 | egrep '^\*\*'
685 893 ** Unknown exception encountered with possibly-broken third-party extension throw
686 894 ** which supports versions unknown of Mercurial.
687 895 ** Please disable throw and try your action again.
688 896 ** If that fixes the bug please report it to http://example.com/bts
689 897 ** Python * (glob)
690 898 ** Mercurial Distributed SCM (*) (glob)
691 899 ** Extensions loaded: throw
692 900 If the extensions declare outdated versions, accuse the older extension first:
693 901 $ echo "from mercurial import util" >> older.py
694 902 $ echo "util.version = lambda:'2.2'" >> older.py
695 903 $ echo "testedwith = '1.9.3'" >> older.py
696 904 $ echo "testedwith = '2.1.1'" >> throw.py
697 905 $ rm -f throw.pyc throw.pyo
698 906 $ hg --config extensions.throw=throw.py --config extensions.older=older.py \
699 907 > throw 2>&1 | egrep '^\*\*'
700 908 ** Unknown exception encountered with possibly-broken third-party extension older
701 909 ** which supports versions 1.9.3 of Mercurial.
702 910 ** Please disable older and try your action again.
703 911 ** If that fixes the bug please report it to the extension author.
704 912 ** Python * (glob)
705 913 ** Mercurial Distributed SCM (version 2.2)
706 914 ** Extensions loaded: throw, older
707 915 One extension only tested with older, one only with newer versions:
708 916 $ echo "util.version = lambda:'2.1.0'" >> older.py
709 917 $ rm -f older.pyc older.pyo
710 918 $ hg --config extensions.throw=throw.py --config extensions.older=older.py \
711 919 > throw 2>&1 | egrep '^\*\*'
712 920 ** Unknown exception encountered with possibly-broken third-party extension older
713 921 ** which supports versions 1.9.3 of Mercurial.
714 922 ** Please disable older and try your action again.
715 923 ** If that fixes the bug please report it to the extension author.
716 924 ** Python * (glob)
717 925 ** Mercurial Distributed SCM (version 2.1.0)
718 926 ** Extensions loaded: throw, older
719 927 Older extension is tested with current version, the other only with newer:
720 928 $ echo "util.version = lambda:'1.9.3'" >> older.py
721 929 $ rm -f older.pyc older.pyo
722 930 $ hg --config extensions.throw=throw.py --config extensions.older=older.py \
723 931 > throw 2>&1 | egrep '^\*\*'
724 932 ** Unknown exception encountered with possibly-broken third-party extension throw
725 933 ** which supports versions 2.1.1 of Mercurial.
726 934 ** Please disable throw and try your action again.
727 935 ** If that fixes the bug please report it to http://example.com/bts
728 936 ** Python * (glob)
729 937 ** Mercurial Distributed SCM (version 1.9.3)
730 938 ** Extensions loaded: throw, older
731 939
732 940 Declare the version as supporting this hg version, show regular bts link:
733 941 $ hgver=`$PYTHON -c 'from mercurial import util; print util.version().split("+")[0]'`
734 942 $ echo 'testedwith = """'"$hgver"'"""' >> throw.py
735 943 $ rm -f throw.pyc throw.pyo
736 944 $ hg --config extensions.throw=throw.py throw 2>&1 | egrep '^\*\*'
737 945 ** unknown exception encountered, please report by visiting
738 946 ** http://mercurial.selenic.com/wiki/BugTracker
739 947 ** Python * (glob)
740 948 ** Mercurial Distributed SCM (*) (glob)
741 949 ** Extensions loaded: throw
742 950
743 951 Test version number support in 'hg version':
744 952 $ echo '__version__ = (1, 2, 3)' >> throw.py
745 953 $ rm -f throw.pyc throw.pyo
746 954 $ hg version -v
747 955 Mercurial Distributed SCM (version *) (glob)
748 956 (see http://mercurial.selenic.com for more information)
749 957
750 958 Copyright (C) 2005-* Matt Mackall and others (glob)
751 959 This is free software; see the source for copying conditions. There is NO
752 960 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
753 961
754 962 Enabled extensions:
755 963
756 964
757 965 $ hg version -v --config extensions.throw=throw.py
758 966 Mercurial Distributed SCM (version *) (glob)
759 967 (see http://mercurial.selenic.com for more information)
760 968
761 969 Copyright (C) 2005-* Matt Mackall and others (glob)
762 970 This is free software; see the source for copying conditions. There is NO
763 971 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
764 972
765 973 Enabled extensions:
766 974
767 975 throw 1.2.3
768 976 $ echo 'getversion = lambda: "1.twentythree"' >> throw.py
769 977 $ rm -f throw.pyc throw.pyo
770 978 $ hg version -v --config extensions.throw=throw.py
771 979 Mercurial Distributed SCM (version *) (glob)
772 980 (see http://mercurial.selenic.com for more information)
773 981
774 982 Copyright (C) 2005-* Matt Mackall and others (glob)
775 983 This is free software; see the source for copying conditions. There is NO
776 984 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
777 985
778 986 Enabled extensions:
779 987
780 988 throw 1.twentythree
781 989
782 990 Restore HGRCPATH
783 991
784 992 $ HGRCPATH=$ORGHGRCPATH
785 993 $ export HGRCPATH
786 994
787 995 Commands handling multiple repositories at a time should invoke only
788 996 "reposetup()" of extensions enabling in the target repository.
789 997
790 998 $ mkdir reposetup-test
791 999 $ cd reposetup-test
792 1000
793 1001 $ cat > $TESTTMP/reposetuptest.py <<EOF
794 1002 > from mercurial import extensions
795 1003 > def reposetup(ui, repo):
796 1004 > ui.write('reposetup() for %s\n' % (repo.root))
797 1005 > EOF
798 1006 $ hg init src
799 1007 $ echo a > src/a
800 1008 $ hg -R src commit -Am '#0 at src/a'
801 1009 adding a
802 1010 $ echo '[extensions]' >> src/.hg/hgrc
803 1011 $ echo '# enable extension locally' >> src/.hg/hgrc
804 1012 $ echo "reposetuptest = $TESTTMP/reposetuptest.py" >> src/.hg/hgrc
805 1013 $ hg -R src status
806 1014 reposetup() for $TESTTMP/reposetup-test/src (glob)
807 1015
808 1016 $ hg clone -U src clone-dst1
809 1017 reposetup() for $TESTTMP/reposetup-test/src (glob)
810 1018 $ hg init push-dst1
811 1019 $ hg -q -R src push push-dst1
812 1020 reposetup() for $TESTTMP/reposetup-test/src (glob)
813 1021 $ hg init pull-src1
814 1022 $ hg -q -R pull-src1 pull src
815 1023 reposetup() for $TESTTMP/reposetup-test/src (glob)
816 1024
817 1025 $ cat <<EOF >> $HGRCPATH
818 1026 > [extensions]
819 1027 > # disable extension globally and explicitly
820 1028 > reposetuptest = !
821 1029 > EOF
822 1030 $ hg clone -U src clone-dst2
823 1031 reposetup() for $TESTTMP/reposetup-test/src (glob)
824 1032 $ hg init push-dst2
825 1033 $ hg -q -R src push push-dst2
826 1034 reposetup() for $TESTTMP/reposetup-test/src (glob)
827 1035 $ hg init pull-src2
828 1036 $ hg -q -R pull-src2 pull src
829 1037 reposetup() for $TESTTMP/reposetup-test/src (glob)
830 1038
831 1039 $ cat <<EOF >> $HGRCPATH
832 1040 > [extensions]
833 1041 > # enable extension globally
834 1042 > reposetuptest = $TESTTMP/reposetuptest.py
835 1043 > EOF
836 1044 $ hg clone -U src clone-dst3
837 1045 reposetup() for $TESTTMP/reposetup-test/src (glob)
838 1046 reposetup() for $TESTTMP/reposetup-test/clone-dst3 (glob)
839 1047 $ hg init push-dst3
840 1048 reposetup() for $TESTTMP/reposetup-test/push-dst3 (glob)
841 1049 $ hg -q -R src push push-dst3
842 1050 reposetup() for $TESTTMP/reposetup-test/src (glob)
843 1051 reposetup() for $TESTTMP/reposetup-test/push-dst3 (glob)
844 1052 $ hg init pull-src3
845 1053 reposetup() for $TESTTMP/reposetup-test/pull-src3 (glob)
846 1054 $ hg -q -R pull-src3 pull src
847 1055 reposetup() for $TESTTMP/reposetup-test/pull-src3 (glob)
848 1056 reposetup() for $TESTTMP/reposetup-test/src (glob)
849 1057
850 1058 $ echo '[extensions]' >> src/.hg/hgrc
851 1059 $ echo '# disable extension locally' >> src/.hg/hgrc
852 1060 $ echo 'reposetuptest = !' >> src/.hg/hgrc
853 1061 $ hg clone -U src clone-dst4
854 1062 reposetup() for $TESTTMP/reposetup-test/clone-dst4 (glob)
855 1063 $ hg init push-dst4
856 1064 reposetup() for $TESTTMP/reposetup-test/push-dst4 (glob)
857 1065 $ hg -q -R src push push-dst4
858 1066 reposetup() for $TESTTMP/reposetup-test/push-dst4 (glob)
859 1067 $ hg init pull-src4
860 1068 reposetup() for $TESTTMP/reposetup-test/pull-src4 (glob)
861 1069 $ hg -q -R pull-src4 pull src
862 1070 reposetup() for $TESTTMP/reposetup-test/pull-src4 (glob)
863 1071
864 1072 disabling in command line overlays with all configuration
865 1073 $ hg --config extensions.reposetuptest=! clone -U src clone-dst5
866 1074 $ hg --config extensions.reposetuptest=! init push-dst5
867 1075 $ hg --config extensions.reposetuptest=! -q -R src push push-dst5
868 1076 $ hg --config extensions.reposetuptest=! init pull-src5
869 1077 $ hg --config extensions.reposetuptest=! -q -R pull-src5 pull src
870 1078
871 1079 $ cat <<EOF >> $HGRCPATH
872 1080 > [extensions]
873 1081 > # disable extension globally and explicitly
874 1082 > reposetuptest = !
875 1083 > EOF
876 1084 $ hg init parent
877 1085 $ hg init parent/sub1
878 1086 $ echo 1 > parent/sub1/1
879 1087 $ hg -R parent/sub1 commit -Am '#0 at parent/sub1'
880 1088 adding 1
881 1089 $ hg init parent/sub2
882 1090 $ hg init parent/sub2/sub21
883 1091 $ echo 21 > parent/sub2/sub21/21
884 1092 $ hg -R parent/sub2/sub21 commit -Am '#0 at parent/sub2/sub21'
885 1093 adding 21
886 1094 $ cat > parent/sub2/.hgsub <<EOF
887 1095 > sub21 = sub21
888 1096 > EOF
889 1097 $ hg -R parent/sub2 commit -Am '#0 at parent/sub2'
890 1098 adding .hgsub
891 1099 $ hg init parent/sub3
892 1100 $ echo 3 > parent/sub3/3
893 1101 $ hg -R parent/sub3 commit -Am '#0 at parent/sub3'
894 1102 adding 3
895 1103 $ cat > parent/.hgsub <<EOF
896 1104 > sub1 = sub1
897 1105 > sub2 = sub2
898 1106 > sub3 = sub3
899 1107 > EOF
900 1108 $ hg -R parent commit -Am '#0 at parent'
901 1109 adding .hgsub
902 1110 $ echo '[extensions]' >> parent/.hg/hgrc
903 1111 $ echo '# enable extension locally' >> parent/.hg/hgrc
904 1112 $ echo "reposetuptest = $TESTTMP/reposetuptest.py" >> parent/.hg/hgrc
905 1113 $ cp parent/.hg/hgrc parent/sub2/.hg/hgrc
906 1114 $ hg -R parent status -S -A
907 1115 reposetup() for $TESTTMP/reposetup-test/parent (glob)
908 1116 reposetup() for $TESTTMP/reposetup-test/parent/sub2 (glob)
909 1117 C .hgsub
910 1118 C .hgsubstate
911 1119 C sub1/1
912 1120 C sub2/.hgsub
913 1121 C sub2/.hgsubstate
914 1122 C sub2/sub21/21
915 1123 C sub3/3
916 1124
917 1125 $ cd ..
General Comments 0
You need to be logged in to leave comments. Login now