##// END OF EJS Templates
hook: raise a separate exception for when loading a hook fails...
Siddharth Agarwal -
r26692:8d1cfd77 default
parent child Browse files
Show More
@@ -1,215 +1,221 b''
1 # error.py - Mercurial exceptions
1 # error.py - Mercurial exceptions
2 #
2 #
3 # Copyright 2005-2008 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005-2008 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 """Mercurial exceptions.
8 """Mercurial exceptions.
9
9
10 This allows us to catch exceptions at higher levels without forcing
10 This allows us to catch exceptions at higher levels without forcing
11 imports.
11 imports.
12 """
12 """
13
13
14 from __future__ import absolute_import
14 from __future__ import absolute_import
15
15
16 # Do not import anything here, please
16 # Do not import anything here, please
17
17
18 class HintException(Exception):
18 class HintException(Exception):
19 def __init__(self, *args, **kw):
19 def __init__(self, *args, **kw):
20 Exception.__init__(self, *args)
20 Exception.__init__(self, *args)
21 self.hint = kw.get('hint')
21 self.hint = kw.get('hint')
22
22
23 class RevlogError(HintException):
23 class RevlogError(HintException):
24 pass
24 pass
25
25
26 class FilteredIndexError(IndexError):
26 class FilteredIndexError(IndexError):
27 pass
27 pass
28
28
29 class LookupError(RevlogError, KeyError):
29 class LookupError(RevlogError, KeyError):
30 def __init__(self, name, index, message):
30 def __init__(self, name, index, message):
31 self.name = name
31 self.name = name
32 self.index = index
32 self.index = index
33 # this can't be called 'message' because at least some installs of
33 # this can't be called 'message' because at least some installs of
34 # Python 2.6+ complain about the 'message' property being deprecated
34 # Python 2.6+ complain about the 'message' property being deprecated
35 self.lookupmessage = message
35 self.lookupmessage = message
36 if isinstance(name, str) and len(name) == 20:
36 if isinstance(name, str) and len(name) == 20:
37 from .node import short
37 from .node import short
38 name = short(name)
38 name = short(name)
39 RevlogError.__init__(self, '%s@%s: %s' % (index, name, message))
39 RevlogError.__init__(self, '%s@%s: %s' % (index, name, message))
40
40
41 def __str__(self):
41 def __str__(self):
42 return RevlogError.__str__(self)
42 return RevlogError.__str__(self)
43
43
44 class FilteredLookupError(LookupError):
44 class FilteredLookupError(LookupError):
45 pass
45 pass
46
46
47 class ManifestLookupError(LookupError):
47 class ManifestLookupError(LookupError):
48 pass
48 pass
49
49
50 class CommandError(Exception):
50 class CommandError(Exception):
51 """Exception raised on errors in parsing the command line."""
51 """Exception raised on errors in parsing the command line."""
52
52
53 class InterventionRequired(Exception):
53 class InterventionRequired(Exception):
54 """Exception raised when a command requires human intervention."""
54 """Exception raised when a command requires human intervention."""
55
55
56 class Abort(HintException):
56 class Abort(HintException):
57 """Raised if a command needs to print an error and exit."""
57 """Raised if a command needs to print an error and exit."""
58 pass
58 pass
59
59
60 class HookLoadError(Abort):
61 """raised when loading a hook fails, aborting an operation
62
63 Exists to allow more specialized catching."""
64 pass
65
60 class HookAbort(Abort):
66 class HookAbort(Abort):
61 """raised when a validation hook fails, aborting an operation
67 """raised when a validation hook fails, aborting an operation
62
68
63 Exists to allow more specialized catching."""
69 Exists to allow more specialized catching."""
64 pass
70 pass
65
71
66 class ConfigError(Abort):
72 class ConfigError(Abort):
67 """Exception raised when parsing config files"""
73 """Exception raised when parsing config files"""
68
74
69 class UpdateAbort(Abort):
75 class UpdateAbort(Abort):
70 """Raised when an update is aborted for destination issue"""
76 """Raised when an update is aborted for destination issue"""
71
77
72 class OutOfBandError(Exception):
78 class OutOfBandError(Exception):
73 """Exception raised when a remote repo reports failure"""
79 """Exception raised when a remote repo reports failure"""
74
80
75 def __init__(self, *args, **kw):
81 def __init__(self, *args, **kw):
76 Exception.__init__(self, *args)
82 Exception.__init__(self, *args)
77 self.hint = kw.get('hint')
83 self.hint = kw.get('hint')
78
84
79 class ParseError(Exception):
85 class ParseError(Exception):
80 """Raised when parsing config files and {rev,file}sets (msg[, pos])"""
86 """Raised when parsing config files and {rev,file}sets (msg[, pos])"""
81
87
82 class UnknownIdentifier(ParseError):
88 class UnknownIdentifier(ParseError):
83 """Exception raised when a {rev,file}set references an unknown identifier"""
89 """Exception raised when a {rev,file}set references an unknown identifier"""
84
90
85 def __init__(self, function, symbols):
91 def __init__(self, function, symbols):
86 from .i18n import _
92 from .i18n import _
87 ParseError.__init__(self, _("unknown identifier: %s") % function)
93 ParseError.__init__(self, _("unknown identifier: %s") % function)
88 self.function = function
94 self.function = function
89 self.symbols = symbols
95 self.symbols = symbols
90
96
91 class RepoError(HintException):
97 class RepoError(HintException):
92 pass
98 pass
93
99
94 class RepoLookupError(RepoError):
100 class RepoLookupError(RepoError):
95 pass
101 pass
96
102
97 class FilteredRepoLookupError(RepoLookupError):
103 class FilteredRepoLookupError(RepoLookupError):
98 pass
104 pass
99
105
100 class CapabilityError(RepoError):
106 class CapabilityError(RepoError):
101 pass
107 pass
102
108
103 class RequirementError(RepoError):
109 class RequirementError(RepoError):
104 """Exception raised if .hg/requires has an unknown entry."""
110 """Exception raised if .hg/requires has an unknown entry."""
105 pass
111 pass
106
112
107 class LockError(IOError):
113 class LockError(IOError):
108 def __init__(self, errno, strerror, filename, desc):
114 def __init__(self, errno, strerror, filename, desc):
109 IOError.__init__(self, errno, strerror, filename)
115 IOError.__init__(self, errno, strerror, filename)
110 self.desc = desc
116 self.desc = desc
111
117
112 class LockHeld(LockError):
118 class LockHeld(LockError):
113 def __init__(self, errno, filename, desc, locker):
119 def __init__(self, errno, filename, desc, locker):
114 LockError.__init__(self, errno, 'Lock held', filename, desc)
120 LockError.__init__(self, errno, 'Lock held', filename, desc)
115 self.locker = locker
121 self.locker = locker
116
122
117 class LockUnavailable(LockError):
123 class LockUnavailable(LockError):
118 pass
124 pass
119
125
120 # LockError is for errors while acquiring the lock -- this is unrelated
126 # LockError is for errors while acquiring the lock -- this is unrelated
121 class LockInheritanceContractViolation(RuntimeError):
127 class LockInheritanceContractViolation(RuntimeError):
122 pass
128 pass
123
129
124 class ResponseError(Exception):
130 class ResponseError(Exception):
125 """Raised to print an error with part of output and exit."""
131 """Raised to print an error with part of output and exit."""
126
132
127 class UnknownCommand(Exception):
133 class UnknownCommand(Exception):
128 """Exception raised if command is not in the command table."""
134 """Exception raised if command is not in the command table."""
129
135
130 class AmbiguousCommand(Exception):
136 class AmbiguousCommand(Exception):
131 """Exception raised if command shortcut matches more than one command."""
137 """Exception raised if command shortcut matches more than one command."""
132
138
133 # derived from KeyboardInterrupt to simplify some breakout code
139 # derived from KeyboardInterrupt to simplify some breakout code
134 class SignalInterrupt(KeyboardInterrupt):
140 class SignalInterrupt(KeyboardInterrupt):
135 """Exception raised on SIGTERM and SIGHUP."""
141 """Exception raised on SIGTERM and SIGHUP."""
136
142
137 class SignatureError(Exception):
143 class SignatureError(Exception):
138 pass
144 pass
139
145
140 class PushRaced(RuntimeError):
146 class PushRaced(RuntimeError):
141 """An exception raised during unbundling that indicate a push race"""
147 """An exception raised during unbundling that indicate a push race"""
142
148
143 # bundle2 related errors
149 # bundle2 related errors
144 class BundleValueError(ValueError):
150 class BundleValueError(ValueError):
145 """error raised when bundle2 cannot be processed"""
151 """error raised when bundle2 cannot be processed"""
146
152
147 class BundleUnknownFeatureError(BundleValueError):
153 class BundleUnknownFeatureError(BundleValueError):
148 def __init__(self, parttype=None, params=(), values=()):
154 def __init__(self, parttype=None, params=(), values=()):
149 self.parttype = parttype
155 self.parttype = parttype
150 self.params = params
156 self.params = params
151 self.values = values
157 self.values = values
152 if self.parttype is None:
158 if self.parttype is None:
153 msg = 'Stream Parameter'
159 msg = 'Stream Parameter'
154 else:
160 else:
155 msg = parttype
161 msg = parttype
156 entries = self.params
162 entries = self.params
157 if self.params and self.values:
163 if self.params and self.values:
158 assert len(self.params) == len(self.values)
164 assert len(self.params) == len(self.values)
159 entries = []
165 entries = []
160 for idx, par in enumerate(self.params):
166 for idx, par in enumerate(self.params):
161 val = self.values[idx]
167 val = self.values[idx]
162 if val is None:
168 if val is None:
163 entries.append(val)
169 entries.append(val)
164 else:
170 else:
165 entries.append("%s=%r" % (par, val))
171 entries.append("%s=%r" % (par, val))
166 if entries:
172 if entries:
167 msg = '%s - %s' % (msg, ', '.join(entries))
173 msg = '%s - %s' % (msg, ', '.join(entries))
168 ValueError.__init__(self, msg)
174 ValueError.__init__(self, msg)
169
175
170 class ReadOnlyPartError(RuntimeError):
176 class ReadOnlyPartError(RuntimeError):
171 """error raised when code tries to alter a part being generated"""
177 """error raised when code tries to alter a part being generated"""
172 pass
178 pass
173
179
174 class PushkeyFailed(Abort):
180 class PushkeyFailed(Abort):
175 """error raised when a pushkey part failed to update a value"""
181 """error raised when a pushkey part failed to update a value"""
176
182
177 def __init__(self, partid, namespace=None, key=None, new=None, old=None,
183 def __init__(self, partid, namespace=None, key=None, new=None, old=None,
178 ret=None):
184 ret=None):
179 self.partid = partid
185 self.partid = partid
180 self.namespace = namespace
186 self.namespace = namespace
181 self.key = key
187 self.key = key
182 self.new = new
188 self.new = new
183 self.old = old
189 self.old = old
184 self.ret = ret
190 self.ret = ret
185 # no i18n expected to be processed into a better message
191 # no i18n expected to be processed into a better message
186 Abort.__init__(self, 'failed to update value for "%s/%s"'
192 Abort.__init__(self, 'failed to update value for "%s/%s"'
187 % (namespace, key))
193 % (namespace, key))
188
194
189 class CensoredNodeError(RevlogError):
195 class CensoredNodeError(RevlogError):
190 """error raised when content verification fails on a censored node
196 """error raised when content verification fails on a censored node
191
197
192 Also contains the tombstone data substituted for the uncensored data.
198 Also contains the tombstone data substituted for the uncensored data.
193 """
199 """
194
200
195 def __init__(self, filename, node, tombstone):
201 def __init__(self, filename, node, tombstone):
196 from .node import short
202 from .node import short
197 RevlogError.__init__(self, '%s:%s' % (filename, short(node)))
203 RevlogError.__init__(self, '%s:%s' % (filename, short(node)))
198 self.tombstone = tombstone
204 self.tombstone = tombstone
199
205
200 class CensoredBaseError(RevlogError):
206 class CensoredBaseError(RevlogError):
201 """error raised when a delta is rejected because its base is censored
207 """error raised when a delta is rejected because its base is censored
202
208
203 A delta based on a censored revision must be formed as single patch
209 A delta based on a censored revision must be formed as single patch
204 operation which replaces the entire base with new content. This ensures
210 operation which replaces the entire base with new content. This ensures
205 the delta may be applied by clones which have not censored the base.
211 the delta may be applied by clones which have not censored the base.
206 """
212 """
207
213
208 class InvalidBundleSpecification(Exception):
214 class InvalidBundleSpecification(Exception):
209 """error raised when a bundle specification is invalid.
215 """error raised when a bundle specification is invalid.
210
216
211 This is used for syntax errors as opposed to support errors.
217 This is used for syntax errors as opposed to support errors.
212 """
218 """
213
219
214 class UnsupportedBundleSpecification(Exception):
220 class UnsupportedBundleSpecification(Exception):
215 """error raised when a bundle specification is not supported."""
221 """error raised when a bundle specification is not supported."""
@@ -1,214 +1,215 b''
1 # hook.py - hook support for mercurial
1 # hook.py - hook support for mercurial
2 #
2 #
3 # Copyright 2007 Matt Mackall <mpm@selenic.com>
3 # Copyright 2007 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 from __future__ import absolute_import
8 from __future__ import absolute_import
9
9
10 import os
10 import os
11 import sys
11 import sys
12 import time
12 import time
13
13
14 from .i18n import _
14 from .i18n import _
15 from . import (
15 from . import (
16 demandimport,
16 demandimport,
17 error,
17 error,
18 extensions,
18 extensions,
19 util,
19 util,
20 )
20 )
21
21
22 def _pythonhook(ui, repo, name, hname, funcname, args, throw):
22 def _pythonhook(ui, repo, name, hname, funcname, args, throw):
23 '''call python hook. hook is callable object, looked up as
23 '''call python hook. hook is callable object, looked up as
24 name in python module. if callable returns "true", hook
24 name in python module. if callable returns "true", hook
25 fails, else passes. if hook raises exception, treated as
25 fails, else passes. if hook raises exception, treated as
26 hook failure. exception propagates if throw is "true".
26 hook failure. exception propagates if throw is "true".
27
27
28 reason for "true" meaning "hook failed" is so that
28 reason for "true" meaning "hook failed" is so that
29 unmodified commands (e.g. mercurial.commands.update) can
29 unmodified commands (e.g. mercurial.commands.update) can
30 be run as hooks without wrappers to convert return values.'''
30 be run as hooks without wrappers to convert return values.'''
31
31
32 if callable(funcname):
32 if callable(funcname):
33 obj = funcname
33 obj = funcname
34 funcname = obj.__module__ + "." + obj.__name__
34 funcname = obj.__module__ + "." + obj.__name__
35 else:
35 else:
36 d = funcname.rfind('.')
36 d = funcname.rfind('.')
37 if d == -1:
37 if d == -1:
38 raise error.Abort(_('%s hook is invalid ("%s" not in '
38 raise error.HookLoadError(
39 'a module)') % (hname, funcname))
39 _('%s hook is invalid ("%s" not in a module)')
40 % (hname, funcname))
40 modname = funcname[:d]
41 modname = funcname[:d]
41 oldpaths = sys.path
42 oldpaths = sys.path
42 if util.mainfrozen():
43 if util.mainfrozen():
43 # binary installs require sys.path manipulation
44 # binary installs require sys.path manipulation
44 modpath, modfile = os.path.split(modname)
45 modpath, modfile = os.path.split(modname)
45 if modpath and modfile:
46 if modpath and modfile:
46 sys.path = sys.path[:] + [modpath]
47 sys.path = sys.path[:] + [modpath]
47 modname = modfile
48 modname = modfile
48 with demandimport.deactivated():
49 with demandimport.deactivated():
49 try:
50 try:
50 obj = __import__(modname)
51 obj = __import__(modname)
51 except ImportError:
52 except ImportError:
52 e1 = sys.exc_type, sys.exc_value, sys.exc_traceback
53 e1 = sys.exc_type, sys.exc_value, sys.exc_traceback
53 try:
54 try:
54 # extensions are loaded with hgext_ prefix
55 # extensions are loaded with hgext_ prefix
55 obj = __import__("hgext_%s" % modname)
56 obj = __import__("hgext_%s" % modname)
56 except ImportError:
57 except ImportError:
57 e2 = sys.exc_type, sys.exc_value, sys.exc_traceback
58 e2 = sys.exc_type, sys.exc_value, sys.exc_traceback
58 if ui.tracebackflag:
59 if ui.tracebackflag:
59 ui.warn(_('exception from first failed import '
60 ui.warn(_('exception from first failed import '
60 'attempt:\n'))
61 'attempt:\n'))
61 ui.traceback(e1)
62 ui.traceback(e1)
62 if ui.tracebackflag:
63 if ui.tracebackflag:
63 ui.warn(_('exception from second failed import '
64 ui.warn(_('exception from second failed import '
64 'attempt:\n'))
65 'attempt:\n'))
65 ui.traceback(e2)
66 ui.traceback(e2)
66 raise error.Abort(_('%s hook is invalid '
67 raise error.HookLoadError(
67 '(import of "%s" failed)') %
68 _('%s hook is invalid (import of "%s" failed)') %
68 (hname, modname))
69 (hname, modname))
69 sys.path = oldpaths
70 sys.path = oldpaths
70 try:
71 try:
71 for p in funcname.split('.')[1:]:
72 for p in funcname.split('.')[1:]:
72 obj = getattr(obj, p)
73 obj = getattr(obj, p)
73 except AttributeError:
74 except AttributeError:
74 raise error.Abort(_('%s hook is invalid '
75 raise error.HookLoadError(
75 '("%s" is not defined)') %
76 _('%s hook is invalid ("%s" is not defined)')
76 (hname, funcname))
77 % (hname, funcname))
77 if not callable(obj):
78 if not callable(obj):
78 raise error.Abort(_('%s hook is invalid '
79 raise error.HookLoadError(
79 '("%s" is not callable)') %
80 _('%s hook is invalid ("%s" is not callable)')
80 (hname, funcname))
81 % (hname, funcname))
81
82
82 ui.note(_("calling hook %s: %s\n") % (hname, funcname))
83 ui.note(_("calling hook %s: %s\n") % (hname, funcname))
83 starttime = time.time()
84 starttime = time.time()
84
85
85 try:
86 try:
86 # redirect IO descriptors to the ui descriptors so hooks
87 # redirect IO descriptors to the ui descriptors so hooks
87 # that write directly to these don't mess up the command
88 # that write directly to these don't mess up the command
88 # protocol when running through the command server
89 # protocol when running through the command server
89 old = sys.stdout, sys.stderr, sys.stdin
90 old = sys.stdout, sys.stderr, sys.stdin
90 sys.stdout, sys.stderr, sys.stdin = ui.fout, ui.ferr, ui.fin
91 sys.stdout, sys.stderr, sys.stdin = ui.fout, ui.ferr, ui.fin
91
92
92 r = obj(ui=ui, repo=repo, hooktype=name, **args)
93 r = obj(ui=ui, repo=repo, hooktype=name, **args)
93 except Exception as exc:
94 except Exception as exc:
94 if isinstance(exc, error.Abort):
95 if isinstance(exc, error.Abort):
95 ui.warn(_('error: %s hook failed: %s\n') %
96 ui.warn(_('error: %s hook failed: %s\n') %
96 (hname, exc.args[0]))
97 (hname, exc.args[0]))
97 else:
98 else:
98 ui.warn(_('error: %s hook raised an exception: '
99 ui.warn(_('error: %s hook raised an exception: '
99 '%s\n') % (hname, exc))
100 '%s\n') % (hname, exc))
100 if throw:
101 if throw:
101 raise
102 raise
102 ui.traceback()
103 ui.traceback()
103 return True
104 return True
104 finally:
105 finally:
105 sys.stdout, sys.stderr, sys.stdin = old
106 sys.stdout, sys.stderr, sys.stdin = old
106 duration = time.time() - starttime
107 duration = time.time() - starttime
107 ui.log('pythonhook', 'pythonhook-%s: %s finished in %0.2f seconds\n',
108 ui.log('pythonhook', 'pythonhook-%s: %s finished in %0.2f seconds\n',
108 name, funcname, duration)
109 name, funcname, duration)
109 if r:
110 if r:
110 if throw:
111 if throw:
111 raise error.HookAbort(_('%s hook failed') % hname)
112 raise error.HookAbort(_('%s hook failed') % hname)
112 ui.warn(_('warning: %s hook failed\n') % hname)
113 ui.warn(_('warning: %s hook failed\n') % hname)
113 return r
114 return r
114
115
115 def _exthook(ui, repo, name, cmd, args, throw):
116 def _exthook(ui, repo, name, cmd, args, throw):
116 ui.note(_("running hook %s: %s\n") % (name, cmd))
117 ui.note(_("running hook %s: %s\n") % (name, cmd))
117
118
118 starttime = time.time()
119 starttime = time.time()
119 env = {}
120 env = {}
120 for k, v in args.iteritems():
121 for k, v in args.iteritems():
121 if callable(v):
122 if callable(v):
122 v = v()
123 v = v()
123 if isinstance(v, dict):
124 if isinstance(v, dict):
124 # make the dictionary element order stable across Python
125 # make the dictionary element order stable across Python
125 # implementations
126 # implementations
126 v = ('{' +
127 v = ('{' +
127 ', '.join('%r: %r' % i for i in sorted(v.iteritems())) +
128 ', '.join('%r: %r' % i for i in sorted(v.iteritems())) +
128 '}')
129 '}')
129 env['HG_' + k.upper()] = v
130 env['HG_' + k.upper()] = v
130
131
131 if repo:
132 if repo:
132 cwd = repo.root
133 cwd = repo.root
133 else:
134 else:
134 cwd = os.getcwd()
135 cwd = os.getcwd()
135 r = ui.system(cmd, environ=env, cwd=cwd)
136 r = ui.system(cmd, environ=env, cwd=cwd)
136
137
137 duration = time.time() - starttime
138 duration = time.time() - starttime
138 ui.log('exthook', 'exthook-%s: %s finished in %0.2f seconds\n',
139 ui.log('exthook', 'exthook-%s: %s finished in %0.2f seconds\n',
139 name, cmd, duration)
140 name, cmd, duration)
140 if r:
141 if r:
141 desc, r = util.explainexit(r)
142 desc, r = util.explainexit(r)
142 if throw:
143 if throw:
143 raise error.HookAbort(_('%s hook %s') % (name, desc))
144 raise error.HookAbort(_('%s hook %s') % (name, desc))
144 ui.warn(_('warning: %s hook %s\n') % (name, desc))
145 ui.warn(_('warning: %s hook %s\n') % (name, desc))
145 return r
146 return r
146
147
147 def _allhooks(ui):
148 def _allhooks(ui):
148 hooks = []
149 hooks = []
149 for name, cmd in ui.configitems('hooks'):
150 for name, cmd in ui.configitems('hooks'):
150 if not name.startswith('priority'):
151 if not name.startswith('priority'):
151 priority = ui.configint('hooks', 'priority.%s' % name, 0)
152 priority = ui.configint('hooks', 'priority.%s' % name, 0)
152 hooks.append((-priority, len(hooks), name, cmd))
153 hooks.append((-priority, len(hooks), name, cmd))
153 return [(k, v) for p, o, k, v in sorted(hooks)]
154 return [(k, v) for p, o, k, v in sorted(hooks)]
154
155
155 _redirect = False
156 _redirect = False
156 def redirect(state):
157 def redirect(state):
157 global _redirect
158 global _redirect
158 _redirect = state
159 _redirect = state
159
160
160 def hook(ui, repo, name, throw=False, **args):
161 def hook(ui, repo, name, throw=False, **args):
161 if not ui.callhooks:
162 if not ui.callhooks:
162 return False
163 return False
163
164
164 r = False
165 r = False
165 oldstdout = -1
166 oldstdout = -1
166
167
167 try:
168 try:
168 for hname, cmd in _allhooks(ui):
169 for hname, cmd in _allhooks(ui):
169 if hname.split('.')[0] != name or not cmd:
170 if hname.split('.')[0] != name or not cmd:
170 continue
171 continue
171
172
172 if oldstdout == -1 and _redirect:
173 if oldstdout == -1 and _redirect:
173 try:
174 try:
174 stdoutno = sys.__stdout__.fileno()
175 stdoutno = sys.__stdout__.fileno()
175 stderrno = sys.__stderr__.fileno()
176 stderrno = sys.__stderr__.fileno()
176 # temporarily redirect stdout to stderr, if possible
177 # temporarily redirect stdout to stderr, if possible
177 if stdoutno >= 0 and stderrno >= 0:
178 if stdoutno >= 0 and stderrno >= 0:
178 sys.__stdout__.flush()
179 sys.__stdout__.flush()
179 oldstdout = os.dup(stdoutno)
180 oldstdout = os.dup(stdoutno)
180 os.dup2(stderrno, stdoutno)
181 os.dup2(stderrno, stdoutno)
181 except (OSError, AttributeError):
182 except (OSError, AttributeError):
182 # files seem to be bogus, give up on redirecting (WSGI, etc)
183 # files seem to be bogus, give up on redirecting (WSGI, etc)
183 pass
184 pass
184
185
185 if callable(cmd):
186 if callable(cmd):
186 r = _pythonhook(ui, repo, name, hname, cmd, args, throw) or r
187 r = _pythonhook(ui, repo, name, hname, cmd, args, throw) or r
187 elif cmd.startswith('python:'):
188 elif cmd.startswith('python:'):
188 if cmd.count(':') >= 2:
189 if cmd.count(':') >= 2:
189 path, cmd = cmd[7:].rsplit(':', 1)
190 path, cmd = cmd[7:].rsplit(':', 1)
190 path = util.expandpath(path)
191 path = util.expandpath(path)
191 if repo:
192 if repo:
192 path = os.path.join(repo.root, path)
193 path = os.path.join(repo.root, path)
193 try:
194 try:
194 mod = extensions.loadpath(path, 'hghook.%s' % hname)
195 mod = extensions.loadpath(path, 'hghook.%s' % hname)
195 except Exception:
196 except Exception:
196 ui.write(_("loading %s hook failed:\n") % hname)
197 ui.write(_("loading %s hook failed:\n") % hname)
197 raise
198 raise
198 hookfn = getattr(mod, cmd)
199 hookfn = getattr(mod, cmd)
199 else:
200 else:
200 hookfn = cmd[7:].strip()
201 hookfn = cmd[7:].strip()
201 r = _pythonhook(ui, repo, name, hname, hookfn, args, throw) or r
202 r = _pythonhook(ui, repo, name, hname, hookfn, args, throw) or r
202 else:
203 else:
203 r = _exthook(ui, repo, hname, cmd, args, throw) or r
204 r = _exthook(ui, repo, hname, cmd, args, throw) or r
204
205
205 # The stderr is fully buffered on Windows when connected to a pipe.
206 # The stderr is fully buffered on Windows when connected to a pipe.
206 # A forcible flush is required to make small stderr data in the
207 # A forcible flush is required to make small stderr data in the
207 # remote side available to the client immediately.
208 # remote side available to the client immediately.
208 sys.stderr.flush()
209 sys.stderr.flush()
209 finally:
210 finally:
210 if _redirect and oldstdout >= 0:
211 if _redirect and oldstdout >= 0:
211 os.dup2(oldstdout, stdoutno)
212 os.dup2(oldstdout, stdoutno)
212 os.close(oldstdout)
213 os.close(oldstdout)
213
214
214 return r
215 return r
@@ -1,710 +1,710 b''
1 commit hooks can see env vars
1 commit hooks can see env vars
2 (and post-transaction one are run unlocked)
2 (and post-transaction one are run unlocked)
3
3
4 $ cat << EOF >> $HGRCPATH
4 $ cat << EOF >> $HGRCPATH
5 > [experimental]
5 > [experimental]
6 > # drop me once bundle2 is the default,
6 > # drop me once bundle2 is the default,
7 > # added to get test change early.
7 > # added to get test change early.
8 > bundle2-exp = True
8 > bundle2-exp = True
9 > EOF
9 > EOF
10
10
11 $ cat > $TESTTMP/txnabort.checkargs.py <<EOF
11 $ cat > $TESTTMP/txnabort.checkargs.py <<EOF
12 > def showargs(ui, repo, hooktype, **kwargs):
12 > def showargs(ui, repo, hooktype, **kwargs):
13 > ui.write('%s python hook: %s\n' % (hooktype, ','.join(sorted(kwargs))))
13 > ui.write('%s python hook: %s\n' % (hooktype, ','.join(sorted(kwargs))))
14 > EOF
14 > EOF
15
15
16 $ hg init a
16 $ hg init a
17 $ cd a
17 $ cd a
18 $ cat > .hg/hgrc <<EOF
18 $ cat > .hg/hgrc <<EOF
19 > [hooks]
19 > [hooks]
20 > commit = sh -c "HG_LOCAL= HG_TAG= printenv.py commit"
20 > commit = sh -c "HG_LOCAL= HG_TAG= printenv.py commit"
21 > commit.b = sh -c "HG_LOCAL= HG_TAG= printenv.py commit.b"
21 > commit.b = sh -c "HG_LOCAL= HG_TAG= printenv.py commit.b"
22 > precommit = sh -c "HG_LOCAL= HG_NODE= HG_TAG= printenv.py precommit"
22 > precommit = sh -c "HG_LOCAL= HG_NODE= HG_TAG= printenv.py precommit"
23 > pretxncommit = sh -c "HG_LOCAL= HG_TAG= printenv.py pretxncommit"
23 > pretxncommit = sh -c "HG_LOCAL= HG_TAG= printenv.py pretxncommit"
24 > pretxncommit.tip = hg -q tip
24 > pretxncommit.tip = hg -q tip
25 > pre-identify = printenv.py pre-identify 1
25 > pre-identify = printenv.py pre-identify 1
26 > pre-cat = printenv.py pre-cat
26 > pre-cat = printenv.py pre-cat
27 > post-cat = printenv.py post-cat
27 > post-cat = printenv.py post-cat
28 > pretxnopen = sh -c "HG_LOCAL= HG_TAG= printenv.py pretxnopen"
28 > pretxnopen = sh -c "HG_LOCAL= HG_TAG= printenv.py pretxnopen"
29 > pretxnclose = sh -c "HG_LOCAL= HG_TAG= printenv.py pretxnclose"
29 > pretxnclose = sh -c "HG_LOCAL= HG_TAG= printenv.py pretxnclose"
30 > txnclose = sh -c "HG_LOCAL= HG_TAG= printenv.py txnclose"
30 > txnclose = sh -c "HG_LOCAL= HG_TAG= printenv.py txnclose"
31 > txnabort.0 = python:$TESTTMP/txnabort.checkargs.py:showargs
31 > txnabort.0 = python:$TESTTMP/txnabort.checkargs.py:showargs
32 > txnabort.1 = sh -c "HG_LOCAL= HG_TAG= printenv.py txnabort"
32 > txnabort.1 = sh -c "HG_LOCAL= HG_TAG= printenv.py txnabort"
33 > txnclose.checklock = sh -c "hg debuglock > /dev/null"
33 > txnclose.checklock = sh -c "hg debuglock > /dev/null"
34 > EOF
34 > EOF
35 $ echo a > a
35 $ echo a > a
36 $ hg add a
36 $ hg add a
37 $ hg commit -m a
37 $ hg commit -m a
38 precommit hook: HG_PARENT1=0000000000000000000000000000000000000000
38 precommit hook: HG_PARENT1=0000000000000000000000000000000000000000
39 pretxnopen hook: HG_TXNID=TXN:* HG_TXNNAME=commit (glob)
39 pretxnopen hook: HG_TXNID=TXN:* HG_TXNNAME=commit (glob)
40 pretxncommit hook: HG_NODE=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b HG_PARENT1=0000000000000000000000000000000000000000 HG_PENDING=$TESTTMP/a
40 pretxncommit hook: HG_NODE=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b HG_PARENT1=0000000000000000000000000000000000000000 HG_PENDING=$TESTTMP/a
41 0:cb9a9f314b8b
41 0:cb9a9f314b8b
42 pretxnclose hook: HG_PENDING=$TESTTMP/a HG_PHASES_MOVED=1 HG_TXNID=TXN:* HG_TXNNAME=commit (glob)
42 pretxnclose hook: HG_PENDING=$TESTTMP/a HG_PHASES_MOVED=1 HG_TXNID=TXN:* HG_TXNNAME=commit (glob)
43 txnclose hook: HG_PHASES_MOVED=1 HG_TXNID=TXN:* HG_TXNNAME=commit (glob)
43 txnclose hook: HG_PHASES_MOVED=1 HG_TXNID=TXN:* HG_TXNNAME=commit (glob)
44 commit hook: HG_NODE=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b HG_PARENT1=0000000000000000000000000000000000000000
44 commit hook: HG_NODE=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b HG_PARENT1=0000000000000000000000000000000000000000
45 commit.b hook: HG_NODE=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b HG_PARENT1=0000000000000000000000000000000000000000
45 commit.b hook: HG_NODE=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b HG_PARENT1=0000000000000000000000000000000000000000
46
46
47 $ hg clone . ../b
47 $ hg clone . ../b
48 updating to branch default
48 updating to branch default
49 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
49 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
50 $ cd ../b
50 $ cd ../b
51
51
52 changegroup hooks can see env vars
52 changegroup hooks can see env vars
53
53
54 $ cat > .hg/hgrc <<EOF
54 $ cat > .hg/hgrc <<EOF
55 > [hooks]
55 > [hooks]
56 > prechangegroup = printenv.py prechangegroup
56 > prechangegroup = printenv.py prechangegroup
57 > changegroup = printenv.py changegroup
57 > changegroup = printenv.py changegroup
58 > incoming = printenv.py incoming
58 > incoming = printenv.py incoming
59 > EOF
59 > EOF
60
60
61 pretxncommit and commit hooks can see both parents of merge
61 pretxncommit and commit hooks can see both parents of merge
62
62
63 $ cd ../a
63 $ cd ../a
64 $ echo b >> a
64 $ echo b >> a
65 $ hg commit -m a1 -d "1 0"
65 $ hg commit -m a1 -d "1 0"
66 precommit hook: HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b
66 precommit hook: HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b
67 pretxnopen hook: HG_TXNID=TXN:* HG_TXNNAME=commit (glob)
67 pretxnopen hook: HG_TXNID=TXN:* HG_TXNNAME=commit (glob)
68 pretxncommit hook: HG_NODE=ab228980c14deea8b9555d91c9581127383e40fd HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b HG_PENDING=$TESTTMP/a
68 pretxncommit hook: HG_NODE=ab228980c14deea8b9555d91c9581127383e40fd HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b HG_PENDING=$TESTTMP/a
69 1:ab228980c14d
69 1:ab228980c14d
70 pretxnclose hook: HG_PENDING=$TESTTMP/a HG_TXNID=TXN:* HG_TXNNAME=commit (glob)
70 pretxnclose hook: HG_PENDING=$TESTTMP/a HG_TXNID=TXN:* HG_TXNNAME=commit (glob)
71 txnclose hook: HG_TXNID=TXN:* HG_TXNNAME=commit (glob)
71 txnclose hook: HG_TXNID=TXN:* HG_TXNNAME=commit (glob)
72 commit hook: HG_NODE=ab228980c14deea8b9555d91c9581127383e40fd HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b
72 commit hook: HG_NODE=ab228980c14deea8b9555d91c9581127383e40fd HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b
73 commit.b hook: HG_NODE=ab228980c14deea8b9555d91c9581127383e40fd HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b
73 commit.b hook: HG_NODE=ab228980c14deea8b9555d91c9581127383e40fd HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b
74 $ hg update -C 0
74 $ hg update -C 0
75 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
75 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
76 $ echo b > b
76 $ echo b > b
77 $ hg add b
77 $ hg add b
78 $ hg commit -m b -d '1 0'
78 $ hg commit -m b -d '1 0'
79 precommit hook: HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b
79 precommit hook: HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b
80 pretxnopen hook: HG_TXNID=TXN:* HG_TXNNAME=commit (glob)
80 pretxnopen hook: HG_TXNID=TXN:* HG_TXNNAME=commit (glob)
81 pretxncommit hook: HG_NODE=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2 HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b HG_PENDING=$TESTTMP/a
81 pretxncommit hook: HG_NODE=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2 HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b HG_PENDING=$TESTTMP/a
82 2:ee9deb46ab31
82 2:ee9deb46ab31
83 pretxnclose hook: HG_PENDING=$TESTTMP/a HG_TXNID=TXN:* HG_TXNNAME=commit (glob)
83 pretxnclose hook: HG_PENDING=$TESTTMP/a HG_TXNID=TXN:* HG_TXNNAME=commit (glob)
84 txnclose hook: HG_TXNID=TXN:* HG_TXNNAME=commit (glob)
84 txnclose hook: HG_TXNID=TXN:* HG_TXNNAME=commit (glob)
85 commit hook: HG_NODE=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2 HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b
85 commit hook: HG_NODE=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2 HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b
86 commit.b hook: HG_NODE=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2 HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b
86 commit.b hook: HG_NODE=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2 HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b
87 created new head
87 created new head
88 $ hg merge 1
88 $ hg merge 1
89 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
89 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
90 (branch merge, don't forget to commit)
90 (branch merge, don't forget to commit)
91 $ hg commit -m merge -d '2 0'
91 $ hg commit -m merge -d '2 0'
92 precommit hook: HG_PARENT1=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2 HG_PARENT2=ab228980c14deea8b9555d91c9581127383e40fd
92 precommit hook: HG_PARENT1=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2 HG_PARENT2=ab228980c14deea8b9555d91c9581127383e40fd
93 pretxnopen hook: HG_TXNID=TXN:* HG_TXNNAME=commit (glob)
93 pretxnopen hook: HG_TXNID=TXN:* HG_TXNNAME=commit (glob)
94 pretxncommit hook: HG_NODE=07f3376c1e655977439df2a814e3cc14b27abac2 HG_PARENT1=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2 HG_PARENT2=ab228980c14deea8b9555d91c9581127383e40fd HG_PENDING=$TESTTMP/a
94 pretxncommit hook: HG_NODE=07f3376c1e655977439df2a814e3cc14b27abac2 HG_PARENT1=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2 HG_PARENT2=ab228980c14deea8b9555d91c9581127383e40fd HG_PENDING=$TESTTMP/a
95 3:07f3376c1e65
95 3:07f3376c1e65
96 pretxnclose hook: HG_PENDING=$TESTTMP/a HG_TXNID=TXN:* HG_TXNNAME=commit (glob)
96 pretxnclose hook: HG_PENDING=$TESTTMP/a HG_TXNID=TXN:* HG_TXNNAME=commit (glob)
97 txnclose hook: HG_TXNID=TXN:* HG_TXNNAME=commit (glob)
97 txnclose hook: HG_TXNID=TXN:* HG_TXNNAME=commit (glob)
98 commit hook: HG_NODE=07f3376c1e655977439df2a814e3cc14b27abac2 HG_PARENT1=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2 HG_PARENT2=ab228980c14deea8b9555d91c9581127383e40fd
98 commit hook: HG_NODE=07f3376c1e655977439df2a814e3cc14b27abac2 HG_PARENT1=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2 HG_PARENT2=ab228980c14deea8b9555d91c9581127383e40fd
99 commit.b hook: HG_NODE=07f3376c1e655977439df2a814e3cc14b27abac2 HG_PARENT1=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2 HG_PARENT2=ab228980c14deea8b9555d91c9581127383e40fd
99 commit.b hook: HG_NODE=07f3376c1e655977439df2a814e3cc14b27abac2 HG_PARENT1=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2 HG_PARENT2=ab228980c14deea8b9555d91c9581127383e40fd
100
100
101 test generic hooks
101 test generic hooks
102
102
103 $ hg id
103 $ hg id
104 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=[]
104 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=[]
105 abort: pre-identify hook exited with status 1
105 abort: pre-identify hook exited with status 1
106 [255]
106 [255]
107 $ hg cat b
107 $ hg cat b
108 pre-cat hook: HG_ARGS=cat b HG_OPTS={'decode': None, 'exclude': [], 'include': [], 'output': '', 'rev': ''} HG_PATS=['b']
108 pre-cat hook: HG_ARGS=cat b HG_OPTS={'decode': None, 'exclude': [], 'include': [], 'output': '', 'rev': ''} HG_PATS=['b']
109 b
109 b
110 post-cat hook: HG_ARGS=cat b HG_OPTS={'decode': None, 'exclude': [], 'include': [], 'output': '', 'rev': ''} HG_PATS=['b'] HG_RESULT=0
110 post-cat hook: HG_ARGS=cat b HG_OPTS={'decode': None, 'exclude': [], 'include': [], 'output': '', 'rev': ''} HG_PATS=['b'] HG_RESULT=0
111
111
112 $ cd ../b
112 $ cd ../b
113 $ hg pull ../a
113 $ hg pull ../a
114 pulling from ../a
114 pulling from ../a
115 searching for changes
115 searching for changes
116 prechangegroup hook: HG_SOURCE=pull HG_TXNID=TXN:* HG_URL=file:$TESTTMP/a (glob)
116 prechangegroup hook: HG_SOURCE=pull HG_TXNID=TXN:* HG_URL=file:$TESTTMP/a (glob)
117 adding changesets
117 adding changesets
118 adding manifests
118 adding manifests
119 adding file changes
119 adding file changes
120 added 3 changesets with 2 changes to 2 files
120 added 3 changesets with 2 changes to 2 files
121 changegroup hook: HG_NODE=ab228980c14deea8b9555d91c9581127383e40fd HG_SOURCE=pull HG_TXNID=TXN:* HG_URL=file:$TESTTMP/a (glob)
121 changegroup hook: HG_NODE=ab228980c14deea8b9555d91c9581127383e40fd HG_SOURCE=pull HG_TXNID=TXN:* HG_URL=file:$TESTTMP/a (glob)
122 incoming hook: HG_NODE=ab228980c14deea8b9555d91c9581127383e40fd HG_SOURCE=pull HG_TXNID=TXN:* HG_URL=file:$TESTTMP/a (glob)
122 incoming hook: HG_NODE=ab228980c14deea8b9555d91c9581127383e40fd HG_SOURCE=pull HG_TXNID=TXN:* HG_URL=file:$TESTTMP/a (glob)
123 incoming hook: HG_NODE=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2 HG_SOURCE=pull HG_TXNID=TXN:* HG_URL=file:$TESTTMP/a (glob)
123 incoming hook: HG_NODE=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2 HG_SOURCE=pull HG_TXNID=TXN:* HG_URL=file:$TESTTMP/a (glob)
124 incoming hook: HG_NODE=07f3376c1e655977439df2a814e3cc14b27abac2 HG_SOURCE=pull HG_TXNID=TXN:* HG_URL=file:$TESTTMP/a (glob)
124 incoming hook: HG_NODE=07f3376c1e655977439df2a814e3cc14b27abac2 HG_SOURCE=pull HG_TXNID=TXN:* HG_URL=file:$TESTTMP/a (glob)
125 (run 'hg update' to get a working copy)
125 (run 'hg update' to get a working copy)
126
126
127 tag hooks can see env vars
127 tag hooks can see env vars
128
128
129 $ cd ../a
129 $ cd ../a
130 $ cat >> .hg/hgrc <<EOF
130 $ cat >> .hg/hgrc <<EOF
131 > pretag = printenv.py pretag
131 > pretag = printenv.py pretag
132 > tag = sh -c "HG_PARENT1= HG_PARENT2= printenv.py tag"
132 > tag = sh -c "HG_PARENT1= HG_PARENT2= printenv.py tag"
133 > EOF
133 > EOF
134 $ hg tag -d '3 0' a
134 $ hg tag -d '3 0' a
135 pretag hook: HG_LOCAL=0 HG_NODE=07f3376c1e655977439df2a814e3cc14b27abac2 HG_TAG=a
135 pretag hook: HG_LOCAL=0 HG_NODE=07f3376c1e655977439df2a814e3cc14b27abac2 HG_TAG=a
136 precommit hook: HG_PARENT1=07f3376c1e655977439df2a814e3cc14b27abac2
136 precommit hook: HG_PARENT1=07f3376c1e655977439df2a814e3cc14b27abac2
137 pretxnopen hook: HG_TXNID=TXN:* HG_TXNNAME=commit (glob)
137 pretxnopen hook: HG_TXNID=TXN:* HG_TXNNAME=commit (glob)
138 pretxncommit hook: HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_PARENT1=07f3376c1e655977439df2a814e3cc14b27abac2 HG_PENDING=$TESTTMP/a
138 pretxncommit hook: HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_PARENT1=07f3376c1e655977439df2a814e3cc14b27abac2 HG_PENDING=$TESTTMP/a
139 4:539e4b31b6dc
139 4:539e4b31b6dc
140 pretxnclose hook: HG_PENDING=$TESTTMP/a HG_TXNID=TXN:* HG_TXNNAME=commit (glob)
140 pretxnclose hook: HG_PENDING=$TESTTMP/a HG_TXNID=TXN:* HG_TXNNAME=commit (glob)
141 tag hook: HG_LOCAL=0 HG_NODE=07f3376c1e655977439df2a814e3cc14b27abac2 HG_TAG=a
141 tag hook: HG_LOCAL=0 HG_NODE=07f3376c1e655977439df2a814e3cc14b27abac2 HG_TAG=a
142 txnclose hook: HG_TXNID=TXN:* HG_TXNNAME=commit (glob)
142 txnclose hook: HG_TXNID=TXN:* HG_TXNNAME=commit (glob)
143 commit hook: HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_PARENT1=07f3376c1e655977439df2a814e3cc14b27abac2
143 commit hook: HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_PARENT1=07f3376c1e655977439df2a814e3cc14b27abac2
144 commit.b hook: HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_PARENT1=07f3376c1e655977439df2a814e3cc14b27abac2
144 commit.b hook: HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_PARENT1=07f3376c1e655977439df2a814e3cc14b27abac2
145 $ hg tag -l la
145 $ hg tag -l la
146 pretag hook: HG_LOCAL=1 HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_TAG=la
146 pretag hook: HG_LOCAL=1 HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_TAG=la
147 tag hook: HG_LOCAL=1 HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_TAG=la
147 tag hook: HG_LOCAL=1 HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_TAG=la
148
148
149 pretag hook can forbid tagging
149 pretag hook can forbid tagging
150
150
151 $ echo "pretag.forbid = printenv.py pretag.forbid 1" >> .hg/hgrc
151 $ echo "pretag.forbid = printenv.py pretag.forbid 1" >> .hg/hgrc
152 $ hg tag -d '4 0' fa
152 $ hg tag -d '4 0' fa
153 pretag hook: HG_LOCAL=0 HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_TAG=fa
153 pretag hook: HG_LOCAL=0 HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_TAG=fa
154 pretag.forbid hook: HG_LOCAL=0 HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_TAG=fa
154 pretag.forbid hook: HG_LOCAL=0 HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_TAG=fa
155 abort: pretag.forbid hook exited with status 1
155 abort: pretag.forbid hook exited with status 1
156 [255]
156 [255]
157 $ hg tag -l fla
157 $ hg tag -l fla
158 pretag hook: HG_LOCAL=1 HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_TAG=fla
158 pretag hook: HG_LOCAL=1 HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_TAG=fla
159 pretag.forbid hook: HG_LOCAL=1 HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_TAG=fla
159 pretag.forbid hook: HG_LOCAL=1 HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_TAG=fla
160 abort: pretag.forbid hook exited with status 1
160 abort: pretag.forbid hook exited with status 1
161 [255]
161 [255]
162
162
163 pretxncommit hook can see changeset, can roll back txn, changeset no
163 pretxncommit hook can see changeset, can roll back txn, changeset no
164 more there after
164 more there after
165
165
166 $ echo "pretxncommit.forbid0 = hg tip -q" >> .hg/hgrc
166 $ echo "pretxncommit.forbid0 = hg tip -q" >> .hg/hgrc
167 $ echo "pretxncommit.forbid1 = printenv.py pretxncommit.forbid 1" >> .hg/hgrc
167 $ echo "pretxncommit.forbid1 = printenv.py pretxncommit.forbid 1" >> .hg/hgrc
168 $ echo z > z
168 $ echo z > z
169 $ hg add z
169 $ hg add z
170 $ hg -q tip
170 $ hg -q tip
171 4:539e4b31b6dc
171 4:539e4b31b6dc
172 $ hg commit -m 'fail' -d '4 0'
172 $ hg commit -m 'fail' -d '4 0'
173 precommit hook: HG_PARENT1=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10
173 precommit hook: HG_PARENT1=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10
174 pretxnopen hook: HG_TXNID=TXN:* HG_TXNNAME=commit (glob)
174 pretxnopen hook: HG_TXNID=TXN:* HG_TXNNAME=commit (glob)
175 pretxncommit hook: HG_NODE=6f611f8018c10e827fee6bd2bc807f937e761567 HG_PARENT1=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_PENDING=$TESTTMP/a
175 pretxncommit hook: HG_NODE=6f611f8018c10e827fee6bd2bc807f937e761567 HG_PARENT1=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_PENDING=$TESTTMP/a
176 5:6f611f8018c1
176 5:6f611f8018c1
177 5:6f611f8018c1
177 5:6f611f8018c1
178 pretxncommit.forbid hook: HG_NODE=6f611f8018c10e827fee6bd2bc807f937e761567 HG_PARENT1=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_PENDING=$TESTTMP/a
178 pretxncommit.forbid hook: HG_NODE=6f611f8018c10e827fee6bd2bc807f937e761567 HG_PARENT1=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_PENDING=$TESTTMP/a
179 transaction abort!
179 transaction abort!
180 txnabort python hook: txnid,txnname
180 txnabort python hook: txnid,txnname
181 txnabort hook: HG_TXNID=TXN:* HG_TXNNAME=commit (glob)
181 txnabort hook: HG_TXNID=TXN:* HG_TXNNAME=commit (glob)
182 rollback completed
182 rollback completed
183 abort: pretxncommit.forbid1 hook exited with status 1
183 abort: pretxncommit.forbid1 hook exited with status 1
184 [255]
184 [255]
185 $ hg -q tip
185 $ hg -q tip
186 4:539e4b31b6dc
186 4:539e4b31b6dc
187
187
188 (Check that no 'changelog.i.a' file were left behind)
188 (Check that no 'changelog.i.a' file were left behind)
189
189
190 $ ls -1 .hg/store/
190 $ ls -1 .hg/store/
191 00changelog.i
191 00changelog.i
192 00manifest.i
192 00manifest.i
193 data
193 data
194 fncache
194 fncache
195 journal.phaseroots
195 journal.phaseroots
196 phaseroots
196 phaseroots
197 undo
197 undo
198 undo.backup.fncache
198 undo.backup.fncache
199 undo.backupfiles
199 undo.backupfiles
200 undo.phaseroots
200 undo.phaseroots
201
201
202
202
203 precommit hook can prevent commit
203 precommit hook can prevent commit
204
204
205 $ echo "precommit.forbid = printenv.py precommit.forbid 1" >> .hg/hgrc
205 $ echo "precommit.forbid = printenv.py precommit.forbid 1" >> .hg/hgrc
206 $ hg commit -m 'fail' -d '4 0'
206 $ hg commit -m 'fail' -d '4 0'
207 precommit hook: HG_PARENT1=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10
207 precommit hook: HG_PARENT1=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10
208 precommit.forbid hook: HG_PARENT1=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10
208 precommit.forbid hook: HG_PARENT1=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10
209 abort: precommit.forbid hook exited with status 1
209 abort: precommit.forbid hook exited with status 1
210 [255]
210 [255]
211 $ hg -q tip
211 $ hg -q tip
212 4:539e4b31b6dc
212 4:539e4b31b6dc
213
213
214 preupdate hook can prevent update
214 preupdate hook can prevent update
215
215
216 $ echo "preupdate = printenv.py preupdate" >> .hg/hgrc
216 $ echo "preupdate = printenv.py preupdate" >> .hg/hgrc
217 $ hg update 1
217 $ hg update 1
218 preupdate hook: HG_PARENT1=ab228980c14d
218 preupdate hook: HG_PARENT1=ab228980c14d
219 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
219 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
220
220
221 update hook
221 update hook
222
222
223 $ echo "update = printenv.py update" >> .hg/hgrc
223 $ echo "update = printenv.py update" >> .hg/hgrc
224 $ hg update
224 $ hg update
225 preupdate hook: HG_PARENT1=539e4b31b6dc
225 preupdate hook: HG_PARENT1=539e4b31b6dc
226 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
226 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
227 update hook: HG_ERROR=0 HG_PARENT1=539e4b31b6dc
227 update hook: HG_ERROR=0 HG_PARENT1=539e4b31b6dc
228
228
229 pushkey hook
229 pushkey hook
230
230
231 $ echo "pushkey = printenv.py pushkey" >> .hg/hgrc
231 $ echo "pushkey = printenv.py pushkey" >> .hg/hgrc
232 $ cd ../b
232 $ cd ../b
233 $ hg bookmark -r null foo
233 $ hg bookmark -r null foo
234 $ hg push -B foo ../a
234 $ hg push -B foo ../a
235 pushing to ../a
235 pushing to ../a
236 searching for changes
236 searching for changes
237 no changes found
237 no changes found
238 pretxnopen hook: HG_TXNID=TXN:* HG_TXNNAME=push (glob)
238 pretxnopen hook: HG_TXNID=TXN:* HG_TXNNAME=push (glob)
239 pretxnclose hook: HG_BOOKMARK_MOVED=1 HG_BUNDLE2=1 HG_PENDING=$TESTTMP/a HG_SOURCE=push HG_TXNID=TXN:* HG_TXNNAME=push HG_URL=push (glob)
239 pretxnclose hook: HG_BOOKMARK_MOVED=1 HG_BUNDLE2=1 HG_PENDING=$TESTTMP/a HG_SOURCE=push HG_TXNID=TXN:* HG_TXNNAME=push HG_URL=push (glob)
240 pushkey hook: HG_KEY=foo HG_NAMESPACE=bookmarks HG_NEW=0000000000000000000000000000000000000000 HG_RET=1
240 pushkey hook: HG_KEY=foo HG_NAMESPACE=bookmarks HG_NEW=0000000000000000000000000000000000000000 HG_RET=1
241 txnclose hook: HG_BOOKMARK_MOVED=1 HG_BUNDLE2=1 HG_SOURCE=push HG_TXNID=TXN:* HG_TXNNAME=push HG_URL=push (glob)
241 txnclose hook: HG_BOOKMARK_MOVED=1 HG_BUNDLE2=1 HG_SOURCE=push HG_TXNID=TXN:* HG_TXNNAME=push HG_URL=push (glob)
242 exporting bookmark foo
242 exporting bookmark foo
243 [1]
243 [1]
244 $ cd ../a
244 $ cd ../a
245
245
246 listkeys hook
246 listkeys hook
247
247
248 $ echo "listkeys = printenv.py listkeys" >> .hg/hgrc
248 $ echo "listkeys = printenv.py listkeys" >> .hg/hgrc
249 $ hg bookmark -r null bar
249 $ hg bookmark -r null bar
250 pretxnopen hook: HG_TXNID=TXN:* HG_TXNNAME=bookmark (glob)
250 pretxnopen hook: HG_TXNID=TXN:* HG_TXNNAME=bookmark (glob)
251 pretxnclose hook: HG_BOOKMARK_MOVED=1 HG_PENDING=$TESTTMP/a HG_TXNID=TXN:* HG_TXNNAME=bookmark (glob)
251 pretxnclose hook: HG_BOOKMARK_MOVED=1 HG_PENDING=$TESTTMP/a HG_TXNID=TXN:* HG_TXNNAME=bookmark (glob)
252 txnclose hook: HG_BOOKMARK_MOVED=1 HG_TXNID=TXN:* HG_TXNNAME=bookmark (glob)
252 txnclose hook: HG_BOOKMARK_MOVED=1 HG_TXNID=TXN:* HG_TXNNAME=bookmark (glob)
253 $ cd ../b
253 $ cd ../b
254 $ hg pull -B bar ../a
254 $ hg pull -B bar ../a
255 pulling from ../a
255 pulling from ../a
256 listkeys hook: HG_NAMESPACE=bookmarks HG_VALUES={'bar': '0000000000000000000000000000000000000000', 'foo': '0000000000000000000000000000000000000000'}
256 listkeys hook: HG_NAMESPACE=bookmarks HG_VALUES={'bar': '0000000000000000000000000000000000000000', 'foo': '0000000000000000000000000000000000000000'}
257 no changes found
257 no changes found
258 listkeys hook: HG_NAMESPACE=phase HG_VALUES={}
258 listkeys hook: HG_NAMESPACE=phase HG_VALUES={}
259 adding remote bookmark bar
259 adding remote bookmark bar
260 listkeys hook: HG_NAMESPACE=phases HG_VALUES={'cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b': '1', 'publishing': 'True'}
260 listkeys hook: HG_NAMESPACE=phases HG_VALUES={'cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b': '1', 'publishing': 'True'}
261 $ cd ../a
261 $ cd ../a
262
262
263 test that prepushkey can prevent incoming keys
263 test that prepushkey can prevent incoming keys
264
264
265 $ echo "prepushkey = printenv.py prepushkey.forbid 1" >> .hg/hgrc
265 $ echo "prepushkey = printenv.py prepushkey.forbid 1" >> .hg/hgrc
266 $ cd ../b
266 $ cd ../b
267 $ hg bookmark -r null baz
267 $ hg bookmark -r null baz
268 $ hg push -B baz ../a
268 $ hg push -B baz ../a
269 pushing to ../a
269 pushing to ../a
270 searching for changes
270 searching for changes
271 listkeys hook: HG_NAMESPACE=phases HG_VALUES={'cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b': '1', 'publishing': 'True'}
271 listkeys hook: HG_NAMESPACE=phases HG_VALUES={'cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b': '1', 'publishing': 'True'}
272 listkeys hook: HG_NAMESPACE=bookmarks HG_VALUES={'bar': '0000000000000000000000000000000000000000', 'foo': '0000000000000000000000000000000000000000'}
272 listkeys hook: HG_NAMESPACE=bookmarks HG_VALUES={'bar': '0000000000000000000000000000000000000000', 'foo': '0000000000000000000000000000000000000000'}
273 no changes found
273 no changes found
274 pretxnopen hook: HG_TXNID=TXN:* HG_TXNNAME=push (glob)
274 pretxnopen hook: HG_TXNID=TXN:* HG_TXNNAME=push (glob)
275 prepushkey.forbid hook: HG_BUNDLE2=1 HG_KEY=baz HG_NAMESPACE=bookmarks HG_NEW=0000000000000000000000000000000000000000 HG_SOURCE=push HG_TXNID=TXN:* HG_URL=push (glob)
275 prepushkey.forbid hook: HG_BUNDLE2=1 HG_KEY=baz HG_NAMESPACE=bookmarks HG_NEW=0000000000000000000000000000000000000000 HG_SOURCE=push HG_TXNID=TXN:* HG_URL=push (glob)
276 pushkey-abort: prepushkey hook exited with status 1
276 pushkey-abort: prepushkey hook exited with status 1
277 abort: exporting bookmark baz failed!
277 abort: exporting bookmark baz failed!
278 [255]
278 [255]
279 $ cd ../a
279 $ cd ../a
280
280
281 test that prelistkeys can prevent listing keys
281 test that prelistkeys can prevent listing keys
282
282
283 $ echo "prelistkeys = printenv.py prelistkeys.forbid 1" >> .hg/hgrc
283 $ echo "prelistkeys = printenv.py prelistkeys.forbid 1" >> .hg/hgrc
284 $ hg bookmark -r null quux
284 $ hg bookmark -r null quux
285 pretxnopen hook: HG_TXNID=TXN:* HG_TXNNAME=bookmark (glob)
285 pretxnopen hook: HG_TXNID=TXN:* HG_TXNNAME=bookmark (glob)
286 pretxnclose hook: HG_BOOKMARK_MOVED=1 HG_PENDING=$TESTTMP/a HG_TXNID=TXN:* HG_TXNNAME=bookmark (glob)
286 pretxnclose hook: HG_BOOKMARK_MOVED=1 HG_PENDING=$TESTTMP/a HG_TXNID=TXN:* HG_TXNNAME=bookmark (glob)
287 txnclose hook: HG_BOOKMARK_MOVED=1 HG_TXNID=TXN:* HG_TXNNAME=bookmark (glob)
287 txnclose hook: HG_BOOKMARK_MOVED=1 HG_TXNID=TXN:* HG_TXNNAME=bookmark (glob)
288 $ cd ../b
288 $ cd ../b
289 $ hg pull -B quux ../a
289 $ hg pull -B quux ../a
290 pulling from ../a
290 pulling from ../a
291 prelistkeys.forbid hook: HG_NAMESPACE=bookmarks
291 prelistkeys.forbid hook: HG_NAMESPACE=bookmarks
292 abort: prelistkeys hook exited with status 1
292 abort: prelistkeys hook exited with status 1
293 [255]
293 [255]
294 $ cd ../a
294 $ cd ../a
295 $ rm .hg/hgrc
295 $ rm .hg/hgrc
296
296
297 prechangegroup hook can prevent incoming changes
297 prechangegroup hook can prevent incoming changes
298
298
299 $ cd ../b
299 $ cd ../b
300 $ hg -q tip
300 $ hg -q tip
301 3:07f3376c1e65
301 3:07f3376c1e65
302 $ cat > .hg/hgrc <<EOF
302 $ cat > .hg/hgrc <<EOF
303 > [hooks]
303 > [hooks]
304 > prechangegroup.forbid = printenv.py prechangegroup.forbid 1
304 > prechangegroup.forbid = printenv.py prechangegroup.forbid 1
305 > EOF
305 > EOF
306 $ hg pull ../a
306 $ hg pull ../a
307 pulling from ../a
307 pulling from ../a
308 searching for changes
308 searching for changes
309 prechangegroup.forbid hook: HG_SOURCE=pull HG_TXNID=TXN:* HG_URL=file:$TESTTMP/a (glob)
309 prechangegroup.forbid hook: HG_SOURCE=pull HG_TXNID=TXN:* HG_URL=file:$TESTTMP/a (glob)
310 abort: prechangegroup.forbid hook exited with status 1
310 abort: prechangegroup.forbid hook exited with status 1
311 [255]
311 [255]
312
312
313 pretxnchangegroup hook can see incoming changes, can roll back txn,
313 pretxnchangegroup hook can see incoming changes, can roll back txn,
314 incoming changes no longer there after
314 incoming changes no longer there after
315
315
316 $ cat > .hg/hgrc <<EOF
316 $ cat > .hg/hgrc <<EOF
317 > [hooks]
317 > [hooks]
318 > pretxnchangegroup.forbid0 = hg tip -q
318 > pretxnchangegroup.forbid0 = hg tip -q
319 > pretxnchangegroup.forbid1 = printenv.py pretxnchangegroup.forbid 1
319 > pretxnchangegroup.forbid1 = printenv.py pretxnchangegroup.forbid 1
320 > EOF
320 > EOF
321 $ hg pull ../a
321 $ hg pull ../a
322 pulling from ../a
322 pulling from ../a
323 searching for changes
323 searching for changes
324 adding changesets
324 adding changesets
325 adding manifests
325 adding manifests
326 adding file changes
326 adding file changes
327 added 1 changesets with 1 changes to 1 files
327 added 1 changesets with 1 changes to 1 files
328 4:539e4b31b6dc
328 4:539e4b31b6dc
329 pretxnchangegroup.forbid hook: HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_PENDING=$TESTTMP/b HG_SOURCE=pull HG_TXNID=TXN:* HG_URL=file:$TESTTMP/a (glob)
329 pretxnchangegroup.forbid hook: HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_PENDING=$TESTTMP/b HG_SOURCE=pull HG_TXNID=TXN:* HG_URL=file:$TESTTMP/a (glob)
330 transaction abort!
330 transaction abort!
331 rollback completed
331 rollback completed
332 abort: pretxnchangegroup.forbid1 hook exited with status 1
332 abort: pretxnchangegroup.forbid1 hook exited with status 1
333 [255]
333 [255]
334 $ hg -q tip
334 $ hg -q tip
335 3:07f3376c1e65
335 3:07f3376c1e65
336
336
337 outgoing hooks can see env vars
337 outgoing hooks can see env vars
338
338
339 $ rm .hg/hgrc
339 $ rm .hg/hgrc
340 $ cat > ../a/.hg/hgrc <<EOF
340 $ cat > ../a/.hg/hgrc <<EOF
341 > [hooks]
341 > [hooks]
342 > preoutgoing = printenv.py preoutgoing
342 > preoutgoing = printenv.py preoutgoing
343 > outgoing = printenv.py outgoing
343 > outgoing = printenv.py outgoing
344 > EOF
344 > EOF
345 $ hg pull ../a
345 $ hg pull ../a
346 pulling from ../a
346 pulling from ../a
347 searching for changes
347 searching for changes
348 preoutgoing hook: HG_SOURCE=pull
348 preoutgoing hook: HG_SOURCE=pull
349 outgoing hook: HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_SOURCE=pull
349 outgoing hook: HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_SOURCE=pull
350 adding changesets
350 adding changesets
351 adding manifests
351 adding manifests
352 adding file changes
352 adding file changes
353 added 1 changesets with 1 changes to 1 files
353 added 1 changesets with 1 changes to 1 files
354 adding remote bookmark quux
354 adding remote bookmark quux
355 (run 'hg update' to get a working copy)
355 (run 'hg update' to get a working copy)
356 $ hg rollback
356 $ hg rollback
357 repository tip rolled back to revision 3 (undo pull)
357 repository tip rolled back to revision 3 (undo pull)
358
358
359 preoutgoing hook can prevent outgoing changes
359 preoutgoing hook can prevent outgoing changes
360
360
361 $ echo "preoutgoing.forbid = printenv.py preoutgoing.forbid 1" >> ../a/.hg/hgrc
361 $ echo "preoutgoing.forbid = printenv.py preoutgoing.forbid 1" >> ../a/.hg/hgrc
362 $ hg pull ../a
362 $ hg pull ../a
363 pulling from ../a
363 pulling from ../a
364 searching for changes
364 searching for changes
365 preoutgoing hook: HG_SOURCE=pull
365 preoutgoing hook: HG_SOURCE=pull
366 preoutgoing.forbid hook: HG_SOURCE=pull
366 preoutgoing.forbid hook: HG_SOURCE=pull
367 abort: preoutgoing.forbid hook exited with status 1
367 abort: preoutgoing.forbid hook exited with status 1
368 [255]
368 [255]
369
369
370 outgoing hooks work for local clones
370 outgoing hooks work for local clones
371
371
372 $ cd ..
372 $ cd ..
373 $ cat > a/.hg/hgrc <<EOF
373 $ cat > a/.hg/hgrc <<EOF
374 > [hooks]
374 > [hooks]
375 > preoutgoing = printenv.py preoutgoing
375 > preoutgoing = printenv.py preoutgoing
376 > outgoing = printenv.py outgoing
376 > outgoing = printenv.py outgoing
377 > EOF
377 > EOF
378 $ hg clone a c
378 $ hg clone a c
379 preoutgoing hook: HG_SOURCE=clone
379 preoutgoing hook: HG_SOURCE=clone
380 outgoing hook: HG_NODE=0000000000000000000000000000000000000000 HG_SOURCE=clone
380 outgoing hook: HG_NODE=0000000000000000000000000000000000000000 HG_SOURCE=clone
381 updating to branch default
381 updating to branch default
382 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
382 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
383 $ rm -rf c
383 $ rm -rf c
384
384
385 preoutgoing hook can prevent outgoing changes for local clones
385 preoutgoing hook can prevent outgoing changes for local clones
386
386
387 $ echo "preoutgoing.forbid = printenv.py preoutgoing.forbid 1" >> a/.hg/hgrc
387 $ echo "preoutgoing.forbid = printenv.py preoutgoing.forbid 1" >> a/.hg/hgrc
388 $ hg clone a zzz
388 $ hg clone a zzz
389 preoutgoing hook: HG_SOURCE=clone
389 preoutgoing hook: HG_SOURCE=clone
390 preoutgoing.forbid hook: HG_SOURCE=clone
390 preoutgoing.forbid hook: HG_SOURCE=clone
391 abort: preoutgoing.forbid hook exited with status 1
391 abort: preoutgoing.forbid hook exited with status 1
392 [255]
392 [255]
393
393
394 $ cd "$TESTTMP/b"
394 $ cd "$TESTTMP/b"
395
395
396 $ cat > hooktests.py <<EOF
396 $ cat > hooktests.py <<EOF
397 > from mercurial import error
397 > from mercurial import error
398 >
398 >
399 > uncallable = 0
399 > uncallable = 0
400 >
400 >
401 > def printargs(args):
401 > def printargs(args):
402 > args.pop('ui', None)
402 > args.pop('ui', None)
403 > args.pop('repo', None)
403 > args.pop('repo', None)
404 > a = list(args.items())
404 > a = list(args.items())
405 > a.sort()
405 > a.sort()
406 > print 'hook args:'
406 > print 'hook args:'
407 > for k, v in a:
407 > for k, v in a:
408 > print ' ', k, v
408 > print ' ', k, v
409 >
409 >
410 > def passhook(**args):
410 > def passhook(**args):
411 > printargs(args)
411 > printargs(args)
412 >
412 >
413 > def failhook(**args):
413 > def failhook(**args):
414 > printargs(args)
414 > printargs(args)
415 > return True
415 > return True
416 >
416 >
417 > class LocalException(Exception):
417 > class LocalException(Exception):
418 > pass
418 > pass
419 >
419 >
420 > def raisehook(**args):
420 > def raisehook(**args):
421 > raise LocalException('exception from hook')
421 > raise LocalException('exception from hook')
422 >
422 >
423 > def aborthook(**args):
423 > def aborthook(**args):
424 > raise error.Abort('raise abort from hook')
424 > raise error.Abort('raise abort from hook')
425 >
425 >
426 > def brokenhook(**args):
426 > def brokenhook(**args):
427 > return 1 + {}
427 > return 1 + {}
428 >
428 >
429 > def verbosehook(ui, **args):
429 > def verbosehook(ui, **args):
430 > ui.note('verbose output from hook\n')
430 > ui.note('verbose output from hook\n')
431 >
431 >
432 > def printtags(ui, repo, **args):
432 > def printtags(ui, repo, **args):
433 > print sorted(repo.tags())
433 > print sorted(repo.tags())
434 >
434 >
435 > class container:
435 > class container:
436 > unreachable = 1
436 > unreachable = 1
437 > EOF
437 > EOF
438
438
439 test python hooks
439 test python hooks
440
440
441 #if windows
441 #if windows
442 $ PYTHONPATH="$TESTTMP/b;$PYTHONPATH"
442 $ PYTHONPATH="$TESTTMP/b;$PYTHONPATH"
443 #else
443 #else
444 $ PYTHONPATH="$TESTTMP/b:$PYTHONPATH"
444 $ PYTHONPATH="$TESTTMP/b:$PYTHONPATH"
445 #endif
445 #endif
446 $ export PYTHONPATH
446 $ export PYTHONPATH
447
447
448 $ echo '[hooks]' > ../a/.hg/hgrc
448 $ echo '[hooks]' > ../a/.hg/hgrc
449 $ echo 'preoutgoing.broken = python:hooktests.brokenhook' >> ../a/.hg/hgrc
449 $ echo 'preoutgoing.broken = python:hooktests.brokenhook' >> ../a/.hg/hgrc
450 $ hg pull ../a 2>&1 | grep 'raised an exception'
450 $ hg pull ../a 2>&1 | grep 'raised an exception'
451 error: preoutgoing.broken hook raised an exception: unsupported operand type(s) for +: 'int' and 'dict'
451 error: preoutgoing.broken hook raised an exception: unsupported operand type(s) for +: 'int' and 'dict'
452
452
453 $ echo '[hooks]' > ../a/.hg/hgrc
453 $ echo '[hooks]' > ../a/.hg/hgrc
454 $ echo 'preoutgoing.raise = python:hooktests.raisehook' >> ../a/.hg/hgrc
454 $ echo 'preoutgoing.raise = python:hooktests.raisehook' >> ../a/.hg/hgrc
455 $ hg pull ../a 2>&1 | grep 'raised an exception'
455 $ hg pull ../a 2>&1 | grep 'raised an exception'
456 error: preoutgoing.raise hook raised an exception: exception from hook
456 error: preoutgoing.raise hook raised an exception: exception from hook
457
457
458 $ echo '[hooks]' > ../a/.hg/hgrc
458 $ echo '[hooks]' > ../a/.hg/hgrc
459 $ echo 'preoutgoing.abort = python:hooktests.aborthook' >> ../a/.hg/hgrc
459 $ echo 'preoutgoing.abort = python:hooktests.aborthook' >> ../a/.hg/hgrc
460 $ hg pull ../a
460 $ hg pull ../a
461 pulling from ../a
461 pulling from ../a
462 searching for changes
462 searching for changes
463 error: preoutgoing.abort hook failed: raise abort from hook
463 error: preoutgoing.abort hook failed: raise abort from hook
464 abort: raise abort from hook
464 abort: raise abort from hook
465 [255]
465 [255]
466
466
467 $ echo '[hooks]' > ../a/.hg/hgrc
467 $ echo '[hooks]' > ../a/.hg/hgrc
468 $ echo 'preoutgoing.fail = python:hooktests.failhook' >> ../a/.hg/hgrc
468 $ echo 'preoutgoing.fail = python:hooktests.failhook' >> ../a/.hg/hgrc
469 $ hg pull ../a
469 $ hg pull ../a
470 pulling from ../a
470 pulling from ../a
471 searching for changes
471 searching for changes
472 hook args:
472 hook args:
473 hooktype preoutgoing
473 hooktype preoutgoing
474 source pull
474 source pull
475 abort: preoutgoing.fail hook failed
475 abort: preoutgoing.fail hook failed
476 [255]
476 [255]
477
477
478 $ echo '[hooks]' > ../a/.hg/hgrc
478 $ echo '[hooks]' > ../a/.hg/hgrc
479 $ echo 'preoutgoing.uncallable = python:hooktests.uncallable' >> ../a/.hg/hgrc
479 $ echo 'preoutgoing.uncallable = python:hooktests.uncallable' >> ../a/.hg/hgrc
480 $ hg pull ../a
480 $ hg pull ../a
481 pulling from ../a
481 pulling from ../a
482 searching for changes
482 searching for changes
483 abort: preoutgoing.uncallable hook is invalid ("hooktests.uncallable" is not callable)
483 abort: preoutgoing.uncallable hook is invalid ("hooktests.uncallable" is not callable)
484 [255]
484 [255]
485
485
486 $ echo '[hooks]' > ../a/.hg/hgrc
486 $ echo '[hooks]' > ../a/.hg/hgrc
487 $ echo 'preoutgoing.nohook = python:hooktests.nohook' >> ../a/.hg/hgrc
487 $ echo 'preoutgoing.nohook = python:hooktests.nohook' >> ../a/.hg/hgrc
488 $ hg pull ../a
488 $ hg pull ../a
489 pulling from ../a
489 pulling from ../a
490 searching for changes
490 searching for changes
491 abort: preoutgoing.nohook hook is invalid ("hooktests.nohook" is not defined)
491 abort: preoutgoing.nohook hook is invalid ("hooktests.nohook" is not defined)
492 [255]
492 [255]
493
493
494 $ echo '[hooks]' > ../a/.hg/hgrc
494 $ echo '[hooks]' > ../a/.hg/hgrc
495 $ echo 'preoutgoing.nomodule = python:nomodule' >> ../a/.hg/hgrc
495 $ echo 'preoutgoing.nomodule = python:nomodule' >> ../a/.hg/hgrc
496 $ hg pull ../a
496 $ hg pull ../a
497 pulling from ../a
497 pulling from ../a
498 searching for changes
498 searching for changes
499 abort: preoutgoing.nomodule hook is invalid ("nomodule" not in a module)
499 abort: preoutgoing.nomodule hook is invalid ("nomodule" not in a module)
500 [255]
500 [255]
501
501
502 $ echo '[hooks]' > ../a/.hg/hgrc
502 $ echo '[hooks]' > ../a/.hg/hgrc
503 $ echo 'preoutgoing.badmodule = python:nomodule.nowhere' >> ../a/.hg/hgrc
503 $ echo 'preoutgoing.badmodule = python:nomodule.nowhere' >> ../a/.hg/hgrc
504 $ hg pull ../a
504 $ hg pull ../a
505 pulling from ../a
505 pulling from ../a
506 searching for changes
506 searching for changes
507 abort: preoutgoing.badmodule hook is invalid (import of "nomodule" failed)
507 abort: preoutgoing.badmodule hook is invalid (import of "nomodule" failed)
508 [255]
508 [255]
509
509
510 $ echo '[hooks]' > ../a/.hg/hgrc
510 $ echo '[hooks]' > ../a/.hg/hgrc
511 $ echo 'preoutgoing.unreachable = python:hooktests.container.unreachable' >> ../a/.hg/hgrc
511 $ echo 'preoutgoing.unreachable = python:hooktests.container.unreachable' >> ../a/.hg/hgrc
512 $ hg pull ../a
512 $ hg pull ../a
513 pulling from ../a
513 pulling from ../a
514 searching for changes
514 searching for changes
515 abort: preoutgoing.unreachable hook is invalid (import of "hooktests.container" failed)
515 abort: preoutgoing.unreachable hook is invalid (import of "hooktests.container" failed)
516 [255]
516 [255]
517
517
518 $ echo '[hooks]' > ../a/.hg/hgrc
518 $ echo '[hooks]' > ../a/.hg/hgrc
519 $ echo 'preoutgoing.pass = python:hooktests.passhook' >> ../a/.hg/hgrc
519 $ echo 'preoutgoing.pass = python:hooktests.passhook' >> ../a/.hg/hgrc
520 $ hg pull ../a
520 $ hg pull ../a
521 pulling from ../a
521 pulling from ../a
522 searching for changes
522 searching for changes
523 hook args:
523 hook args:
524 hooktype preoutgoing
524 hooktype preoutgoing
525 source pull
525 source pull
526 adding changesets
526 adding changesets
527 adding manifests
527 adding manifests
528 adding file changes
528 adding file changes
529 added 1 changesets with 1 changes to 1 files
529 added 1 changesets with 1 changes to 1 files
530 adding remote bookmark quux
530 adding remote bookmark quux
531 (run 'hg update' to get a working copy)
531 (run 'hg update' to get a working copy)
532
532
533 make sure --traceback works
533 make sure --traceback works
534
534
535 $ echo '[hooks]' > .hg/hgrc
535 $ echo '[hooks]' > .hg/hgrc
536 $ echo 'commit.abort = python:hooktests.aborthook' >> .hg/hgrc
536 $ echo 'commit.abort = python:hooktests.aborthook' >> .hg/hgrc
537
537
538 $ echo aa > a
538 $ echo aa > a
539 $ hg --traceback commit -d '0 0' -ma 2>&1 | grep '^Traceback'
539 $ hg --traceback commit -d '0 0' -ma 2>&1 | grep '^Traceback'
540 Traceback (most recent call last):
540 Traceback (most recent call last):
541
541
542 $ cd ..
542 $ cd ..
543 $ hg init c
543 $ hg init c
544 $ cd c
544 $ cd c
545
545
546 $ cat > hookext.py <<EOF
546 $ cat > hookext.py <<EOF
547 > def autohook(**args):
547 > def autohook(**args):
548 > print "Automatically installed hook"
548 > print "Automatically installed hook"
549 >
549 >
550 > def reposetup(ui, repo):
550 > def reposetup(ui, repo):
551 > repo.ui.setconfig("hooks", "commit.auto", autohook)
551 > repo.ui.setconfig("hooks", "commit.auto", autohook)
552 > EOF
552 > EOF
553 $ echo '[extensions]' >> .hg/hgrc
553 $ echo '[extensions]' >> .hg/hgrc
554 $ echo 'hookext = hookext.py' >> .hg/hgrc
554 $ echo 'hookext = hookext.py' >> .hg/hgrc
555
555
556 $ touch foo
556 $ touch foo
557 $ hg add foo
557 $ hg add foo
558 $ hg ci -d '0 0' -m 'add foo'
558 $ hg ci -d '0 0' -m 'add foo'
559 Automatically installed hook
559 Automatically installed hook
560 $ echo >> foo
560 $ echo >> foo
561 $ hg ci --debug -d '0 0' -m 'change foo'
561 $ hg ci --debug -d '0 0' -m 'change foo'
562 committing files:
562 committing files:
563 foo
563 foo
564 committing manifest
564 committing manifest
565 committing changelog
565 committing changelog
566 calling hook commit.auto: hgext_hookext.autohook
566 calling hook commit.auto: hgext_hookext.autohook
567 Automatically installed hook
567 Automatically installed hook
568 committed changeset 1:52998019f6252a2b893452765fcb0a47351a5708
568 committed changeset 1:52998019f6252a2b893452765fcb0a47351a5708
569
569
570 $ hg showconfig hooks
570 $ hg showconfig hooks
571 hooks.commit.auto=<function autohook at *> (glob)
571 hooks.commit.auto=<function autohook at *> (glob)
572
572
573 test python hook configured with python:[file]:[hook] syntax
573 test python hook configured with python:[file]:[hook] syntax
574
574
575 $ cd ..
575 $ cd ..
576 $ mkdir d
576 $ mkdir d
577 $ cd d
577 $ cd d
578 $ hg init repo
578 $ hg init repo
579 $ mkdir hooks
579 $ mkdir hooks
580
580
581 $ cd hooks
581 $ cd hooks
582 $ cat > testhooks.py <<EOF
582 $ cat > testhooks.py <<EOF
583 > def testhook(**args):
583 > def testhook(**args):
584 > print 'hook works'
584 > print 'hook works'
585 > EOF
585 > EOF
586 $ echo '[hooks]' > ../repo/.hg/hgrc
586 $ echo '[hooks]' > ../repo/.hg/hgrc
587 $ echo "pre-commit.test = python:`pwd`/testhooks.py:testhook" >> ../repo/.hg/hgrc
587 $ echo "pre-commit.test = python:`pwd`/testhooks.py:testhook" >> ../repo/.hg/hgrc
588
588
589 $ cd ../repo
589 $ cd ../repo
590 $ hg commit -d '0 0'
590 $ hg commit -d '0 0'
591 hook works
591 hook works
592 nothing changed
592 nothing changed
593 [1]
593 [1]
594
594
595 $ echo '[hooks]' > .hg/hgrc
595 $ echo '[hooks]' > .hg/hgrc
596 $ echo "update.ne = python:`pwd`/nonexistent.py:testhook" >> .hg/hgrc
596 $ echo "update.ne = python:`pwd`/nonexistent.py:testhook" >> .hg/hgrc
597 $ echo "pre-identify.npmd = python:`pwd`/:no_python_module_dir" >> .hg/hgrc
597 $ echo "pre-identify.npmd = python:`pwd`/:no_python_module_dir" >> .hg/hgrc
598
598
599 $ hg up null
599 $ hg up null
600 loading update.ne hook failed:
600 loading update.ne hook failed:
601 abort: No such file or directory: $TESTTMP/d/repo/nonexistent.py
601 abort: No such file or directory: $TESTTMP/d/repo/nonexistent.py
602 [255]
602 [255]
603
603
604 $ hg id
604 $ hg id
605 loading pre-identify.npmd hook failed:
605 loading pre-identify.npmd hook failed:
606 abort: No module named repo!
606 abort: No module named repo!
607 [255]
607 [255]
608
608
609 $ cd ../../b
609 $ cd ../../b
610
610
611 make sure --traceback works on hook import failure
611 make sure --traceback works on hook import failure
612
612
613 $ cat > importfail.py <<EOF
613 $ cat > importfail.py <<EOF
614 > import somebogusmodule
614 > import somebogusmodule
615 > # dereference something in the module to force demandimport to load it
615 > # dereference something in the module to force demandimport to load it
616 > somebogusmodule.whatever
616 > somebogusmodule.whatever
617 > EOF
617 > EOF
618
618
619 $ echo '[hooks]' > .hg/hgrc
619 $ echo '[hooks]' > .hg/hgrc
620 $ echo 'precommit.importfail = python:importfail.whatever' >> .hg/hgrc
620 $ echo 'precommit.importfail = python:importfail.whatever' >> .hg/hgrc
621
621
622 $ echo a >> a
622 $ echo a >> a
623 $ hg --traceback commit -ma 2>&1 | egrep -v '^( +File| [a-zA-Z(])'
623 $ hg --traceback commit -ma 2>&1 | egrep -v '^( +File| [a-zA-Z(])'
624 exception from first failed import attempt:
624 exception from first failed import attempt:
625 Traceback (most recent call last):
625 Traceback (most recent call last):
626 ImportError: No module named somebogusmodule
626 ImportError: No module named somebogusmodule
627 exception from second failed import attempt:
627 exception from second failed import attempt:
628 Traceback (most recent call last):
628 Traceback (most recent call last):
629 ImportError: No module named hgext_importfail
629 ImportError: No module named hgext_importfail
630 Traceback (most recent call last):
630 Traceback (most recent call last):
631 Abort: precommit.importfail hook is invalid (import of "importfail" failed)
631 HookLoadError: precommit.importfail hook is invalid (import of "importfail" failed)
632 abort: precommit.importfail hook is invalid (import of "importfail" failed)
632 abort: precommit.importfail hook is invalid (import of "importfail" failed)
633
633
634 Issue1827: Hooks Update & Commit not completely post operation
634 Issue1827: Hooks Update & Commit not completely post operation
635
635
636 commit and update hooks should run after command completion. The largefiles
636 commit and update hooks should run after command completion. The largefiles
637 use demonstrates a recursive wlock, showing the hook doesn't run until the
637 use demonstrates a recursive wlock, showing the hook doesn't run until the
638 final release (and dirstate flush).
638 final release (and dirstate flush).
639
639
640 $ echo '[hooks]' > .hg/hgrc
640 $ echo '[hooks]' > .hg/hgrc
641 $ echo 'commit = hg id' >> .hg/hgrc
641 $ echo 'commit = hg id' >> .hg/hgrc
642 $ echo 'update = hg id' >> .hg/hgrc
642 $ echo 'update = hg id' >> .hg/hgrc
643 $ echo bb > a
643 $ echo bb > a
644 $ hg ci -ma
644 $ hg ci -ma
645 223eafe2750c tip
645 223eafe2750c tip
646 $ hg up 0 --config extensions.largefiles=
646 $ hg up 0 --config extensions.largefiles=
647 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
647 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
648 cb9a9f314b8b
648 cb9a9f314b8b
649
649
650 make sure --verbose (and --quiet/--debug etc.) are propagated to the local ui
650 make sure --verbose (and --quiet/--debug etc.) are propagated to the local ui
651 that is passed to pre/post hooks
651 that is passed to pre/post hooks
652
652
653 $ echo '[hooks]' > .hg/hgrc
653 $ echo '[hooks]' > .hg/hgrc
654 $ echo 'pre-identify = python:hooktests.verbosehook' >> .hg/hgrc
654 $ echo 'pre-identify = python:hooktests.verbosehook' >> .hg/hgrc
655 $ hg id
655 $ hg id
656 cb9a9f314b8b
656 cb9a9f314b8b
657 $ hg id --verbose
657 $ hg id --verbose
658 calling hook pre-identify: hooktests.verbosehook
658 calling hook pre-identify: hooktests.verbosehook
659 verbose output from hook
659 verbose output from hook
660 cb9a9f314b8b
660 cb9a9f314b8b
661
661
662 Ensure hooks can be prioritized
662 Ensure hooks can be prioritized
663
663
664 $ echo '[hooks]' > .hg/hgrc
664 $ echo '[hooks]' > .hg/hgrc
665 $ echo 'pre-identify.a = python:hooktests.verbosehook' >> .hg/hgrc
665 $ echo 'pre-identify.a = python:hooktests.verbosehook' >> .hg/hgrc
666 $ echo 'pre-identify.b = python:hooktests.verbosehook' >> .hg/hgrc
666 $ echo 'pre-identify.b = python:hooktests.verbosehook' >> .hg/hgrc
667 $ echo 'priority.pre-identify.b = 1' >> .hg/hgrc
667 $ echo 'priority.pre-identify.b = 1' >> .hg/hgrc
668 $ echo 'pre-identify.c = python:hooktests.verbosehook' >> .hg/hgrc
668 $ echo 'pre-identify.c = python:hooktests.verbosehook' >> .hg/hgrc
669 $ hg id --verbose
669 $ hg id --verbose
670 calling hook pre-identify.b: hooktests.verbosehook
670 calling hook pre-identify.b: hooktests.verbosehook
671 verbose output from hook
671 verbose output from hook
672 calling hook pre-identify.a: hooktests.verbosehook
672 calling hook pre-identify.a: hooktests.verbosehook
673 verbose output from hook
673 verbose output from hook
674 calling hook pre-identify.c: hooktests.verbosehook
674 calling hook pre-identify.c: hooktests.verbosehook
675 verbose output from hook
675 verbose output from hook
676 cb9a9f314b8b
676 cb9a9f314b8b
677
677
678 new tags must be visible in pretxncommit (issue3210)
678 new tags must be visible in pretxncommit (issue3210)
679
679
680 $ echo 'pretxncommit.printtags = python:hooktests.printtags' >> .hg/hgrc
680 $ echo 'pretxncommit.printtags = python:hooktests.printtags' >> .hg/hgrc
681 $ hg tag -f foo
681 $ hg tag -f foo
682 ['a', 'foo', 'tip']
682 ['a', 'foo', 'tip']
683
683
684 new commits must be visible in pretxnchangegroup (issue3428)
684 new commits must be visible in pretxnchangegroup (issue3428)
685
685
686 $ cd ..
686 $ cd ..
687 $ hg init to
687 $ hg init to
688 $ echo '[hooks]' >> to/.hg/hgrc
688 $ echo '[hooks]' >> to/.hg/hgrc
689 $ echo 'pretxnchangegroup = hg --traceback tip' >> to/.hg/hgrc
689 $ echo 'pretxnchangegroup = hg --traceback tip' >> to/.hg/hgrc
690 $ echo a >> to/a
690 $ echo a >> to/a
691 $ hg --cwd to ci -Ama
691 $ hg --cwd to ci -Ama
692 adding a
692 adding a
693 $ hg clone to from
693 $ hg clone to from
694 updating to branch default
694 updating to branch default
695 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
695 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
696 $ echo aa >> from/a
696 $ echo aa >> from/a
697 $ hg --cwd from ci -mb
697 $ hg --cwd from ci -mb
698 $ hg --cwd from push
698 $ hg --cwd from push
699 pushing to $TESTTMP/to (glob)
699 pushing to $TESTTMP/to (glob)
700 searching for changes
700 searching for changes
701 adding changesets
701 adding changesets
702 adding manifests
702 adding manifests
703 adding file changes
703 adding file changes
704 added 1 changesets with 1 changes to 1 files
704 added 1 changesets with 1 changes to 1 files
705 changeset: 1:9836a07b9b9d
705 changeset: 1:9836a07b9b9d
706 tag: tip
706 tag: tip
707 user: test
707 user: test
708 date: Thu Jan 01 00:00:00 1970 +0000
708 date: Thu Jan 01 00:00:00 1970 +0000
709 summary: b
709 summary: b
710
710
General Comments 0
You need to be logged in to leave comments. Login now