##// END OF EJS Templates
dispatch: print 'abort:' when a pre-command hook fails (BC)...
Siddharth Agarwal -
r19011:12acbea1 default
parent child Browse files
Show More
@@ -1,844 +1,842
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 i18n import _
8 from i18n import _
9 import os, sys, atexit, signal, pdb, socket, errno, shlex, time, traceback, re
9 import os, sys, atexit, signal, pdb, socket, errno, shlex, time, traceback, re
10 import util, commands, hg, fancyopts, extensions, hook, error
10 import util, commands, hg, fancyopts, extensions, hook, error
11 import cmdutil, encoding
11 import cmdutil, encoding
12 import ui as uimod
12 import ui as uimod
13
13
14 class request(object):
14 class request(object):
15 def __init__(self, args, ui=None, repo=None, fin=None, fout=None,
15 def __init__(self, args, ui=None, repo=None, fin=None, fout=None,
16 ferr=None):
16 ferr=None):
17 self.args = args
17 self.args = args
18 self.ui = ui
18 self.ui = ui
19 self.repo = repo
19 self.repo = repo
20
20
21 # input/output/error streams
21 # input/output/error streams
22 self.fin = fin
22 self.fin = fin
23 self.fout = fout
23 self.fout = fout
24 self.ferr = ferr
24 self.ferr = ferr
25
25
26 def run():
26 def run():
27 "run the command in sys.argv"
27 "run the command in sys.argv"
28 sys.exit((dispatch(request(sys.argv[1:])) or 0) & 255)
28 sys.exit((dispatch(request(sys.argv[1:])) or 0) & 255)
29
29
30 def dispatch(req):
30 def dispatch(req):
31 "run the command specified in req.args"
31 "run the command specified in req.args"
32 if req.ferr:
32 if req.ferr:
33 ferr = req.ferr
33 ferr = req.ferr
34 elif req.ui:
34 elif req.ui:
35 ferr = req.ui.ferr
35 ferr = req.ui.ferr
36 else:
36 else:
37 ferr = sys.stderr
37 ferr = sys.stderr
38
38
39 try:
39 try:
40 if not req.ui:
40 if not req.ui:
41 req.ui = uimod.ui()
41 req.ui = uimod.ui()
42 if '--traceback' in req.args:
42 if '--traceback' in req.args:
43 req.ui.setconfig('ui', 'traceback', 'on')
43 req.ui.setconfig('ui', 'traceback', 'on')
44
44
45 # set ui streams from the request
45 # set ui streams from the request
46 if req.fin:
46 if req.fin:
47 req.ui.fin = req.fin
47 req.ui.fin = req.fin
48 if req.fout:
48 if req.fout:
49 req.ui.fout = req.fout
49 req.ui.fout = req.fout
50 if req.ferr:
50 if req.ferr:
51 req.ui.ferr = req.ferr
51 req.ui.ferr = req.ferr
52 except util.Abort, inst:
52 except util.Abort, inst:
53 ferr.write(_("abort: %s\n") % inst)
53 ferr.write(_("abort: %s\n") % inst)
54 if inst.hint:
54 if inst.hint:
55 ferr.write(_("(%s)\n") % inst.hint)
55 ferr.write(_("(%s)\n") % inst.hint)
56 return -1
56 return -1
57 except error.ParseError, inst:
57 except error.ParseError, inst:
58 if len(inst.args) > 1:
58 if len(inst.args) > 1:
59 ferr.write(_("hg: parse error at %s: %s\n") %
59 ferr.write(_("hg: parse error at %s: %s\n") %
60 (inst.args[1], inst.args[0]))
60 (inst.args[1], inst.args[0]))
61 else:
61 else:
62 ferr.write(_("hg: parse error: %s\n") % inst.args[0])
62 ferr.write(_("hg: parse error: %s\n") % inst.args[0])
63 return -1
63 return -1
64
64
65 return _runcatch(req)
65 return _runcatch(req)
66
66
67 def _runcatch(req):
67 def _runcatch(req):
68 def catchterm(*args):
68 def catchterm(*args):
69 raise error.SignalInterrupt
69 raise error.SignalInterrupt
70
70
71 ui = req.ui
71 ui = req.ui
72 try:
72 try:
73 for name in 'SIGBREAK', 'SIGHUP', 'SIGTERM':
73 for name in 'SIGBREAK', 'SIGHUP', 'SIGTERM':
74 num = getattr(signal, name, None)
74 num = getattr(signal, name, None)
75 if num:
75 if num:
76 signal.signal(num, catchterm)
76 signal.signal(num, catchterm)
77 except ValueError:
77 except ValueError:
78 pass # happens if called in a thread
78 pass # happens if called in a thread
79
79
80 try:
80 try:
81 try:
81 try:
82 # enter the debugger before command execution
82 # enter the debugger before command execution
83 if '--debugger' in req.args:
83 if '--debugger' in req.args:
84 ui.warn(_("entering debugger - "
84 ui.warn(_("entering debugger - "
85 "type c to continue starting hg or h for help\n"))
85 "type c to continue starting hg or h for help\n"))
86 pdb.set_trace()
86 pdb.set_trace()
87 try:
87 try:
88 return _dispatch(req)
88 return _dispatch(req)
89 finally:
89 finally:
90 ui.flush()
90 ui.flush()
91 except: # re-raises
91 except: # re-raises
92 # enter the debugger when we hit an exception
92 # enter the debugger when we hit an exception
93 if '--debugger' in req.args:
93 if '--debugger' in req.args:
94 traceback.print_exc()
94 traceback.print_exc()
95 pdb.post_mortem(sys.exc_info()[2])
95 pdb.post_mortem(sys.exc_info()[2])
96 ui.traceback()
96 ui.traceback()
97 raise
97 raise
98
98
99 # Global exception handling, alphabetically
99 # Global exception handling, alphabetically
100 # Mercurial-specific first, followed by built-in and library exceptions
100 # Mercurial-specific first, followed by built-in and library exceptions
101 except error.AmbiguousCommand, inst:
101 except error.AmbiguousCommand, inst:
102 ui.warn(_("hg: command '%s' is ambiguous:\n %s\n") %
102 ui.warn(_("hg: command '%s' is ambiguous:\n %s\n") %
103 (inst.args[0], " ".join(inst.args[1])))
103 (inst.args[0], " ".join(inst.args[1])))
104 except error.ParseError, inst:
104 except error.ParseError, inst:
105 if len(inst.args) > 1:
105 if len(inst.args) > 1:
106 ui.warn(_("hg: parse error at %s: %s\n") %
106 ui.warn(_("hg: parse error at %s: %s\n") %
107 (inst.args[1], inst.args[0]))
107 (inst.args[1], inst.args[0]))
108 else:
108 else:
109 ui.warn(_("hg: parse error: %s\n") % inst.args[0])
109 ui.warn(_("hg: parse error: %s\n") % inst.args[0])
110 return -1
110 return -1
111 except error.LockHeld, inst:
111 except error.LockHeld, inst:
112 if inst.errno == errno.ETIMEDOUT:
112 if inst.errno == errno.ETIMEDOUT:
113 reason = _('timed out waiting for lock held by %s') % inst.locker
113 reason = _('timed out waiting for lock held by %s') % inst.locker
114 else:
114 else:
115 reason = _('lock held by %s') % inst.locker
115 reason = _('lock held by %s') % inst.locker
116 ui.warn(_("abort: %s: %s\n") % (inst.desc or inst.filename, reason))
116 ui.warn(_("abort: %s: %s\n") % (inst.desc or inst.filename, reason))
117 except error.LockUnavailable, inst:
117 except error.LockUnavailable, inst:
118 ui.warn(_("abort: could not lock %s: %s\n") %
118 ui.warn(_("abort: could not lock %s: %s\n") %
119 (inst.desc or inst.filename, inst.strerror))
119 (inst.desc or inst.filename, inst.strerror))
120 except error.CommandError, inst:
120 except error.CommandError, inst:
121 if inst.args[0]:
121 if inst.args[0]:
122 ui.warn(_("hg %s: %s\n") % (inst.args[0], inst.args[1]))
122 ui.warn(_("hg %s: %s\n") % (inst.args[0], inst.args[1]))
123 commands.help_(ui, inst.args[0], full=False, command=True)
123 commands.help_(ui, inst.args[0], full=False, command=True)
124 else:
124 else:
125 ui.warn(_("hg: %s\n") % inst.args[1])
125 ui.warn(_("hg: %s\n") % inst.args[1])
126 commands.help_(ui, 'shortlist')
126 commands.help_(ui, 'shortlist')
127 except error.OutOfBandError, inst:
127 except error.OutOfBandError, inst:
128 ui.warn(_("abort: remote error:\n"))
128 ui.warn(_("abort: remote error:\n"))
129 ui.warn(''.join(inst.args))
129 ui.warn(''.join(inst.args))
130 except error.RepoError, inst:
130 except error.RepoError, inst:
131 ui.warn(_("abort: %s!\n") % inst)
131 ui.warn(_("abort: %s!\n") % inst)
132 if inst.hint:
132 if inst.hint:
133 ui.warn(_("(%s)\n") % inst.hint)
133 ui.warn(_("(%s)\n") % inst.hint)
134 except error.ResponseError, inst:
134 except error.ResponseError, inst:
135 ui.warn(_("abort: %s") % inst.args[0])
135 ui.warn(_("abort: %s") % inst.args[0])
136 if not isinstance(inst.args[1], basestring):
136 if not isinstance(inst.args[1], basestring):
137 ui.warn(" %r\n" % (inst.args[1],))
137 ui.warn(" %r\n" % (inst.args[1],))
138 elif not inst.args[1]:
138 elif not inst.args[1]:
139 ui.warn(_(" empty string\n"))
139 ui.warn(_(" empty string\n"))
140 else:
140 else:
141 ui.warn("\n%r\n" % util.ellipsis(inst.args[1]))
141 ui.warn("\n%r\n" % util.ellipsis(inst.args[1]))
142 except error.RevlogError, inst:
142 except error.RevlogError, inst:
143 ui.warn(_("abort: %s!\n") % inst)
143 ui.warn(_("abort: %s!\n") % inst)
144 except error.SignalInterrupt:
144 except error.SignalInterrupt:
145 ui.warn(_("killed!\n"))
145 ui.warn(_("killed!\n"))
146 except error.UnknownCommand, inst:
146 except error.UnknownCommand, inst:
147 ui.warn(_("hg: unknown command '%s'\n") % inst.args[0])
147 ui.warn(_("hg: unknown command '%s'\n") % inst.args[0])
148 try:
148 try:
149 # check if the command is in a disabled extension
149 # check if the command is in a disabled extension
150 # (but don't check for extensions themselves)
150 # (but don't check for extensions themselves)
151 commands.help_(ui, inst.args[0], unknowncmd=True)
151 commands.help_(ui, inst.args[0], unknowncmd=True)
152 except error.UnknownCommand:
152 except error.UnknownCommand:
153 commands.help_(ui, 'shortlist')
153 commands.help_(ui, 'shortlist')
154 except error.InterventionRequired, inst:
154 except error.InterventionRequired, inst:
155 ui.warn("%s\n" % inst)
155 ui.warn("%s\n" % inst)
156 return 1
156 return 1
157 except util.Abort, inst:
157 except util.Abort, inst:
158 ui.warn(_("abort: %s\n") % inst)
158 ui.warn(_("abort: %s\n") % inst)
159 if inst.hint:
159 if inst.hint:
160 ui.warn(_("(%s)\n") % inst.hint)
160 ui.warn(_("(%s)\n") % inst.hint)
161 except ImportError, inst:
161 except ImportError, inst:
162 ui.warn(_("abort: %s!\n") % inst)
162 ui.warn(_("abort: %s!\n") % inst)
163 m = str(inst).split()[-1]
163 m = str(inst).split()[-1]
164 if m in "mpatch bdiff".split():
164 if m in "mpatch bdiff".split():
165 ui.warn(_("(did you forget to compile extensions?)\n"))
165 ui.warn(_("(did you forget to compile extensions?)\n"))
166 elif m in "zlib".split():
166 elif m in "zlib".split():
167 ui.warn(_("(is your Python install correct?)\n"))
167 ui.warn(_("(is your Python install correct?)\n"))
168 except IOError, inst:
168 except IOError, inst:
169 if util.safehasattr(inst, "code"):
169 if util.safehasattr(inst, "code"):
170 ui.warn(_("abort: %s\n") % inst)
170 ui.warn(_("abort: %s\n") % inst)
171 elif util.safehasattr(inst, "reason"):
171 elif util.safehasattr(inst, "reason"):
172 try: # usually it is in the form (errno, strerror)
172 try: # usually it is in the form (errno, strerror)
173 reason = inst.reason.args[1]
173 reason = inst.reason.args[1]
174 except (AttributeError, IndexError):
174 except (AttributeError, IndexError):
175 # it might be anything, for example a string
175 # it might be anything, for example a string
176 reason = inst.reason
176 reason = inst.reason
177 ui.warn(_("abort: error: %s\n") % reason)
177 ui.warn(_("abort: error: %s\n") % reason)
178 elif util.safehasattr(inst, "args") and inst.args[0] == errno.EPIPE:
178 elif util.safehasattr(inst, "args") and inst.args[0] == errno.EPIPE:
179 if ui.debugflag:
179 if ui.debugflag:
180 ui.warn(_("broken pipe\n"))
180 ui.warn(_("broken pipe\n"))
181 elif getattr(inst, "strerror", None):
181 elif getattr(inst, "strerror", None):
182 if getattr(inst, "filename", None):
182 if getattr(inst, "filename", None):
183 ui.warn(_("abort: %s: %s\n") % (inst.strerror, inst.filename))
183 ui.warn(_("abort: %s: %s\n") % (inst.strerror, inst.filename))
184 else:
184 else:
185 ui.warn(_("abort: %s\n") % inst.strerror)
185 ui.warn(_("abort: %s\n") % inst.strerror)
186 else:
186 else:
187 raise
187 raise
188 except OSError, inst:
188 except OSError, inst:
189 if getattr(inst, "filename", None) is not None:
189 if getattr(inst, "filename", None) is not None:
190 ui.warn(_("abort: %s: '%s'\n") % (inst.strerror, inst.filename))
190 ui.warn(_("abort: %s: '%s'\n") % (inst.strerror, inst.filename))
191 else:
191 else:
192 ui.warn(_("abort: %s\n") % inst.strerror)
192 ui.warn(_("abort: %s\n") % inst.strerror)
193 except KeyboardInterrupt:
193 except KeyboardInterrupt:
194 try:
194 try:
195 ui.warn(_("interrupted!\n"))
195 ui.warn(_("interrupted!\n"))
196 except IOError, inst:
196 except IOError, inst:
197 if inst.errno == errno.EPIPE:
197 if inst.errno == errno.EPIPE:
198 if ui.debugflag:
198 if ui.debugflag:
199 ui.warn(_("\nbroken pipe\n"))
199 ui.warn(_("\nbroken pipe\n"))
200 else:
200 else:
201 raise
201 raise
202 except MemoryError:
202 except MemoryError:
203 ui.warn(_("abort: out of memory\n"))
203 ui.warn(_("abort: out of memory\n"))
204 except SystemExit, inst:
204 except SystemExit, inst:
205 # Commands shouldn't sys.exit directly, but give a return code.
205 # Commands shouldn't sys.exit directly, but give a return code.
206 # Just in case catch this and and pass exit code to caller.
206 # Just in case catch this and and pass exit code to caller.
207 return inst.code
207 return inst.code
208 except socket.error, inst:
208 except socket.error, inst:
209 ui.warn(_("abort: %s\n") % inst.args[-1])
209 ui.warn(_("abort: %s\n") % inst.args[-1])
210 except: # re-raises
210 except: # re-raises
211 myver = util.version()
211 myver = util.version()
212 # For compatibility checking, we discard the portion of the hg
212 # For compatibility checking, we discard the portion of the hg
213 # version after the + on the assumption that if a "normal
213 # version after the + on the assumption that if a "normal
214 # user" is running a build with a + in it the packager
214 # user" is running a build with a + in it the packager
215 # probably built from fairly close to a tag and anyone with a
215 # probably built from fairly close to a tag and anyone with a
216 # 'make local' copy of hg (where the version number can be out
216 # 'make local' copy of hg (where the version number can be out
217 # of date) will be clueful enough to notice the implausible
217 # of date) will be clueful enough to notice the implausible
218 # version number and try updating.
218 # version number and try updating.
219 compare = myver.split('+')[0]
219 compare = myver.split('+')[0]
220 ct = tuplever(compare)
220 ct = tuplever(compare)
221 worst = None, ct, ''
221 worst = None, ct, ''
222 for name, mod in extensions.extensions():
222 for name, mod in extensions.extensions():
223 testedwith = getattr(mod, 'testedwith', '')
223 testedwith = getattr(mod, 'testedwith', '')
224 report = getattr(mod, 'buglink', _('the extension author.'))
224 report = getattr(mod, 'buglink', _('the extension author.'))
225 if not testedwith.strip():
225 if not testedwith.strip():
226 # We found an untested extension. It's likely the culprit.
226 # We found an untested extension. It's likely the culprit.
227 worst = name, 'unknown', report
227 worst = name, 'unknown', report
228 break
228 break
229 if compare not in testedwith.split() and testedwith != 'internal':
229 if compare not in testedwith.split() and testedwith != 'internal':
230 tested = [tuplever(v) for v in testedwith.split()]
230 tested = [tuplever(v) for v in testedwith.split()]
231 lower = [t for t in tested if t < ct]
231 lower = [t for t in tested if t < ct]
232 nearest = max(lower or tested)
232 nearest = max(lower or tested)
233 if worst[0] is None or nearest < worst[1]:
233 if worst[0] is None or nearest < worst[1]:
234 worst = name, nearest, report
234 worst = name, nearest, report
235 if worst[0] is not None:
235 if worst[0] is not None:
236 name, testedwith, report = worst
236 name, testedwith, report = worst
237 if not isinstance(testedwith, str):
237 if not isinstance(testedwith, str):
238 testedwith = '.'.join([str(c) for c in testedwith])
238 testedwith = '.'.join([str(c) for c in testedwith])
239 warning = (_('** Unknown exception encountered with '
239 warning = (_('** Unknown exception encountered with '
240 'possibly-broken third-party extension %s\n'
240 'possibly-broken third-party extension %s\n'
241 '** which supports versions %s of Mercurial.\n'
241 '** which supports versions %s of Mercurial.\n'
242 '** Please disable %s and try your action again.\n'
242 '** Please disable %s and try your action again.\n'
243 '** If that fixes the bug please report it to %s\n')
243 '** If that fixes the bug please report it to %s\n')
244 % (name, testedwith, name, report))
244 % (name, testedwith, name, report))
245 else:
245 else:
246 warning = (_("** unknown exception encountered, "
246 warning = (_("** unknown exception encountered, "
247 "please report by visiting\n") +
247 "please report by visiting\n") +
248 _("** http://mercurial.selenic.com/wiki/BugTracker\n"))
248 _("** http://mercurial.selenic.com/wiki/BugTracker\n"))
249 warning += ((_("** Python %s\n") % sys.version.replace('\n', '')) +
249 warning += ((_("** Python %s\n") % sys.version.replace('\n', '')) +
250 (_("** Mercurial Distributed SCM (version %s)\n") % myver) +
250 (_("** Mercurial Distributed SCM (version %s)\n") % myver) +
251 (_("** Extensions loaded: %s\n") %
251 (_("** Extensions loaded: %s\n") %
252 ", ".join([x[0] for x in extensions.extensions()])))
252 ", ".join([x[0] for x in extensions.extensions()])))
253 ui.log("commandexception", "%s\n%s\n", warning, traceback.format_exc())
253 ui.log("commandexception", "%s\n%s\n", warning, traceback.format_exc())
254 ui.warn(warning)
254 ui.warn(warning)
255 raise
255 raise
256
256
257 return -1
257 return -1
258
258
259 def tuplever(v):
259 def tuplever(v):
260 try:
260 try:
261 return tuple([int(i) for i in v.split('.')])
261 return tuple([int(i) for i in v.split('.')])
262 except ValueError:
262 except ValueError:
263 return tuple()
263 return tuple()
264
264
265 def aliasargs(fn, givenargs):
265 def aliasargs(fn, givenargs):
266 args = getattr(fn, 'args', [])
266 args = getattr(fn, 'args', [])
267 if args:
267 if args:
268 cmd = ' '.join(map(util.shellquote, args))
268 cmd = ' '.join(map(util.shellquote, args))
269
269
270 nums = []
270 nums = []
271 def replacer(m):
271 def replacer(m):
272 num = int(m.group(1)) - 1
272 num = int(m.group(1)) - 1
273 nums.append(num)
273 nums.append(num)
274 if num < len(givenargs):
274 if num < len(givenargs):
275 return givenargs[num]
275 return givenargs[num]
276 raise util.Abort(_('too few arguments for command alias'))
276 raise util.Abort(_('too few arguments for command alias'))
277 cmd = re.sub(r'\$(\d+|\$)', replacer, cmd)
277 cmd = re.sub(r'\$(\d+|\$)', replacer, cmd)
278 givenargs = [x for i, x in enumerate(givenargs)
278 givenargs = [x for i, x in enumerate(givenargs)
279 if i not in nums]
279 if i not in nums]
280 args = shlex.split(cmd)
280 args = shlex.split(cmd)
281 return args + givenargs
281 return args + givenargs
282
282
283 class cmdalias(object):
283 class cmdalias(object):
284 def __init__(self, name, definition, cmdtable):
284 def __init__(self, name, definition, cmdtable):
285 self.name = self.cmd = name
285 self.name = self.cmd = name
286 self.cmdname = ''
286 self.cmdname = ''
287 self.definition = definition
287 self.definition = definition
288 self.args = []
288 self.args = []
289 self.opts = []
289 self.opts = []
290 self.help = ''
290 self.help = ''
291 self.norepo = True
291 self.norepo = True
292 self.optionalrepo = False
292 self.optionalrepo = False
293 self.badalias = False
293 self.badalias = False
294
294
295 try:
295 try:
296 aliases, entry = cmdutil.findcmd(self.name, cmdtable)
296 aliases, entry = cmdutil.findcmd(self.name, cmdtable)
297 for alias, e in cmdtable.iteritems():
297 for alias, e in cmdtable.iteritems():
298 if e is entry:
298 if e is entry:
299 self.cmd = alias
299 self.cmd = alias
300 break
300 break
301 self.shadows = True
301 self.shadows = True
302 except error.UnknownCommand:
302 except error.UnknownCommand:
303 self.shadows = False
303 self.shadows = False
304
304
305 if not self.definition:
305 if not self.definition:
306 def fn(ui, *args):
306 def fn(ui, *args):
307 ui.warn(_("no definition for alias '%s'\n") % self.name)
307 ui.warn(_("no definition for alias '%s'\n") % self.name)
308 return 1
308 return 1
309 self.fn = fn
309 self.fn = fn
310 self.badalias = True
310 self.badalias = True
311 return
311 return
312
312
313 if self.definition.startswith('!'):
313 if self.definition.startswith('!'):
314 self.shell = True
314 self.shell = True
315 def fn(ui, *args):
315 def fn(ui, *args):
316 env = {'HG_ARGS': ' '.join((self.name,) + args)}
316 env = {'HG_ARGS': ' '.join((self.name,) + args)}
317 def _checkvar(m):
317 def _checkvar(m):
318 if m.groups()[0] == '$':
318 if m.groups()[0] == '$':
319 return m.group()
319 return m.group()
320 elif int(m.groups()[0]) <= len(args):
320 elif int(m.groups()[0]) <= len(args):
321 return m.group()
321 return m.group()
322 else:
322 else:
323 ui.debug("No argument found for substitution "
323 ui.debug("No argument found for substitution "
324 "of %i variable in alias '%s' definition."
324 "of %i variable in alias '%s' definition."
325 % (int(m.groups()[0]), self.name))
325 % (int(m.groups()[0]), self.name))
326 return ''
326 return ''
327 cmd = re.sub(r'\$(\d+|\$)', _checkvar, self.definition[1:])
327 cmd = re.sub(r'\$(\d+|\$)', _checkvar, self.definition[1:])
328 replace = dict((str(i + 1), arg) for i, arg in enumerate(args))
328 replace = dict((str(i + 1), arg) for i, arg in enumerate(args))
329 replace['0'] = self.name
329 replace['0'] = self.name
330 replace['@'] = ' '.join(args)
330 replace['@'] = ' '.join(args)
331 cmd = util.interpolate(r'\$', replace, cmd, escape_prefix=True)
331 cmd = util.interpolate(r'\$', replace, cmd, escape_prefix=True)
332 return util.system(cmd, environ=env, out=ui.fout)
332 return util.system(cmd, environ=env, out=ui.fout)
333 self.fn = fn
333 self.fn = fn
334 return
334 return
335
335
336 args = shlex.split(self.definition)
336 args = shlex.split(self.definition)
337 self.cmdname = cmd = args.pop(0)
337 self.cmdname = cmd = args.pop(0)
338 args = map(util.expandpath, args)
338 args = map(util.expandpath, args)
339
339
340 for invalidarg in ("--cwd", "-R", "--repository", "--repo", "--config"):
340 for invalidarg in ("--cwd", "-R", "--repository", "--repo", "--config"):
341 if _earlygetopt([invalidarg], args):
341 if _earlygetopt([invalidarg], args):
342 def fn(ui, *args):
342 def fn(ui, *args):
343 ui.warn(_("error in definition for alias '%s': %s may only "
343 ui.warn(_("error in definition for alias '%s': %s may only "
344 "be given on the command line\n")
344 "be given on the command line\n")
345 % (self.name, invalidarg))
345 % (self.name, invalidarg))
346 return 1
346 return 1
347
347
348 self.fn = fn
348 self.fn = fn
349 self.badalias = True
349 self.badalias = True
350 return
350 return
351
351
352 try:
352 try:
353 tableentry = cmdutil.findcmd(cmd, cmdtable, False)[1]
353 tableentry = cmdutil.findcmd(cmd, cmdtable, False)[1]
354 if len(tableentry) > 2:
354 if len(tableentry) > 2:
355 self.fn, self.opts, self.help = tableentry
355 self.fn, self.opts, self.help = tableentry
356 else:
356 else:
357 self.fn, self.opts = tableentry
357 self.fn, self.opts = tableentry
358
358
359 self.args = aliasargs(self.fn, args)
359 self.args = aliasargs(self.fn, args)
360 if cmd not in commands.norepo.split(' '):
360 if cmd not in commands.norepo.split(' '):
361 self.norepo = False
361 self.norepo = False
362 if cmd in commands.optionalrepo.split(' '):
362 if cmd in commands.optionalrepo.split(' '):
363 self.optionalrepo = True
363 self.optionalrepo = True
364 if self.help.startswith("hg " + cmd):
364 if self.help.startswith("hg " + cmd):
365 # drop prefix in old-style help lines so hg shows the alias
365 # drop prefix in old-style help lines so hg shows the alias
366 self.help = self.help[4 + len(cmd):]
366 self.help = self.help[4 + len(cmd):]
367 self.__doc__ = self.fn.__doc__
367 self.__doc__ = self.fn.__doc__
368
368
369 except error.UnknownCommand:
369 except error.UnknownCommand:
370 def fn(ui, *args):
370 def fn(ui, *args):
371 ui.warn(_("alias '%s' resolves to unknown command '%s'\n") \
371 ui.warn(_("alias '%s' resolves to unknown command '%s'\n") \
372 % (self.name, cmd))
372 % (self.name, cmd))
373 try:
373 try:
374 # check if the command is in a disabled extension
374 # check if the command is in a disabled extension
375 commands.help_(ui, cmd, unknowncmd=True)
375 commands.help_(ui, cmd, unknowncmd=True)
376 except error.UnknownCommand:
376 except error.UnknownCommand:
377 pass
377 pass
378 return 1
378 return 1
379 self.fn = fn
379 self.fn = fn
380 self.badalias = True
380 self.badalias = True
381 except error.AmbiguousCommand:
381 except error.AmbiguousCommand:
382 def fn(ui, *args):
382 def fn(ui, *args):
383 ui.warn(_("alias '%s' resolves to ambiguous command '%s'\n") \
383 ui.warn(_("alias '%s' resolves to ambiguous command '%s'\n") \
384 % (self.name, cmd))
384 % (self.name, cmd))
385 return 1
385 return 1
386 self.fn = fn
386 self.fn = fn
387 self.badalias = True
387 self.badalias = True
388
388
389 def __call__(self, ui, *args, **opts):
389 def __call__(self, ui, *args, **opts):
390 if self.shadows:
390 if self.shadows:
391 ui.debug("alias '%s' shadows command '%s'\n" %
391 ui.debug("alias '%s' shadows command '%s'\n" %
392 (self.name, self.cmdname))
392 (self.name, self.cmdname))
393
393
394 if util.safehasattr(self, 'shell'):
394 if util.safehasattr(self, 'shell'):
395 return self.fn(ui, *args, **opts)
395 return self.fn(ui, *args, **opts)
396 else:
396 else:
397 try:
397 try:
398 util.checksignature(self.fn)(ui, *args, **opts)
398 util.checksignature(self.fn)(ui, *args, **opts)
399 except error.SignatureError:
399 except error.SignatureError:
400 args = ' '.join([self.cmdname] + self.args)
400 args = ' '.join([self.cmdname] + self.args)
401 ui.debug("alias '%s' expands to '%s'\n" % (self.name, args))
401 ui.debug("alias '%s' expands to '%s'\n" % (self.name, args))
402 raise
402 raise
403
403
404 def addaliases(ui, cmdtable):
404 def addaliases(ui, cmdtable):
405 # aliases are processed after extensions have been loaded, so they
405 # aliases are processed after extensions have been loaded, so they
406 # may use extension commands. Aliases can also use other alias definitions,
406 # may use extension commands. Aliases can also use other alias definitions,
407 # but only if they have been defined prior to the current definition.
407 # but only if they have been defined prior to the current definition.
408 for alias, definition in ui.configitems('alias'):
408 for alias, definition in ui.configitems('alias'):
409 aliasdef = cmdalias(alias, definition, cmdtable)
409 aliasdef = cmdalias(alias, definition, cmdtable)
410
410
411 try:
411 try:
412 olddef = cmdtable[aliasdef.cmd][0]
412 olddef = cmdtable[aliasdef.cmd][0]
413 if olddef.definition == aliasdef.definition:
413 if olddef.definition == aliasdef.definition:
414 continue
414 continue
415 except (KeyError, AttributeError):
415 except (KeyError, AttributeError):
416 # definition might not exist or it might not be a cmdalias
416 # definition might not exist or it might not be a cmdalias
417 pass
417 pass
418
418
419 cmdtable[aliasdef.name] = (aliasdef, aliasdef.opts, aliasdef.help)
419 cmdtable[aliasdef.name] = (aliasdef, aliasdef.opts, aliasdef.help)
420 if aliasdef.norepo:
420 if aliasdef.norepo:
421 commands.norepo += ' %s' % alias
421 commands.norepo += ' %s' % alias
422 if aliasdef.optionalrepo:
422 if aliasdef.optionalrepo:
423 commands.optionalrepo += ' %s' % alias
423 commands.optionalrepo += ' %s' % alias
424
424
425 def _parse(ui, args):
425 def _parse(ui, args):
426 options = {}
426 options = {}
427 cmdoptions = {}
427 cmdoptions = {}
428
428
429 try:
429 try:
430 args = fancyopts.fancyopts(args, commands.globalopts, options)
430 args = fancyopts.fancyopts(args, commands.globalopts, options)
431 except fancyopts.getopt.GetoptError, inst:
431 except fancyopts.getopt.GetoptError, inst:
432 raise error.CommandError(None, inst)
432 raise error.CommandError(None, inst)
433
433
434 if args:
434 if args:
435 cmd, args = args[0], args[1:]
435 cmd, args = args[0], args[1:]
436 aliases, entry = cmdutil.findcmd(cmd, commands.table,
436 aliases, entry = cmdutil.findcmd(cmd, commands.table,
437 ui.configbool("ui", "strict"))
437 ui.configbool("ui", "strict"))
438 cmd = aliases[0]
438 cmd = aliases[0]
439 args = aliasargs(entry[0], args)
439 args = aliasargs(entry[0], args)
440 defaults = ui.config("defaults", cmd)
440 defaults = ui.config("defaults", cmd)
441 if defaults:
441 if defaults:
442 args = map(util.expandpath, shlex.split(defaults)) + args
442 args = map(util.expandpath, shlex.split(defaults)) + args
443 c = list(entry[1])
443 c = list(entry[1])
444 else:
444 else:
445 cmd = None
445 cmd = None
446 c = []
446 c = []
447
447
448 # combine global options into local
448 # combine global options into local
449 for o in commands.globalopts:
449 for o in commands.globalopts:
450 c.append((o[0], o[1], options[o[1]], o[3]))
450 c.append((o[0], o[1], options[o[1]], o[3]))
451
451
452 try:
452 try:
453 args = fancyopts.fancyopts(args, c, cmdoptions, True)
453 args = fancyopts.fancyopts(args, c, cmdoptions, True)
454 except fancyopts.getopt.GetoptError, inst:
454 except fancyopts.getopt.GetoptError, inst:
455 raise error.CommandError(cmd, inst)
455 raise error.CommandError(cmd, inst)
456
456
457 # separate global options back out
457 # separate global options back out
458 for o in commands.globalopts:
458 for o in commands.globalopts:
459 n = o[1]
459 n = o[1]
460 options[n] = cmdoptions[n]
460 options[n] = cmdoptions[n]
461 del cmdoptions[n]
461 del cmdoptions[n]
462
462
463 return (cmd, cmd and entry[0] or None, args, options, cmdoptions)
463 return (cmd, cmd and entry[0] or None, args, options, cmdoptions)
464
464
465 def _parseconfig(ui, config):
465 def _parseconfig(ui, config):
466 """parse the --config options from the command line"""
466 """parse the --config options from the command line"""
467 configs = []
467 configs = []
468
468
469 for cfg in config:
469 for cfg in config:
470 try:
470 try:
471 name, value = cfg.split('=', 1)
471 name, value = cfg.split('=', 1)
472 section, name = name.split('.', 1)
472 section, name = name.split('.', 1)
473 if not section or not name:
473 if not section or not name:
474 raise IndexError
474 raise IndexError
475 ui.setconfig(section, name, value)
475 ui.setconfig(section, name, value)
476 configs.append((section, name, value))
476 configs.append((section, name, value))
477 except (IndexError, ValueError):
477 except (IndexError, ValueError):
478 raise util.Abort(_('malformed --config option: %r '
478 raise util.Abort(_('malformed --config option: %r '
479 '(use --config section.name=value)') % cfg)
479 '(use --config section.name=value)') % cfg)
480
480
481 return configs
481 return configs
482
482
483 def _earlygetopt(aliases, args):
483 def _earlygetopt(aliases, args):
484 """Return list of values for an option (or aliases).
484 """Return list of values for an option (or aliases).
485
485
486 The values are listed in the order they appear in args.
486 The values are listed in the order they appear in args.
487 The options and values are removed from args.
487 The options and values are removed from args.
488 """
488 """
489 try:
489 try:
490 argcount = args.index("--")
490 argcount = args.index("--")
491 except ValueError:
491 except ValueError:
492 argcount = len(args)
492 argcount = len(args)
493 shortopts = [opt for opt in aliases if len(opt) == 2]
493 shortopts = [opt for opt in aliases if len(opt) == 2]
494 values = []
494 values = []
495 pos = 0
495 pos = 0
496 while pos < argcount:
496 while pos < argcount:
497 if args[pos] in aliases:
497 if args[pos] in aliases:
498 if pos + 1 >= argcount:
498 if pos + 1 >= argcount:
499 # ignore and let getopt report an error if there is no value
499 # ignore and let getopt report an error if there is no value
500 break
500 break
501 del args[pos]
501 del args[pos]
502 values.append(args.pop(pos))
502 values.append(args.pop(pos))
503 argcount -= 2
503 argcount -= 2
504 elif args[pos][:2] in shortopts:
504 elif args[pos][:2] in shortopts:
505 # short option can have no following space, e.g. hg log -Rfoo
505 # short option can have no following space, e.g. hg log -Rfoo
506 values.append(args.pop(pos)[2:])
506 values.append(args.pop(pos)[2:])
507 argcount -= 1
507 argcount -= 1
508 else:
508 else:
509 pos += 1
509 pos += 1
510 return values
510 return values
511
511
512 def runcommand(lui, repo, cmd, fullargs, ui, options, d, cmdpats, cmdoptions):
512 def runcommand(lui, repo, cmd, fullargs, ui, options, d, cmdpats, cmdoptions):
513 # run pre-hook, and abort if it fails
513 # run pre-hook, and abort if it fails
514 ret = hook.hook(lui, repo, "pre-%s" % cmd, False, args=" ".join(fullargs),
514 hook.hook(lui, repo, "pre-%s" % cmd, True, args=" ".join(fullargs),
515 pats=cmdpats, opts=cmdoptions)
515 pats=cmdpats, opts=cmdoptions)
516 if ret:
517 return ret
518 ret = _runcommand(ui, options, cmd, d)
516 ret = _runcommand(ui, options, cmd, d)
519 # run post-hook, passing command result
517 # run post-hook, passing command result
520 hook.hook(lui, repo, "post-%s" % cmd, False, args=" ".join(fullargs),
518 hook.hook(lui, repo, "post-%s" % cmd, False, args=" ".join(fullargs),
521 result=ret, pats=cmdpats, opts=cmdoptions)
519 result=ret, pats=cmdpats, opts=cmdoptions)
522 return ret
520 return ret
523
521
524 def _getlocal(ui, rpath):
522 def _getlocal(ui, rpath):
525 """Return (path, local ui object) for the given target path.
523 """Return (path, local ui object) for the given target path.
526
524
527 Takes paths in [cwd]/.hg/hgrc into account."
525 Takes paths in [cwd]/.hg/hgrc into account."
528 """
526 """
529 try:
527 try:
530 wd = os.getcwd()
528 wd = os.getcwd()
531 except OSError, e:
529 except OSError, e:
532 raise util.Abort(_("error getting current working directory: %s") %
530 raise util.Abort(_("error getting current working directory: %s") %
533 e.strerror)
531 e.strerror)
534 path = cmdutil.findrepo(wd) or ""
532 path = cmdutil.findrepo(wd) or ""
535 if not path:
533 if not path:
536 lui = ui
534 lui = ui
537 else:
535 else:
538 lui = ui.copy()
536 lui = ui.copy()
539 lui.readconfig(os.path.join(path, ".hg", "hgrc"), path)
537 lui.readconfig(os.path.join(path, ".hg", "hgrc"), path)
540
538
541 if rpath and rpath[-1]:
539 if rpath and rpath[-1]:
542 path = lui.expandpath(rpath[-1])
540 path = lui.expandpath(rpath[-1])
543 lui = ui.copy()
541 lui = ui.copy()
544 lui.readconfig(os.path.join(path, ".hg", "hgrc"), path)
542 lui.readconfig(os.path.join(path, ".hg", "hgrc"), path)
545
543
546 return path, lui
544 return path, lui
547
545
548 def _checkshellalias(lui, ui, args):
546 def _checkshellalias(lui, ui, args):
549 options = {}
547 options = {}
550
548
551 try:
549 try:
552 args = fancyopts.fancyopts(args, commands.globalopts, options)
550 args = fancyopts.fancyopts(args, commands.globalopts, options)
553 except fancyopts.getopt.GetoptError:
551 except fancyopts.getopt.GetoptError:
554 return
552 return
555
553
556 if not args:
554 if not args:
557 return
555 return
558
556
559 norepo = commands.norepo
557 norepo = commands.norepo
560 optionalrepo = commands.optionalrepo
558 optionalrepo = commands.optionalrepo
561 def restorecommands():
559 def restorecommands():
562 commands.norepo = norepo
560 commands.norepo = norepo
563 commands.optionalrepo = optionalrepo
561 commands.optionalrepo = optionalrepo
564
562
565 cmdtable = commands.table.copy()
563 cmdtable = commands.table.copy()
566 addaliases(lui, cmdtable)
564 addaliases(lui, cmdtable)
567
565
568 cmd = args[0]
566 cmd = args[0]
569 try:
567 try:
570 aliases, entry = cmdutil.findcmd(cmd, cmdtable,
568 aliases, entry = cmdutil.findcmd(cmd, cmdtable,
571 lui.configbool("ui", "strict"))
569 lui.configbool("ui", "strict"))
572 except (error.AmbiguousCommand, error.UnknownCommand):
570 except (error.AmbiguousCommand, error.UnknownCommand):
573 restorecommands()
571 restorecommands()
574 return
572 return
575
573
576 cmd = aliases[0]
574 cmd = aliases[0]
577 fn = entry[0]
575 fn = entry[0]
578
576
579 if cmd and util.safehasattr(fn, 'shell'):
577 if cmd and util.safehasattr(fn, 'shell'):
580 d = lambda: fn(ui, *args[1:])
578 d = lambda: fn(ui, *args[1:])
581 return lambda: runcommand(lui, None, cmd, args[:1], ui, options, d,
579 return lambda: runcommand(lui, None, cmd, args[:1], ui, options, d,
582 [], {})
580 [], {})
583
581
584 restorecommands()
582 restorecommands()
585
583
586 _loaded = set()
584 _loaded = set()
587 def _dispatch(req):
585 def _dispatch(req):
588 args = req.args
586 args = req.args
589 ui = req.ui
587 ui = req.ui
590
588
591 # read --config before doing anything else
589 # read --config before doing anything else
592 # (e.g. to change trust settings for reading .hg/hgrc)
590 # (e.g. to change trust settings for reading .hg/hgrc)
593 cfgs = _parseconfig(ui, _earlygetopt(['--config'], args))
591 cfgs = _parseconfig(ui, _earlygetopt(['--config'], args))
594
592
595 # check for cwd
593 # check for cwd
596 cwd = _earlygetopt(['--cwd'], args)
594 cwd = _earlygetopt(['--cwd'], args)
597 if cwd:
595 if cwd:
598 os.chdir(cwd[-1])
596 os.chdir(cwd[-1])
599
597
600 rpath = _earlygetopt(["-R", "--repository", "--repo"], args)
598 rpath = _earlygetopt(["-R", "--repository", "--repo"], args)
601 path, lui = _getlocal(ui, rpath)
599 path, lui = _getlocal(ui, rpath)
602
600
603 # Now that we're operating in the right directory/repository with
601 # Now that we're operating in the right directory/repository with
604 # the right config settings, check for shell aliases
602 # the right config settings, check for shell aliases
605 shellaliasfn = _checkshellalias(lui, ui, args)
603 shellaliasfn = _checkshellalias(lui, ui, args)
606 if shellaliasfn:
604 if shellaliasfn:
607 return shellaliasfn()
605 return shellaliasfn()
608
606
609 # Configure extensions in phases: uisetup, extsetup, cmdtable, and
607 # Configure extensions in phases: uisetup, extsetup, cmdtable, and
610 # reposetup. Programs like TortoiseHg will call _dispatch several
608 # reposetup. Programs like TortoiseHg will call _dispatch several
611 # times so we keep track of configured extensions in _loaded.
609 # times so we keep track of configured extensions in _loaded.
612 extensions.loadall(lui)
610 extensions.loadall(lui)
613 exts = [ext for ext in extensions.extensions() if ext[0] not in _loaded]
611 exts = [ext for ext in extensions.extensions() if ext[0] not in _loaded]
614 # Propagate any changes to lui.__class__ by extensions
612 # Propagate any changes to lui.__class__ by extensions
615 ui.__class__ = lui.__class__
613 ui.__class__ = lui.__class__
616
614
617 # (uisetup and extsetup are handled in extensions.loadall)
615 # (uisetup and extsetup are handled in extensions.loadall)
618
616
619 for name, module in exts:
617 for name, module in exts:
620 cmdtable = getattr(module, 'cmdtable', {})
618 cmdtable = getattr(module, 'cmdtable', {})
621 overrides = [cmd for cmd in cmdtable if cmd in commands.table]
619 overrides = [cmd for cmd in cmdtable if cmd in commands.table]
622 if overrides:
620 if overrides:
623 ui.warn(_("extension '%s' overrides commands: %s\n")
621 ui.warn(_("extension '%s' overrides commands: %s\n")
624 % (name, " ".join(overrides)))
622 % (name, " ".join(overrides)))
625 commands.table.update(cmdtable)
623 commands.table.update(cmdtable)
626 _loaded.add(name)
624 _loaded.add(name)
627
625
628 # (reposetup is handled in hg.repository)
626 # (reposetup is handled in hg.repository)
629
627
630 addaliases(lui, commands.table)
628 addaliases(lui, commands.table)
631
629
632 # check for fallback encoding
630 # check for fallback encoding
633 fallback = lui.config('ui', 'fallbackencoding')
631 fallback = lui.config('ui', 'fallbackencoding')
634 if fallback:
632 if fallback:
635 encoding.fallbackencoding = fallback
633 encoding.fallbackencoding = fallback
636
634
637 fullargs = args
635 fullargs = args
638 cmd, func, args, options, cmdoptions = _parse(lui, args)
636 cmd, func, args, options, cmdoptions = _parse(lui, args)
639
637
640 if options["config"]:
638 if options["config"]:
641 raise util.Abort(_("option --config may not be abbreviated!"))
639 raise util.Abort(_("option --config may not be abbreviated!"))
642 if options["cwd"]:
640 if options["cwd"]:
643 raise util.Abort(_("option --cwd may not be abbreviated!"))
641 raise util.Abort(_("option --cwd may not be abbreviated!"))
644 if options["repository"]:
642 if options["repository"]:
645 raise util.Abort(_(
643 raise util.Abort(_(
646 "option -R has to be separated from other options (e.g. not -qR) "
644 "option -R has to be separated from other options (e.g. not -qR) "
647 "and --repository may only be abbreviated as --repo!"))
645 "and --repository may only be abbreviated as --repo!"))
648
646
649 if options["encoding"]:
647 if options["encoding"]:
650 encoding.encoding = options["encoding"]
648 encoding.encoding = options["encoding"]
651 if options["encodingmode"]:
649 if options["encodingmode"]:
652 encoding.encodingmode = options["encodingmode"]
650 encoding.encodingmode = options["encodingmode"]
653 if options["time"]:
651 if options["time"]:
654 def get_times():
652 def get_times():
655 t = os.times()
653 t = os.times()
656 if t[4] == 0.0: # Windows leaves this as zero, so use time.clock()
654 if t[4] == 0.0: # Windows leaves this as zero, so use time.clock()
657 t = (t[0], t[1], t[2], t[3], time.clock())
655 t = (t[0], t[1], t[2], t[3], time.clock())
658 return t
656 return t
659 s = get_times()
657 s = get_times()
660 def print_time():
658 def print_time():
661 t = get_times()
659 t = get_times()
662 ui.warn(_("time: real %.3f secs (user %.3f+%.3f sys %.3f+%.3f)\n") %
660 ui.warn(_("time: real %.3f secs (user %.3f+%.3f sys %.3f+%.3f)\n") %
663 (t[4]-s[4], t[0]-s[0], t[2]-s[2], t[1]-s[1], t[3]-s[3]))
661 (t[4]-s[4], t[0]-s[0], t[2]-s[2], t[1]-s[1], t[3]-s[3]))
664 atexit.register(print_time)
662 atexit.register(print_time)
665
663
666 uis = set([ui, lui])
664 uis = set([ui, lui])
667
665
668 if req.repo:
666 if req.repo:
669 uis.add(req.repo.ui)
667 uis.add(req.repo.ui)
670
668
671 # copy configs that were passed on the cmdline (--config) to the repo ui
669 # copy configs that were passed on the cmdline (--config) to the repo ui
672 for cfg in cfgs:
670 for cfg in cfgs:
673 req.repo.ui.setconfig(*cfg)
671 req.repo.ui.setconfig(*cfg)
674
672
675 if options['verbose'] or options['debug'] or options['quiet']:
673 if options['verbose'] or options['debug'] or options['quiet']:
676 for opt in ('verbose', 'debug', 'quiet'):
674 for opt in ('verbose', 'debug', 'quiet'):
677 val = str(bool(options[opt]))
675 val = str(bool(options[opt]))
678 for ui_ in uis:
676 for ui_ in uis:
679 ui_.setconfig('ui', opt, val)
677 ui_.setconfig('ui', opt, val)
680
678
681 if options['traceback']:
679 if options['traceback']:
682 for ui_ in uis:
680 for ui_ in uis:
683 ui_.setconfig('ui', 'traceback', 'on')
681 ui_.setconfig('ui', 'traceback', 'on')
684
682
685 if options['noninteractive']:
683 if options['noninteractive']:
686 for ui_ in uis:
684 for ui_ in uis:
687 ui_.setconfig('ui', 'interactive', 'off')
685 ui_.setconfig('ui', 'interactive', 'off')
688
686
689 if cmdoptions.get('insecure', False):
687 if cmdoptions.get('insecure', False):
690 for ui_ in uis:
688 for ui_ in uis:
691 ui_.setconfig('web', 'cacerts', '')
689 ui_.setconfig('web', 'cacerts', '')
692
690
693 if options['version']:
691 if options['version']:
694 return commands.version_(ui)
692 return commands.version_(ui)
695 if options['help']:
693 if options['help']:
696 return commands.help_(ui, cmd)
694 return commands.help_(ui, cmd)
697 elif not cmd:
695 elif not cmd:
698 return commands.help_(ui, 'shortlist')
696 return commands.help_(ui, 'shortlist')
699
697
700 repo = None
698 repo = None
701 cmdpats = args[:]
699 cmdpats = args[:]
702 if cmd not in commands.norepo.split():
700 if cmd not in commands.norepo.split():
703 # use the repo from the request only if we don't have -R
701 # use the repo from the request only if we don't have -R
704 if not rpath and not cwd:
702 if not rpath and not cwd:
705 repo = req.repo
703 repo = req.repo
706
704
707 if repo:
705 if repo:
708 # set the descriptors of the repo ui to those of ui
706 # set the descriptors of the repo ui to those of ui
709 repo.ui.fin = ui.fin
707 repo.ui.fin = ui.fin
710 repo.ui.fout = ui.fout
708 repo.ui.fout = ui.fout
711 repo.ui.ferr = ui.ferr
709 repo.ui.ferr = ui.ferr
712 else:
710 else:
713 try:
711 try:
714 repo = hg.repository(ui, path=path)
712 repo = hg.repository(ui, path=path)
715 if not repo.local():
713 if not repo.local():
716 raise util.Abort(_("repository '%s' is not local") % path)
714 raise util.Abort(_("repository '%s' is not local") % path)
717 if options['hidden']:
715 if options['hidden']:
718 repo = repo.unfiltered()
716 repo = repo.unfiltered()
719 repo.ui.setconfig("bundle", "mainreporoot", repo.root)
717 repo.ui.setconfig("bundle", "mainreporoot", repo.root)
720 except error.RequirementError:
718 except error.RequirementError:
721 raise
719 raise
722 except error.RepoError:
720 except error.RepoError:
723 if cmd not in commands.optionalrepo.split():
721 if cmd not in commands.optionalrepo.split():
724 if (cmd in commands.inferrepo.split() and
722 if (cmd in commands.inferrepo.split() and
725 args and not path): # try to infer -R from command args
723 args and not path): # try to infer -R from command args
726 repos = map(cmdutil.findrepo, args)
724 repos = map(cmdutil.findrepo, args)
727 guess = repos[0]
725 guess = repos[0]
728 if guess and repos.count(guess) == len(repos):
726 if guess and repos.count(guess) == len(repos):
729 req.args = ['--repository', guess] + fullargs
727 req.args = ['--repository', guess] + fullargs
730 return _dispatch(req)
728 return _dispatch(req)
731 if not path:
729 if not path:
732 raise error.RepoError(_("no repository found in '%s'"
730 raise error.RepoError(_("no repository found in '%s'"
733 " (.hg not found)")
731 " (.hg not found)")
734 % os.getcwd())
732 % os.getcwd())
735 raise
733 raise
736 if repo:
734 if repo:
737 ui = repo.ui
735 ui = repo.ui
738 args.insert(0, repo)
736 args.insert(0, repo)
739 elif rpath:
737 elif rpath:
740 ui.warn(_("warning: --repository ignored\n"))
738 ui.warn(_("warning: --repository ignored\n"))
741
739
742 msg = ' '.join(' ' in a and repr(a) or a for a in fullargs)
740 msg = ' '.join(' ' in a and repr(a) or a for a in fullargs)
743 ui.log("command", '%s\n', msg)
741 ui.log("command", '%s\n', msg)
744 d = lambda: util.checksignature(func)(ui, *args, **cmdoptions)
742 d = lambda: util.checksignature(func)(ui, *args, **cmdoptions)
745 starttime = time.time()
743 starttime = time.time()
746 ret = None
744 ret = None
747 try:
745 try:
748 ret = runcommand(lui, repo, cmd, fullargs, ui, options, d,
746 ret = runcommand(lui, repo, cmd, fullargs, ui, options, d,
749 cmdpats, cmdoptions)
747 cmdpats, cmdoptions)
750 return ret
748 return ret
751 finally:
749 finally:
752 duration = time.time() - starttime
750 duration = time.time() - starttime
753 ui.log("commandfinish", "%s exited %s after %0.2f seconds\n",
751 ui.log("commandfinish", "%s exited %s after %0.2f seconds\n",
754 cmd, ret, duration)
752 cmd, ret, duration)
755 if repo and repo != req.repo:
753 if repo and repo != req.repo:
756 repo.close()
754 repo.close()
757
755
758 def lsprofile(ui, func, fp):
756 def lsprofile(ui, func, fp):
759 format = ui.config('profiling', 'format', default='text')
757 format = ui.config('profiling', 'format', default='text')
760 field = ui.config('profiling', 'sort', default='inlinetime')
758 field = ui.config('profiling', 'sort', default='inlinetime')
761 limit = ui.configint('profiling', 'limit', default=30)
759 limit = ui.configint('profiling', 'limit', default=30)
762 climit = ui.configint('profiling', 'nested', default=5)
760 climit = ui.configint('profiling', 'nested', default=5)
763
761
764 if format not in ['text', 'kcachegrind']:
762 if format not in ['text', 'kcachegrind']:
765 ui.warn(_("unrecognized profiling format '%s'"
763 ui.warn(_("unrecognized profiling format '%s'"
766 " - Ignored\n") % format)
764 " - Ignored\n") % format)
767 format = 'text'
765 format = 'text'
768
766
769 try:
767 try:
770 from mercurial import lsprof
768 from mercurial import lsprof
771 except ImportError:
769 except ImportError:
772 raise util.Abort(_(
770 raise util.Abort(_(
773 'lsprof not available - install from '
771 'lsprof not available - install from '
774 'http://codespeak.net/svn/user/arigo/hack/misc/lsprof/'))
772 'http://codespeak.net/svn/user/arigo/hack/misc/lsprof/'))
775 p = lsprof.Profiler()
773 p = lsprof.Profiler()
776 p.enable(subcalls=True)
774 p.enable(subcalls=True)
777 try:
775 try:
778 return func()
776 return func()
779 finally:
777 finally:
780 p.disable()
778 p.disable()
781
779
782 if format == 'kcachegrind':
780 if format == 'kcachegrind':
783 import lsprofcalltree
781 import lsprofcalltree
784 calltree = lsprofcalltree.KCacheGrind(p)
782 calltree = lsprofcalltree.KCacheGrind(p)
785 calltree.output(fp)
783 calltree.output(fp)
786 else:
784 else:
787 # format == 'text'
785 # format == 'text'
788 stats = lsprof.Stats(p.getstats())
786 stats = lsprof.Stats(p.getstats())
789 stats.sort(field)
787 stats.sort(field)
790 stats.pprint(limit=limit, file=fp, climit=climit)
788 stats.pprint(limit=limit, file=fp, climit=climit)
791
789
792 def statprofile(ui, func, fp):
790 def statprofile(ui, func, fp):
793 try:
791 try:
794 import statprof
792 import statprof
795 except ImportError:
793 except ImportError:
796 raise util.Abort(_(
794 raise util.Abort(_(
797 'statprof not available - install using "easy_install statprof"'))
795 'statprof not available - install using "easy_install statprof"'))
798
796
799 freq = ui.configint('profiling', 'freq', default=1000)
797 freq = ui.configint('profiling', 'freq', default=1000)
800 if freq > 0:
798 if freq > 0:
801 statprof.reset(freq)
799 statprof.reset(freq)
802 else:
800 else:
803 ui.warn(_("invalid sampling frequency '%s' - ignoring\n") % freq)
801 ui.warn(_("invalid sampling frequency '%s' - ignoring\n") % freq)
804
802
805 statprof.start()
803 statprof.start()
806 try:
804 try:
807 return func()
805 return func()
808 finally:
806 finally:
809 statprof.stop()
807 statprof.stop()
810 statprof.display(fp)
808 statprof.display(fp)
811
809
812 def _runcommand(ui, options, cmd, cmdfunc):
810 def _runcommand(ui, options, cmd, cmdfunc):
813 def checkargs():
811 def checkargs():
814 try:
812 try:
815 return cmdfunc()
813 return cmdfunc()
816 except error.SignatureError:
814 except error.SignatureError:
817 raise error.CommandError(cmd, _("invalid arguments"))
815 raise error.CommandError(cmd, _("invalid arguments"))
818
816
819 if options['profile']:
817 if options['profile']:
820 profiler = os.getenv('HGPROF')
818 profiler = os.getenv('HGPROF')
821 if profiler is None:
819 if profiler is None:
822 profiler = ui.config('profiling', 'type', default='ls')
820 profiler = ui.config('profiling', 'type', default='ls')
823 if profiler not in ('ls', 'stat'):
821 if profiler not in ('ls', 'stat'):
824 ui.warn(_("unrecognized profiler '%s' - ignored\n") % profiler)
822 ui.warn(_("unrecognized profiler '%s' - ignored\n") % profiler)
825 profiler = 'ls'
823 profiler = 'ls'
826
824
827 output = ui.config('profiling', 'output')
825 output = ui.config('profiling', 'output')
828
826
829 if output:
827 if output:
830 path = ui.expandpath(output)
828 path = ui.expandpath(output)
831 fp = open(path, 'wb')
829 fp = open(path, 'wb')
832 else:
830 else:
833 fp = sys.stderr
831 fp = sys.stderr
834
832
835 try:
833 try:
836 if profiler == 'ls':
834 if profiler == 'ls':
837 return lsprofile(ui, checkargs, fp)
835 return lsprofile(ui, checkargs, fp)
838 else:
836 else:
839 return statprofile(ui, checkargs, fp)
837 return statprofile(ui, checkargs, fp)
840 finally:
838 finally:
841 if output:
839 if output:
842 fp.close()
840 fp.close()
843 else:
841 else:
844 return checkargs()
842 return checkargs()
@@ -1,644 +1,644
1 commit hooks can see env vars
1 commit hooks can see env vars
2
2
3 $ hg init a
3 $ hg init a
4 $ cd a
4 $ cd a
5 $ cat > .hg/hgrc <<EOF
5 $ cat > .hg/hgrc <<EOF
6 > [hooks]
6 > [hooks]
7 > commit = sh -c "HG_LOCAL= HG_TAG= python \"$TESTDIR/printenv.py\" commit"
7 > commit = sh -c "HG_LOCAL= HG_TAG= python \"$TESTDIR/printenv.py\" commit"
8 > commit.b = sh -c "HG_LOCAL= HG_TAG= python \"$TESTDIR/printenv.py\" commit.b"
8 > commit.b = sh -c "HG_LOCAL= HG_TAG= python \"$TESTDIR/printenv.py\" commit.b"
9 > precommit = sh -c "HG_LOCAL= HG_NODE= HG_TAG= python \"$TESTDIR/printenv.py\" precommit"
9 > precommit = sh -c "HG_LOCAL= HG_NODE= HG_TAG= python \"$TESTDIR/printenv.py\" precommit"
10 > pretxncommit = sh -c "HG_LOCAL= HG_TAG= python \"$TESTDIR/printenv.py\" pretxncommit"
10 > pretxncommit = sh -c "HG_LOCAL= HG_TAG= python \"$TESTDIR/printenv.py\" pretxncommit"
11 > pretxncommit.tip = hg -q tip
11 > pretxncommit.tip = hg -q tip
12 > pre-identify = python "$TESTDIR/printenv.py" pre-identify 1
12 > pre-identify = python "$TESTDIR/printenv.py" pre-identify 1
13 > pre-cat = python "$TESTDIR/printenv.py" pre-cat
13 > pre-cat = python "$TESTDIR/printenv.py" pre-cat
14 > post-cat = python "$TESTDIR/printenv.py" post-cat
14 > post-cat = python "$TESTDIR/printenv.py" post-cat
15 > EOF
15 > EOF
16 $ echo a > a
16 $ echo a > a
17 $ hg add a
17 $ hg add a
18 $ hg commit -m a
18 $ hg commit -m a
19 precommit hook: HG_PARENT1=0000000000000000000000000000000000000000
19 precommit hook: HG_PARENT1=0000000000000000000000000000000000000000
20 pretxncommit hook: HG_NODE=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b HG_PARENT1=0000000000000000000000000000000000000000 HG_PENDING=$TESTTMP/a
20 pretxncommit hook: HG_NODE=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b HG_PARENT1=0000000000000000000000000000000000000000 HG_PENDING=$TESTTMP/a
21 0:cb9a9f314b8b
21 0:cb9a9f314b8b
22 commit hook: HG_NODE=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b HG_PARENT1=0000000000000000000000000000000000000000
22 commit hook: HG_NODE=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b HG_PARENT1=0000000000000000000000000000000000000000
23 commit.b hook: HG_NODE=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b HG_PARENT1=0000000000000000000000000000000000000000
23 commit.b hook: HG_NODE=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b HG_PARENT1=0000000000000000000000000000000000000000
24
24
25 $ hg clone . ../b
25 $ hg clone . ../b
26 updating to branch default
26 updating to branch default
27 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
27 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
28 $ cd ../b
28 $ cd ../b
29
29
30 changegroup hooks can see env vars
30 changegroup hooks can see env vars
31
31
32 $ cat > .hg/hgrc <<EOF
32 $ cat > .hg/hgrc <<EOF
33 > [hooks]
33 > [hooks]
34 > prechangegroup = python "$TESTDIR/printenv.py" prechangegroup
34 > prechangegroup = python "$TESTDIR/printenv.py" prechangegroup
35 > changegroup = python "$TESTDIR/printenv.py" changegroup
35 > changegroup = python "$TESTDIR/printenv.py" changegroup
36 > incoming = python "$TESTDIR/printenv.py" incoming
36 > incoming = python "$TESTDIR/printenv.py" incoming
37 > EOF
37 > EOF
38
38
39 pretxncommit and commit hooks can see both parents of merge
39 pretxncommit and commit hooks can see both parents of merge
40
40
41 $ cd ../a
41 $ cd ../a
42 $ echo b >> a
42 $ echo b >> a
43 $ hg commit -m a1 -d "1 0"
43 $ hg commit -m a1 -d "1 0"
44 precommit hook: HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b
44 precommit hook: HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b
45 pretxncommit hook: HG_NODE=ab228980c14deea8b9555d91c9581127383e40fd HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b HG_PENDING=$TESTTMP/a
45 pretxncommit hook: HG_NODE=ab228980c14deea8b9555d91c9581127383e40fd HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b HG_PENDING=$TESTTMP/a
46 1:ab228980c14d
46 1:ab228980c14d
47 commit hook: HG_NODE=ab228980c14deea8b9555d91c9581127383e40fd HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b
47 commit hook: HG_NODE=ab228980c14deea8b9555d91c9581127383e40fd HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b
48 commit.b hook: HG_NODE=ab228980c14deea8b9555d91c9581127383e40fd HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b
48 commit.b hook: HG_NODE=ab228980c14deea8b9555d91c9581127383e40fd HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b
49 $ hg update -C 0
49 $ hg update -C 0
50 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
50 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
51 $ echo b > b
51 $ echo b > b
52 $ hg add b
52 $ hg add b
53 $ hg commit -m b -d '1 0'
53 $ hg commit -m b -d '1 0'
54 precommit hook: HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b
54 precommit hook: HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b
55 pretxncommit hook: HG_NODE=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2 HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b HG_PENDING=$TESTTMP/a
55 pretxncommit hook: HG_NODE=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2 HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b HG_PENDING=$TESTTMP/a
56 2:ee9deb46ab31
56 2:ee9deb46ab31
57 commit hook: HG_NODE=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2 HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b
57 commit hook: HG_NODE=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2 HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b
58 commit.b hook: HG_NODE=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2 HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b
58 commit.b hook: HG_NODE=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2 HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b
59 created new head
59 created new head
60 $ hg merge 1
60 $ hg merge 1
61 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
61 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
62 (branch merge, don't forget to commit)
62 (branch merge, don't forget to commit)
63 $ hg commit -m merge -d '2 0'
63 $ hg commit -m merge -d '2 0'
64 precommit hook: HG_PARENT1=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2 HG_PARENT2=ab228980c14deea8b9555d91c9581127383e40fd
64 precommit hook: HG_PARENT1=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2 HG_PARENT2=ab228980c14deea8b9555d91c9581127383e40fd
65 pretxncommit hook: HG_NODE=07f3376c1e655977439df2a814e3cc14b27abac2 HG_PARENT1=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2 HG_PARENT2=ab228980c14deea8b9555d91c9581127383e40fd HG_PENDING=$TESTTMP/a
65 pretxncommit hook: HG_NODE=07f3376c1e655977439df2a814e3cc14b27abac2 HG_PARENT1=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2 HG_PARENT2=ab228980c14deea8b9555d91c9581127383e40fd HG_PENDING=$TESTTMP/a
66 3:07f3376c1e65
66 3:07f3376c1e65
67 commit hook: HG_NODE=07f3376c1e655977439df2a814e3cc14b27abac2 HG_PARENT1=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2 HG_PARENT2=ab228980c14deea8b9555d91c9581127383e40fd
67 commit hook: HG_NODE=07f3376c1e655977439df2a814e3cc14b27abac2 HG_PARENT1=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2 HG_PARENT2=ab228980c14deea8b9555d91c9581127383e40fd
68 commit.b hook: HG_NODE=07f3376c1e655977439df2a814e3cc14b27abac2 HG_PARENT1=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2 HG_PARENT2=ab228980c14deea8b9555d91c9581127383e40fd
68 commit.b hook: HG_NODE=07f3376c1e655977439df2a814e3cc14b27abac2 HG_PARENT1=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2 HG_PARENT2=ab228980c14deea8b9555d91c9581127383e40fd
69
69
70 test generic hooks
70 test generic hooks
71
71
72 $ hg id
72 $ hg id
73 pre-identify hook: HG_ARGS=id HG_OPTS={'bookmarks': None, 'branch': None, 'id': None, 'insecure': None, 'num': None, 'remotecmd': '', 'rev': '', 'ssh': '', 'tags': None} HG_PATS=[]
73 pre-identify hook: HG_ARGS=id HG_OPTS={'bookmarks': None, 'branch': None, 'id': None, 'insecure': None, 'num': None, 'remotecmd': '', 'rev': '', 'ssh': '', 'tags': None} HG_PATS=[]
74 warning: pre-identify hook exited with status 1
74 abort: pre-identify hook exited with status 1
75 [1]
75 [255]
76 $ hg cat b
76 $ hg cat b
77 pre-cat hook: HG_ARGS=cat b HG_OPTS={'decode': None, 'exclude': [], 'include': [], 'output': '', 'rev': ''} HG_PATS=['b']
77 pre-cat hook: HG_ARGS=cat b HG_OPTS={'decode': None, 'exclude': [], 'include': [], 'output': '', 'rev': ''} HG_PATS=['b']
78 b
78 b
79 post-cat hook: HG_ARGS=cat b HG_OPTS={'decode': None, 'exclude': [], 'include': [], 'output': '', 'rev': ''} HG_PATS=['b'] HG_RESULT=0
79 post-cat hook: HG_ARGS=cat b HG_OPTS={'decode': None, 'exclude': [], 'include': [], 'output': '', 'rev': ''} HG_PATS=['b'] HG_RESULT=0
80
80
81 $ cd ../b
81 $ cd ../b
82 $ hg pull ../a
82 $ hg pull ../a
83 pulling from ../a
83 pulling from ../a
84 searching for changes
84 searching for changes
85 prechangegroup hook: HG_SOURCE=pull HG_URL=file:$TESTTMP/a
85 prechangegroup hook: HG_SOURCE=pull HG_URL=file:$TESTTMP/a
86 adding changesets
86 adding changesets
87 adding manifests
87 adding manifests
88 adding file changes
88 adding file changes
89 added 3 changesets with 2 changes to 2 files
89 added 3 changesets with 2 changes to 2 files
90 changegroup hook: HG_NODE=ab228980c14deea8b9555d91c9581127383e40fd HG_SOURCE=pull HG_URL=file:$TESTTMP/a
90 changegroup hook: HG_NODE=ab228980c14deea8b9555d91c9581127383e40fd HG_SOURCE=pull HG_URL=file:$TESTTMP/a
91 incoming hook: HG_NODE=ab228980c14deea8b9555d91c9581127383e40fd HG_SOURCE=pull HG_URL=file:$TESTTMP/a
91 incoming hook: HG_NODE=ab228980c14deea8b9555d91c9581127383e40fd HG_SOURCE=pull HG_URL=file:$TESTTMP/a
92 incoming hook: HG_NODE=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2 HG_SOURCE=pull HG_URL=file:$TESTTMP/a
92 incoming hook: HG_NODE=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2 HG_SOURCE=pull HG_URL=file:$TESTTMP/a
93 incoming hook: HG_NODE=07f3376c1e655977439df2a814e3cc14b27abac2 HG_SOURCE=pull HG_URL=file:$TESTTMP/a
93 incoming hook: HG_NODE=07f3376c1e655977439df2a814e3cc14b27abac2 HG_SOURCE=pull HG_URL=file:$TESTTMP/a
94 (run 'hg update' to get a working copy)
94 (run 'hg update' to get a working copy)
95
95
96 tag hooks can see env vars
96 tag hooks can see env vars
97
97
98 $ cd ../a
98 $ cd ../a
99 $ cat >> .hg/hgrc <<EOF
99 $ cat >> .hg/hgrc <<EOF
100 > pretag = python "$TESTDIR/printenv.py" pretag
100 > pretag = python "$TESTDIR/printenv.py" pretag
101 > tag = sh -c "HG_PARENT1= HG_PARENT2= python \"$TESTDIR/printenv.py\" tag"
101 > tag = sh -c "HG_PARENT1= HG_PARENT2= python \"$TESTDIR/printenv.py\" tag"
102 > EOF
102 > EOF
103 $ hg tag -d '3 0' a
103 $ hg tag -d '3 0' a
104 pretag hook: HG_LOCAL=0 HG_NODE=07f3376c1e655977439df2a814e3cc14b27abac2 HG_TAG=a
104 pretag hook: HG_LOCAL=0 HG_NODE=07f3376c1e655977439df2a814e3cc14b27abac2 HG_TAG=a
105 precommit hook: HG_PARENT1=07f3376c1e655977439df2a814e3cc14b27abac2
105 precommit hook: HG_PARENT1=07f3376c1e655977439df2a814e3cc14b27abac2
106 pretxncommit hook: HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_PARENT1=07f3376c1e655977439df2a814e3cc14b27abac2 HG_PENDING=$TESTTMP/a
106 pretxncommit hook: HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_PARENT1=07f3376c1e655977439df2a814e3cc14b27abac2 HG_PENDING=$TESTTMP/a
107 4:539e4b31b6dc
107 4:539e4b31b6dc
108 tag hook: HG_LOCAL=0 HG_NODE=07f3376c1e655977439df2a814e3cc14b27abac2 HG_TAG=a
108 tag hook: HG_LOCAL=0 HG_NODE=07f3376c1e655977439df2a814e3cc14b27abac2 HG_TAG=a
109 commit hook: HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_PARENT1=07f3376c1e655977439df2a814e3cc14b27abac2
109 commit hook: HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_PARENT1=07f3376c1e655977439df2a814e3cc14b27abac2
110 commit.b hook: HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_PARENT1=07f3376c1e655977439df2a814e3cc14b27abac2
110 commit.b hook: HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_PARENT1=07f3376c1e655977439df2a814e3cc14b27abac2
111 $ hg tag -l la
111 $ hg tag -l la
112 pretag hook: HG_LOCAL=1 HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_TAG=la
112 pretag hook: HG_LOCAL=1 HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_TAG=la
113 tag hook: HG_LOCAL=1 HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_TAG=la
113 tag hook: HG_LOCAL=1 HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_TAG=la
114
114
115 pretag hook can forbid tagging
115 pretag hook can forbid tagging
116
116
117 $ echo "pretag.forbid = python \"$TESTDIR/printenv.py\" pretag.forbid 1" >> .hg/hgrc
117 $ echo "pretag.forbid = python \"$TESTDIR/printenv.py\" pretag.forbid 1" >> .hg/hgrc
118 $ hg tag -d '4 0' fa
118 $ hg tag -d '4 0' fa
119 pretag hook: HG_LOCAL=0 HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_TAG=fa
119 pretag hook: HG_LOCAL=0 HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_TAG=fa
120 pretag.forbid hook: HG_LOCAL=0 HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_TAG=fa
120 pretag.forbid hook: HG_LOCAL=0 HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_TAG=fa
121 abort: pretag.forbid hook exited with status 1
121 abort: pretag.forbid hook exited with status 1
122 [255]
122 [255]
123 $ hg tag -l fla
123 $ hg tag -l fla
124 pretag hook: HG_LOCAL=1 HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_TAG=fla
124 pretag hook: HG_LOCAL=1 HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_TAG=fla
125 pretag.forbid hook: HG_LOCAL=1 HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_TAG=fla
125 pretag.forbid hook: HG_LOCAL=1 HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_TAG=fla
126 abort: pretag.forbid hook exited with status 1
126 abort: pretag.forbid hook exited with status 1
127 [255]
127 [255]
128
128
129 pretxncommit hook can see changeset, can roll back txn, changeset no
129 pretxncommit hook can see changeset, can roll back txn, changeset no
130 more there after
130 more there after
131
131
132 $ echo "pretxncommit.forbid0 = hg tip -q" >> .hg/hgrc
132 $ echo "pretxncommit.forbid0 = hg tip -q" >> .hg/hgrc
133 $ echo "pretxncommit.forbid1 = python \"$TESTDIR/printenv.py\" pretxncommit.forbid 1" >> .hg/hgrc
133 $ echo "pretxncommit.forbid1 = python \"$TESTDIR/printenv.py\" pretxncommit.forbid 1" >> .hg/hgrc
134 $ echo z > z
134 $ echo z > z
135 $ hg add z
135 $ hg add z
136 $ hg -q tip
136 $ hg -q tip
137 4:539e4b31b6dc
137 4:539e4b31b6dc
138 $ hg commit -m 'fail' -d '4 0'
138 $ hg commit -m 'fail' -d '4 0'
139 precommit hook: HG_PARENT1=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10
139 precommit hook: HG_PARENT1=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10
140 pretxncommit hook: HG_NODE=6f611f8018c10e827fee6bd2bc807f937e761567 HG_PARENT1=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_PENDING=$TESTTMP/a
140 pretxncommit hook: HG_NODE=6f611f8018c10e827fee6bd2bc807f937e761567 HG_PARENT1=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_PENDING=$TESTTMP/a
141 5:6f611f8018c1
141 5:6f611f8018c1
142 5:6f611f8018c1
142 5:6f611f8018c1
143 pretxncommit.forbid hook: HG_NODE=6f611f8018c10e827fee6bd2bc807f937e761567 HG_PARENT1=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_PENDING=$TESTTMP/a
143 pretxncommit.forbid hook: HG_NODE=6f611f8018c10e827fee6bd2bc807f937e761567 HG_PARENT1=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_PENDING=$TESTTMP/a
144 transaction abort!
144 transaction abort!
145 rollback completed
145 rollback completed
146 abort: pretxncommit.forbid1 hook exited with status 1
146 abort: pretxncommit.forbid1 hook exited with status 1
147 [255]
147 [255]
148 $ hg -q tip
148 $ hg -q tip
149 4:539e4b31b6dc
149 4:539e4b31b6dc
150
150
151 precommit hook can prevent commit
151 precommit hook can prevent commit
152
152
153 $ echo "precommit.forbid = python \"$TESTDIR/printenv.py\" precommit.forbid 1" >> .hg/hgrc
153 $ echo "precommit.forbid = python \"$TESTDIR/printenv.py\" precommit.forbid 1" >> .hg/hgrc
154 $ hg commit -m 'fail' -d '4 0'
154 $ hg commit -m 'fail' -d '4 0'
155 precommit hook: HG_PARENT1=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10
155 precommit hook: HG_PARENT1=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10
156 precommit.forbid hook: HG_PARENT1=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10
156 precommit.forbid hook: HG_PARENT1=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10
157 abort: precommit.forbid hook exited with status 1
157 abort: precommit.forbid hook exited with status 1
158 [255]
158 [255]
159 $ hg -q tip
159 $ hg -q tip
160 4:539e4b31b6dc
160 4:539e4b31b6dc
161
161
162 preupdate hook can prevent update
162 preupdate hook can prevent update
163
163
164 $ echo "preupdate = python \"$TESTDIR/printenv.py\" preupdate" >> .hg/hgrc
164 $ echo "preupdate = python \"$TESTDIR/printenv.py\" preupdate" >> .hg/hgrc
165 $ hg update 1
165 $ hg update 1
166 preupdate hook: HG_PARENT1=ab228980c14d
166 preupdate hook: HG_PARENT1=ab228980c14d
167 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
167 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
168
168
169 update hook
169 update hook
170
170
171 $ echo "update = python \"$TESTDIR/printenv.py\" update" >> .hg/hgrc
171 $ echo "update = python \"$TESTDIR/printenv.py\" update" >> .hg/hgrc
172 $ hg update
172 $ hg update
173 preupdate hook: HG_PARENT1=539e4b31b6dc
173 preupdate hook: HG_PARENT1=539e4b31b6dc
174 update hook: HG_ERROR=0 HG_PARENT1=539e4b31b6dc
174 update hook: HG_ERROR=0 HG_PARENT1=539e4b31b6dc
175 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
175 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
176
176
177 pushkey hook
177 pushkey hook
178
178
179 $ echo "pushkey = python \"$TESTDIR/printenv.py\" pushkey" >> .hg/hgrc
179 $ echo "pushkey = python \"$TESTDIR/printenv.py\" pushkey" >> .hg/hgrc
180 $ cd ../b
180 $ cd ../b
181 $ hg bookmark -r null foo
181 $ hg bookmark -r null foo
182 $ hg push -B foo ../a
182 $ hg push -B foo ../a
183 pushing to ../a
183 pushing to ../a
184 searching for changes
184 searching for changes
185 no changes found
185 no changes found
186 exporting bookmark foo
186 exporting bookmark foo
187 pushkey hook: HG_KEY=foo HG_NAMESPACE=bookmarks HG_NEW=0000000000000000000000000000000000000000 HG_RET=1
187 pushkey hook: HG_KEY=foo HG_NAMESPACE=bookmarks HG_NEW=0000000000000000000000000000000000000000 HG_RET=1
188 [1]
188 [1]
189 $ cd ../a
189 $ cd ../a
190
190
191 listkeys hook
191 listkeys hook
192
192
193 $ echo "listkeys = python \"$TESTDIR/printenv.py\" listkeys" >> .hg/hgrc
193 $ echo "listkeys = python \"$TESTDIR/printenv.py\" listkeys" >> .hg/hgrc
194 $ hg bookmark -r null bar
194 $ hg bookmark -r null bar
195 $ cd ../b
195 $ cd ../b
196 $ hg pull -B bar ../a
196 $ hg pull -B bar ../a
197 pulling from ../a
197 pulling from ../a
198 listkeys hook: HG_NAMESPACE=bookmarks HG_VALUES={'bar': '0000000000000000000000000000000000000000', 'foo': '0000000000000000000000000000000000000000'}
198 listkeys hook: HG_NAMESPACE=bookmarks HG_VALUES={'bar': '0000000000000000000000000000000000000000', 'foo': '0000000000000000000000000000000000000000'}
199 no changes found
199 no changes found
200 listkeys hook: HG_NAMESPACE=phases HG_VALUES={'cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b': '1', 'publishing': 'True'}
200 listkeys hook: HG_NAMESPACE=phases HG_VALUES={'cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b': '1', 'publishing': 'True'}
201 adding remote bookmark bar
201 adding remote bookmark bar
202 importing bookmark bar
202 importing bookmark bar
203 $ cd ../a
203 $ cd ../a
204
204
205 test that prepushkey can prevent incoming keys
205 test that prepushkey can prevent incoming keys
206
206
207 $ echo "prepushkey = python \"$TESTDIR/printenv.py\" prepushkey.forbid 1" >> .hg/hgrc
207 $ echo "prepushkey = python \"$TESTDIR/printenv.py\" prepushkey.forbid 1" >> .hg/hgrc
208 $ cd ../b
208 $ cd ../b
209 $ hg bookmark -r null baz
209 $ hg bookmark -r null baz
210 $ hg push -B baz ../a
210 $ hg push -B baz ../a
211 pushing to ../a
211 pushing to ../a
212 searching for changes
212 searching for changes
213 no changes found
213 no changes found
214 listkeys hook: HG_NAMESPACE=phases HG_VALUES={'cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b': '1', 'publishing': 'True'}
214 listkeys hook: HG_NAMESPACE=phases HG_VALUES={'cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b': '1', 'publishing': 'True'}
215 listkeys hook: HG_NAMESPACE=bookmarks HG_VALUES={'bar': '0000000000000000000000000000000000000000', 'foo': '0000000000000000000000000000000000000000'}
215 listkeys hook: HG_NAMESPACE=bookmarks HG_VALUES={'bar': '0000000000000000000000000000000000000000', 'foo': '0000000000000000000000000000000000000000'}
216 listkeys hook: HG_NAMESPACE=bookmarks HG_VALUES={'bar': '0000000000000000000000000000000000000000', 'foo': '0000000000000000000000000000000000000000'}
216 listkeys hook: HG_NAMESPACE=bookmarks HG_VALUES={'bar': '0000000000000000000000000000000000000000', 'foo': '0000000000000000000000000000000000000000'}
217 exporting bookmark baz
217 exporting bookmark baz
218 prepushkey.forbid hook: HG_KEY=baz HG_NAMESPACE=bookmarks HG_NEW=0000000000000000000000000000000000000000
218 prepushkey.forbid hook: HG_KEY=baz HG_NAMESPACE=bookmarks HG_NEW=0000000000000000000000000000000000000000
219 abort: prepushkey hook exited with status 1
219 abort: prepushkey hook exited with status 1
220 [255]
220 [255]
221 $ cd ../a
221 $ cd ../a
222
222
223 test that prelistkeys can prevent listing keys
223 test that prelistkeys can prevent listing keys
224
224
225 $ echo "prelistkeys = python \"$TESTDIR/printenv.py\" prelistkeys.forbid 1" >> .hg/hgrc
225 $ echo "prelistkeys = python \"$TESTDIR/printenv.py\" prelistkeys.forbid 1" >> .hg/hgrc
226 $ hg bookmark -r null quux
226 $ hg bookmark -r null quux
227 $ cd ../b
227 $ cd ../b
228 $ hg pull -B quux ../a
228 $ hg pull -B quux ../a
229 pulling from ../a
229 pulling from ../a
230 prelistkeys.forbid hook: HG_NAMESPACE=bookmarks
230 prelistkeys.forbid hook: HG_NAMESPACE=bookmarks
231 abort: prelistkeys hook exited with status 1
231 abort: prelistkeys hook exited with status 1
232 [255]
232 [255]
233 $ cd ../a
233 $ cd ../a
234 $ rm .hg/hgrc
234 $ rm .hg/hgrc
235
235
236 prechangegroup hook can prevent incoming changes
236 prechangegroup hook can prevent incoming changes
237
237
238 $ cd ../b
238 $ cd ../b
239 $ hg -q tip
239 $ hg -q tip
240 3:07f3376c1e65
240 3:07f3376c1e65
241 $ cat > .hg/hgrc <<EOF
241 $ cat > .hg/hgrc <<EOF
242 > [hooks]
242 > [hooks]
243 > prechangegroup.forbid = python "$TESTDIR/printenv.py" prechangegroup.forbid 1
243 > prechangegroup.forbid = python "$TESTDIR/printenv.py" prechangegroup.forbid 1
244 > EOF
244 > EOF
245 $ hg pull ../a
245 $ hg pull ../a
246 pulling from ../a
246 pulling from ../a
247 searching for changes
247 searching for changes
248 prechangegroup.forbid hook: HG_SOURCE=pull HG_URL=file:$TESTTMP/a
248 prechangegroup.forbid hook: HG_SOURCE=pull HG_URL=file:$TESTTMP/a
249 abort: prechangegroup.forbid hook exited with status 1
249 abort: prechangegroup.forbid hook exited with status 1
250 [255]
250 [255]
251
251
252 pretxnchangegroup hook can see incoming changes, can roll back txn,
252 pretxnchangegroup hook can see incoming changes, can roll back txn,
253 incoming changes no longer there after
253 incoming changes no longer there after
254
254
255 $ cat > .hg/hgrc <<EOF
255 $ cat > .hg/hgrc <<EOF
256 > [hooks]
256 > [hooks]
257 > pretxnchangegroup.forbid0 = hg tip -q
257 > pretxnchangegroup.forbid0 = hg tip -q
258 > pretxnchangegroup.forbid1 = python "$TESTDIR/printenv.py" pretxnchangegroup.forbid 1
258 > pretxnchangegroup.forbid1 = python "$TESTDIR/printenv.py" pretxnchangegroup.forbid 1
259 > EOF
259 > EOF
260 $ hg pull ../a
260 $ hg pull ../a
261 pulling from ../a
261 pulling from ../a
262 searching for changes
262 searching for changes
263 adding changesets
263 adding changesets
264 adding manifests
264 adding manifests
265 adding file changes
265 adding file changes
266 added 1 changesets with 1 changes to 1 files
266 added 1 changesets with 1 changes to 1 files
267 4:539e4b31b6dc
267 4:539e4b31b6dc
268 pretxnchangegroup.forbid hook: HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_PENDING=$TESTTMP/b HG_SOURCE=pull HG_URL=file:$TESTTMP/a
268 pretxnchangegroup.forbid hook: HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_PENDING=$TESTTMP/b HG_SOURCE=pull HG_URL=file:$TESTTMP/a
269 transaction abort!
269 transaction abort!
270 rollback completed
270 rollback completed
271 abort: pretxnchangegroup.forbid1 hook exited with status 1
271 abort: pretxnchangegroup.forbid1 hook exited with status 1
272 [255]
272 [255]
273 $ hg -q tip
273 $ hg -q tip
274 3:07f3376c1e65
274 3:07f3376c1e65
275
275
276 outgoing hooks can see env vars
276 outgoing hooks can see env vars
277
277
278 $ rm .hg/hgrc
278 $ rm .hg/hgrc
279 $ cat > ../a/.hg/hgrc <<EOF
279 $ cat > ../a/.hg/hgrc <<EOF
280 > [hooks]
280 > [hooks]
281 > preoutgoing = python "$TESTDIR/printenv.py" preoutgoing
281 > preoutgoing = python "$TESTDIR/printenv.py" preoutgoing
282 > outgoing = python "$TESTDIR/printenv.py" outgoing
282 > outgoing = python "$TESTDIR/printenv.py" outgoing
283 > EOF
283 > EOF
284 $ hg pull ../a
284 $ hg pull ../a
285 pulling from ../a
285 pulling from ../a
286 searching for changes
286 searching for changes
287 preoutgoing hook: HG_SOURCE=pull
287 preoutgoing hook: HG_SOURCE=pull
288 adding changesets
288 adding changesets
289 outgoing hook: HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_SOURCE=pull
289 outgoing hook: HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_SOURCE=pull
290 adding manifests
290 adding manifests
291 adding file changes
291 adding file changes
292 added 1 changesets with 1 changes to 1 files
292 added 1 changesets with 1 changes to 1 files
293 adding remote bookmark quux
293 adding remote bookmark quux
294 (run 'hg update' to get a working copy)
294 (run 'hg update' to get a working copy)
295 $ hg rollback
295 $ hg rollback
296 repository tip rolled back to revision 3 (undo pull)
296 repository tip rolled back to revision 3 (undo pull)
297
297
298 preoutgoing hook can prevent outgoing changes
298 preoutgoing hook can prevent outgoing changes
299
299
300 $ echo "preoutgoing.forbid = python \"$TESTDIR/printenv.py\" preoutgoing.forbid 1" >> ../a/.hg/hgrc
300 $ echo "preoutgoing.forbid = python \"$TESTDIR/printenv.py\" preoutgoing.forbid 1" >> ../a/.hg/hgrc
301 $ hg pull ../a
301 $ hg pull ../a
302 pulling from ../a
302 pulling from ../a
303 searching for changes
303 searching for changes
304 preoutgoing hook: HG_SOURCE=pull
304 preoutgoing hook: HG_SOURCE=pull
305 preoutgoing.forbid hook: HG_SOURCE=pull
305 preoutgoing.forbid hook: HG_SOURCE=pull
306 abort: preoutgoing.forbid hook exited with status 1
306 abort: preoutgoing.forbid hook exited with status 1
307 [255]
307 [255]
308
308
309 outgoing hooks work for local clones
309 outgoing hooks work for local clones
310
310
311 $ cd ..
311 $ cd ..
312 $ cat > a/.hg/hgrc <<EOF
312 $ cat > a/.hg/hgrc <<EOF
313 > [hooks]
313 > [hooks]
314 > preoutgoing = python "$TESTDIR/printenv.py" preoutgoing
314 > preoutgoing = python "$TESTDIR/printenv.py" preoutgoing
315 > outgoing = python "$TESTDIR/printenv.py" outgoing
315 > outgoing = python "$TESTDIR/printenv.py" outgoing
316 > EOF
316 > EOF
317 $ hg clone a c
317 $ hg clone a c
318 preoutgoing hook: HG_SOURCE=clone
318 preoutgoing hook: HG_SOURCE=clone
319 outgoing hook: HG_NODE=0000000000000000000000000000000000000000 HG_SOURCE=clone
319 outgoing hook: HG_NODE=0000000000000000000000000000000000000000 HG_SOURCE=clone
320 updating to branch default
320 updating to branch default
321 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
321 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
322 $ rm -rf c
322 $ rm -rf c
323
323
324 preoutgoing hook can prevent outgoing changes for local clones
324 preoutgoing hook can prevent outgoing changes for local clones
325
325
326 $ echo "preoutgoing.forbid = python \"$TESTDIR/printenv.py\" preoutgoing.forbid 1" >> a/.hg/hgrc
326 $ echo "preoutgoing.forbid = python \"$TESTDIR/printenv.py\" preoutgoing.forbid 1" >> a/.hg/hgrc
327 $ hg clone a zzz
327 $ hg clone a zzz
328 preoutgoing hook: HG_SOURCE=clone
328 preoutgoing hook: HG_SOURCE=clone
329 preoutgoing.forbid hook: HG_SOURCE=clone
329 preoutgoing.forbid hook: HG_SOURCE=clone
330 abort: preoutgoing.forbid hook exited with status 1
330 abort: preoutgoing.forbid hook exited with status 1
331 [255]
331 [255]
332
332
333 $ cd "$TESTTMP/b"
333 $ cd "$TESTTMP/b"
334
334
335 $ cat > hooktests.py <<EOF
335 $ cat > hooktests.py <<EOF
336 > from mercurial import util
336 > from mercurial import util
337 >
337 >
338 > uncallable = 0
338 > uncallable = 0
339 >
339 >
340 > def printargs(args):
340 > def printargs(args):
341 > args.pop('ui', None)
341 > args.pop('ui', None)
342 > args.pop('repo', None)
342 > args.pop('repo', None)
343 > a = list(args.items())
343 > a = list(args.items())
344 > a.sort()
344 > a.sort()
345 > print 'hook args:'
345 > print 'hook args:'
346 > for k, v in a:
346 > for k, v in a:
347 > print ' ', k, v
347 > print ' ', k, v
348 >
348 >
349 > def passhook(**args):
349 > def passhook(**args):
350 > printargs(args)
350 > printargs(args)
351 >
351 >
352 > def failhook(**args):
352 > def failhook(**args):
353 > printargs(args)
353 > printargs(args)
354 > return True
354 > return True
355 >
355 >
356 > class LocalException(Exception):
356 > class LocalException(Exception):
357 > pass
357 > pass
358 >
358 >
359 > def raisehook(**args):
359 > def raisehook(**args):
360 > raise LocalException('exception from hook')
360 > raise LocalException('exception from hook')
361 >
361 >
362 > def aborthook(**args):
362 > def aborthook(**args):
363 > raise util.Abort('raise abort from hook')
363 > raise util.Abort('raise abort from hook')
364 >
364 >
365 > def brokenhook(**args):
365 > def brokenhook(**args):
366 > return 1 + {}
366 > return 1 + {}
367 >
367 >
368 > def verbosehook(ui, **args):
368 > def verbosehook(ui, **args):
369 > ui.note('verbose output from hook\n')
369 > ui.note('verbose output from hook\n')
370 >
370 >
371 > def printtags(ui, repo, **args):
371 > def printtags(ui, repo, **args):
372 > print sorted(repo.tags())
372 > print sorted(repo.tags())
373 >
373 >
374 > class container:
374 > class container:
375 > unreachable = 1
375 > unreachable = 1
376 > EOF
376 > EOF
377
377
378 test python hooks
378 test python hooks
379
379
380 #if windows
380 #if windows
381 $ PYTHONPATH="$TESTTMP/b;$PYTHONPATH"
381 $ PYTHONPATH="$TESTTMP/b;$PYTHONPATH"
382 #else
382 #else
383 $ PYTHONPATH="$TESTTMP/b:$PYTHONPATH"
383 $ PYTHONPATH="$TESTTMP/b:$PYTHONPATH"
384 #endif
384 #endif
385 $ export PYTHONPATH
385 $ export PYTHONPATH
386
386
387 $ echo '[hooks]' > ../a/.hg/hgrc
387 $ echo '[hooks]' > ../a/.hg/hgrc
388 $ echo 'preoutgoing.broken = python:hooktests.brokenhook' >> ../a/.hg/hgrc
388 $ echo 'preoutgoing.broken = python:hooktests.brokenhook' >> ../a/.hg/hgrc
389 $ hg pull ../a 2>&1 | grep 'raised an exception'
389 $ hg pull ../a 2>&1 | grep 'raised an exception'
390 error: preoutgoing.broken hook raised an exception: unsupported operand type(s) for +: 'int' and 'dict'
390 error: preoutgoing.broken hook raised an exception: unsupported operand type(s) for +: 'int' and 'dict'
391
391
392 $ echo '[hooks]' > ../a/.hg/hgrc
392 $ echo '[hooks]' > ../a/.hg/hgrc
393 $ echo 'preoutgoing.raise = python:hooktests.raisehook' >> ../a/.hg/hgrc
393 $ echo 'preoutgoing.raise = python:hooktests.raisehook' >> ../a/.hg/hgrc
394 $ hg pull ../a 2>&1 | grep 'raised an exception'
394 $ hg pull ../a 2>&1 | grep 'raised an exception'
395 error: preoutgoing.raise hook raised an exception: exception from hook
395 error: preoutgoing.raise hook raised an exception: exception from hook
396
396
397 $ echo '[hooks]' > ../a/.hg/hgrc
397 $ echo '[hooks]' > ../a/.hg/hgrc
398 $ echo 'preoutgoing.abort = python:hooktests.aborthook' >> ../a/.hg/hgrc
398 $ echo 'preoutgoing.abort = python:hooktests.aborthook' >> ../a/.hg/hgrc
399 $ hg pull ../a
399 $ hg pull ../a
400 pulling from ../a
400 pulling from ../a
401 searching for changes
401 searching for changes
402 error: preoutgoing.abort hook failed: raise abort from hook
402 error: preoutgoing.abort hook failed: raise abort from hook
403 abort: raise abort from hook
403 abort: raise abort from hook
404 [255]
404 [255]
405
405
406 $ echo '[hooks]' > ../a/.hg/hgrc
406 $ echo '[hooks]' > ../a/.hg/hgrc
407 $ echo 'preoutgoing.fail = python:hooktests.failhook' >> ../a/.hg/hgrc
407 $ echo 'preoutgoing.fail = python:hooktests.failhook' >> ../a/.hg/hgrc
408 $ hg pull ../a
408 $ hg pull ../a
409 pulling from ../a
409 pulling from ../a
410 searching for changes
410 searching for changes
411 hook args:
411 hook args:
412 hooktype preoutgoing
412 hooktype preoutgoing
413 source pull
413 source pull
414 abort: preoutgoing.fail hook failed
414 abort: preoutgoing.fail hook failed
415 [255]
415 [255]
416
416
417 $ echo '[hooks]' > ../a/.hg/hgrc
417 $ echo '[hooks]' > ../a/.hg/hgrc
418 $ echo 'preoutgoing.uncallable = python:hooktests.uncallable' >> ../a/.hg/hgrc
418 $ echo 'preoutgoing.uncallable = python:hooktests.uncallable' >> ../a/.hg/hgrc
419 $ hg pull ../a
419 $ hg pull ../a
420 pulling from ../a
420 pulling from ../a
421 searching for changes
421 searching for changes
422 abort: preoutgoing.uncallable hook is invalid ("hooktests.uncallable" is not callable)
422 abort: preoutgoing.uncallable hook is invalid ("hooktests.uncallable" is not callable)
423 [255]
423 [255]
424
424
425 $ echo '[hooks]' > ../a/.hg/hgrc
425 $ echo '[hooks]' > ../a/.hg/hgrc
426 $ echo 'preoutgoing.nohook = python:hooktests.nohook' >> ../a/.hg/hgrc
426 $ echo 'preoutgoing.nohook = python:hooktests.nohook' >> ../a/.hg/hgrc
427 $ hg pull ../a
427 $ hg pull ../a
428 pulling from ../a
428 pulling from ../a
429 searching for changes
429 searching for changes
430 abort: preoutgoing.nohook hook is invalid ("hooktests.nohook" is not defined)
430 abort: preoutgoing.nohook hook is invalid ("hooktests.nohook" is not defined)
431 [255]
431 [255]
432
432
433 $ echo '[hooks]' > ../a/.hg/hgrc
433 $ echo '[hooks]' > ../a/.hg/hgrc
434 $ echo 'preoutgoing.nomodule = python:nomodule' >> ../a/.hg/hgrc
434 $ echo 'preoutgoing.nomodule = python:nomodule' >> ../a/.hg/hgrc
435 $ hg pull ../a
435 $ hg pull ../a
436 pulling from ../a
436 pulling from ../a
437 searching for changes
437 searching for changes
438 abort: preoutgoing.nomodule hook is invalid ("nomodule" not in a module)
438 abort: preoutgoing.nomodule hook is invalid ("nomodule" not in a module)
439 [255]
439 [255]
440
440
441 $ echo '[hooks]' > ../a/.hg/hgrc
441 $ echo '[hooks]' > ../a/.hg/hgrc
442 $ echo 'preoutgoing.badmodule = python:nomodule.nowhere' >> ../a/.hg/hgrc
442 $ echo 'preoutgoing.badmodule = python:nomodule.nowhere' >> ../a/.hg/hgrc
443 $ hg pull ../a
443 $ hg pull ../a
444 pulling from ../a
444 pulling from ../a
445 searching for changes
445 searching for changes
446 abort: preoutgoing.badmodule hook is invalid (import of "nomodule" failed)
446 abort: preoutgoing.badmodule hook is invalid (import of "nomodule" failed)
447 [255]
447 [255]
448
448
449 $ echo '[hooks]' > ../a/.hg/hgrc
449 $ echo '[hooks]' > ../a/.hg/hgrc
450 $ echo 'preoutgoing.unreachable = python:hooktests.container.unreachable' >> ../a/.hg/hgrc
450 $ echo 'preoutgoing.unreachable = python:hooktests.container.unreachable' >> ../a/.hg/hgrc
451 $ hg pull ../a
451 $ hg pull ../a
452 pulling from ../a
452 pulling from ../a
453 searching for changes
453 searching for changes
454 abort: preoutgoing.unreachable hook is invalid (import of "hooktests.container" failed)
454 abort: preoutgoing.unreachable hook is invalid (import of "hooktests.container" failed)
455 [255]
455 [255]
456
456
457 $ echo '[hooks]' > ../a/.hg/hgrc
457 $ echo '[hooks]' > ../a/.hg/hgrc
458 $ echo 'preoutgoing.pass = python:hooktests.passhook' >> ../a/.hg/hgrc
458 $ echo 'preoutgoing.pass = python:hooktests.passhook' >> ../a/.hg/hgrc
459 $ hg pull ../a
459 $ hg pull ../a
460 pulling from ../a
460 pulling from ../a
461 searching for changes
461 searching for changes
462 hook args:
462 hook args:
463 hooktype preoutgoing
463 hooktype preoutgoing
464 source pull
464 source pull
465 adding changesets
465 adding changesets
466 adding manifests
466 adding manifests
467 adding file changes
467 adding file changes
468 added 1 changesets with 1 changes to 1 files
468 added 1 changesets with 1 changes to 1 files
469 adding remote bookmark quux
469 adding remote bookmark quux
470 (run 'hg update' to get a working copy)
470 (run 'hg update' to get a working copy)
471
471
472 make sure --traceback works
472 make sure --traceback works
473
473
474 $ echo '[hooks]' > .hg/hgrc
474 $ echo '[hooks]' > .hg/hgrc
475 $ echo 'commit.abort = python:hooktests.aborthook' >> .hg/hgrc
475 $ echo 'commit.abort = python:hooktests.aborthook' >> .hg/hgrc
476
476
477 $ echo aa > a
477 $ echo aa > a
478 $ hg --traceback commit -d '0 0' -ma 2>&1 | grep '^Traceback'
478 $ hg --traceback commit -d '0 0' -ma 2>&1 | grep '^Traceback'
479 Traceback (most recent call last):
479 Traceback (most recent call last):
480
480
481 $ cd ..
481 $ cd ..
482 $ hg init c
482 $ hg init c
483 $ cd c
483 $ cd c
484
484
485 $ cat > hookext.py <<EOF
485 $ cat > hookext.py <<EOF
486 > def autohook(**args):
486 > def autohook(**args):
487 > print "Automatically installed hook"
487 > print "Automatically installed hook"
488 >
488 >
489 > def reposetup(ui, repo):
489 > def reposetup(ui, repo):
490 > repo.ui.setconfig("hooks", "commit.auto", autohook)
490 > repo.ui.setconfig("hooks", "commit.auto", autohook)
491 > EOF
491 > EOF
492 $ echo '[extensions]' >> .hg/hgrc
492 $ echo '[extensions]' >> .hg/hgrc
493 $ echo 'hookext = hookext.py' >> .hg/hgrc
493 $ echo 'hookext = hookext.py' >> .hg/hgrc
494
494
495 $ touch foo
495 $ touch foo
496 $ hg add foo
496 $ hg add foo
497 $ hg ci -d '0 0' -m 'add foo'
497 $ hg ci -d '0 0' -m 'add foo'
498 Automatically installed hook
498 Automatically installed hook
499 $ echo >> foo
499 $ echo >> foo
500 $ hg ci --debug -d '0 0' -m 'change foo'
500 $ hg ci --debug -d '0 0' -m 'change foo'
501 foo
501 foo
502 calling hook commit.auto: <function autohook at *> (glob)
502 calling hook commit.auto: <function autohook at *> (glob)
503 Automatically installed hook
503 Automatically installed hook
504 committed changeset 1:52998019f6252a2b893452765fcb0a47351a5708
504 committed changeset 1:52998019f6252a2b893452765fcb0a47351a5708
505
505
506 $ hg showconfig hooks
506 $ hg showconfig hooks
507 hooks.commit.auto=<function autohook at *> (glob)
507 hooks.commit.auto=<function autohook at *> (glob)
508
508
509 test python hook configured with python:[file]:[hook] syntax
509 test python hook configured with python:[file]:[hook] syntax
510
510
511 $ cd ..
511 $ cd ..
512 $ mkdir d
512 $ mkdir d
513 $ cd d
513 $ cd d
514 $ hg init repo
514 $ hg init repo
515 $ mkdir hooks
515 $ mkdir hooks
516
516
517 $ cd hooks
517 $ cd hooks
518 $ cat > testhooks.py <<EOF
518 $ cat > testhooks.py <<EOF
519 > def testhook(**args):
519 > def testhook(**args):
520 > print 'hook works'
520 > print 'hook works'
521 > EOF
521 > EOF
522 $ echo '[hooks]' > ../repo/.hg/hgrc
522 $ echo '[hooks]' > ../repo/.hg/hgrc
523 $ echo "pre-commit.test = python:`pwd`/testhooks.py:testhook" >> ../repo/.hg/hgrc
523 $ echo "pre-commit.test = python:`pwd`/testhooks.py:testhook" >> ../repo/.hg/hgrc
524
524
525 $ cd ../repo
525 $ cd ../repo
526 $ hg commit -d '0 0'
526 $ hg commit -d '0 0'
527 hook works
527 hook works
528 nothing changed
528 nothing changed
529 [1]
529 [1]
530
530
531 $ echo '[hooks]' > .hg/hgrc
531 $ echo '[hooks]' > .hg/hgrc
532 $ echo "update.ne = python:`pwd`/nonexistent.py:testhook" >> .hg/hgrc
532 $ echo "update.ne = python:`pwd`/nonexistent.py:testhook" >> .hg/hgrc
533 $ echo "pre-identify.npmd = python:`pwd`/:no_python_module_dir" >> .hg/hgrc
533 $ echo "pre-identify.npmd = python:`pwd`/:no_python_module_dir" >> .hg/hgrc
534
534
535 $ hg up null
535 $ hg up null
536 loading update.ne hook failed:
536 loading update.ne hook failed:
537 abort: No such file or directory: $TESTTMP/d/repo/nonexistent.py
537 abort: No such file or directory: $TESTTMP/d/repo/nonexistent.py
538 [255]
538 [255]
539
539
540 $ hg id
540 $ hg id
541 loading pre-identify.npmd hook failed:
541 loading pre-identify.npmd hook failed:
542 abort: No module named repo!
542 abort: No module named repo!
543 [255]
543 [255]
544
544
545 $ cd ../../b
545 $ cd ../../b
546
546
547 make sure --traceback works on hook import failure
547 make sure --traceback works on hook import failure
548
548
549 $ cat > importfail.py <<EOF
549 $ cat > importfail.py <<EOF
550 > import somebogusmodule
550 > import somebogusmodule
551 > # dereference something in the module to force demandimport to load it
551 > # dereference something in the module to force demandimport to load it
552 > somebogusmodule.whatever
552 > somebogusmodule.whatever
553 > EOF
553 > EOF
554
554
555 $ echo '[hooks]' > .hg/hgrc
555 $ echo '[hooks]' > .hg/hgrc
556 $ echo 'precommit.importfail = python:importfail.whatever' >> .hg/hgrc
556 $ echo 'precommit.importfail = python:importfail.whatever' >> .hg/hgrc
557
557
558 $ echo a >> a
558 $ echo a >> a
559 $ hg --traceback commit -ma 2>&1 | egrep -v '^( +File| [a-zA-Z(])'
559 $ hg --traceback commit -ma 2>&1 | egrep -v '^( +File| [a-zA-Z(])'
560 exception from first failed import attempt:
560 exception from first failed import attempt:
561 Traceback (most recent call last):
561 Traceback (most recent call last):
562 ImportError: No module named somebogusmodule
562 ImportError: No module named somebogusmodule
563 exception from second failed import attempt:
563 exception from second failed import attempt:
564 Traceback (most recent call last):
564 Traceback (most recent call last):
565 ImportError: No module named hgext_importfail
565 ImportError: No module named hgext_importfail
566 Traceback (most recent call last):
566 Traceback (most recent call last):
567 Abort: precommit.importfail hook is invalid (import of "importfail" failed)
567 Abort: precommit.importfail hook is invalid (import of "importfail" failed)
568 abort: precommit.importfail hook is invalid (import of "importfail" failed)
568 abort: precommit.importfail hook is invalid (import of "importfail" failed)
569
569
570 Issue1827: Hooks Update & Commit not completely post operation
570 Issue1827: Hooks Update & Commit not completely post operation
571
571
572 commit and update hooks should run after command completion
572 commit and update hooks should run after command completion
573
573
574 $ echo '[hooks]' > .hg/hgrc
574 $ echo '[hooks]' > .hg/hgrc
575 $ echo 'commit = hg id' >> .hg/hgrc
575 $ echo 'commit = hg id' >> .hg/hgrc
576 $ echo 'update = hg id' >> .hg/hgrc
576 $ echo 'update = hg id' >> .hg/hgrc
577 $ echo bb > a
577 $ echo bb > a
578 $ hg ci -ma
578 $ hg ci -ma
579 223eafe2750c tip
579 223eafe2750c tip
580 $ hg up 0
580 $ hg up 0
581 cb9a9f314b8b
581 cb9a9f314b8b
582 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
582 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
583
583
584 make sure --verbose (and --quiet/--debug etc.) are propagated to the local ui
584 make sure --verbose (and --quiet/--debug etc.) are propagated to the local ui
585 that is passed to pre/post hooks
585 that is passed to pre/post hooks
586
586
587 $ echo '[hooks]' > .hg/hgrc
587 $ echo '[hooks]' > .hg/hgrc
588 $ echo 'pre-identify = python:hooktests.verbosehook' >> .hg/hgrc
588 $ echo 'pre-identify = python:hooktests.verbosehook' >> .hg/hgrc
589 $ hg id
589 $ hg id
590 cb9a9f314b8b
590 cb9a9f314b8b
591 $ hg id --verbose
591 $ hg id --verbose
592 calling hook pre-identify: hooktests.verbosehook
592 calling hook pre-identify: hooktests.verbosehook
593 verbose output from hook
593 verbose output from hook
594 cb9a9f314b8b
594 cb9a9f314b8b
595
595
596 Ensure hooks can be prioritized
596 Ensure hooks can be prioritized
597
597
598 $ echo '[hooks]' > .hg/hgrc
598 $ echo '[hooks]' > .hg/hgrc
599 $ echo 'pre-identify.a = python:hooktests.verbosehook' >> .hg/hgrc
599 $ echo 'pre-identify.a = python:hooktests.verbosehook' >> .hg/hgrc
600 $ echo 'pre-identify.b = python:hooktests.verbosehook' >> .hg/hgrc
600 $ echo 'pre-identify.b = python:hooktests.verbosehook' >> .hg/hgrc
601 $ echo 'priority.pre-identify.b = 1' >> .hg/hgrc
601 $ echo 'priority.pre-identify.b = 1' >> .hg/hgrc
602 $ echo 'pre-identify.c = python:hooktests.verbosehook' >> .hg/hgrc
602 $ echo 'pre-identify.c = python:hooktests.verbosehook' >> .hg/hgrc
603 $ hg id --verbose
603 $ hg id --verbose
604 calling hook pre-identify.b: hooktests.verbosehook
604 calling hook pre-identify.b: hooktests.verbosehook
605 verbose output from hook
605 verbose output from hook
606 calling hook pre-identify.a: hooktests.verbosehook
606 calling hook pre-identify.a: hooktests.verbosehook
607 verbose output from hook
607 verbose output from hook
608 calling hook pre-identify.c: hooktests.verbosehook
608 calling hook pre-identify.c: hooktests.verbosehook
609 verbose output from hook
609 verbose output from hook
610 cb9a9f314b8b
610 cb9a9f314b8b
611
611
612 new tags must be visible in pretxncommit (issue3210)
612 new tags must be visible in pretxncommit (issue3210)
613
613
614 $ echo 'pretxncommit.printtags = python:hooktests.printtags' >> .hg/hgrc
614 $ echo 'pretxncommit.printtags = python:hooktests.printtags' >> .hg/hgrc
615 $ hg tag -f foo
615 $ hg tag -f foo
616 ['a', 'foo', 'tip']
616 ['a', 'foo', 'tip']
617
617
618 new commits must be visible in pretxnchangegroup (issue3428)
618 new commits must be visible in pretxnchangegroup (issue3428)
619
619
620 $ cd ..
620 $ cd ..
621 $ hg init to
621 $ hg init to
622 $ echo '[hooks]' >> to/.hg/hgrc
622 $ echo '[hooks]' >> to/.hg/hgrc
623 $ echo 'pretxnchangegroup = hg --traceback tip' >> to/.hg/hgrc
623 $ echo 'pretxnchangegroup = hg --traceback tip' >> to/.hg/hgrc
624 $ echo a >> to/a
624 $ echo a >> to/a
625 $ hg --cwd to ci -Ama
625 $ hg --cwd to ci -Ama
626 adding a
626 adding a
627 $ hg clone to from
627 $ hg clone to from
628 updating to branch default
628 updating to branch default
629 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
629 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
630 $ echo aa >> from/a
630 $ echo aa >> from/a
631 $ hg --cwd from ci -mb
631 $ hg --cwd from ci -mb
632 $ hg --cwd from push
632 $ hg --cwd from push
633 pushing to $TESTTMP/to (glob)
633 pushing to $TESTTMP/to (glob)
634 searching for changes
634 searching for changes
635 adding changesets
635 adding changesets
636 adding manifests
636 adding manifests
637 adding file changes
637 adding file changes
638 added 1 changesets with 1 changes to 1 files
638 added 1 changesets with 1 changes to 1 files
639 changeset: 1:9836a07b9b9d
639 changeset: 1:9836a07b9b9d
640 tag: tip
640 tag: tip
641 user: test
641 user: test
642 date: Thu Jan 01 00:00:00 1970 +0000
642 date: Thu Jan 01 00:00:00 1970 +0000
643 summary: b
643 summary: b
644
644
General Comments 0
You need to be logged in to leave comments. Login now