##// END OF EJS Templates
dispatch: replace mayberepr with shellquote...
Augie Fackler -
r31500:bc315e66 default
parent child Browse files
Show More
@@ -1,930 +1,925 b''
1 # dispatch.py - command dispatching for mercurial
1 # dispatch.py - command dispatching for mercurial
2 #
2 #
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 from __future__ import absolute_import, print_function
8 from __future__ import absolute_import, print_function
9
9
10 import atexit
10 import atexit
11 import difflib
11 import difflib
12 import errno
12 import errno
13 import getopt
13 import getopt
14 import os
14 import os
15 import pdb
15 import pdb
16 import re
16 import re
17 import signal
17 import signal
18 import sys
18 import sys
19 import time
19 import time
20 import traceback
20 import traceback
21
21
22
22
23 from .i18n import _
23 from .i18n import _
24
24
25 from . import (
25 from . import (
26 cmdutil,
26 cmdutil,
27 color,
27 color,
28 commands,
28 commands,
29 debugcommands,
29 debugcommands,
30 demandimport,
30 demandimport,
31 encoding,
31 encoding,
32 error,
32 error,
33 extensions,
33 extensions,
34 fancyopts,
34 fancyopts,
35 fileset,
35 fileset,
36 help,
36 help,
37 hg,
37 hg,
38 hook,
38 hook,
39 profiling,
39 profiling,
40 pycompat,
40 pycompat,
41 revset,
41 revset,
42 scmutil,
42 scmutil,
43 templatefilters,
43 templatefilters,
44 templatekw,
44 templatekw,
45 templater,
45 templater,
46 ui as uimod,
46 ui as uimod,
47 util,
47 util,
48 )
48 )
49
49
50 class request(object):
50 class request(object):
51 def __init__(self, args, ui=None, repo=None, fin=None, fout=None,
51 def __init__(self, args, ui=None, repo=None, fin=None, fout=None,
52 ferr=None):
52 ferr=None):
53 self.args = args
53 self.args = args
54 self.ui = ui
54 self.ui = ui
55 self.repo = repo
55 self.repo = repo
56
56
57 # input/output/error streams
57 # input/output/error streams
58 self.fin = fin
58 self.fin = fin
59 self.fout = fout
59 self.fout = fout
60 self.ferr = ferr
60 self.ferr = ferr
61
61
62 def run():
62 def run():
63 "run the command in sys.argv"
63 "run the command in sys.argv"
64 sys.exit((dispatch(request(pycompat.sysargv[1:])) or 0) & 255)
64 sys.exit((dispatch(request(pycompat.sysargv[1:])) or 0) & 255)
65
65
66 def _getsimilar(symbols, value):
66 def _getsimilar(symbols, value):
67 sim = lambda x: difflib.SequenceMatcher(None, value, x).ratio()
67 sim = lambda x: difflib.SequenceMatcher(None, value, x).ratio()
68 # The cutoff for similarity here is pretty arbitrary. It should
68 # The cutoff for similarity here is pretty arbitrary. It should
69 # probably be investigated and tweaked.
69 # probably be investigated and tweaked.
70 return [s for s in symbols if sim(s) > 0.6]
70 return [s for s in symbols if sim(s) > 0.6]
71
71
72 def _reportsimilar(write, similar):
72 def _reportsimilar(write, similar):
73 if len(similar) == 1:
73 if len(similar) == 1:
74 write(_("(did you mean %s?)\n") % similar[0])
74 write(_("(did you mean %s?)\n") % similar[0])
75 elif similar:
75 elif similar:
76 ss = ", ".join(sorted(similar))
76 ss = ", ".join(sorted(similar))
77 write(_("(did you mean one of %s?)\n") % ss)
77 write(_("(did you mean one of %s?)\n") % ss)
78
78
79 def _formatparse(write, inst):
79 def _formatparse(write, inst):
80 similar = []
80 similar = []
81 if isinstance(inst, error.UnknownIdentifier):
81 if isinstance(inst, error.UnknownIdentifier):
82 # make sure to check fileset first, as revset can invoke fileset
82 # make sure to check fileset first, as revset can invoke fileset
83 similar = _getsimilar(inst.symbols, inst.function)
83 similar = _getsimilar(inst.symbols, inst.function)
84 if len(inst.args) > 1:
84 if len(inst.args) > 1:
85 write(_("hg: parse error at %s: %s\n") %
85 write(_("hg: parse error at %s: %s\n") %
86 (inst.args[1], inst.args[0]))
86 (inst.args[1], inst.args[0]))
87 if (inst.args[0][0] == ' '):
87 if (inst.args[0][0] == ' '):
88 write(_("unexpected leading whitespace\n"))
88 write(_("unexpected leading whitespace\n"))
89 else:
89 else:
90 write(_("hg: parse error: %s\n") % inst.args[0])
90 write(_("hg: parse error: %s\n") % inst.args[0])
91 _reportsimilar(write, similar)
91 _reportsimilar(write, similar)
92 if inst.hint:
92 if inst.hint:
93 write(_("(%s)\n") % inst.hint)
93 write(_("(%s)\n") % inst.hint)
94
94
95 def _mayberepr(a):
96 if ' ' in a:
97 return encoding.strtolocal(repr(a))
98 return a
99
100 def _formatargs(args):
95 def _formatargs(args):
101 return ' '.join(_mayberepr(a) for a in args)
96 return ' '.join(util.shellquote(a) for a in args)
102
97
103 def dispatch(req):
98 def dispatch(req):
104 "run the command specified in req.args"
99 "run the command specified in req.args"
105 if req.ferr:
100 if req.ferr:
106 ferr = req.ferr
101 ferr = req.ferr
107 elif req.ui:
102 elif req.ui:
108 ferr = req.ui.ferr
103 ferr = req.ui.ferr
109 else:
104 else:
110 ferr = util.stderr
105 ferr = util.stderr
111
106
112 try:
107 try:
113 if not req.ui:
108 if not req.ui:
114 req.ui = uimod.ui.load()
109 req.ui = uimod.ui.load()
115 if '--traceback' in req.args:
110 if '--traceback' in req.args:
116 req.ui.setconfig('ui', 'traceback', 'on', '--traceback')
111 req.ui.setconfig('ui', 'traceback', 'on', '--traceback')
117
112
118 # set ui streams from the request
113 # set ui streams from the request
119 if req.fin:
114 if req.fin:
120 req.ui.fin = req.fin
115 req.ui.fin = req.fin
121 if req.fout:
116 if req.fout:
122 req.ui.fout = req.fout
117 req.ui.fout = req.fout
123 if req.ferr:
118 if req.ferr:
124 req.ui.ferr = req.ferr
119 req.ui.ferr = req.ferr
125 except error.Abort as inst:
120 except error.Abort as inst:
126 ferr.write(_("abort: %s\n") % inst)
121 ferr.write(_("abort: %s\n") % inst)
127 if inst.hint:
122 if inst.hint:
128 ferr.write(_("(%s)\n") % inst.hint)
123 ferr.write(_("(%s)\n") % inst.hint)
129 return -1
124 return -1
130 except error.ParseError as inst:
125 except error.ParseError as inst:
131 _formatparse(ferr.write, inst)
126 _formatparse(ferr.write, inst)
132 return -1
127 return -1
133
128
134 msg = _formatargs(req.args)
129 msg = _formatargs(req.args)
135 starttime = util.timer()
130 starttime = util.timer()
136 ret = None
131 ret = None
137 try:
132 try:
138 ret = _runcatch(req)
133 ret = _runcatch(req)
139 except KeyboardInterrupt:
134 except KeyboardInterrupt:
140 try:
135 try:
141 req.ui.warn(_("interrupted!\n"))
136 req.ui.warn(_("interrupted!\n"))
142 except IOError as inst:
137 except IOError as inst:
143 if inst.errno != errno.EPIPE:
138 if inst.errno != errno.EPIPE:
144 raise
139 raise
145 ret = -1
140 ret = -1
146 finally:
141 finally:
147 duration = util.timer() - starttime
142 duration = util.timer() - starttime
148 req.ui.flush()
143 req.ui.flush()
149 if req.ui.logblockedtimes:
144 if req.ui.logblockedtimes:
150 req.ui._blockedtimes['command_duration'] = duration * 1000
145 req.ui._blockedtimes['command_duration'] = duration * 1000
151 req.ui.log('uiblocked', 'ui blocked ms', **req.ui._blockedtimes)
146 req.ui.log('uiblocked', 'ui blocked ms', **req.ui._blockedtimes)
152 req.ui.log("commandfinish", "%s exited %s after %0.2f seconds\n",
147 req.ui.log("commandfinish", "%s exited %s after %0.2f seconds\n",
153 msg, ret or 0, duration)
148 msg, ret or 0, duration)
154 return ret
149 return ret
155
150
156 def _runcatch(req):
151 def _runcatch(req):
157 def catchterm(*args):
152 def catchterm(*args):
158 raise error.SignalInterrupt
153 raise error.SignalInterrupt
159
154
160 ui = req.ui
155 ui = req.ui
161 try:
156 try:
162 for name in 'SIGBREAK', 'SIGHUP', 'SIGTERM':
157 for name in 'SIGBREAK', 'SIGHUP', 'SIGTERM':
163 num = getattr(signal, name, None)
158 num = getattr(signal, name, None)
164 if num:
159 if num:
165 signal.signal(num, catchterm)
160 signal.signal(num, catchterm)
166 except ValueError:
161 except ValueError:
167 pass # happens if called in a thread
162 pass # happens if called in a thread
168
163
169 def _runcatchfunc():
164 def _runcatchfunc():
170 try:
165 try:
171 debugger = 'pdb'
166 debugger = 'pdb'
172 debugtrace = {
167 debugtrace = {
173 'pdb' : pdb.set_trace
168 'pdb' : pdb.set_trace
174 }
169 }
175 debugmortem = {
170 debugmortem = {
176 'pdb' : pdb.post_mortem
171 'pdb' : pdb.post_mortem
177 }
172 }
178
173
179 # read --config before doing anything else
174 # read --config before doing anything else
180 # (e.g. to change trust settings for reading .hg/hgrc)
175 # (e.g. to change trust settings for reading .hg/hgrc)
181 cfgs = _parseconfig(req.ui, _earlygetopt(['--config'], req.args))
176 cfgs = _parseconfig(req.ui, _earlygetopt(['--config'], req.args))
182
177
183 if req.repo:
178 if req.repo:
184 # copy configs that were passed on the cmdline (--config) to
179 # copy configs that were passed on the cmdline (--config) to
185 # the repo ui
180 # the repo ui
186 for sec, name, val in cfgs:
181 for sec, name, val in cfgs:
187 req.repo.ui.setconfig(sec, name, val, source='--config')
182 req.repo.ui.setconfig(sec, name, val, source='--config')
188
183
189 # developer config: ui.debugger
184 # developer config: ui.debugger
190 debugger = ui.config("ui", "debugger")
185 debugger = ui.config("ui", "debugger")
191 debugmod = pdb
186 debugmod = pdb
192 if not debugger or ui.plain():
187 if not debugger or ui.plain():
193 # if we are in HGPLAIN mode, then disable custom debugging
188 # if we are in HGPLAIN mode, then disable custom debugging
194 debugger = 'pdb'
189 debugger = 'pdb'
195 elif '--debugger' in req.args:
190 elif '--debugger' in req.args:
196 # This import can be slow for fancy debuggers, so only
191 # This import can be slow for fancy debuggers, so only
197 # do it when absolutely necessary, i.e. when actual
192 # do it when absolutely necessary, i.e. when actual
198 # debugging has been requested
193 # debugging has been requested
199 with demandimport.deactivated():
194 with demandimport.deactivated():
200 try:
195 try:
201 debugmod = __import__(debugger)
196 debugmod = __import__(debugger)
202 except ImportError:
197 except ImportError:
203 pass # Leave debugmod = pdb
198 pass # Leave debugmod = pdb
204
199
205 debugtrace[debugger] = debugmod.set_trace
200 debugtrace[debugger] = debugmod.set_trace
206 debugmortem[debugger] = debugmod.post_mortem
201 debugmortem[debugger] = debugmod.post_mortem
207
202
208 # enter the debugger before command execution
203 # enter the debugger before command execution
209 if '--debugger' in req.args:
204 if '--debugger' in req.args:
210 ui.warn(_("entering debugger - "
205 ui.warn(_("entering debugger - "
211 "type c to continue starting hg or h for help\n"))
206 "type c to continue starting hg or h for help\n"))
212
207
213 if (debugger != 'pdb' and
208 if (debugger != 'pdb' and
214 debugtrace[debugger] == debugtrace['pdb']):
209 debugtrace[debugger] == debugtrace['pdb']):
215 ui.warn(_("%s debugger specified "
210 ui.warn(_("%s debugger specified "
216 "but its module was not found\n") % debugger)
211 "but its module was not found\n") % debugger)
217 with demandimport.deactivated():
212 with demandimport.deactivated():
218 debugtrace[debugger]()
213 debugtrace[debugger]()
219 try:
214 try:
220 return _dispatch(req)
215 return _dispatch(req)
221 finally:
216 finally:
222 ui.flush()
217 ui.flush()
223 except: # re-raises
218 except: # re-raises
224 # enter the debugger when we hit an exception
219 # enter the debugger when we hit an exception
225 if '--debugger' in req.args:
220 if '--debugger' in req.args:
226 traceback.print_exc()
221 traceback.print_exc()
227 debugmortem[debugger](sys.exc_info()[2])
222 debugmortem[debugger](sys.exc_info()[2])
228 ui.traceback()
223 ui.traceback()
229 raise
224 raise
230
225
231 return callcatch(ui, _runcatchfunc)
226 return callcatch(ui, _runcatchfunc)
232
227
233 def callcatch(ui, func):
228 def callcatch(ui, func):
234 """like scmutil.callcatch but handles more high-level exceptions about
229 """like scmutil.callcatch but handles more high-level exceptions about
235 config parsing and commands. besides, use handlecommandexception to handle
230 config parsing and commands. besides, use handlecommandexception to handle
236 uncaught exceptions.
231 uncaught exceptions.
237 """
232 """
238 try:
233 try:
239 return scmutil.callcatch(ui, func)
234 return scmutil.callcatch(ui, func)
240 except error.AmbiguousCommand as inst:
235 except error.AmbiguousCommand as inst:
241 ui.warn(_("hg: command '%s' is ambiguous:\n %s\n") %
236 ui.warn(_("hg: command '%s' is ambiguous:\n %s\n") %
242 (inst.args[0], " ".join(inst.args[1])))
237 (inst.args[0], " ".join(inst.args[1])))
243 except error.CommandError as inst:
238 except error.CommandError as inst:
244 if inst.args[0]:
239 if inst.args[0]:
245 ui.pager('help')
240 ui.pager('help')
246 ui.warn(_("hg %s: %s\n") % (inst.args[0], inst.args[1]))
241 ui.warn(_("hg %s: %s\n") % (inst.args[0], inst.args[1]))
247 commands.help_(ui, inst.args[0], full=False, command=True)
242 commands.help_(ui, inst.args[0], full=False, command=True)
248 else:
243 else:
249 ui.pager('help')
244 ui.pager('help')
250 ui.warn(_("hg: %s\n") % inst.args[1])
245 ui.warn(_("hg: %s\n") % inst.args[1])
251 commands.help_(ui, 'shortlist')
246 commands.help_(ui, 'shortlist')
252 except error.ParseError as inst:
247 except error.ParseError as inst:
253 _formatparse(ui.warn, inst)
248 _formatparse(ui.warn, inst)
254 return -1
249 return -1
255 except error.UnknownCommand as inst:
250 except error.UnknownCommand as inst:
256 nocmdmsg = _("hg: unknown command '%s'\n") % inst.args[0]
251 nocmdmsg = _("hg: unknown command '%s'\n") % inst.args[0]
257 try:
252 try:
258 # check if the command is in a disabled extension
253 # check if the command is in a disabled extension
259 # (but don't check for extensions themselves)
254 # (but don't check for extensions themselves)
260 formatted = help.formattedhelp(ui, inst.args[0], unknowncmd=True)
255 formatted = help.formattedhelp(ui, inst.args[0], unknowncmd=True)
261 ui.warn(nocmdmsg)
256 ui.warn(nocmdmsg)
262 ui.write(formatted)
257 ui.write(formatted)
263 except (error.UnknownCommand, error.Abort):
258 except (error.UnknownCommand, error.Abort):
264 suggested = False
259 suggested = False
265 if len(inst.args) == 2:
260 if len(inst.args) == 2:
266 sim = _getsimilar(inst.args[1], inst.args[0])
261 sim = _getsimilar(inst.args[1], inst.args[0])
267 if sim:
262 if sim:
268 ui.warn(nocmdmsg)
263 ui.warn(nocmdmsg)
269 _reportsimilar(ui.warn, sim)
264 _reportsimilar(ui.warn, sim)
270 suggested = True
265 suggested = True
271 if not suggested:
266 if not suggested:
272 ui.pager('help')
267 ui.pager('help')
273 ui.warn(nocmdmsg)
268 ui.warn(nocmdmsg)
274 commands.help_(ui, 'shortlist')
269 commands.help_(ui, 'shortlist')
275 except IOError:
270 except IOError:
276 raise
271 raise
277 except KeyboardInterrupt:
272 except KeyboardInterrupt:
278 raise
273 raise
279 except: # probably re-raises
274 except: # probably re-raises
280 if not handlecommandexception(ui):
275 if not handlecommandexception(ui):
281 raise
276 raise
282
277
283 return -1
278 return -1
284
279
285 def aliasargs(fn, givenargs):
280 def aliasargs(fn, givenargs):
286 args = getattr(fn, 'args', [])
281 args = getattr(fn, 'args', [])
287 if args:
282 if args:
288 cmd = ' '.join(map(util.shellquote, args))
283 cmd = ' '.join(map(util.shellquote, args))
289
284
290 nums = []
285 nums = []
291 def replacer(m):
286 def replacer(m):
292 num = int(m.group(1)) - 1
287 num = int(m.group(1)) - 1
293 nums.append(num)
288 nums.append(num)
294 if num < len(givenargs):
289 if num < len(givenargs):
295 return givenargs[num]
290 return givenargs[num]
296 raise error.Abort(_('too few arguments for command alias'))
291 raise error.Abort(_('too few arguments for command alias'))
297 cmd = re.sub(br'\$(\d+|\$)', replacer, cmd)
292 cmd = re.sub(br'\$(\d+|\$)', replacer, cmd)
298 givenargs = [x for i, x in enumerate(givenargs)
293 givenargs = [x for i, x in enumerate(givenargs)
299 if i not in nums]
294 if i not in nums]
300 args = pycompat.shlexsplit(cmd)
295 args = pycompat.shlexsplit(cmd)
301 return args + givenargs
296 return args + givenargs
302
297
303 def aliasinterpolate(name, args, cmd):
298 def aliasinterpolate(name, args, cmd):
304 '''interpolate args into cmd for shell aliases
299 '''interpolate args into cmd for shell aliases
305
300
306 This also handles $0, $@ and "$@".
301 This also handles $0, $@ and "$@".
307 '''
302 '''
308 # util.interpolate can't deal with "$@" (with quotes) because it's only
303 # util.interpolate can't deal with "$@" (with quotes) because it's only
309 # built to match prefix + patterns.
304 # built to match prefix + patterns.
310 replacemap = dict(('$%d' % (i + 1), arg) for i, arg in enumerate(args))
305 replacemap = dict(('$%d' % (i + 1), arg) for i, arg in enumerate(args))
311 replacemap['$0'] = name
306 replacemap['$0'] = name
312 replacemap['$$'] = '$'
307 replacemap['$$'] = '$'
313 replacemap['$@'] = ' '.join(args)
308 replacemap['$@'] = ' '.join(args)
314 # Typical Unix shells interpolate "$@" (with quotes) as all the positional
309 # Typical Unix shells interpolate "$@" (with quotes) as all the positional
315 # parameters, separated out into words. Emulate the same behavior here by
310 # parameters, separated out into words. Emulate the same behavior here by
316 # quoting the arguments individually. POSIX shells will then typically
311 # quoting the arguments individually. POSIX shells will then typically
317 # tokenize each argument into exactly one word.
312 # tokenize each argument into exactly one word.
318 replacemap['"$@"'] = ' '.join(util.shellquote(arg) for arg in args)
313 replacemap['"$@"'] = ' '.join(util.shellquote(arg) for arg in args)
319 # escape '\$' for regex
314 # escape '\$' for regex
320 regex = '|'.join(replacemap.keys()).replace('$', r'\$')
315 regex = '|'.join(replacemap.keys()).replace('$', r'\$')
321 r = re.compile(regex)
316 r = re.compile(regex)
322 return r.sub(lambda x: replacemap[x.group()], cmd)
317 return r.sub(lambda x: replacemap[x.group()], cmd)
323
318
324 class cmdalias(object):
319 class cmdalias(object):
325 def __init__(self, name, definition, cmdtable, source):
320 def __init__(self, name, definition, cmdtable, source):
326 self.name = self.cmd = name
321 self.name = self.cmd = name
327 self.cmdname = ''
322 self.cmdname = ''
328 self.definition = definition
323 self.definition = definition
329 self.fn = None
324 self.fn = None
330 self.givenargs = []
325 self.givenargs = []
331 self.opts = []
326 self.opts = []
332 self.help = ''
327 self.help = ''
333 self.badalias = None
328 self.badalias = None
334 self.unknowncmd = False
329 self.unknowncmd = False
335 self.source = source
330 self.source = source
336
331
337 try:
332 try:
338 aliases, entry = cmdutil.findcmd(self.name, cmdtable)
333 aliases, entry = cmdutil.findcmd(self.name, cmdtable)
339 for alias, e in cmdtable.iteritems():
334 for alias, e in cmdtable.iteritems():
340 if e is entry:
335 if e is entry:
341 self.cmd = alias
336 self.cmd = alias
342 break
337 break
343 self.shadows = True
338 self.shadows = True
344 except error.UnknownCommand:
339 except error.UnknownCommand:
345 self.shadows = False
340 self.shadows = False
346
341
347 if not self.definition:
342 if not self.definition:
348 self.badalias = _("no definition for alias '%s'") % self.name
343 self.badalias = _("no definition for alias '%s'") % self.name
349 return
344 return
350
345
351 if self.definition.startswith('!'):
346 if self.definition.startswith('!'):
352 self.shell = True
347 self.shell = True
353 def fn(ui, *args):
348 def fn(ui, *args):
354 env = {'HG_ARGS': ' '.join((self.name,) + args)}
349 env = {'HG_ARGS': ' '.join((self.name,) + args)}
355 def _checkvar(m):
350 def _checkvar(m):
356 if m.groups()[0] == '$':
351 if m.groups()[0] == '$':
357 return m.group()
352 return m.group()
358 elif int(m.groups()[0]) <= len(args):
353 elif int(m.groups()[0]) <= len(args):
359 return m.group()
354 return m.group()
360 else:
355 else:
361 ui.debug("No argument found for substitution "
356 ui.debug("No argument found for substitution "
362 "of %i variable in alias '%s' definition."
357 "of %i variable in alias '%s' definition."
363 % (int(m.groups()[0]), self.name))
358 % (int(m.groups()[0]), self.name))
364 return ''
359 return ''
365 cmd = re.sub(r'\$(\d+|\$)', _checkvar, self.definition[1:])
360 cmd = re.sub(r'\$(\d+|\$)', _checkvar, self.definition[1:])
366 cmd = aliasinterpolate(self.name, args, cmd)
361 cmd = aliasinterpolate(self.name, args, cmd)
367 return ui.system(cmd, environ=env,
362 return ui.system(cmd, environ=env,
368 blockedtag='alias_%s' % self.name)
363 blockedtag='alias_%s' % self.name)
369 self.fn = fn
364 self.fn = fn
370 return
365 return
371
366
372 try:
367 try:
373 args = pycompat.shlexsplit(self.definition)
368 args = pycompat.shlexsplit(self.definition)
374 except ValueError as inst:
369 except ValueError as inst:
375 self.badalias = (_("error in definition for alias '%s': %s")
370 self.badalias = (_("error in definition for alias '%s': %s")
376 % (self.name, inst))
371 % (self.name, inst))
377 return
372 return
378 self.cmdname = cmd = args.pop(0)
373 self.cmdname = cmd = args.pop(0)
379 self.givenargs = args
374 self.givenargs = args
380
375
381 for invalidarg in ("--cwd", "-R", "--repository", "--repo", "--config"):
376 for invalidarg in ("--cwd", "-R", "--repository", "--repo", "--config"):
382 if _earlygetopt([invalidarg], args):
377 if _earlygetopt([invalidarg], args):
383 self.badalias = (_("error in definition for alias '%s': %s may "
378 self.badalias = (_("error in definition for alias '%s': %s may "
384 "only be given on the command line")
379 "only be given on the command line")
385 % (self.name, invalidarg))
380 % (self.name, invalidarg))
386 return
381 return
387
382
388 try:
383 try:
389 tableentry = cmdutil.findcmd(cmd, cmdtable, False)[1]
384 tableentry = cmdutil.findcmd(cmd, cmdtable, False)[1]
390 if len(tableentry) > 2:
385 if len(tableentry) > 2:
391 self.fn, self.opts, self.help = tableentry
386 self.fn, self.opts, self.help = tableentry
392 else:
387 else:
393 self.fn, self.opts = tableentry
388 self.fn, self.opts = tableentry
394
389
395 if self.help.startswith("hg " + cmd):
390 if self.help.startswith("hg " + cmd):
396 # drop prefix in old-style help lines so hg shows the alias
391 # drop prefix in old-style help lines so hg shows the alias
397 self.help = self.help[4 + len(cmd):]
392 self.help = self.help[4 + len(cmd):]
398 self.__doc__ = self.fn.__doc__
393 self.__doc__ = self.fn.__doc__
399
394
400 except error.UnknownCommand:
395 except error.UnknownCommand:
401 self.badalias = (_("alias '%s' resolves to unknown command '%s'")
396 self.badalias = (_("alias '%s' resolves to unknown command '%s'")
402 % (self.name, cmd))
397 % (self.name, cmd))
403 self.unknowncmd = True
398 self.unknowncmd = True
404 except error.AmbiguousCommand:
399 except error.AmbiguousCommand:
405 self.badalias = (_("alias '%s' resolves to ambiguous command '%s'")
400 self.badalias = (_("alias '%s' resolves to ambiguous command '%s'")
406 % (self.name, cmd))
401 % (self.name, cmd))
407
402
408 @property
403 @property
409 def args(self):
404 def args(self):
410 args = map(util.expandpath, self.givenargs)
405 args = map(util.expandpath, self.givenargs)
411 return aliasargs(self.fn, args)
406 return aliasargs(self.fn, args)
412
407
413 def __getattr__(self, name):
408 def __getattr__(self, name):
414 adefaults = {'norepo': True, 'optionalrepo': False, 'inferrepo': False}
409 adefaults = {'norepo': True, 'optionalrepo': False, 'inferrepo': False}
415 if name not in adefaults:
410 if name not in adefaults:
416 raise AttributeError(name)
411 raise AttributeError(name)
417 if self.badalias or util.safehasattr(self, 'shell'):
412 if self.badalias or util.safehasattr(self, 'shell'):
418 return adefaults[name]
413 return adefaults[name]
419 return getattr(self.fn, name)
414 return getattr(self.fn, name)
420
415
421 def __call__(self, ui, *args, **opts):
416 def __call__(self, ui, *args, **opts):
422 if self.badalias:
417 if self.badalias:
423 hint = None
418 hint = None
424 if self.unknowncmd:
419 if self.unknowncmd:
425 try:
420 try:
426 # check if the command is in a disabled extension
421 # check if the command is in a disabled extension
427 cmd, ext = extensions.disabledcmd(ui, self.cmdname)[:2]
422 cmd, ext = extensions.disabledcmd(ui, self.cmdname)[:2]
428 hint = _("'%s' is provided by '%s' extension") % (cmd, ext)
423 hint = _("'%s' is provided by '%s' extension") % (cmd, ext)
429 except error.UnknownCommand:
424 except error.UnknownCommand:
430 pass
425 pass
431 raise error.Abort(self.badalias, hint=hint)
426 raise error.Abort(self.badalias, hint=hint)
432 if self.shadows:
427 if self.shadows:
433 ui.debug("alias '%s' shadows command '%s'\n" %
428 ui.debug("alias '%s' shadows command '%s'\n" %
434 (self.name, self.cmdname))
429 (self.name, self.cmdname))
435
430
436 ui.log('commandalias', "alias '%s' expands to '%s'\n",
431 ui.log('commandalias', "alias '%s' expands to '%s'\n",
437 self.name, self.definition)
432 self.name, self.definition)
438 if util.safehasattr(self, 'shell'):
433 if util.safehasattr(self, 'shell'):
439 return self.fn(ui, *args, **opts)
434 return self.fn(ui, *args, **opts)
440 else:
435 else:
441 try:
436 try:
442 return util.checksignature(self.fn)(ui, *args, **opts)
437 return util.checksignature(self.fn)(ui, *args, **opts)
443 except error.SignatureError:
438 except error.SignatureError:
444 args = ' '.join([self.cmdname] + self.args)
439 args = ' '.join([self.cmdname] + self.args)
445 ui.debug("alias '%s' expands to '%s'\n" % (self.name, args))
440 ui.debug("alias '%s' expands to '%s'\n" % (self.name, args))
446 raise
441 raise
447
442
448 def addaliases(ui, cmdtable):
443 def addaliases(ui, cmdtable):
449 # aliases are processed after extensions have been loaded, so they
444 # aliases are processed after extensions have been loaded, so they
450 # may use extension commands. Aliases can also use other alias definitions,
445 # may use extension commands. Aliases can also use other alias definitions,
451 # but only if they have been defined prior to the current definition.
446 # but only if they have been defined prior to the current definition.
452 for alias, definition in ui.configitems('alias'):
447 for alias, definition in ui.configitems('alias'):
453 source = ui.configsource('alias', alias)
448 source = ui.configsource('alias', alias)
454 aliasdef = cmdalias(alias, definition, cmdtable, source)
449 aliasdef = cmdalias(alias, definition, cmdtable, source)
455
450
456 try:
451 try:
457 olddef = cmdtable[aliasdef.cmd][0]
452 olddef = cmdtable[aliasdef.cmd][0]
458 if olddef.definition == aliasdef.definition:
453 if olddef.definition == aliasdef.definition:
459 continue
454 continue
460 except (KeyError, AttributeError):
455 except (KeyError, AttributeError):
461 # definition might not exist or it might not be a cmdalias
456 # definition might not exist or it might not be a cmdalias
462 pass
457 pass
463
458
464 cmdtable[aliasdef.name] = (aliasdef, aliasdef.opts, aliasdef.help)
459 cmdtable[aliasdef.name] = (aliasdef, aliasdef.opts, aliasdef.help)
465
460
466 def _parse(ui, args):
461 def _parse(ui, args):
467 options = {}
462 options = {}
468 cmdoptions = {}
463 cmdoptions = {}
469
464
470 try:
465 try:
471 args = fancyopts.fancyopts(args, commands.globalopts, options)
466 args = fancyopts.fancyopts(args, commands.globalopts, options)
472 except getopt.GetoptError as inst:
467 except getopt.GetoptError as inst:
473 raise error.CommandError(None, inst)
468 raise error.CommandError(None, inst)
474
469
475 if args:
470 if args:
476 cmd, args = args[0], args[1:]
471 cmd, args = args[0], args[1:]
477 aliases, entry = cmdutil.findcmd(cmd, commands.table,
472 aliases, entry = cmdutil.findcmd(cmd, commands.table,
478 ui.configbool("ui", "strict"))
473 ui.configbool("ui", "strict"))
479 cmd = aliases[0]
474 cmd = aliases[0]
480 args = aliasargs(entry[0], args)
475 args = aliasargs(entry[0], args)
481 defaults = ui.config("defaults", cmd)
476 defaults = ui.config("defaults", cmd)
482 if defaults:
477 if defaults:
483 args = map(util.expandpath, pycompat.shlexsplit(defaults)) + args
478 args = map(util.expandpath, pycompat.shlexsplit(defaults)) + args
484 c = list(entry[1])
479 c = list(entry[1])
485 else:
480 else:
486 cmd = None
481 cmd = None
487 c = []
482 c = []
488
483
489 # combine global options into local
484 # combine global options into local
490 for o in commands.globalopts:
485 for o in commands.globalopts:
491 c.append((o[0], o[1], options[o[1]], o[3]))
486 c.append((o[0], o[1], options[o[1]], o[3]))
492
487
493 try:
488 try:
494 args = fancyopts.fancyopts(args, c, cmdoptions, gnu=True)
489 args = fancyopts.fancyopts(args, c, cmdoptions, gnu=True)
495 except getopt.GetoptError as inst:
490 except getopt.GetoptError as inst:
496 raise error.CommandError(cmd, inst)
491 raise error.CommandError(cmd, inst)
497
492
498 # separate global options back out
493 # separate global options back out
499 for o in commands.globalopts:
494 for o in commands.globalopts:
500 n = o[1]
495 n = o[1]
501 options[n] = cmdoptions[n]
496 options[n] = cmdoptions[n]
502 del cmdoptions[n]
497 del cmdoptions[n]
503
498
504 return (cmd, cmd and entry[0] or None, args, options, cmdoptions)
499 return (cmd, cmd and entry[0] or None, args, options, cmdoptions)
505
500
506 def _parseconfig(ui, config):
501 def _parseconfig(ui, config):
507 """parse the --config options from the command line"""
502 """parse the --config options from the command line"""
508 configs = []
503 configs = []
509
504
510 for cfg in config:
505 for cfg in config:
511 try:
506 try:
512 name, value = [cfgelem.strip()
507 name, value = [cfgelem.strip()
513 for cfgelem in cfg.split('=', 1)]
508 for cfgelem in cfg.split('=', 1)]
514 section, name = name.split('.', 1)
509 section, name = name.split('.', 1)
515 if not section or not name:
510 if not section or not name:
516 raise IndexError
511 raise IndexError
517 ui.setconfig(section, name, value, '--config')
512 ui.setconfig(section, name, value, '--config')
518 configs.append((section, name, value))
513 configs.append((section, name, value))
519 except (IndexError, ValueError):
514 except (IndexError, ValueError):
520 raise error.Abort(_('malformed --config option: %r '
515 raise error.Abort(_('malformed --config option: %r '
521 '(use --config section.name=value)') % cfg)
516 '(use --config section.name=value)') % cfg)
522
517
523 return configs
518 return configs
524
519
525 def _earlygetopt(aliases, args):
520 def _earlygetopt(aliases, args):
526 """Return list of values for an option (or aliases).
521 """Return list of values for an option (or aliases).
527
522
528 The values are listed in the order they appear in args.
523 The values are listed in the order they appear in args.
529 The options and values are removed from args.
524 The options and values are removed from args.
530
525
531 >>> args = ['x', '--cwd', 'foo', 'y']
526 >>> args = ['x', '--cwd', 'foo', 'y']
532 >>> _earlygetopt(['--cwd'], args), args
527 >>> _earlygetopt(['--cwd'], args), args
533 (['foo'], ['x', 'y'])
528 (['foo'], ['x', 'y'])
534
529
535 >>> args = ['x', '--cwd=bar', 'y']
530 >>> args = ['x', '--cwd=bar', 'y']
536 >>> _earlygetopt(['--cwd'], args), args
531 >>> _earlygetopt(['--cwd'], args), args
537 (['bar'], ['x', 'y'])
532 (['bar'], ['x', 'y'])
538
533
539 >>> args = ['x', '-R', 'foo', 'y']
534 >>> args = ['x', '-R', 'foo', 'y']
540 >>> _earlygetopt(['-R'], args), args
535 >>> _earlygetopt(['-R'], args), args
541 (['foo'], ['x', 'y'])
536 (['foo'], ['x', 'y'])
542
537
543 >>> args = ['x', '-Rbar', 'y']
538 >>> args = ['x', '-Rbar', 'y']
544 >>> _earlygetopt(['-R'], args), args
539 >>> _earlygetopt(['-R'], args), args
545 (['bar'], ['x', 'y'])
540 (['bar'], ['x', 'y'])
546 """
541 """
547 try:
542 try:
548 argcount = args.index("--")
543 argcount = args.index("--")
549 except ValueError:
544 except ValueError:
550 argcount = len(args)
545 argcount = len(args)
551 shortopts = [opt for opt in aliases if len(opt) == 2]
546 shortopts = [opt for opt in aliases if len(opt) == 2]
552 values = []
547 values = []
553 pos = 0
548 pos = 0
554 while pos < argcount:
549 while pos < argcount:
555 fullarg = arg = args[pos]
550 fullarg = arg = args[pos]
556 equals = arg.find('=')
551 equals = arg.find('=')
557 if equals > -1:
552 if equals > -1:
558 arg = arg[:equals]
553 arg = arg[:equals]
559 if arg in aliases:
554 if arg in aliases:
560 del args[pos]
555 del args[pos]
561 if equals > -1:
556 if equals > -1:
562 values.append(fullarg[equals + 1:])
557 values.append(fullarg[equals + 1:])
563 argcount -= 1
558 argcount -= 1
564 else:
559 else:
565 if pos + 1 >= argcount:
560 if pos + 1 >= argcount:
566 # ignore and let getopt report an error if there is no value
561 # ignore and let getopt report an error if there is no value
567 break
562 break
568 values.append(args.pop(pos))
563 values.append(args.pop(pos))
569 argcount -= 2
564 argcount -= 2
570 elif arg[:2] in shortopts:
565 elif arg[:2] in shortopts:
571 # short option can have no following space, e.g. hg log -Rfoo
566 # short option can have no following space, e.g. hg log -Rfoo
572 values.append(args.pop(pos)[2:])
567 values.append(args.pop(pos)[2:])
573 argcount -= 1
568 argcount -= 1
574 else:
569 else:
575 pos += 1
570 pos += 1
576 return values
571 return values
577
572
578 def runcommand(lui, repo, cmd, fullargs, ui, options, d, cmdpats, cmdoptions):
573 def runcommand(lui, repo, cmd, fullargs, ui, options, d, cmdpats, cmdoptions):
579 # run pre-hook, and abort if it fails
574 # run pre-hook, and abort if it fails
580 hook.hook(lui, repo, "pre-%s" % cmd, True, args=" ".join(fullargs),
575 hook.hook(lui, repo, "pre-%s" % cmd, True, args=" ".join(fullargs),
581 pats=cmdpats, opts=cmdoptions)
576 pats=cmdpats, opts=cmdoptions)
582 try:
577 try:
583 ret = _runcommand(ui, options, cmd, d)
578 ret = _runcommand(ui, options, cmd, d)
584 # run post-hook, passing command result
579 # run post-hook, passing command result
585 hook.hook(lui, repo, "post-%s" % cmd, False, args=" ".join(fullargs),
580 hook.hook(lui, repo, "post-%s" % cmd, False, args=" ".join(fullargs),
586 result=ret, pats=cmdpats, opts=cmdoptions)
581 result=ret, pats=cmdpats, opts=cmdoptions)
587 except Exception:
582 except Exception:
588 # run failure hook and re-raise
583 # run failure hook and re-raise
589 hook.hook(lui, repo, "fail-%s" % cmd, False, args=" ".join(fullargs),
584 hook.hook(lui, repo, "fail-%s" % cmd, False, args=" ".join(fullargs),
590 pats=cmdpats, opts=cmdoptions)
585 pats=cmdpats, opts=cmdoptions)
591 raise
586 raise
592 return ret
587 return ret
593
588
594 def _getlocal(ui, rpath, wd=None):
589 def _getlocal(ui, rpath, wd=None):
595 """Return (path, local ui object) for the given target path.
590 """Return (path, local ui object) for the given target path.
596
591
597 Takes paths in [cwd]/.hg/hgrc into account."
592 Takes paths in [cwd]/.hg/hgrc into account."
598 """
593 """
599 if wd is None:
594 if wd is None:
600 try:
595 try:
601 wd = pycompat.getcwd()
596 wd = pycompat.getcwd()
602 except OSError as e:
597 except OSError as e:
603 raise error.Abort(_("error getting current working directory: %s") %
598 raise error.Abort(_("error getting current working directory: %s") %
604 e.strerror)
599 e.strerror)
605 path = cmdutil.findrepo(wd) or ""
600 path = cmdutil.findrepo(wd) or ""
606 if not path:
601 if not path:
607 lui = ui
602 lui = ui
608 else:
603 else:
609 lui = ui.copy()
604 lui = ui.copy()
610 lui.readconfig(os.path.join(path, ".hg", "hgrc"), path)
605 lui.readconfig(os.path.join(path, ".hg", "hgrc"), path)
611
606
612 if rpath and rpath[-1]:
607 if rpath and rpath[-1]:
613 path = lui.expandpath(rpath[-1])
608 path = lui.expandpath(rpath[-1])
614 lui = ui.copy()
609 lui = ui.copy()
615 lui.readconfig(os.path.join(path, ".hg", "hgrc"), path)
610 lui.readconfig(os.path.join(path, ".hg", "hgrc"), path)
616
611
617 return path, lui
612 return path, lui
618
613
619 def _checkshellalias(lui, ui, args):
614 def _checkshellalias(lui, ui, args):
620 """Return the function to run the shell alias, if it is required"""
615 """Return the function to run the shell alias, if it is required"""
621 options = {}
616 options = {}
622
617
623 try:
618 try:
624 args = fancyopts.fancyopts(args, commands.globalopts, options)
619 args = fancyopts.fancyopts(args, commands.globalopts, options)
625 except getopt.GetoptError:
620 except getopt.GetoptError:
626 return
621 return
627
622
628 if not args:
623 if not args:
629 return
624 return
630
625
631 cmdtable = commands.table
626 cmdtable = commands.table
632
627
633 cmd = args[0]
628 cmd = args[0]
634 try:
629 try:
635 strict = ui.configbool("ui", "strict")
630 strict = ui.configbool("ui", "strict")
636 aliases, entry = cmdutil.findcmd(cmd, cmdtable, strict)
631 aliases, entry = cmdutil.findcmd(cmd, cmdtable, strict)
637 except (error.AmbiguousCommand, error.UnknownCommand):
632 except (error.AmbiguousCommand, error.UnknownCommand):
638 return
633 return
639
634
640 cmd = aliases[0]
635 cmd = aliases[0]
641 fn = entry[0]
636 fn = entry[0]
642
637
643 if cmd and util.safehasattr(fn, 'shell'):
638 if cmd and util.safehasattr(fn, 'shell'):
644 d = lambda: fn(ui, *args[1:])
639 d = lambda: fn(ui, *args[1:])
645 return lambda: runcommand(lui, None, cmd, args[:1], ui, options, d,
640 return lambda: runcommand(lui, None, cmd, args[:1], ui, options, d,
646 [], {})
641 [], {})
647
642
648 _loaded = set()
643 _loaded = set()
649
644
650 # list of (objname, loadermod, loadername) tuple:
645 # list of (objname, loadermod, loadername) tuple:
651 # - objname is the name of an object in extension module, from which
646 # - objname is the name of an object in extension module, from which
652 # extra information is loaded
647 # extra information is loaded
653 # - loadermod is the module where loader is placed
648 # - loadermod is the module where loader is placed
654 # - loadername is the name of the function, which takes (ui, extensionname,
649 # - loadername is the name of the function, which takes (ui, extensionname,
655 # extraobj) arguments
650 # extraobj) arguments
656 extraloaders = [
651 extraloaders = [
657 ('cmdtable', commands, 'loadcmdtable'),
652 ('cmdtable', commands, 'loadcmdtable'),
658 ('colortable', color, 'loadcolortable'),
653 ('colortable', color, 'loadcolortable'),
659 ('filesetpredicate', fileset, 'loadpredicate'),
654 ('filesetpredicate', fileset, 'loadpredicate'),
660 ('revsetpredicate', revset, 'loadpredicate'),
655 ('revsetpredicate', revset, 'loadpredicate'),
661 ('templatefilter', templatefilters, 'loadfilter'),
656 ('templatefilter', templatefilters, 'loadfilter'),
662 ('templatefunc', templater, 'loadfunction'),
657 ('templatefunc', templater, 'loadfunction'),
663 ('templatekeyword', templatekw, 'loadkeyword'),
658 ('templatekeyword', templatekw, 'loadkeyword'),
664 ]
659 ]
665
660
666 def _dispatch(req):
661 def _dispatch(req):
667 args = req.args
662 args = req.args
668 ui = req.ui
663 ui = req.ui
669
664
670 # check for cwd
665 # check for cwd
671 cwd = _earlygetopt(['--cwd'], args)
666 cwd = _earlygetopt(['--cwd'], args)
672 if cwd:
667 if cwd:
673 os.chdir(cwd[-1])
668 os.chdir(cwd[-1])
674
669
675 rpath = _earlygetopt(["-R", "--repository", "--repo"], args)
670 rpath = _earlygetopt(["-R", "--repository", "--repo"], args)
676 path, lui = _getlocal(ui, rpath)
671 path, lui = _getlocal(ui, rpath)
677
672
678 # Side-effect of accessing is debugcommands module is guaranteed to be
673 # Side-effect of accessing is debugcommands module is guaranteed to be
679 # imported and commands.table is populated.
674 # imported and commands.table is populated.
680 debugcommands.command
675 debugcommands.command
681
676
682 uis = set([ui, lui])
677 uis = set([ui, lui])
683
678
684 if req.repo:
679 if req.repo:
685 uis.add(req.repo.ui)
680 uis.add(req.repo.ui)
686
681
687 if '--profile' in args:
682 if '--profile' in args:
688 for ui_ in uis:
683 for ui_ in uis:
689 ui_.setconfig('profiling', 'enabled', 'true', '--profile')
684 ui_.setconfig('profiling', 'enabled', 'true', '--profile')
690
685
691 with profiling.maybeprofile(lui):
686 with profiling.maybeprofile(lui):
692 # Configure extensions in phases: uisetup, extsetup, cmdtable, and
687 # Configure extensions in phases: uisetup, extsetup, cmdtable, and
693 # reposetup. Programs like TortoiseHg will call _dispatch several
688 # reposetup. Programs like TortoiseHg will call _dispatch several
694 # times so we keep track of configured extensions in _loaded.
689 # times so we keep track of configured extensions in _loaded.
695 extensions.loadall(lui)
690 extensions.loadall(lui)
696 exts = [ext for ext in extensions.extensions() if ext[0] not in _loaded]
691 exts = [ext for ext in extensions.extensions() if ext[0] not in _loaded]
697 # Propagate any changes to lui.__class__ by extensions
692 # Propagate any changes to lui.__class__ by extensions
698 ui.__class__ = lui.__class__
693 ui.__class__ = lui.__class__
699
694
700 # (uisetup and extsetup are handled in extensions.loadall)
695 # (uisetup and extsetup are handled in extensions.loadall)
701
696
702 for name, module in exts:
697 for name, module in exts:
703 for objname, loadermod, loadername in extraloaders:
698 for objname, loadermod, loadername in extraloaders:
704 extraobj = getattr(module, objname, None)
699 extraobj = getattr(module, objname, None)
705 if extraobj is not None:
700 if extraobj is not None:
706 getattr(loadermod, loadername)(ui, name, extraobj)
701 getattr(loadermod, loadername)(ui, name, extraobj)
707 _loaded.add(name)
702 _loaded.add(name)
708
703
709 # (reposetup is handled in hg.repository)
704 # (reposetup is handled in hg.repository)
710
705
711 addaliases(lui, commands.table)
706 addaliases(lui, commands.table)
712
707
713 # All aliases and commands are completely defined, now.
708 # All aliases and commands are completely defined, now.
714 # Check abbreviation/ambiguity of shell alias.
709 # Check abbreviation/ambiguity of shell alias.
715 shellaliasfn = _checkshellalias(lui, ui, args)
710 shellaliasfn = _checkshellalias(lui, ui, args)
716 if shellaliasfn:
711 if shellaliasfn:
717 return shellaliasfn()
712 return shellaliasfn()
718
713
719 # check for fallback encoding
714 # check for fallback encoding
720 fallback = lui.config('ui', 'fallbackencoding')
715 fallback = lui.config('ui', 'fallbackencoding')
721 if fallback:
716 if fallback:
722 encoding.fallbackencoding = fallback
717 encoding.fallbackencoding = fallback
723
718
724 fullargs = args
719 fullargs = args
725 cmd, func, args, options, cmdoptions = _parse(lui, args)
720 cmd, func, args, options, cmdoptions = _parse(lui, args)
726
721
727 if options["config"]:
722 if options["config"]:
728 raise error.Abort(_("option --config may not be abbreviated!"))
723 raise error.Abort(_("option --config may not be abbreviated!"))
729 if options["cwd"]:
724 if options["cwd"]:
730 raise error.Abort(_("option --cwd may not be abbreviated!"))
725 raise error.Abort(_("option --cwd may not be abbreviated!"))
731 if options["repository"]:
726 if options["repository"]:
732 raise error.Abort(_(
727 raise error.Abort(_(
733 "option -R has to be separated from other options (e.g. not "
728 "option -R has to be separated from other options (e.g. not "
734 "-qR) and --repository may only be abbreviated as --repo!"))
729 "-qR) and --repository may only be abbreviated as --repo!"))
735
730
736 if options["encoding"]:
731 if options["encoding"]:
737 encoding.encoding = options["encoding"]
732 encoding.encoding = options["encoding"]
738 if options["encodingmode"]:
733 if options["encodingmode"]:
739 encoding.encodingmode = options["encodingmode"]
734 encoding.encodingmode = options["encodingmode"]
740 if options["time"]:
735 if options["time"]:
741 def get_times():
736 def get_times():
742 t = os.times()
737 t = os.times()
743 if t[4] == 0.0:
738 if t[4] == 0.0:
744 # Windows leaves this as zero, so use time.clock()
739 # Windows leaves this as zero, so use time.clock()
745 t = (t[0], t[1], t[2], t[3], time.clock())
740 t = (t[0], t[1], t[2], t[3], time.clock())
746 return t
741 return t
747 s = get_times()
742 s = get_times()
748 def print_time():
743 def print_time():
749 t = get_times()
744 t = get_times()
750 ui.warn(
745 ui.warn(
751 _("time: real %.3f secs (user %.3f+%.3f sys %.3f+%.3f)\n") %
746 _("time: real %.3f secs (user %.3f+%.3f sys %.3f+%.3f)\n") %
752 (t[4]-s[4], t[0]-s[0], t[2]-s[2], t[1]-s[1], t[3]-s[3]))
747 (t[4]-s[4], t[0]-s[0], t[2]-s[2], t[1]-s[1], t[3]-s[3]))
753 atexit.register(print_time)
748 atexit.register(print_time)
754
749
755 if options['verbose'] or options['debug'] or options['quiet']:
750 if options['verbose'] or options['debug'] or options['quiet']:
756 for opt in ('verbose', 'debug', 'quiet'):
751 for opt in ('verbose', 'debug', 'quiet'):
757 val = str(bool(options[opt]))
752 val = str(bool(options[opt]))
758 if pycompat.ispy3:
753 if pycompat.ispy3:
759 val = val.encode('ascii')
754 val = val.encode('ascii')
760 for ui_ in uis:
755 for ui_ in uis:
761 ui_.setconfig('ui', opt, val, '--' + opt)
756 ui_.setconfig('ui', opt, val, '--' + opt)
762
757
763 if options['traceback']:
758 if options['traceback']:
764 for ui_ in uis:
759 for ui_ in uis:
765 ui_.setconfig('ui', 'traceback', 'on', '--traceback')
760 ui_.setconfig('ui', 'traceback', 'on', '--traceback')
766
761
767 if options['noninteractive']:
762 if options['noninteractive']:
768 for ui_ in uis:
763 for ui_ in uis:
769 ui_.setconfig('ui', 'interactive', 'off', '-y')
764 ui_.setconfig('ui', 'interactive', 'off', '-y')
770
765
771 if util.parsebool(options['pager']):
766 if util.parsebool(options['pager']):
772 ui.pager('internal-always-' + cmd)
767 ui.pager('internal-always-' + cmd)
773 elif options['pager'] != 'auto':
768 elif options['pager'] != 'auto':
774 ui.disablepager()
769 ui.disablepager()
775
770
776 if cmdoptions.get('insecure', False):
771 if cmdoptions.get('insecure', False):
777 for ui_ in uis:
772 for ui_ in uis:
778 ui_.insecureconnections = True
773 ui_.insecureconnections = True
779
774
780 # setup color handling
775 # setup color handling
781 coloropt = options['color']
776 coloropt = options['color']
782 for ui_ in uis:
777 for ui_ in uis:
783 if coloropt:
778 if coloropt:
784 ui_.setconfig('ui', 'color', coloropt, '--color')
779 ui_.setconfig('ui', 'color', coloropt, '--color')
785 color.setup(ui_)
780 color.setup(ui_)
786
781
787 if options['version']:
782 if options['version']:
788 return commands.version_(ui)
783 return commands.version_(ui)
789 if options['help']:
784 if options['help']:
790 return commands.help_(ui, cmd, command=cmd is not None)
785 return commands.help_(ui, cmd, command=cmd is not None)
791 elif not cmd:
786 elif not cmd:
792 return commands.help_(ui, 'shortlist')
787 return commands.help_(ui, 'shortlist')
793
788
794 repo = None
789 repo = None
795 cmdpats = args[:]
790 cmdpats = args[:]
796 if not func.norepo:
791 if not func.norepo:
797 # use the repo from the request only if we don't have -R
792 # use the repo from the request only if we don't have -R
798 if not rpath and not cwd:
793 if not rpath and not cwd:
799 repo = req.repo
794 repo = req.repo
800
795
801 if repo:
796 if repo:
802 # set the descriptors of the repo ui to those of ui
797 # set the descriptors of the repo ui to those of ui
803 repo.ui.fin = ui.fin
798 repo.ui.fin = ui.fin
804 repo.ui.fout = ui.fout
799 repo.ui.fout = ui.fout
805 repo.ui.ferr = ui.ferr
800 repo.ui.ferr = ui.ferr
806 else:
801 else:
807 try:
802 try:
808 repo = hg.repository(ui, path=path)
803 repo = hg.repository(ui, path=path)
809 if not repo.local():
804 if not repo.local():
810 raise error.Abort(_("repository '%s' is not local")
805 raise error.Abort(_("repository '%s' is not local")
811 % path)
806 % path)
812 repo.ui.setconfig("bundle", "mainreporoot", repo.root,
807 repo.ui.setconfig("bundle", "mainreporoot", repo.root,
813 'repo')
808 'repo')
814 except error.RequirementError:
809 except error.RequirementError:
815 raise
810 raise
816 except error.RepoError:
811 except error.RepoError:
817 if rpath and rpath[-1]: # invalid -R path
812 if rpath and rpath[-1]: # invalid -R path
818 raise
813 raise
819 if not func.optionalrepo:
814 if not func.optionalrepo:
820 if func.inferrepo and args and not path:
815 if func.inferrepo and args and not path:
821 # try to infer -R from command args
816 # try to infer -R from command args
822 repos = map(cmdutil.findrepo, args)
817 repos = map(cmdutil.findrepo, args)
823 guess = repos[0]
818 guess = repos[0]
824 if guess and repos.count(guess) == len(repos):
819 if guess and repos.count(guess) == len(repos):
825 req.args = ['--repository', guess] + fullargs
820 req.args = ['--repository', guess] + fullargs
826 return _dispatch(req)
821 return _dispatch(req)
827 if not path:
822 if not path:
828 raise error.RepoError(_("no repository found in"
823 raise error.RepoError(_("no repository found in"
829 " '%s' (.hg not found)")
824 " '%s' (.hg not found)")
830 % pycompat.getcwd())
825 % pycompat.getcwd())
831 raise
826 raise
832 if repo:
827 if repo:
833 ui = repo.ui
828 ui = repo.ui
834 if options['hidden']:
829 if options['hidden']:
835 repo = repo.unfiltered()
830 repo = repo.unfiltered()
836 args.insert(0, repo)
831 args.insert(0, repo)
837 elif rpath:
832 elif rpath:
838 ui.warn(_("warning: --repository ignored\n"))
833 ui.warn(_("warning: --repository ignored\n"))
839
834
840 msg = _formatargs(fullargs)
835 msg = _formatargs(fullargs)
841 ui.log("command", '%s\n', msg)
836 ui.log("command", '%s\n', msg)
842 strcmdopt = pycompat.strkwargs(cmdoptions)
837 strcmdopt = pycompat.strkwargs(cmdoptions)
843 d = lambda: util.checksignature(func)(ui, *args, **strcmdopt)
838 d = lambda: util.checksignature(func)(ui, *args, **strcmdopt)
844 try:
839 try:
845 return runcommand(lui, repo, cmd, fullargs, ui, options, d,
840 return runcommand(lui, repo, cmd, fullargs, ui, options, d,
846 cmdpats, cmdoptions)
841 cmdpats, cmdoptions)
847 finally:
842 finally:
848 if repo and repo != req.repo:
843 if repo and repo != req.repo:
849 repo.close()
844 repo.close()
850
845
851 def _runcommand(ui, options, cmd, cmdfunc):
846 def _runcommand(ui, options, cmd, cmdfunc):
852 """Run a command function, possibly with profiling enabled."""
847 """Run a command function, possibly with profiling enabled."""
853 try:
848 try:
854 return cmdfunc()
849 return cmdfunc()
855 except error.SignatureError:
850 except error.SignatureError:
856 raise error.CommandError(cmd, _('invalid arguments'))
851 raise error.CommandError(cmd, _('invalid arguments'))
857
852
858 def _exceptionwarning(ui):
853 def _exceptionwarning(ui):
859 """Produce a warning message for the current active exception"""
854 """Produce a warning message for the current active exception"""
860
855
861 # For compatibility checking, we discard the portion of the hg
856 # For compatibility checking, we discard the portion of the hg
862 # version after the + on the assumption that if a "normal
857 # version after the + on the assumption that if a "normal
863 # user" is running a build with a + in it the packager
858 # user" is running a build with a + in it the packager
864 # probably built from fairly close to a tag and anyone with a
859 # probably built from fairly close to a tag and anyone with a
865 # 'make local' copy of hg (where the version number can be out
860 # 'make local' copy of hg (where the version number can be out
866 # of date) will be clueful enough to notice the implausible
861 # of date) will be clueful enough to notice the implausible
867 # version number and try updating.
862 # version number and try updating.
868 ct = util.versiontuple(n=2)
863 ct = util.versiontuple(n=2)
869 worst = None, ct, ''
864 worst = None, ct, ''
870 if ui.config('ui', 'supportcontact', None) is None:
865 if ui.config('ui', 'supportcontact', None) is None:
871 for name, mod in extensions.extensions():
866 for name, mod in extensions.extensions():
872 testedwith = getattr(mod, 'testedwith', '')
867 testedwith = getattr(mod, 'testedwith', '')
873 if pycompat.ispy3 and isinstance(testedwith, str):
868 if pycompat.ispy3 and isinstance(testedwith, str):
874 testedwith = testedwith.encode(u'utf-8')
869 testedwith = testedwith.encode(u'utf-8')
875 report = getattr(mod, 'buglink', _('the extension author.'))
870 report = getattr(mod, 'buglink', _('the extension author.'))
876 if not testedwith.strip():
871 if not testedwith.strip():
877 # We found an untested extension. It's likely the culprit.
872 # We found an untested extension. It's likely the culprit.
878 worst = name, 'unknown', report
873 worst = name, 'unknown', report
879 break
874 break
880
875
881 # Never blame on extensions bundled with Mercurial.
876 # Never blame on extensions bundled with Mercurial.
882 if extensions.ismoduleinternal(mod):
877 if extensions.ismoduleinternal(mod):
883 continue
878 continue
884
879
885 tested = [util.versiontuple(t, 2) for t in testedwith.split()]
880 tested = [util.versiontuple(t, 2) for t in testedwith.split()]
886 if ct in tested:
881 if ct in tested:
887 continue
882 continue
888
883
889 lower = [t for t in tested if t < ct]
884 lower = [t for t in tested if t < ct]
890 nearest = max(lower or tested)
885 nearest = max(lower or tested)
891 if worst[0] is None or nearest < worst[1]:
886 if worst[0] is None or nearest < worst[1]:
892 worst = name, nearest, report
887 worst = name, nearest, report
893 if worst[0] is not None:
888 if worst[0] is not None:
894 name, testedwith, report = worst
889 name, testedwith, report = worst
895 if not isinstance(testedwith, (bytes, str)):
890 if not isinstance(testedwith, (bytes, str)):
896 testedwith = '.'.join([str(c) for c in testedwith])
891 testedwith = '.'.join([str(c) for c in testedwith])
897 warning = (_('** Unknown exception encountered with '
892 warning = (_('** Unknown exception encountered with '
898 'possibly-broken third-party extension %s\n'
893 'possibly-broken third-party extension %s\n'
899 '** which supports versions %s of Mercurial.\n'
894 '** which supports versions %s of Mercurial.\n'
900 '** Please disable %s and try your action again.\n'
895 '** Please disable %s and try your action again.\n'
901 '** If that fixes the bug please report it to %s\n')
896 '** If that fixes the bug please report it to %s\n')
902 % (name, testedwith, name, report))
897 % (name, testedwith, name, report))
903 else:
898 else:
904 bugtracker = ui.config('ui', 'supportcontact', None)
899 bugtracker = ui.config('ui', 'supportcontact', None)
905 if bugtracker is None:
900 if bugtracker is None:
906 bugtracker = _("https://mercurial-scm.org/wiki/BugTracker")
901 bugtracker = _("https://mercurial-scm.org/wiki/BugTracker")
907 warning = (_("** unknown exception encountered, "
902 warning = (_("** unknown exception encountered, "
908 "please report by visiting\n** ") + bugtracker + '\n')
903 "please report by visiting\n** ") + bugtracker + '\n')
909 if pycompat.ispy3:
904 if pycompat.ispy3:
910 sysversion = sys.version.encode(u'utf-8')
905 sysversion = sys.version.encode(u'utf-8')
911 else:
906 else:
912 sysversion = sys.version
907 sysversion = sys.version
913 sysversion = sysversion.replace('\n', '')
908 sysversion = sysversion.replace('\n', '')
914 warning += ((_("** Python %s\n") % sysversion) +
909 warning += ((_("** Python %s\n") % sysversion) +
915 (_("** Mercurial Distributed SCM (version %s)\n") %
910 (_("** Mercurial Distributed SCM (version %s)\n") %
916 util.version()) +
911 util.version()) +
917 (_("** Extensions loaded: %s\n") %
912 (_("** Extensions loaded: %s\n") %
918 ", ".join([x[0] for x in extensions.extensions()])))
913 ", ".join([x[0] for x in extensions.extensions()])))
919 return warning
914 return warning
920
915
921 def handlecommandexception(ui):
916 def handlecommandexception(ui):
922 """Produce a warning message for broken commands
917 """Produce a warning message for broken commands
923
918
924 Called when handling an exception; the exception is reraised if
919 Called when handling an exception; the exception is reraised if
925 this function returns False, ignored otherwise.
920 this function returns False, ignored otherwise.
926 """
921 """
927 warning = _exceptionwarning(ui)
922 warning = _exceptionwarning(ui)
928 ui.log("commandexception", "%s\n%s\n", warning, traceback.format_exc())
923 ui.log("commandexception", "%s\n%s\n", warning, traceback.format_exc())
929 ui.warn(warning)
924 ui.warn(warning)
930 return False # re-raise the exception
925 return False # re-raise the exception
@@ -1,223 +1,223 b''
1 setup
1 setup
2 $ cat >> $HGRCPATH <<EOF
2 $ cat >> $HGRCPATH <<EOF
3 > [extensions]
3 > [extensions]
4 > blackbox=
4 > blackbox=
5 > mock=$TESTDIR/mockblackbox.py
5 > mock=$TESTDIR/mockblackbox.py
6 > mq=
6 > mq=
7 > [alias]
7 > [alias]
8 > confuse = log --limit 3
8 > confuse = log --limit 3
9 > EOF
9 > EOF
10 $ hg init blackboxtest
10 $ hg init blackboxtest
11 $ cd blackboxtest
11 $ cd blackboxtest
12
12
13 command, exit codes, and duration
13 command, exit codes, and duration
14
14
15 $ echo a > a
15 $ echo a > a
16 $ hg add a
16 $ hg add a
17 $ hg blackbox --config blackbox.dirty=True
17 $ hg blackbox --config blackbox.dirty=True
18 1970/01/01 00:00:00 bob @0000000000000000000000000000000000000000 (5000)> add a
18 1970/01/01 00:00:00 bob @0000000000000000000000000000000000000000 (5000)> add a
19 1970/01/01 00:00:00 bob @0000000000000000000000000000000000000000 (5000)> add a exited 0 after * seconds (glob)
19 1970/01/01 00:00:00 bob @0000000000000000000000000000000000000000 (5000)> add a exited 0 after * seconds (glob)
20 1970/01/01 00:00:00 bob @0000000000000000000000000000000000000000+ (5000)> blackbox
20 1970/01/01 00:00:00 bob @0000000000000000000000000000000000000000+ (5000)> blackbox
21
21
22 alias expansion is logged
22 alias expansion is logged
23 $ hg confuse
23 $ hg confuse
24 $ hg blackbox
24 $ hg blackbox
25 1970/01/01 00:00:00 bob @0000000000000000000000000000000000000000 (5000)> add a
25 1970/01/01 00:00:00 bob @0000000000000000000000000000000000000000 (5000)> add a
26 1970/01/01 00:00:00 bob @0000000000000000000000000000000000000000 (5000)> add a exited 0 after * seconds (glob)
26 1970/01/01 00:00:00 bob @0000000000000000000000000000000000000000 (5000)> add a exited 0 after * seconds (glob)
27 1970/01/01 00:00:00 bob @0000000000000000000000000000000000000000+ (5000)> blackbox
27 1970/01/01 00:00:00 bob @0000000000000000000000000000000000000000+ (5000)> blackbox
28 1970/01/01 00:00:00 bob @0000000000000000000000000000000000000000+ (5000)> blackbox --config blackbox.dirty=True exited 0 after * seconds (glob)
28 1970/01/01 00:00:00 bob @0000000000000000000000000000000000000000+ (5000)> blackbox --config 'blackbox.dirty=True' exited 0 after * seconds (glob)
29 1970/01/01 00:00:00 bob @0000000000000000000000000000000000000000 (5000)> confuse
29 1970/01/01 00:00:00 bob @0000000000000000000000000000000000000000 (5000)> confuse
30 1970/01/01 00:00:00 bob @0000000000000000000000000000000000000000 (5000)> alias 'confuse' expands to 'log --limit 3'
30 1970/01/01 00:00:00 bob @0000000000000000000000000000000000000000 (5000)> alias 'confuse' expands to 'log --limit 3'
31 1970/01/01 00:00:00 bob @0000000000000000000000000000000000000000 (5000)> confuse exited 0 after * seconds (glob)
31 1970/01/01 00:00:00 bob @0000000000000000000000000000000000000000 (5000)> confuse exited 0 after * seconds (glob)
32 1970/01/01 00:00:00 bob @0000000000000000000000000000000000000000 (5000)> blackbox
32 1970/01/01 00:00:00 bob @0000000000000000000000000000000000000000 (5000)> blackbox
33
33
34 incoming change tracking
34 incoming change tracking
35
35
36 create two heads to verify that we only see one change in the log later
36 create two heads to verify that we only see one change in the log later
37 $ hg commit -ma
37 $ hg commit -ma
38 $ hg up null
38 $ hg up null
39 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
39 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
40 $ echo b > b
40 $ echo b > b
41 $ hg commit -Amb
41 $ hg commit -Amb
42 adding b
42 adding b
43 created new head
43 created new head
44
44
45 clone, commit, pull
45 clone, commit, pull
46 $ hg clone . ../blackboxtest2
46 $ hg clone . ../blackboxtest2
47 updating to branch default
47 updating to branch default
48 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
48 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
49 $ echo c > c
49 $ echo c > c
50 $ hg commit -Amc
50 $ hg commit -Amc
51 adding c
51 adding c
52 $ cd ../blackboxtest2
52 $ cd ../blackboxtest2
53 $ hg pull
53 $ hg pull
54 pulling from $TESTTMP/blackboxtest (glob)
54 pulling from $TESTTMP/blackboxtest (glob)
55 searching for changes
55 searching for changes
56 adding changesets
56 adding changesets
57 adding manifests
57 adding manifests
58 adding file changes
58 adding file changes
59 added 1 changesets with 1 changes to 1 files
59 added 1 changesets with 1 changes to 1 files
60 (run 'hg update' to get a working copy)
60 (run 'hg update' to get a working copy)
61 $ hg blackbox -l 6
61 $ hg blackbox -l 6
62 1970/01/01 00:00:00 bob @6563da9dcf87b1949716e38ff3e3dfaa3198eb06 (5000)> pull
62 1970/01/01 00:00:00 bob @6563da9dcf87b1949716e38ff3e3dfaa3198eb06 (5000)> pull
63 1970/01/01 00:00:00 bob @6563da9dcf87b1949716e38ff3e3dfaa3198eb06 (5000)> updated served branch cache in * seconds (glob)
63 1970/01/01 00:00:00 bob @6563da9dcf87b1949716e38ff3e3dfaa3198eb06 (5000)> updated served branch cache in * seconds (glob)
64 1970/01/01 00:00:00 bob @6563da9dcf87b1949716e38ff3e3dfaa3198eb06 (5000)> wrote served branch cache with 1 labels and 2 nodes
64 1970/01/01 00:00:00 bob @6563da9dcf87b1949716e38ff3e3dfaa3198eb06 (5000)> wrote served branch cache with 1 labels and 2 nodes
65 1970/01/01 00:00:00 bob @6563da9dcf87b1949716e38ff3e3dfaa3198eb06 (5000)> 1 incoming changes - new heads: d02f48003e62
65 1970/01/01 00:00:00 bob @6563da9dcf87b1949716e38ff3e3dfaa3198eb06 (5000)> 1 incoming changes - new heads: d02f48003e62
66 1970/01/01 00:00:00 bob @6563da9dcf87b1949716e38ff3e3dfaa3198eb06 (5000)> pull exited 0 after * seconds (glob)
66 1970/01/01 00:00:00 bob @6563da9dcf87b1949716e38ff3e3dfaa3198eb06 (5000)> pull exited 0 after * seconds (glob)
67 1970/01/01 00:00:00 bob @6563da9dcf87b1949716e38ff3e3dfaa3198eb06 (5000)> blackbox -l 6
67 1970/01/01 00:00:00 bob @6563da9dcf87b1949716e38ff3e3dfaa3198eb06 (5000)> blackbox -l 6
68
68
69 we must not cause a failure if we cannot write to the log
69 we must not cause a failure if we cannot write to the log
70
70
71 $ hg rollback
71 $ hg rollback
72 repository tip rolled back to revision 1 (undo pull)
72 repository tip rolled back to revision 1 (undo pull)
73
73
74 $ mv .hg/blackbox.log .hg/blackbox.log-
74 $ mv .hg/blackbox.log .hg/blackbox.log-
75 $ mkdir .hg/blackbox.log
75 $ mkdir .hg/blackbox.log
76 $ hg --debug incoming
76 $ hg --debug incoming
77 warning: cannot write to blackbox.log: * (glob)
77 warning: cannot write to blackbox.log: * (glob)
78 comparing with $TESTTMP/blackboxtest (glob)
78 comparing with $TESTTMP/blackboxtest (glob)
79 query 1; heads
79 query 1; heads
80 searching for changes
80 searching for changes
81 all local heads known remotely
81 all local heads known remotely
82 changeset: 2:d02f48003e62c24e2659d97d30f2a83abe5d5d51
82 changeset: 2:d02f48003e62c24e2659d97d30f2a83abe5d5d51
83 tag: tip
83 tag: tip
84 phase: draft
84 phase: draft
85 parent: 1:6563da9dcf87b1949716e38ff3e3dfaa3198eb06
85 parent: 1:6563da9dcf87b1949716e38ff3e3dfaa3198eb06
86 parent: -1:0000000000000000000000000000000000000000
86 parent: -1:0000000000000000000000000000000000000000
87 manifest: 2:ab9d46b053ebf45b7996f2922b9893ff4b63d892
87 manifest: 2:ab9d46b053ebf45b7996f2922b9893ff4b63d892
88 user: test
88 user: test
89 date: Thu Jan 01 00:00:00 1970 +0000
89 date: Thu Jan 01 00:00:00 1970 +0000
90 files+: c
90 files+: c
91 extra: branch=default
91 extra: branch=default
92 description:
92 description:
93 c
93 c
94
94
95
95
96 $ hg pull
96 $ hg pull
97 pulling from $TESTTMP/blackboxtest (glob)
97 pulling from $TESTTMP/blackboxtest (glob)
98 searching for changes
98 searching for changes
99 adding changesets
99 adding changesets
100 adding manifests
100 adding manifests
101 adding file changes
101 adding file changes
102 added 1 changesets with 1 changes to 1 files
102 added 1 changesets with 1 changes to 1 files
103 (run 'hg update' to get a working copy)
103 (run 'hg update' to get a working copy)
104
104
105 a failure reading from the log is fatal
105 a failure reading from the log is fatal
106
106
107 $ hg blackbox -l 3
107 $ hg blackbox -l 3
108 abort: *$TESTTMP/blackboxtest2/.hg/blackbox.log* (glob)
108 abort: *$TESTTMP/blackboxtest2/.hg/blackbox.log* (glob)
109 [255]
109 [255]
110
110
111 $ rmdir .hg/blackbox.log
111 $ rmdir .hg/blackbox.log
112 $ mv .hg/blackbox.log- .hg/blackbox.log
112 $ mv .hg/blackbox.log- .hg/blackbox.log
113
113
114 backup bundles get logged
114 backup bundles get logged
115
115
116 $ touch d
116 $ touch d
117 $ hg commit -Amd
117 $ hg commit -Amd
118 adding d
118 adding d
119 created new head
119 created new head
120 $ hg strip tip
120 $ hg strip tip
121 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
121 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
122 saved backup bundle to $TESTTMP/blackboxtest2/.hg/strip-backup/*-backup.hg (glob)
122 saved backup bundle to $TESTTMP/blackboxtest2/.hg/strip-backup/*-backup.hg (glob)
123 $ hg blackbox -l 6
123 $ hg blackbox -l 6
124 1970/01/01 00:00:00 bob @73f6ee326b27d820b0472f1a825e3a50f3dc489b (5000)> strip tip
124 1970/01/01 00:00:00 bob @73f6ee326b27d820b0472f1a825e3a50f3dc489b (5000)> strip tip
125 1970/01/01 00:00:00 bob @6563da9dcf87b1949716e38ff3e3dfaa3198eb06 (5000)> saved backup bundle to $TESTTMP/blackboxtest2/.hg/strip-backup/73f6ee326b27-7612e004-backup.hg (glob)
125 1970/01/01 00:00:00 bob @6563da9dcf87b1949716e38ff3e3dfaa3198eb06 (5000)> saved backup bundle to $TESTTMP/blackboxtest2/.hg/strip-backup/73f6ee326b27-7612e004-backup.hg (glob)
126 1970/01/01 00:00:00 bob @6563da9dcf87b1949716e38ff3e3dfaa3198eb06 (5000)> updated base branch cache in * seconds (glob)
126 1970/01/01 00:00:00 bob @6563da9dcf87b1949716e38ff3e3dfaa3198eb06 (5000)> updated base branch cache in * seconds (glob)
127 1970/01/01 00:00:00 bob @6563da9dcf87b1949716e38ff3e3dfaa3198eb06 (5000)> wrote base branch cache with 1 labels and 2 nodes
127 1970/01/01 00:00:00 bob @6563da9dcf87b1949716e38ff3e3dfaa3198eb06 (5000)> wrote base branch cache with 1 labels and 2 nodes
128 1970/01/01 00:00:00 bob @6563da9dcf87b1949716e38ff3e3dfaa3198eb06 (5000)> strip tip exited 0 after * seconds (glob)
128 1970/01/01 00:00:00 bob @6563da9dcf87b1949716e38ff3e3dfaa3198eb06 (5000)> strip tip exited 0 after * seconds (glob)
129 1970/01/01 00:00:00 bob @6563da9dcf87b1949716e38ff3e3dfaa3198eb06 (5000)> blackbox -l 6
129 1970/01/01 00:00:00 bob @6563da9dcf87b1949716e38ff3e3dfaa3198eb06 (5000)> blackbox -l 6
130
130
131 extension and python hooks - use the eol extension for a pythonhook
131 extension and python hooks - use the eol extension for a pythonhook
132
132
133 $ echo '[extensions]' >> .hg/hgrc
133 $ echo '[extensions]' >> .hg/hgrc
134 $ echo 'eol=' >> .hg/hgrc
134 $ echo 'eol=' >> .hg/hgrc
135 $ echo '[hooks]' >> .hg/hgrc
135 $ echo '[hooks]' >> .hg/hgrc
136 $ echo 'update = echo hooked' >> .hg/hgrc
136 $ echo 'update = echo hooked' >> .hg/hgrc
137 $ hg update
137 $ hg update
138 hooked
138 hooked
139 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
139 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
140 1 other heads for branch "default"
140 1 other heads for branch "default"
141 $ hg blackbox -l 6
141 $ hg blackbox -l 6
142 1970/01/01 00:00:00 bob @6563da9dcf87b1949716e38ff3e3dfaa3198eb06 (5000)> update
142 1970/01/01 00:00:00 bob @6563da9dcf87b1949716e38ff3e3dfaa3198eb06 (5000)> update
143 1970/01/01 00:00:00 bob @6563da9dcf87b1949716e38ff3e3dfaa3198eb06 (5000)> writing .hg/cache/tags2-visible with 0 tags
143 1970/01/01 00:00:00 bob @6563da9dcf87b1949716e38ff3e3dfaa3198eb06 (5000)> writing .hg/cache/tags2-visible with 0 tags
144 1970/01/01 00:00:00 bob @6563da9dcf87b1949716e38ff3e3dfaa3198eb06 (5000)> pythonhook-preupdate: hgext.eol.preupdate finished in * seconds (glob)
144 1970/01/01 00:00:00 bob @6563da9dcf87b1949716e38ff3e3dfaa3198eb06 (5000)> pythonhook-preupdate: hgext.eol.preupdate finished in * seconds (glob)
145 1970/01/01 00:00:00 bob @d02f48003e62c24e2659d97d30f2a83abe5d5d51 (5000)> exthook-update: echo hooked finished in * seconds (glob)
145 1970/01/01 00:00:00 bob @d02f48003e62c24e2659d97d30f2a83abe5d5d51 (5000)> exthook-update: echo hooked finished in * seconds (glob)
146 1970/01/01 00:00:00 bob @d02f48003e62c24e2659d97d30f2a83abe5d5d51 (5000)> update exited 0 after * seconds (glob)
146 1970/01/01 00:00:00 bob @d02f48003e62c24e2659d97d30f2a83abe5d5d51 (5000)> update exited 0 after * seconds (glob)
147 1970/01/01 00:00:00 bob @d02f48003e62c24e2659d97d30f2a83abe5d5d51 (5000)> blackbox -l 6
147 1970/01/01 00:00:00 bob @d02f48003e62c24e2659d97d30f2a83abe5d5d51 (5000)> blackbox -l 6
148
148
149 log rotation
149 log rotation
150
150
151 $ echo '[blackbox]' >> .hg/hgrc
151 $ echo '[blackbox]' >> .hg/hgrc
152 $ echo 'maxsize = 20 b' >> .hg/hgrc
152 $ echo 'maxsize = 20 b' >> .hg/hgrc
153 $ echo 'maxfiles = 3' >> .hg/hgrc
153 $ echo 'maxfiles = 3' >> .hg/hgrc
154 $ hg status
154 $ hg status
155 $ hg status
155 $ hg status
156 $ hg status
156 $ hg status
157 $ hg tip -q
157 $ hg tip -q
158 2:d02f48003e62
158 2:d02f48003e62
159 $ ls .hg/blackbox.log*
159 $ ls .hg/blackbox.log*
160 .hg/blackbox.log
160 .hg/blackbox.log
161 .hg/blackbox.log.1
161 .hg/blackbox.log.1
162 .hg/blackbox.log.2
162 .hg/blackbox.log.2
163 $ cd ..
163 $ cd ..
164
164
165 $ hg init blackboxtest3
165 $ hg init blackboxtest3
166 $ cd blackboxtest3
166 $ cd blackboxtest3
167 $ hg blackbox
167 $ hg blackbox
168 1970/01/01 00:00:00 bob @0000000000000000000000000000000000000000 (5000)> blackbox
168 1970/01/01 00:00:00 bob @0000000000000000000000000000000000000000 (5000)> blackbox
169 $ mv .hg/blackbox.log .hg/blackbox.log-
169 $ mv .hg/blackbox.log .hg/blackbox.log-
170 $ mkdir .hg/blackbox.log
170 $ mkdir .hg/blackbox.log
171 $ sed -e 's/\(.*test1.*\)/#\1/; s#\(.*commit2.*\)#os.rmdir(".hg/blackbox.log")\
171 $ sed -e 's/\(.*test1.*\)/#\1/; s#\(.*commit2.*\)#os.rmdir(".hg/blackbox.log")\
172 > os.rename(".hg/blackbox.log-", ".hg/blackbox.log")\
172 > os.rename(".hg/blackbox.log-", ".hg/blackbox.log")\
173 > \1#' $TESTDIR/test-dispatch.py > ../test-dispatch.py
173 > \1#' $TESTDIR/test-dispatch.py > ../test-dispatch.py
174 $ python $TESTDIR/blackbox-readonly-dispatch.py
174 $ python $TESTDIR/blackbox-readonly-dispatch.py
175 running: add foo
175 running: add foo
176 result: 0
176 result: 0
177 running: commit -m commit1 -d 2000-01-01 foo
177 running: commit -m commit1 -d 2000-01-01 foo
178 result: None
178 result: None
179 running: commit -m commit2 -d 2000-01-02 foo
179 running: commit -m commit2 -d 2000-01-02 foo
180 result: None
180 result: None
181 running: log -r 0
181 running: log -r 0
182 changeset: 0:0e4634943879
182 changeset: 0:0e4634943879
183 user: test
183 user: test
184 date: Sat Jan 01 00:00:00 2000 +0000
184 date: Sat Jan 01 00:00:00 2000 +0000
185 summary: commit1
185 summary: commit1
186
186
187 result: None
187 result: None
188 running: log -r tip
188 running: log -r tip
189 changeset: 1:45589e459b2e
189 changeset: 1:45589e459b2e
190 tag: tip
190 tag: tip
191 user: test
191 user: test
192 date: Sun Jan 02 00:00:00 2000 +0000
192 date: Sun Jan 02 00:00:00 2000 +0000
193 summary: commit2
193 summary: commit2
194
194
195 result: None
195 result: None
196 $ hg blackbox
196 $ hg blackbox
197 1970/01/01 00:00:00 bob @0e46349438790c460c5c9f7546bfcd39b267bbd2 (5000)> commit -m commit2 -d 2000-01-02 foo
197 1970/01/01 00:00:00 bob @0e46349438790c460c5c9f7546bfcd39b267bbd2 (5000)> commit -m commit2 -d 2000-01-02 foo
198 1970/01/01 00:00:00 bob @0e46349438790c460c5c9f7546bfcd39b267bbd2 (5000)> updated served branch cache in * seconds (glob)
198 1970/01/01 00:00:00 bob @0e46349438790c460c5c9f7546bfcd39b267bbd2 (5000)> updated served branch cache in * seconds (glob)
199 1970/01/01 00:00:00 bob @0e46349438790c460c5c9f7546bfcd39b267bbd2 (5000)> wrote served branch cache with 1 labels and 1 nodes
199 1970/01/01 00:00:00 bob @0e46349438790c460c5c9f7546bfcd39b267bbd2 (5000)> wrote served branch cache with 1 labels and 1 nodes
200 1970/01/01 00:00:00 bob @45589e459b2edfbf3dbde7e01f611d2c1e7453d7 (5000)> commit -m commit2 -d 2000-01-02 foo exited 0 after * seconds (glob)
200 1970/01/01 00:00:00 bob @45589e459b2edfbf3dbde7e01f611d2c1e7453d7 (5000)> commit -m commit2 -d 2000-01-02 foo exited 0 after * seconds (glob)
201 1970/01/01 00:00:00 bob @45589e459b2edfbf3dbde7e01f611d2c1e7453d7 (5000)> log -r 0
201 1970/01/01 00:00:00 bob @45589e459b2edfbf3dbde7e01f611d2c1e7453d7 (5000)> log -r 0
202 1970/01/01 00:00:00 bob @45589e459b2edfbf3dbde7e01f611d2c1e7453d7 (5000)> writing .hg/cache/tags2-visible with 0 tags
202 1970/01/01 00:00:00 bob @45589e459b2edfbf3dbde7e01f611d2c1e7453d7 (5000)> writing .hg/cache/tags2-visible with 0 tags
203 1970/01/01 00:00:00 bob @45589e459b2edfbf3dbde7e01f611d2c1e7453d7 (5000)> log -r 0 exited 0 after * seconds (glob)
203 1970/01/01 00:00:00 bob @45589e459b2edfbf3dbde7e01f611d2c1e7453d7 (5000)> log -r 0 exited 0 after * seconds (glob)
204 1970/01/01 00:00:00 bob @45589e459b2edfbf3dbde7e01f611d2c1e7453d7 (5000)> log -r tip
204 1970/01/01 00:00:00 bob @45589e459b2edfbf3dbde7e01f611d2c1e7453d7 (5000)> log -r tip
205 1970/01/01 00:00:00 bob @45589e459b2edfbf3dbde7e01f611d2c1e7453d7 (5000)> log -r tip exited 0 after * seconds (glob)
205 1970/01/01 00:00:00 bob @45589e459b2edfbf3dbde7e01f611d2c1e7453d7 (5000)> log -r tip exited 0 after * seconds (glob)
206 1970/01/01 00:00:00 bob @45589e459b2edfbf3dbde7e01f611d2c1e7453d7 (5000)> blackbox
206 1970/01/01 00:00:00 bob @45589e459b2edfbf3dbde7e01f611d2c1e7453d7 (5000)> blackbox
207
207
208 Test log recursion from dirty status check
208 Test log recursion from dirty status check
209
209
210 $ cat > ../r.py <<EOF
210 $ cat > ../r.py <<EOF
211 > from mercurial import context, error, extensions
211 > from mercurial import context, error, extensions
212 > x=[False]
212 > x=[False]
213 > def status(orig, *args, **opts):
213 > def status(orig, *args, **opts):
214 > args[0].repo().ui.log("broken", "recursion?")
214 > args[0].repo().ui.log("broken", "recursion?")
215 > return orig(*args, **opts)
215 > return orig(*args, **opts)
216 > def reposetup(ui, repo):
216 > def reposetup(ui, repo):
217 > extensions.wrapfunction(context.basectx, 'status', status)
217 > extensions.wrapfunction(context.basectx, 'status', status)
218 > EOF
218 > EOF
219 $ hg id --config extensions.x=../r.py --config blackbox.dirty=True
219 $ hg id --config extensions.x=../r.py --config blackbox.dirty=True
220 45589e459b2e tip
220 45589e459b2e tip
221
221
222 cleanup
222 cleanup
223 $ cd ..
223 $ cd ..
@@ -1,179 +1,179 b''
1
1
2 $ cat << EOF > buggylocking.py
2 $ cat << EOF > buggylocking.py
3 > """A small extension that tests our developer warnings
3 > """A small extension that tests our developer warnings
4 > """
4 > """
5 >
5 >
6 > from mercurial import cmdutil, repair, revset
6 > from mercurial import cmdutil, repair, revset
7 >
7 >
8 > cmdtable = {}
8 > cmdtable = {}
9 > command = cmdutil.command(cmdtable)
9 > command = cmdutil.command(cmdtable)
10 >
10 >
11 > @command('buggylocking', [], '')
11 > @command('buggylocking', [], '')
12 > def buggylocking(ui, repo):
12 > def buggylocking(ui, repo):
13 > lo = repo.lock()
13 > lo = repo.lock()
14 > wl = repo.wlock()
14 > wl = repo.wlock()
15 > wl.release()
15 > wl.release()
16 > lo.release()
16 > lo.release()
17 >
17 >
18 > @command('buggytransaction', [], '')
18 > @command('buggytransaction', [], '')
19 > def buggylocking(ui, repo):
19 > def buggylocking(ui, repo):
20 > tr = repo.transaction('buggy')
20 > tr = repo.transaction('buggy')
21 > # make sure we rollback the transaction as we don't want to rely on the__del__
21 > # make sure we rollback the transaction as we don't want to rely on the__del__
22 > tr.release()
22 > tr.release()
23 >
23 >
24 > @command('properlocking', [], '')
24 > @command('properlocking', [], '')
25 > def properlocking(ui, repo):
25 > def properlocking(ui, repo):
26 > """check that reentrance is fine"""
26 > """check that reentrance is fine"""
27 > wl = repo.wlock()
27 > wl = repo.wlock()
28 > lo = repo.lock()
28 > lo = repo.lock()
29 > tr = repo.transaction('proper')
29 > tr = repo.transaction('proper')
30 > tr2 = repo.transaction('proper')
30 > tr2 = repo.transaction('proper')
31 > lo2 = repo.lock()
31 > lo2 = repo.lock()
32 > wl2 = repo.wlock()
32 > wl2 = repo.wlock()
33 > wl2.release()
33 > wl2.release()
34 > lo2.release()
34 > lo2.release()
35 > tr2.close()
35 > tr2.close()
36 > tr.close()
36 > tr.close()
37 > lo.release()
37 > lo.release()
38 > wl.release()
38 > wl.release()
39 >
39 >
40 > @command('nowaitlocking', [], '')
40 > @command('nowaitlocking', [], '')
41 > def nowaitlocking(ui, repo):
41 > def nowaitlocking(ui, repo):
42 > lo = repo.lock()
42 > lo = repo.lock()
43 > wl = repo.wlock(wait=False)
43 > wl = repo.wlock(wait=False)
44 > wl.release()
44 > wl.release()
45 > lo.release()
45 > lo.release()
46 >
46 >
47 > @command('stripintr', [], '')
47 > @command('stripintr', [], '')
48 > def stripintr(ui, repo):
48 > def stripintr(ui, repo):
49 > lo = repo.lock()
49 > lo = repo.lock()
50 > tr = repo.transaction('foobar')
50 > tr = repo.transaction('foobar')
51 > try:
51 > try:
52 > repair.strip(repo.ui, repo, [repo['.'].node()])
52 > repair.strip(repo.ui, repo, [repo['.'].node()])
53 > finally:
53 > finally:
54 > lo.release()
54 > lo.release()
55 > @command('oldanddeprecated', [], '')
55 > @command('oldanddeprecated', [], '')
56 > def oldanddeprecated(ui, repo):
56 > def oldanddeprecated(ui, repo):
57 > """test deprecation warning API"""
57 > """test deprecation warning API"""
58 > def foobar(ui):
58 > def foobar(ui):
59 > ui.deprecwarn('foorbar is deprecated, go shopping', '42.1337')
59 > ui.deprecwarn('foorbar is deprecated, go shopping', '42.1337')
60 > foobar(ui)
60 > foobar(ui)
61 >
61 >
62 > def oldstylerevset(repo, subset, x):
62 > def oldstylerevset(repo, subset, x):
63 > return list(subset)
63 > return list(subset)
64 >
64 >
65 > revset.symbols['oldstyle'] = oldstylerevset
65 > revset.symbols['oldstyle'] = oldstylerevset
66 > EOF
66 > EOF
67
67
68 $ cat << EOF >> $HGRCPATH
68 $ cat << EOF >> $HGRCPATH
69 > [extensions]
69 > [extensions]
70 > buggylocking=$TESTTMP/buggylocking.py
70 > buggylocking=$TESTTMP/buggylocking.py
71 > mock=$TESTDIR/mockblackbox.py
71 > mock=$TESTDIR/mockblackbox.py
72 > blackbox=
72 > blackbox=
73 > [devel]
73 > [devel]
74 > all-warnings=1
74 > all-warnings=1
75 > EOF
75 > EOF
76
76
77 $ hg init lock-checker
77 $ hg init lock-checker
78 $ cd lock-checker
78 $ cd lock-checker
79 $ hg buggylocking
79 $ hg buggylocking
80 devel-warn: "wlock" acquired after "lock" at: $TESTTMP/buggylocking.py:* (buggylocking) (glob)
80 devel-warn: "wlock" acquired after "lock" at: $TESTTMP/buggylocking.py:* (buggylocking) (glob)
81 $ cat << EOF >> $HGRCPATH
81 $ cat << EOF >> $HGRCPATH
82 > [devel]
82 > [devel]
83 > all=0
83 > all=0
84 > check-locks=1
84 > check-locks=1
85 > EOF
85 > EOF
86 $ hg buggylocking
86 $ hg buggylocking
87 devel-warn: "wlock" acquired after "lock" at: $TESTTMP/buggylocking.py:* (buggylocking) (glob)
87 devel-warn: "wlock" acquired after "lock" at: $TESTTMP/buggylocking.py:* (buggylocking) (glob)
88 $ hg buggylocking --traceback
88 $ hg buggylocking --traceback
89 devel-warn: "wlock" acquired after "lock" at:
89 devel-warn: "wlock" acquired after "lock" at:
90 */hg:* in * (glob)
90 */hg:* in * (glob)
91 */mercurial/dispatch.py:* in run (glob)
91 */mercurial/dispatch.py:* in run (glob)
92 */mercurial/dispatch.py:* in dispatch (glob)
92 */mercurial/dispatch.py:* in dispatch (glob)
93 */mercurial/dispatch.py:* in _runcatch (glob)
93 */mercurial/dispatch.py:* in _runcatch (glob)
94 */mercurial/dispatch.py:* in callcatch (glob)
94 */mercurial/dispatch.py:* in callcatch (glob)
95 */mercurial/scmutil.py* in callcatch (glob)
95 */mercurial/scmutil.py* in callcatch (glob)
96 */mercurial/dispatch.py:* in _runcatchfunc (glob)
96 */mercurial/dispatch.py:* in _runcatchfunc (glob)
97 */mercurial/dispatch.py:* in _dispatch (glob)
97 */mercurial/dispatch.py:* in _dispatch (glob)
98 */mercurial/dispatch.py:* in runcommand (glob)
98 */mercurial/dispatch.py:* in runcommand (glob)
99 */mercurial/dispatch.py:* in _runcommand (glob)
99 */mercurial/dispatch.py:* in _runcommand (glob)
100 */mercurial/dispatch.py:* in <lambda> (glob)
100 */mercurial/dispatch.py:* in <lambda> (glob)
101 */mercurial/util.py:* in check (glob)
101 */mercurial/util.py:* in check (glob)
102 $TESTTMP/buggylocking.py:* in buggylocking (glob)
102 $TESTTMP/buggylocking.py:* in buggylocking (glob)
103 $ hg properlocking
103 $ hg properlocking
104 $ hg nowaitlocking
104 $ hg nowaitlocking
105
105
106 $ echo a > a
106 $ echo a > a
107 $ hg add a
107 $ hg add a
108 $ hg commit -m a
108 $ hg commit -m a
109 $ hg stripintr
109 $ hg stripintr
110 saved backup bundle to $TESTTMP/lock-checker/.hg/strip-backup/*-backup.hg (glob)
110 saved backup bundle to $TESTTMP/lock-checker/.hg/strip-backup/*-backup.hg (glob)
111 abort: programming error: cannot strip from inside a transaction
111 abort: programming error: cannot strip from inside a transaction
112 (contact your extension maintainer)
112 (contact your extension maintainer)
113 [255]
113 [255]
114
114
115 $ hg log -r "oldstyle()" -T '{rev}\n'
115 $ hg log -r "oldstyle()" -T '{rev}\n'
116 devel-warn: revset "oldstyle" uses list instead of smartset
116 devel-warn: revset "oldstyle" uses list instead of smartset
117 (compatibility will be dropped after Mercurial-3.9, update your code.) at: *mercurial/revset.py:* (mfunc) (glob)
117 (compatibility will be dropped after Mercurial-3.9, update your code.) at: *mercurial/revset.py:* (mfunc) (glob)
118 0
118 0
119 $ hg oldanddeprecated
119 $ hg oldanddeprecated
120 devel-warn: foorbar is deprecated, go shopping
120 devel-warn: foorbar is deprecated, go shopping
121 (compatibility will be dropped after Mercurial-42.1337, update your code.) at: $TESTTMP/buggylocking.py:* (oldanddeprecated) (glob)
121 (compatibility will be dropped after Mercurial-42.1337, update your code.) at: $TESTTMP/buggylocking.py:* (oldanddeprecated) (glob)
122
122
123 $ hg oldanddeprecated --traceback
123 $ hg oldanddeprecated --traceback
124 devel-warn: foorbar is deprecated, go shopping
124 devel-warn: foorbar is deprecated, go shopping
125 (compatibility will be dropped after Mercurial-42.1337, update your code.) at:
125 (compatibility will be dropped after Mercurial-42.1337, update your code.) at:
126 */hg:* in <module> (glob)
126 */hg:* in <module> (glob)
127 */mercurial/dispatch.py:* in run (glob)
127 */mercurial/dispatch.py:* in run (glob)
128 */mercurial/dispatch.py:* in dispatch (glob)
128 */mercurial/dispatch.py:* in dispatch (glob)
129 */mercurial/dispatch.py:* in _runcatch (glob)
129 */mercurial/dispatch.py:* in _runcatch (glob)
130 */mercurial/dispatch.py:* in callcatch (glob)
130 */mercurial/dispatch.py:* in callcatch (glob)
131 */mercurial/scmutil.py* in callcatch (glob)
131 */mercurial/scmutil.py* in callcatch (glob)
132 */mercurial/dispatch.py:* in _runcatchfunc (glob)
132 */mercurial/dispatch.py:* in _runcatchfunc (glob)
133 */mercurial/dispatch.py:* in _dispatch (glob)
133 */mercurial/dispatch.py:* in _dispatch (glob)
134 */mercurial/dispatch.py:* in runcommand (glob)
134 */mercurial/dispatch.py:* in runcommand (glob)
135 */mercurial/dispatch.py:* in _runcommand (glob)
135 */mercurial/dispatch.py:* in _runcommand (glob)
136 */mercurial/dispatch.py:* in <lambda> (glob)
136 */mercurial/dispatch.py:* in <lambda> (glob)
137 */mercurial/util.py:* in check (glob)
137 */mercurial/util.py:* in check (glob)
138 $TESTTMP/buggylocking.py:* in oldanddeprecated (glob)
138 $TESTTMP/buggylocking.py:* in oldanddeprecated (glob)
139 $ hg blackbox -l 9
139 $ hg blackbox -l 9
140 1970/01/01 00:00:00 bob @cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b (5000)> devel-warn: revset "oldstyle" uses list instead of smartset
140 1970/01/01 00:00:00 bob @cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b (5000)> devel-warn: revset "oldstyle" uses list instead of smartset
141 (compatibility will be dropped after Mercurial-3.9, update your code.) at: *mercurial/revset.py:* (mfunc) (glob)
141 (compatibility will be dropped after Mercurial-3.9, update your code.) at: *mercurial/revset.py:* (mfunc) (glob)
142 1970/01/01 00:00:00 bob @cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b (5000)> log -r oldstyle() -T {rev}\n exited 0 after * seconds (glob)
142 1970/01/01 00:00:00 bob @cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b (5000)> log -r 'oldstyle()' -T '{rev}\n' exited 0 after * seconds (glob)
143 1970/01/01 00:00:00 bob @cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b (5000)> oldanddeprecated
143 1970/01/01 00:00:00 bob @cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b (5000)> oldanddeprecated
144 1970/01/01 00:00:00 bob @cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b (5000)> devel-warn: foorbar is deprecated, go shopping
144 1970/01/01 00:00:00 bob @cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b (5000)> devel-warn: foorbar is deprecated, go shopping
145 (compatibility will be dropped after Mercurial-42.1337, update your code.) at: $TESTTMP/buggylocking.py:* (oldanddeprecated) (glob)
145 (compatibility will be dropped after Mercurial-42.1337, update your code.) at: $TESTTMP/buggylocking.py:* (oldanddeprecated) (glob)
146 1970/01/01 00:00:00 bob @cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b (5000)> oldanddeprecated exited 0 after * seconds (glob)
146 1970/01/01 00:00:00 bob @cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b (5000)> oldanddeprecated exited 0 after * seconds (glob)
147 1970/01/01 00:00:00 bob @cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b (5000)> oldanddeprecated --traceback
147 1970/01/01 00:00:00 bob @cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b (5000)> oldanddeprecated --traceback
148 1970/01/01 00:00:00 bob @cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b (5000)> devel-warn: foorbar is deprecated, go shopping
148 1970/01/01 00:00:00 bob @cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b (5000)> devel-warn: foorbar is deprecated, go shopping
149 (compatibility will be dropped after Mercurial-42.1337, update your code.) at:
149 (compatibility will be dropped after Mercurial-42.1337, update your code.) at:
150 */hg:* in <module> (glob)
150 */hg:* in <module> (glob)
151 */mercurial/dispatch.py:* in run (glob)
151 */mercurial/dispatch.py:* in run (glob)
152 */mercurial/dispatch.py:* in dispatch (glob)
152 */mercurial/dispatch.py:* in dispatch (glob)
153 */mercurial/dispatch.py:* in _runcatch (glob)
153 */mercurial/dispatch.py:* in _runcatch (glob)
154 */mercurial/dispatch.py:* in callcatch (glob)
154 */mercurial/dispatch.py:* in callcatch (glob)
155 */mercurial/scmutil.py* in callcatch (glob)
155 */mercurial/scmutil.py* in callcatch (glob)
156 */mercurial/dispatch.py:* in _runcatchfunc (glob)
156 */mercurial/dispatch.py:* in _runcatchfunc (glob)
157 */mercurial/dispatch.py:* in _dispatch (glob)
157 */mercurial/dispatch.py:* in _dispatch (glob)
158 */mercurial/dispatch.py:* in runcommand (glob)
158 */mercurial/dispatch.py:* in runcommand (glob)
159 */mercurial/dispatch.py:* in _runcommand (glob)
159 */mercurial/dispatch.py:* in _runcommand (glob)
160 */mercurial/dispatch.py:* in <lambda> (glob)
160 */mercurial/dispatch.py:* in <lambda> (glob)
161 */mercurial/util.py:* in check (glob)
161 */mercurial/util.py:* in check (glob)
162 $TESTTMP/buggylocking.py:* in oldanddeprecated (glob)
162 $TESTTMP/buggylocking.py:* in oldanddeprecated (glob)
163 1970/01/01 00:00:00 bob @cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b (5000)> oldanddeprecated --traceback exited 0 after * seconds (glob)
163 1970/01/01 00:00:00 bob @cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b (5000)> oldanddeprecated --traceback exited 0 after * seconds (glob)
164 1970/01/01 00:00:00 bob @cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b (5000)> blackbox -l 9
164 1970/01/01 00:00:00 bob @cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b (5000)> blackbox -l 9
165
165
166 Test programming error failure:
166 Test programming error failure:
167
167
168 $ hg buggytransaction 2>&1 | egrep -v '^ '
168 $ hg buggytransaction 2>&1 | egrep -v '^ '
169 ** Unknown exception encountered with possibly-broken third-party extension buggylocking
169 ** Unknown exception encountered with possibly-broken third-party extension buggylocking
170 ** which supports versions unknown of Mercurial.
170 ** which supports versions unknown of Mercurial.
171 ** Please disable buggylocking and try your action again.
171 ** Please disable buggylocking and try your action again.
172 ** If that fixes the bug please report it to the extension author.
172 ** If that fixes the bug please report it to the extension author.
173 ** Python * (glob)
173 ** Python * (glob)
174 ** Mercurial Distributed SCM (*) (glob)
174 ** Mercurial Distributed SCM (*) (glob)
175 ** Extensions loaded: * (glob)
175 ** Extensions loaded: * (glob)
176 Traceback (most recent call last):
176 Traceback (most recent call last):
177 mercurial.error.ProgrammingError: transaction requires locking
177 mercurial.error.ProgrammingError: transaction requires locking
178
178
179 $ cd ..
179 $ cd ..
General Comments 0
You need to be logged in to leave comments. Login now