##// END OF EJS Templates
hook: do not redirect stdout/err/in to ui while running in-process hooks (BC)...
Yuya Nishihara -
r30363:a1259e50 default
parent child Browse files
Show More
@@ -1,271 +1,264
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.HookLoadError(
38 raise error.HookLoadError(
39 _('%s hook is invalid: "%s" not in a module')
39 _('%s hook is invalid: "%s" not in a module')
40 % (hname, funcname))
40 % (hname, funcname))
41 modname = funcname[:d]
41 modname = funcname[:d]
42 oldpaths = sys.path
42 oldpaths = sys.path
43 if util.mainfrozen():
43 if util.mainfrozen():
44 # binary installs require sys.path manipulation
44 # binary installs require sys.path manipulation
45 modpath, modfile = os.path.split(modname)
45 modpath, modfile = os.path.split(modname)
46 if modpath and modfile:
46 if modpath and modfile:
47 sys.path = sys.path[:] + [modpath]
47 sys.path = sys.path[:] + [modpath]
48 modname = modfile
48 modname = modfile
49 with demandimport.deactivated():
49 with demandimport.deactivated():
50 try:
50 try:
51 obj = __import__(modname)
51 obj = __import__(modname)
52 except (ImportError, SyntaxError):
52 except (ImportError, SyntaxError):
53 e1 = sys.exc_info()
53 e1 = sys.exc_info()
54 try:
54 try:
55 # extensions are loaded with hgext_ prefix
55 # extensions are loaded with hgext_ prefix
56 obj = __import__("hgext_%s" % modname)
56 obj = __import__("hgext_%s" % modname)
57 except (ImportError, SyntaxError):
57 except (ImportError, SyntaxError):
58 e2 = sys.exc_info()
58 e2 = sys.exc_info()
59 if ui.tracebackflag:
59 if ui.tracebackflag:
60 ui.warn(_('exception from first failed import '
60 ui.warn(_('exception from first failed import '
61 'attempt:\n'))
61 'attempt:\n'))
62 ui.traceback(e1)
62 ui.traceback(e1)
63 if ui.tracebackflag:
63 if ui.tracebackflag:
64 ui.warn(_('exception from second failed import '
64 ui.warn(_('exception from second failed import '
65 'attempt:\n'))
65 'attempt:\n'))
66 ui.traceback(e2)
66 ui.traceback(e2)
67
67
68 if not ui.tracebackflag:
68 if not ui.tracebackflag:
69 tracebackhint = _(
69 tracebackhint = _(
70 'run with --traceback for stack trace')
70 'run with --traceback for stack trace')
71 else:
71 else:
72 tracebackhint = None
72 tracebackhint = None
73 raise error.HookLoadError(
73 raise error.HookLoadError(
74 _('%s hook is invalid: import of "%s" failed') %
74 _('%s hook is invalid: import of "%s" failed') %
75 (hname, modname), hint=tracebackhint)
75 (hname, modname), hint=tracebackhint)
76 sys.path = oldpaths
76 sys.path = oldpaths
77 try:
77 try:
78 for p in funcname.split('.')[1:]:
78 for p in funcname.split('.')[1:]:
79 obj = getattr(obj, p)
79 obj = getattr(obj, p)
80 except AttributeError:
80 except AttributeError:
81 raise error.HookLoadError(
81 raise error.HookLoadError(
82 _('%s hook is invalid: "%s" is not defined')
82 _('%s hook is invalid: "%s" is not defined')
83 % (hname, funcname))
83 % (hname, funcname))
84 if not callable(obj):
84 if not callable(obj):
85 raise error.HookLoadError(
85 raise error.HookLoadError(
86 _('%s hook is invalid: "%s" is not callable')
86 _('%s hook is invalid: "%s" is not callable')
87 % (hname, funcname))
87 % (hname, funcname))
88
88
89 ui.note(_("calling hook %s: %s\n") % (hname, funcname))
89 ui.note(_("calling hook %s: %s\n") % (hname, funcname))
90 starttime = time.time()
90 starttime = time.time()
91
91
92 try:
92 try:
93 # redirect IO descriptors to the ui descriptors so hooks
94 # that write directly to these don't mess up the command
95 # protocol when running through the command server
96 old = sys.stdout, sys.stderr, sys.stdin
97 sys.stdout, sys.stderr, sys.stdin = ui.fout, ui.ferr, ui.fin
98
99 r = obj(ui=ui, repo=repo, hooktype=name, **args)
93 r = obj(ui=ui, repo=repo, hooktype=name, **args)
100 except Exception as exc:
94 except Exception as exc:
101 if isinstance(exc, error.Abort):
95 if isinstance(exc, error.Abort):
102 ui.warn(_('error: %s hook failed: %s\n') %
96 ui.warn(_('error: %s hook failed: %s\n') %
103 (hname, exc.args[0]))
97 (hname, exc.args[0]))
104 else:
98 else:
105 ui.warn(_('error: %s hook raised an exception: '
99 ui.warn(_('error: %s hook raised an exception: '
106 '%s\n') % (hname, exc))
100 '%s\n') % (hname, exc))
107 if throw:
101 if throw:
108 raise
102 raise
109 if not ui.tracebackflag:
103 if not ui.tracebackflag:
110 ui.warn(_('(run with --traceback for stack trace)\n'))
104 ui.warn(_('(run with --traceback for stack trace)\n'))
111 ui.traceback()
105 ui.traceback()
112 return True, True
106 return True, True
113 finally:
107 finally:
114 sys.stdout, sys.stderr, sys.stdin = old
115 duration = time.time() - starttime
108 duration = time.time() - starttime
116 ui.log('pythonhook', 'pythonhook-%s: %s finished in %0.2f seconds\n',
109 ui.log('pythonhook', 'pythonhook-%s: %s finished in %0.2f seconds\n',
117 name, funcname, duration)
110 name, funcname, duration)
118 if r:
111 if r:
119 if throw:
112 if throw:
120 raise error.HookAbort(_('%s hook failed') % hname)
113 raise error.HookAbort(_('%s hook failed') % hname)
121 ui.warn(_('warning: %s hook failed\n') % hname)
114 ui.warn(_('warning: %s hook failed\n') % hname)
122 return r, False
115 return r, False
123
116
124 def _exthook(ui, repo, name, cmd, args, throw):
117 def _exthook(ui, repo, name, cmd, args, throw):
125 ui.note(_("running hook %s: %s\n") % (name, cmd))
118 ui.note(_("running hook %s: %s\n") % (name, cmd))
126
119
127 starttime = time.time()
120 starttime = time.time()
128 env = {}
121 env = {}
129
122
130 # make in-memory changes visible to external process
123 # make in-memory changes visible to external process
131 if repo is not None:
124 if repo is not None:
132 tr = repo.currenttransaction()
125 tr = repo.currenttransaction()
133 repo.dirstate.write(tr)
126 repo.dirstate.write(tr)
134 if tr and tr.writepending():
127 if tr and tr.writepending():
135 env['HG_PENDING'] = repo.root
128 env['HG_PENDING'] = repo.root
136
129
137 for k, v in args.iteritems():
130 for k, v in args.iteritems():
138 if callable(v):
131 if callable(v):
139 v = v()
132 v = v()
140 if isinstance(v, dict):
133 if isinstance(v, dict):
141 # make the dictionary element order stable across Python
134 # make the dictionary element order stable across Python
142 # implementations
135 # implementations
143 v = ('{' +
136 v = ('{' +
144 ', '.join('%r: %r' % i for i in sorted(v.iteritems())) +
137 ', '.join('%r: %r' % i for i in sorted(v.iteritems())) +
145 '}')
138 '}')
146 env['HG_' + k.upper()] = v
139 env['HG_' + k.upper()] = v
147
140
148 if repo:
141 if repo:
149 cwd = repo.root
142 cwd = repo.root
150 else:
143 else:
151 cwd = os.getcwd()
144 cwd = os.getcwd()
152 r = ui.system(cmd, environ=env, cwd=cwd)
145 r = ui.system(cmd, environ=env, cwd=cwd)
153
146
154 duration = time.time() - starttime
147 duration = time.time() - starttime
155 ui.log('exthook', 'exthook-%s: %s finished in %0.2f seconds\n',
148 ui.log('exthook', 'exthook-%s: %s finished in %0.2f seconds\n',
156 name, cmd, duration)
149 name, cmd, duration)
157 if r:
150 if r:
158 desc, r = util.explainexit(r)
151 desc, r = util.explainexit(r)
159 if throw:
152 if throw:
160 raise error.HookAbort(_('%s hook %s') % (name, desc))
153 raise error.HookAbort(_('%s hook %s') % (name, desc))
161 ui.warn(_('warning: %s hook %s\n') % (name, desc))
154 ui.warn(_('warning: %s hook %s\n') % (name, desc))
162 return r
155 return r
163
156
164 # represent an untrusted hook command
157 # represent an untrusted hook command
165 _fromuntrusted = object()
158 _fromuntrusted = object()
166
159
167 def _allhooks(ui):
160 def _allhooks(ui):
168 """return a list of (hook-id, cmd) pairs sorted by priority"""
161 """return a list of (hook-id, cmd) pairs sorted by priority"""
169 hooks = _hookitems(ui)
162 hooks = _hookitems(ui)
170 # Be careful in this section, propagating the real commands from untrusted
163 # Be careful in this section, propagating the real commands from untrusted
171 # sources would create a security vulnerability, make sure anything altered
164 # sources would create a security vulnerability, make sure anything altered
172 # in that section uses "_fromuntrusted" as its command.
165 # in that section uses "_fromuntrusted" as its command.
173 untrustedhooks = _hookitems(ui, _untrusted=True)
166 untrustedhooks = _hookitems(ui, _untrusted=True)
174 for name, value in untrustedhooks.items():
167 for name, value in untrustedhooks.items():
175 trustedvalue = hooks.get(name, (None, None, name, _fromuntrusted))
168 trustedvalue = hooks.get(name, (None, None, name, _fromuntrusted))
176 if value != trustedvalue:
169 if value != trustedvalue:
177 (lp, lo, lk, lv) = trustedvalue
170 (lp, lo, lk, lv) = trustedvalue
178 hooks[name] = (lp, lo, lk, _fromuntrusted)
171 hooks[name] = (lp, lo, lk, _fromuntrusted)
179 # (end of the security sensitive section)
172 # (end of the security sensitive section)
180 return [(k, v) for p, o, k, v in sorted(hooks.values())]
173 return [(k, v) for p, o, k, v in sorted(hooks.values())]
181
174
182 def _hookitems(ui, _untrusted=False):
175 def _hookitems(ui, _untrusted=False):
183 """return all hooks items ready to be sorted"""
176 """return all hooks items ready to be sorted"""
184 hooks = {}
177 hooks = {}
185 for name, cmd in ui.configitems('hooks', untrusted=_untrusted):
178 for name, cmd in ui.configitems('hooks', untrusted=_untrusted):
186 if not name.startswith('priority'):
179 if not name.startswith('priority'):
187 priority = ui.configint('hooks', 'priority.%s' % name, 0)
180 priority = ui.configint('hooks', 'priority.%s' % name, 0)
188 hooks[name] = (-priority, len(hooks), name, cmd)
181 hooks[name] = (-priority, len(hooks), name, cmd)
189 return hooks
182 return hooks
190
183
191 _redirect = False
184 _redirect = False
192 def redirect(state):
185 def redirect(state):
193 global _redirect
186 global _redirect
194 _redirect = state
187 _redirect = state
195
188
196 def hook(ui, repo, name, throw=False, **args):
189 def hook(ui, repo, name, throw=False, **args):
197 if not ui.callhooks:
190 if not ui.callhooks:
198 return False
191 return False
199
192
200 hooks = []
193 hooks = []
201 for hname, cmd in _allhooks(ui):
194 for hname, cmd in _allhooks(ui):
202 if hname.split('.')[0] == name and cmd:
195 if hname.split('.')[0] == name and cmd:
203 hooks.append((hname, cmd))
196 hooks.append((hname, cmd))
204
197
205 res = runhooks(ui, repo, name, hooks, throw=throw, **args)
198 res = runhooks(ui, repo, name, hooks, throw=throw, **args)
206 r = False
199 r = False
207 for hname, cmd in hooks:
200 for hname, cmd in hooks:
208 r = res[hname][0] or r
201 r = res[hname][0] or r
209 return r
202 return r
210
203
211 def runhooks(ui, repo, name, hooks, throw=False, **args):
204 def runhooks(ui, repo, name, hooks, throw=False, **args):
212 res = {}
205 res = {}
213 oldstdout = -1
206 oldstdout = -1
214
207
215 try:
208 try:
216 for hname, cmd in hooks:
209 for hname, cmd in hooks:
217 if oldstdout == -1 and _redirect:
210 if oldstdout == -1 and _redirect:
218 try:
211 try:
219 stdoutno = sys.__stdout__.fileno()
212 stdoutno = sys.__stdout__.fileno()
220 stderrno = sys.__stderr__.fileno()
213 stderrno = sys.__stderr__.fileno()
221 # temporarily redirect stdout to stderr, if possible
214 # temporarily redirect stdout to stderr, if possible
222 if stdoutno >= 0 and stderrno >= 0:
215 if stdoutno >= 0 and stderrno >= 0:
223 sys.__stdout__.flush()
216 sys.__stdout__.flush()
224 oldstdout = os.dup(stdoutno)
217 oldstdout = os.dup(stdoutno)
225 os.dup2(stderrno, stdoutno)
218 os.dup2(stderrno, stdoutno)
226 except (OSError, AttributeError):
219 except (OSError, AttributeError):
227 # files seem to be bogus, give up on redirecting (WSGI, etc)
220 # files seem to be bogus, give up on redirecting (WSGI, etc)
228 pass
221 pass
229
222
230 if cmd is _fromuntrusted:
223 if cmd is _fromuntrusted:
231 if throw:
224 if throw:
232 raise error.HookAbort(
225 raise error.HookAbort(
233 _('untrusted hook %s not executed') % name,
226 _('untrusted hook %s not executed') % name,
234 hint = _("see 'hg help config.trusted'"))
227 hint = _("see 'hg help config.trusted'"))
235 ui.warn(_('warning: untrusted hook %s not executed\n') % name)
228 ui.warn(_('warning: untrusted hook %s not executed\n') % name)
236 r = 1
229 r = 1
237 raised = False
230 raised = False
238 elif callable(cmd):
231 elif callable(cmd):
239 r, raised = _pythonhook(ui, repo, name, hname, cmd, args, throw)
232 r, raised = _pythonhook(ui, repo, name, hname, cmd, args, throw)
240 elif cmd.startswith('python:'):
233 elif cmd.startswith('python:'):
241 if cmd.count(':') >= 2:
234 if cmd.count(':') >= 2:
242 path, cmd = cmd[7:].rsplit(':', 1)
235 path, cmd = cmd[7:].rsplit(':', 1)
243 path = util.expandpath(path)
236 path = util.expandpath(path)
244 if repo:
237 if repo:
245 path = os.path.join(repo.root, path)
238 path = os.path.join(repo.root, path)
246 try:
239 try:
247 mod = extensions.loadpath(path, 'hghook.%s' % hname)
240 mod = extensions.loadpath(path, 'hghook.%s' % hname)
248 except Exception:
241 except Exception:
249 ui.write(_("loading %s hook failed:\n") % hname)
242 ui.write(_("loading %s hook failed:\n") % hname)
250 raise
243 raise
251 hookfn = getattr(mod, cmd)
244 hookfn = getattr(mod, cmd)
252 else:
245 else:
253 hookfn = cmd[7:].strip()
246 hookfn = cmd[7:].strip()
254 r, raised = _pythonhook(ui, repo, name, hname, hookfn, args,
247 r, raised = _pythonhook(ui, repo, name, hname, hookfn, args,
255 throw)
248 throw)
256 else:
249 else:
257 r = _exthook(ui, repo, hname, cmd, args, throw)
250 r = _exthook(ui, repo, hname, cmd, args, throw)
258 raised = False
251 raised = False
259
252
260 res[hname] = r, raised
253 res[hname] = r, raised
261
254
262 # The stderr is fully buffered on Windows when connected to a pipe.
255 # The stderr is fully buffered on Windows when connected to a pipe.
263 # A forcible flush is required to make small stderr data in the
256 # A forcible flush is required to make small stderr data in the
264 # remote side available to the client immediately.
257 # remote side available to the client immediately.
265 sys.stderr.flush()
258 sys.stderr.flush()
266 finally:
259 finally:
267 if _redirect and oldstdout >= 0:
260 if _redirect and oldstdout >= 0:
268 os.dup2(oldstdout, stdoutno)
261 os.dup2(oldstdout, stdoutno)
269 os.close(oldstdout)
262 os.close(oldstdout)
270
263
271 return res
264 return res
@@ -1,902 +1,900
1 #if windows
1 #if windows
2 $ PYTHONPATH="$TESTDIR/../contrib;$PYTHONPATH"
2 $ PYTHONPATH="$TESTDIR/../contrib;$PYTHONPATH"
3 #else
3 #else
4 $ PYTHONPATH="$TESTDIR/../contrib:$PYTHONPATH"
4 $ PYTHONPATH="$TESTDIR/../contrib:$PYTHONPATH"
5 #endif
5 #endif
6 $ export PYTHONPATH
6 $ export PYTHONPATH
7
7
8 typical client does not want echo-back messages, so test without it:
8 typical client does not want echo-back messages, so test without it:
9
9
10 $ grep -v '^promptecho ' < $HGRCPATH >> $HGRCPATH.new
10 $ grep -v '^promptecho ' < $HGRCPATH >> $HGRCPATH.new
11 $ mv $HGRCPATH.new $HGRCPATH
11 $ mv $HGRCPATH.new $HGRCPATH
12
12
13 $ hg init repo
13 $ hg init repo
14 $ cd repo
14 $ cd repo
15
15
16 >>> from __future__ import print_function
16 >>> from __future__ import print_function
17 >>> from hgclient import readchannel, runcommand, check
17 >>> from hgclient import readchannel, runcommand, check
18 >>> @check
18 >>> @check
19 ... def hellomessage(server):
19 ... def hellomessage(server):
20 ... ch, data = readchannel(server)
20 ... ch, data = readchannel(server)
21 ... print('%c, %r' % (ch, data))
21 ... print('%c, %r' % (ch, data))
22 ... # run an arbitrary command to make sure the next thing the server
22 ... # run an arbitrary command to make sure the next thing the server
23 ... # sends isn't part of the hello message
23 ... # sends isn't part of the hello message
24 ... runcommand(server, ['id'])
24 ... runcommand(server, ['id'])
25 o, 'capabilities: getencoding runcommand\nencoding: *\npid: *' (glob)
25 o, 'capabilities: getencoding runcommand\nencoding: *\npid: *' (glob)
26 *** runcommand id
26 *** runcommand id
27 000000000000 tip
27 000000000000 tip
28
28
29 >>> from hgclient import check
29 >>> from hgclient import check
30 >>> @check
30 >>> @check
31 ... def unknowncommand(server):
31 ... def unknowncommand(server):
32 ... server.stdin.write('unknowncommand\n')
32 ... server.stdin.write('unknowncommand\n')
33 abort: unknown command unknowncommand
33 abort: unknown command unknowncommand
34
34
35 >>> from hgclient import readchannel, runcommand, check
35 >>> from hgclient import readchannel, runcommand, check
36 >>> @check
36 >>> @check
37 ... def checkruncommand(server):
37 ... def checkruncommand(server):
38 ... # hello block
38 ... # hello block
39 ... readchannel(server)
39 ... readchannel(server)
40 ...
40 ...
41 ... # no args
41 ... # no args
42 ... runcommand(server, [])
42 ... runcommand(server, [])
43 ...
43 ...
44 ... # global options
44 ... # global options
45 ... runcommand(server, ['id', '--quiet'])
45 ... runcommand(server, ['id', '--quiet'])
46 ...
46 ...
47 ... # make sure global options don't stick through requests
47 ... # make sure global options don't stick through requests
48 ... runcommand(server, ['id'])
48 ... runcommand(server, ['id'])
49 ...
49 ...
50 ... # --config
50 ... # --config
51 ... runcommand(server, ['id', '--config', 'ui.quiet=True'])
51 ... runcommand(server, ['id', '--config', 'ui.quiet=True'])
52 ...
52 ...
53 ... # make sure --config doesn't stick
53 ... # make sure --config doesn't stick
54 ... runcommand(server, ['id'])
54 ... runcommand(server, ['id'])
55 ...
55 ...
56 ... # negative return code should be masked
56 ... # negative return code should be masked
57 ... runcommand(server, ['id', '-runknown'])
57 ... runcommand(server, ['id', '-runknown'])
58 *** runcommand
58 *** runcommand
59 Mercurial Distributed SCM
59 Mercurial Distributed SCM
60
60
61 basic commands:
61 basic commands:
62
62
63 add add the specified files on the next commit
63 add add the specified files on the next commit
64 annotate show changeset information by line for each file
64 annotate show changeset information by line for each file
65 clone make a copy of an existing repository
65 clone make a copy of an existing repository
66 commit commit the specified files or all outstanding changes
66 commit commit the specified files or all outstanding changes
67 diff diff repository (or selected files)
67 diff diff repository (or selected files)
68 export dump the header and diffs for one or more changesets
68 export dump the header and diffs for one or more changesets
69 forget forget the specified files on the next commit
69 forget forget the specified files on the next commit
70 init create a new repository in the given directory
70 init create a new repository in the given directory
71 log show revision history of entire repository or files
71 log show revision history of entire repository or files
72 merge merge another revision into working directory
72 merge merge another revision into working directory
73 pull pull changes from the specified source
73 pull pull changes from the specified source
74 push push changes to the specified destination
74 push push changes to the specified destination
75 remove remove the specified files on the next commit
75 remove remove the specified files on the next commit
76 serve start stand-alone webserver
76 serve start stand-alone webserver
77 status show changed files in the working directory
77 status show changed files in the working directory
78 summary summarize working directory state
78 summary summarize working directory state
79 update update working directory (or switch revisions)
79 update update working directory (or switch revisions)
80
80
81 (use 'hg help' for the full list of commands or 'hg -v' for details)
81 (use 'hg help' for the full list of commands or 'hg -v' for details)
82 *** runcommand id --quiet
82 *** runcommand id --quiet
83 000000000000
83 000000000000
84 *** runcommand id
84 *** runcommand id
85 000000000000 tip
85 000000000000 tip
86 *** runcommand id --config ui.quiet=True
86 *** runcommand id --config ui.quiet=True
87 000000000000
87 000000000000
88 *** runcommand id
88 *** runcommand id
89 000000000000 tip
89 000000000000 tip
90 *** runcommand id -runknown
90 *** runcommand id -runknown
91 abort: unknown revision 'unknown'!
91 abort: unknown revision 'unknown'!
92 [255]
92 [255]
93
93
94 >>> from hgclient import readchannel, check
94 >>> from hgclient import readchannel, check
95 >>> @check
95 >>> @check
96 ... def inputeof(server):
96 ... def inputeof(server):
97 ... readchannel(server)
97 ... readchannel(server)
98 ... server.stdin.write('runcommand\n')
98 ... server.stdin.write('runcommand\n')
99 ... # close stdin while server is waiting for input
99 ... # close stdin while server is waiting for input
100 ... server.stdin.close()
100 ... server.stdin.close()
101 ...
101 ...
102 ... # server exits with 1 if the pipe closed while reading the command
102 ... # server exits with 1 if the pipe closed while reading the command
103 ... print('server exit code =', server.wait())
103 ... print('server exit code =', server.wait())
104 server exit code = 1
104 server exit code = 1
105
105
106 >>> from hgclient import readchannel, runcommand, check, stringio
106 >>> from hgclient import readchannel, runcommand, check, stringio
107 >>> @check
107 >>> @check
108 ... def serverinput(server):
108 ... def serverinput(server):
109 ... readchannel(server)
109 ... readchannel(server)
110 ...
110 ...
111 ... patch = """
111 ... patch = """
112 ... # HG changeset patch
112 ... # HG changeset patch
113 ... # User test
113 ... # User test
114 ... # Date 0 0
114 ... # Date 0 0
115 ... # Node ID c103a3dec114d882c98382d684d8af798d09d857
115 ... # Node ID c103a3dec114d882c98382d684d8af798d09d857
116 ... # Parent 0000000000000000000000000000000000000000
116 ... # Parent 0000000000000000000000000000000000000000
117 ... 1
117 ... 1
118 ...
118 ...
119 ... diff -r 000000000000 -r c103a3dec114 a
119 ... diff -r 000000000000 -r c103a3dec114 a
120 ... --- /dev/null Thu Jan 01 00:00:00 1970 +0000
120 ... --- /dev/null Thu Jan 01 00:00:00 1970 +0000
121 ... +++ b/a Thu Jan 01 00:00:00 1970 +0000
121 ... +++ b/a Thu Jan 01 00:00:00 1970 +0000
122 ... @@ -0,0 +1,1 @@
122 ... @@ -0,0 +1,1 @@
123 ... +1
123 ... +1
124 ... """
124 ... """
125 ...
125 ...
126 ... runcommand(server, ['import', '-'], input=stringio(patch))
126 ... runcommand(server, ['import', '-'], input=stringio(patch))
127 ... runcommand(server, ['log'])
127 ... runcommand(server, ['log'])
128 *** runcommand import -
128 *** runcommand import -
129 applying patch from stdin
129 applying patch from stdin
130 *** runcommand log
130 *** runcommand log
131 changeset: 0:eff892de26ec
131 changeset: 0:eff892de26ec
132 tag: tip
132 tag: tip
133 user: test
133 user: test
134 date: Thu Jan 01 00:00:00 1970 +0000
134 date: Thu Jan 01 00:00:00 1970 +0000
135 summary: 1
135 summary: 1
136
136
137
137
138 check that "histedit --commands=-" can read rules from the input channel:
138 check that "histedit --commands=-" can read rules from the input channel:
139
139
140 >>> import cStringIO
140 >>> import cStringIO
141 >>> from hgclient import readchannel, runcommand, check
141 >>> from hgclient import readchannel, runcommand, check
142 >>> @check
142 >>> @check
143 ... def serverinput(server):
143 ... def serverinput(server):
144 ... readchannel(server)
144 ... readchannel(server)
145 ... rules = 'pick eff892de26ec\n'
145 ... rules = 'pick eff892de26ec\n'
146 ... runcommand(server, ['histedit', '0', '--commands=-',
146 ... runcommand(server, ['histedit', '0', '--commands=-',
147 ... '--config', 'extensions.histedit='],
147 ... '--config', 'extensions.histedit='],
148 ... input=cStringIO.StringIO(rules))
148 ... input=cStringIO.StringIO(rules))
149 *** runcommand histedit 0 --commands=- --config extensions.histedit=
149 *** runcommand histedit 0 --commands=- --config extensions.histedit=
150
150
151 check that --cwd doesn't persist between requests:
151 check that --cwd doesn't persist between requests:
152
152
153 $ mkdir foo
153 $ mkdir foo
154 $ touch foo/bar
154 $ touch foo/bar
155 >>> from hgclient import readchannel, runcommand, check
155 >>> from hgclient import readchannel, runcommand, check
156 >>> @check
156 >>> @check
157 ... def cwd(server):
157 ... def cwd(server):
158 ... readchannel(server)
158 ... readchannel(server)
159 ... runcommand(server, ['--cwd', 'foo', 'st', 'bar'])
159 ... runcommand(server, ['--cwd', 'foo', 'st', 'bar'])
160 ... runcommand(server, ['st', 'foo/bar'])
160 ... runcommand(server, ['st', 'foo/bar'])
161 *** runcommand --cwd foo st bar
161 *** runcommand --cwd foo st bar
162 ? bar
162 ? bar
163 *** runcommand st foo/bar
163 *** runcommand st foo/bar
164 ? foo/bar
164 ? foo/bar
165
165
166 $ rm foo/bar
166 $ rm foo/bar
167
167
168
168
169 check that local configs for the cached repo aren't inherited when -R is used:
169 check that local configs for the cached repo aren't inherited when -R is used:
170
170
171 $ cat <<EOF >> .hg/hgrc
171 $ cat <<EOF >> .hg/hgrc
172 > [ui]
172 > [ui]
173 > foo = bar
173 > foo = bar
174 > EOF
174 > EOF
175
175
176 >>> from hgclient import readchannel, sep, runcommand, check
176 >>> from hgclient import readchannel, sep, runcommand, check
177 >>> @check
177 >>> @check
178 ... def localhgrc(server):
178 ... def localhgrc(server):
179 ... readchannel(server)
179 ... readchannel(server)
180 ...
180 ...
181 ... # the cached repo local hgrc contains ui.foo=bar, so showconfig should
181 ... # the cached repo local hgrc contains ui.foo=bar, so showconfig should
182 ... # show it
182 ... # show it
183 ... runcommand(server, ['showconfig'], outfilter=sep)
183 ... runcommand(server, ['showconfig'], outfilter=sep)
184 ...
184 ...
185 ... # but not for this repo
185 ... # but not for this repo
186 ... runcommand(server, ['init', 'foo'])
186 ... runcommand(server, ['init', 'foo'])
187 ... runcommand(server, ['-R', 'foo', 'showconfig', 'ui', 'defaults'])
187 ... runcommand(server, ['-R', 'foo', 'showconfig', 'ui', 'defaults'])
188 *** runcommand showconfig
188 *** runcommand showconfig
189 bundle.mainreporoot=$TESTTMP/repo
189 bundle.mainreporoot=$TESTTMP/repo
190 defaults.backout=-d "0 0"
190 defaults.backout=-d "0 0"
191 defaults.commit=-d "0 0"
191 defaults.commit=-d "0 0"
192 defaults.shelve=--date "0 0"
192 defaults.shelve=--date "0 0"
193 defaults.tag=-d "0 0"
193 defaults.tag=-d "0 0"
194 devel.all-warnings=true
194 devel.all-warnings=true
195 largefiles.usercache=$TESTTMP/.cache/largefiles
195 largefiles.usercache=$TESTTMP/.cache/largefiles
196 ui.slash=True
196 ui.slash=True
197 ui.interactive=False
197 ui.interactive=False
198 ui.mergemarkers=detailed
198 ui.mergemarkers=detailed
199 ui.usehttp2=true (?)
199 ui.usehttp2=true (?)
200 ui.foo=bar
200 ui.foo=bar
201 ui.nontty=true
201 ui.nontty=true
202 *** runcommand init foo
202 *** runcommand init foo
203 *** runcommand -R foo showconfig ui defaults
203 *** runcommand -R foo showconfig ui defaults
204 defaults.backout=-d "0 0"
204 defaults.backout=-d "0 0"
205 defaults.commit=-d "0 0"
205 defaults.commit=-d "0 0"
206 defaults.shelve=--date "0 0"
206 defaults.shelve=--date "0 0"
207 defaults.tag=-d "0 0"
207 defaults.tag=-d "0 0"
208 ui.slash=True
208 ui.slash=True
209 ui.interactive=False
209 ui.interactive=False
210 ui.mergemarkers=detailed
210 ui.mergemarkers=detailed
211 ui.usehttp2=true (?)
211 ui.usehttp2=true (?)
212 ui.nontty=true
212 ui.nontty=true
213
213
214 $ rm -R foo
214 $ rm -R foo
215
215
216 #if windows
216 #if windows
217 $ PYTHONPATH="$TESTTMP/repo;$PYTHONPATH"
217 $ PYTHONPATH="$TESTTMP/repo;$PYTHONPATH"
218 #else
218 #else
219 $ PYTHONPATH="$TESTTMP/repo:$PYTHONPATH"
219 $ PYTHONPATH="$TESTTMP/repo:$PYTHONPATH"
220 #endif
220 #endif
221
221
222 $ cat <<EOF > hook.py
222 $ cat <<EOF > hook.py
223 > from __future__ import print_function
223 > from __future__ import print_function
224 > import sys
224 > import sys
225 > def hook(**args):
225 > def hook(**args):
226 > print('hook talking')
226 > print('hook talking')
227 > print('now try to read something: %r' % sys.stdin.read())
227 > print('now try to read something: %r' % sys.stdin.read())
228 > EOF
228 > EOF
229
229
230 >>> from hgclient import readchannel, runcommand, check, stringio
230 >>> from hgclient import readchannel, runcommand, check, stringio
231 >>> @check
231 >>> @check
232 ... def hookoutput(server):
232 ... def hookoutput(server):
233 ... readchannel(server)
233 ... readchannel(server)
234 ... runcommand(server, ['--config',
234 ... runcommand(server, ['--config',
235 ... 'hooks.pre-identify=python:hook.hook',
235 ... 'hooks.pre-identify=python:hook.hook',
236 ... 'id'],
236 ... 'id'],
237 ... input=stringio('some input'))
237 ... input=stringio('some input'))
238 *** runcommand --config hooks.pre-identify=python:hook.hook id
238 *** runcommand --config hooks.pre-identify=python:hook.hook id
239 hook talking
240 now try to read something: 'some input'
241 eff892de26ec tip
239 eff892de26ec tip
242
240
243 $ rm hook.py*
241 $ rm hook.py*
244
242
245 $ echo a >> a
243 $ echo a >> a
246 >>> import os
244 >>> import os
247 >>> from hgclient import readchannel, runcommand, check
245 >>> from hgclient import readchannel, runcommand, check
248 >>> @check
246 >>> @check
249 ... def outsidechanges(server):
247 ... def outsidechanges(server):
250 ... readchannel(server)
248 ... readchannel(server)
251 ... runcommand(server, ['status'])
249 ... runcommand(server, ['status'])
252 ... os.system('hg ci -Am2')
250 ... os.system('hg ci -Am2')
253 ... runcommand(server, ['tip'])
251 ... runcommand(server, ['tip'])
254 ... runcommand(server, ['status'])
252 ... runcommand(server, ['status'])
255 *** runcommand status
253 *** runcommand status
256 M a
254 M a
257 *** runcommand tip
255 *** runcommand tip
258 changeset: 1:d3a0a68be6de
256 changeset: 1:d3a0a68be6de
259 tag: tip
257 tag: tip
260 user: test
258 user: test
261 date: Thu Jan 01 00:00:00 1970 +0000
259 date: Thu Jan 01 00:00:00 1970 +0000
262 summary: 2
260 summary: 2
263
261
264 *** runcommand status
262 *** runcommand status
265
263
266 >>> import os
264 >>> import os
267 >>> from hgclient import readchannel, runcommand, check
265 >>> from hgclient import readchannel, runcommand, check
268 >>> @check
266 >>> @check
269 ... def bookmarks(server):
267 ... def bookmarks(server):
270 ... readchannel(server)
268 ... readchannel(server)
271 ... runcommand(server, ['bookmarks'])
269 ... runcommand(server, ['bookmarks'])
272 ...
270 ...
273 ... # changes .hg/bookmarks
271 ... # changes .hg/bookmarks
274 ... os.system('hg bookmark -i bm1')
272 ... os.system('hg bookmark -i bm1')
275 ... os.system('hg bookmark -i bm2')
273 ... os.system('hg bookmark -i bm2')
276 ... runcommand(server, ['bookmarks'])
274 ... runcommand(server, ['bookmarks'])
277 ...
275 ...
278 ... # changes .hg/bookmarks.current
276 ... # changes .hg/bookmarks.current
279 ... os.system('hg upd bm1 -q')
277 ... os.system('hg upd bm1 -q')
280 ... runcommand(server, ['bookmarks'])
278 ... runcommand(server, ['bookmarks'])
281 ...
279 ...
282 ... runcommand(server, ['bookmarks', 'bm3'])
280 ... runcommand(server, ['bookmarks', 'bm3'])
283 ... f = open('a', 'ab')
281 ... f = open('a', 'ab')
284 ... f.write('a\n')
282 ... f.write('a\n')
285 ... f.close()
283 ... f.close()
286 ... runcommand(server, ['commit', '-Amm'])
284 ... runcommand(server, ['commit', '-Amm'])
287 ... runcommand(server, ['bookmarks'])
285 ... runcommand(server, ['bookmarks'])
288 *** runcommand bookmarks
286 *** runcommand bookmarks
289 no bookmarks set
287 no bookmarks set
290 *** runcommand bookmarks
288 *** runcommand bookmarks
291 bm1 1:d3a0a68be6de
289 bm1 1:d3a0a68be6de
292 bm2 1:d3a0a68be6de
290 bm2 1:d3a0a68be6de
293 *** runcommand bookmarks
291 *** runcommand bookmarks
294 * bm1 1:d3a0a68be6de
292 * bm1 1:d3a0a68be6de
295 bm2 1:d3a0a68be6de
293 bm2 1:d3a0a68be6de
296 *** runcommand bookmarks bm3
294 *** runcommand bookmarks bm3
297 *** runcommand commit -Amm
295 *** runcommand commit -Amm
298 *** runcommand bookmarks
296 *** runcommand bookmarks
299 bm1 1:d3a0a68be6de
297 bm1 1:d3a0a68be6de
300 bm2 1:d3a0a68be6de
298 bm2 1:d3a0a68be6de
301 * bm3 2:aef17e88f5f0
299 * bm3 2:aef17e88f5f0
302
300
303 >>> import os
301 >>> import os
304 >>> from hgclient import readchannel, runcommand, check
302 >>> from hgclient import readchannel, runcommand, check
305 >>> @check
303 >>> @check
306 ... def tagscache(server):
304 ... def tagscache(server):
307 ... readchannel(server)
305 ... readchannel(server)
308 ... runcommand(server, ['id', '-t', '-r', '0'])
306 ... runcommand(server, ['id', '-t', '-r', '0'])
309 ... os.system('hg tag -r 0 foo')
307 ... os.system('hg tag -r 0 foo')
310 ... runcommand(server, ['id', '-t', '-r', '0'])
308 ... runcommand(server, ['id', '-t', '-r', '0'])
311 *** runcommand id -t -r 0
309 *** runcommand id -t -r 0
312
310
313 *** runcommand id -t -r 0
311 *** runcommand id -t -r 0
314 foo
312 foo
315
313
316 >>> import os
314 >>> import os
317 >>> from hgclient import readchannel, runcommand, check
315 >>> from hgclient import readchannel, runcommand, check
318 >>> @check
316 >>> @check
319 ... def setphase(server):
317 ... def setphase(server):
320 ... readchannel(server)
318 ... readchannel(server)
321 ... runcommand(server, ['phase', '-r', '.'])
319 ... runcommand(server, ['phase', '-r', '.'])
322 ... os.system('hg phase -r . -p')
320 ... os.system('hg phase -r . -p')
323 ... runcommand(server, ['phase', '-r', '.'])
321 ... runcommand(server, ['phase', '-r', '.'])
324 *** runcommand phase -r .
322 *** runcommand phase -r .
325 3: draft
323 3: draft
326 *** runcommand phase -r .
324 *** runcommand phase -r .
327 3: public
325 3: public
328
326
329 $ echo a >> a
327 $ echo a >> a
330 >>> from hgclient import readchannel, runcommand, check
328 >>> from hgclient import readchannel, runcommand, check
331 >>> @check
329 >>> @check
332 ... def rollback(server):
330 ... def rollback(server):
333 ... readchannel(server)
331 ... readchannel(server)
334 ... runcommand(server, ['phase', '-r', '.', '-p'])
332 ... runcommand(server, ['phase', '-r', '.', '-p'])
335 ... runcommand(server, ['commit', '-Am.'])
333 ... runcommand(server, ['commit', '-Am.'])
336 ... runcommand(server, ['rollback'])
334 ... runcommand(server, ['rollback'])
337 ... runcommand(server, ['phase', '-r', '.'])
335 ... runcommand(server, ['phase', '-r', '.'])
338 *** runcommand phase -r . -p
336 *** runcommand phase -r . -p
339 no phases changed
337 no phases changed
340 *** runcommand commit -Am.
338 *** runcommand commit -Am.
341 *** runcommand rollback
339 *** runcommand rollback
342 repository tip rolled back to revision 3 (undo commit)
340 repository tip rolled back to revision 3 (undo commit)
343 working directory now based on revision 3
341 working directory now based on revision 3
344 *** runcommand phase -r .
342 *** runcommand phase -r .
345 3: public
343 3: public
346
344
347 >>> import os
345 >>> import os
348 >>> from hgclient import readchannel, runcommand, check
346 >>> from hgclient import readchannel, runcommand, check
349 >>> @check
347 >>> @check
350 ... def branch(server):
348 ... def branch(server):
351 ... readchannel(server)
349 ... readchannel(server)
352 ... runcommand(server, ['branch'])
350 ... runcommand(server, ['branch'])
353 ... os.system('hg branch foo')
351 ... os.system('hg branch foo')
354 ... runcommand(server, ['branch'])
352 ... runcommand(server, ['branch'])
355 ... os.system('hg branch default')
353 ... os.system('hg branch default')
356 *** runcommand branch
354 *** runcommand branch
357 default
355 default
358 marked working directory as branch foo
356 marked working directory as branch foo
359 (branches are permanent and global, did you want a bookmark?)
357 (branches are permanent and global, did you want a bookmark?)
360 *** runcommand branch
358 *** runcommand branch
361 foo
359 foo
362 marked working directory as branch default
360 marked working directory as branch default
363 (branches are permanent and global, did you want a bookmark?)
361 (branches are permanent and global, did you want a bookmark?)
364
362
365 $ touch .hgignore
363 $ touch .hgignore
366 >>> import os
364 >>> import os
367 >>> from hgclient import readchannel, runcommand, check
365 >>> from hgclient import readchannel, runcommand, check
368 >>> @check
366 >>> @check
369 ... def hgignore(server):
367 ... def hgignore(server):
370 ... readchannel(server)
368 ... readchannel(server)
371 ... runcommand(server, ['commit', '-Am.'])
369 ... runcommand(server, ['commit', '-Am.'])
372 ... f = open('ignored-file', 'ab')
370 ... f = open('ignored-file', 'ab')
373 ... f.write('')
371 ... f.write('')
374 ... f.close()
372 ... f.close()
375 ... f = open('.hgignore', 'ab')
373 ... f = open('.hgignore', 'ab')
376 ... f.write('ignored-file')
374 ... f.write('ignored-file')
377 ... f.close()
375 ... f.close()
378 ... runcommand(server, ['status', '-i', '-u'])
376 ... runcommand(server, ['status', '-i', '-u'])
379 *** runcommand commit -Am.
377 *** runcommand commit -Am.
380 adding .hgignore
378 adding .hgignore
381 *** runcommand status -i -u
379 *** runcommand status -i -u
382 I ignored-file
380 I ignored-file
383
381
384 cache of non-public revisions should be invalidated on repository change
382 cache of non-public revisions should be invalidated on repository change
385 (issue4855):
383 (issue4855):
386
384
387 >>> import os
385 >>> import os
388 >>> from hgclient import readchannel, runcommand, check
386 >>> from hgclient import readchannel, runcommand, check
389 >>> @check
387 >>> @check
390 ... def phasesetscacheaftercommit(server):
388 ... def phasesetscacheaftercommit(server):
391 ... readchannel(server)
389 ... readchannel(server)
392 ... # load _phasecache._phaserevs and _phasesets
390 ... # load _phasecache._phaserevs and _phasesets
393 ... runcommand(server, ['log', '-qr', 'draft()'])
391 ... runcommand(server, ['log', '-qr', 'draft()'])
394 ... # create draft commits by another process
392 ... # create draft commits by another process
395 ... for i in xrange(5, 7):
393 ... for i in xrange(5, 7):
396 ... f = open('a', 'ab')
394 ... f = open('a', 'ab')
397 ... f.seek(0, os.SEEK_END)
395 ... f.seek(0, os.SEEK_END)
398 ... f.write('a\n')
396 ... f.write('a\n')
399 ... f.close()
397 ... f.close()
400 ... os.system('hg commit -Aqm%d' % i)
398 ... os.system('hg commit -Aqm%d' % i)
401 ... # new commits should be listed as draft revisions
399 ... # new commits should be listed as draft revisions
402 ... runcommand(server, ['log', '-qr', 'draft()'])
400 ... runcommand(server, ['log', '-qr', 'draft()'])
403 *** runcommand log -qr draft()
401 *** runcommand log -qr draft()
404 4:7966c8e3734d
402 4:7966c8e3734d
405 *** runcommand log -qr draft()
403 *** runcommand log -qr draft()
406 4:7966c8e3734d
404 4:7966c8e3734d
407 5:41f6602d1c4f
405 5:41f6602d1c4f
408 6:10501e202c35
406 6:10501e202c35
409
407
410 >>> import os
408 >>> import os
411 >>> from hgclient import readchannel, runcommand, check
409 >>> from hgclient import readchannel, runcommand, check
412 >>> @check
410 >>> @check
413 ... def phasesetscacheafterstrip(server):
411 ... def phasesetscacheafterstrip(server):
414 ... readchannel(server)
412 ... readchannel(server)
415 ... # load _phasecache._phaserevs and _phasesets
413 ... # load _phasecache._phaserevs and _phasesets
416 ... runcommand(server, ['log', '-qr', 'draft()'])
414 ... runcommand(server, ['log', '-qr', 'draft()'])
417 ... # strip cached revisions by another process
415 ... # strip cached revisions by another process
418 ... os.system('hg --config extensions.strip= strip -q 5')
416 ... os.system('hg --config extensions.strip= strip -q 5')
419 ... # shouldn't abort by "unknown revision '6'"
417 ... # shouldn't abort by "unknown revision '6'"
420 ... runcommand(server, ['log', '-qr', 'draft()'])
418 ... runcommand(server, ['log', '-qr', 'draft()'])
421 *** runcommand log -qr draft()
419 *** runcommand log -qr draft()
422 4:7966c8e3734d
420 4:7966c8e3734d
423 5:41f6602d1c4f
421 5:41f6602d1c4f
424 6:10501e202c35
422 6:10501e202c35
425 *** runcommand log -qr draft()
423 *** runcommand log -qr draft()
426 4:7966c8e3734d
424 4:7966c8e3734d
427
425
428 cache of phase roots should be invalidated on strip (issue3827):
426 cache of phase roots should be invalidated on strip (issue3827):
429
427
430 >>> import os
428 >>> import os
431 >>> from hgclient import readchannel, sep, runcommand, check
429 >>> from hgclient import readchannel, sep, runcommand, check
432 >>> @check
430 >>> @check
433 ... def phasecacheafterstrip(server):
431 ... def phasecacheafterstrip(server):
434 ... readchannel(server)
432 ... readchannel(server)
435 ...
433 ...
436 ... # create new head, 5:731265503d86
434 ... # create new head, 5:731265503d86
437 ... runcommand(server, ['update', '-C', '0'])
435 ... runcommand(server, ['update', '-C', '0'])
438 ... f = open('a', 'ab')
436 ... f = open('a', 'ab')
439 ... f.write('a\n')
437 ... f.write('a\n')
440 ... f.close()
438 ... f.close()
441 ... runcommand(server, ['commit', '-Am.', 'a'])
439 ... runcommand(server, ['commit', '-Am.', 'a'])
442 ... runcommand(server, ['log', '-Gq'])
440 ... runcommand(server, ['log', '-Gq'])
443 ...
441 ...
444 ... # make it public; draft marker moves to 4:7966c8e3734d
442 ... # make it public; draft marker moves to 4:7966c8e3734d
445 ... runcommand(server, ['phase', '-p', '.'])
443 ... runcommand(server, ['phase', '-p', '.'])
446 ... # load _phasecache.phaseroots
444 ... # load _phasecache.phaseroots
447 ... runcommand(server, ['phase', '.'], outfilter=sep)
445 ... runcommand(server, ['phase', '.'], outfilter=sep)
448 ...
446 ...
449 ... # strip 1::4 outside server
447 ... # strip 1::4 outside server
450 ... os.system('hg -q --config extensions.mq= strip 1')
448 ... os.system('hg -q --config extensions.mq= strip 1')
451 ...
449 ...
452 ... # shouldn't raise "7966c8e3734d: no node!"
450 ... # shouldn't raise "7966c8e3734d: no node!"
453 ... runcommand(server, ['branches'])
451 ... runcommand(server, ['branches'])
454 *** runcommand update -C 0
452 *** runcommand update -C 0
455 1 files updated, 0 files merged, 2 files removed, 0 files unresolved
453 1 files updated, 0 files merged, 2 files removed, 0 files unresolved
456 (leaving bookmark bm3)
454 (leaving bookmark bm3)
457 *** runcommand commit -Am. a
455 *** runcommand commit -Am. a
458 created new head
456 created new head
459 *** runcommand log -Gq
457 *** runcommand log -Gq
460 @ 5:731265503d86
458 @ 5:731265503d86
461 |
459 |
462 | o 4:7966c8e3734d
460 | o 4:7966c8e3734d
463 | |
461 | |
464 | o 3:b9b85890c400
462 | o 3:b9b85890c400
465 | |
463 | |
466 | o 2:aef17e88f5f0
464 | o 2:aef17e88f5f0
467 | |
465 | |
468 | o 1:d3a0a68be6de
466 | o 1:d3a0a68be6de
469 |/
467 |/
470 o 0:eff892de26ec
468 o 0:eff892de26ec
471
469
472 *** runcommand phase -p .
470 *** runcommand phase -p .
473 *** runcommand phase .
471 *** runcommand phase .
474 5: public
472 5: public
475 *** runcommand branches
473 *** runcommand branches
476 default 1:731265503d86
474 default 1:731265503d86
477
475
478 in-memory cache must be reloaded if transaction is aborted. otherwise
476 in-memory cache must be reloaded if transaction is aborted. otherwise
479 changelog and manifest would have invalid node:
477 changelog and manifest would have invalid node:
480
478
481 $ echo a >> a
479 $ echo a >> a
482 >>> from hgclient import readchannel, runcommand, check
480 >>> from hgclient import readchannel, runcommand, check
483 >>> @check
481 >>> @check
484 ... def txabort(server):
482 ... def txabort(server):
485 ... readchannel(server)
483 ... readchannel(server)
486 ... runcommand(server, ['commit', '--config', 'hooks.pretxncommit=false',
484 ... runcommand(server, ['commit', '--config', 'hooks.pretxncommit=false',
487 ... '-mfoo'])
485 ... '-mfoo'])
488 ... runcommand(server, ['verify'])
486 ... runcommand(server, ['verify'])
489 *** runcommand commit --config hooks.pretxncommit=false -mfoo
487 *** runcommand commit --config hooks.pretxncommit=false -mfoo
490 transaction abort!
488 transaction abort!
491 rollback completed
489 rollback completed
492 abort: pretxncommit hook exited with status 1
490 abort: pretxncommit hook exited with status 1
493 [255]
491 [255]
494 *** runcommand verify
492 *** runcommand verify
495 checking changesets
493 checking changesets
496 checking manifests
494 checking manifests
497 crosschecking files in changesets and manifests
495 crosschecking files in changesets and manifests
498 checking files
496 checking files
499 1 files, 2 changesets, 2 total revisions
497 1 files, 2 changesets, 2 total revisions
500 $ hg revert --no-backup -aq
498 $ hg revert --no-backup -aq
501
499
502 $ cat >> .hg/hgrc << EOF
500 $ cat >> .hg/hgrc << EOF
503 > [experimental]
501 > [experimental]
504 > evolution=createmarkers
502 > evolution=createmarkers
505 > EOF
503 > EOF
506
504
507 >>> import os
505 >>> import os
508 >>> from hgclient import readchannel, runcommand, check
506 >>> from hgclient import readchannel, runcommand, check
509 >>> @check
507 >>> @check
510 ... def obsolete(server):
508 ... def obsolete(server):
511 ... readchannel(server)
509 ... readchannel(server)
512 ...
510 ...
513 ... runcommand(server, ['up', 'null'])
511 ... runcommand(server, ['up', 'null'])
514 ... runcommand(server, ['phase', '-df', 'tip'])
512 ... runcommand(server, ['phase', '-df', 'tip'])
515 ... cmd = 'hg debugobsolete `hg log -r tip --template {node}`'
513 ... cmd = 'hg debugobsolete `hg log -r tip --template {node}`'
516 ... if os.name == 'nt':
514 ... if os.name == 'nt':
517 ... cmd = 'sh -c "%s"' % cmd # run in sh, not cmd.exe
515 ... cmd = 'sh -c "%s"' % cmd # run in sh, not cmd.exe
518 ... os.system(cmd)
516 ... os.system(cmd)
519 ... runcommand(server, ['log', '--hidden'])
517 ... runcommand(server, ['log', '--hidden'])
520 ... runcommand(server, ['log'])
518 ... runcommand(server, ['log'])
521 *** runcommand up null
519 *** runcommand up null
522 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
520 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
523 *** runcommand phase -df tip
521 *** runcommand phase -df tip
524 *** runcommand log --hidden
522 *** runcommand log --hidden
525 changeset: 1:731265503d86
523 changeset: 1:731265503d86
526 tag: tip
524 tag: tip
527 user: test
525 user: test
528 date: Thu Jan 01 00:00:00 1970 +0000
526 date: Thu Jan 01 00:00:00 1970 +0000
529 summary: .
527 summary: .
530
528
531 changeset: 0:eff892de26ec
529 changeset: 0:eff892de26ec
532 bookmark: bm1
530 bookmark: bm1
533 bookmark: bm2
531 bookmark: bm2
534 bookmark: bm3
532 bookmark: bm3
535 user: test
533 user: test
536 date: Thu Jan 01 00:00:00 1970 +0000
534 date: Thu Jan 01 00:00:00 1970 +0000
537 summary: 1
535 summary: 1
538
536
539 *** runcommand log
537 *** runcommand log
540 changeset: 0:eff892de26ec
538 changeset: 0:eff892de26ec
541 bookmark: bm1
539 bookmark: bm1
542 bookmark: bm2
540 bookmark: bm2
543 bookmark: bm3
541 bookmark: bm3
544 tag: tip
542 tag: tip
545 user: test
543 user: test
546 date: Thu Jan 01 00:00:00 1970 +0000
544 date: Thu Jan 01 00:00:00 1970 +0000
547 summary: 1
545 summary: 1
548
546
549
547
550 $ cat <<EOF >> .hg/hgrc
548 $ cat <<EOF >> .hg/hgrc
551 > [extensions]
549 > [extensions]
552 > mq =
550 > mq =
553 > EOF
551 > EOF
554
552
555 >>> import os
553 >>> import os
556 >>> from hgclient import readchannel, runcommand, check
554 >>> from hgclient import readchannel, runcommand, check
557 >>> @check
555 >>> @check
558 ... def mqoutsidechanges(server):
556 ... def mqoutsidechanges(server):
559 ... readchannel(server)
557 ... readchannel(server)
560 ...
558 ...
561 ... # load repo.mq
559 ... # load repo.mq
562 ... runcommand(server, ['qapplied'])
560 ... runcommand(server, ['qapplied'])
563 ... os.system('hg qnew 0.diff')
561 ... os.system('hg qnew 0.diff')
564 ... # repo.mq should be invalidated
562 ... # repo.mq should be invalidated
565 ... runcommand(server, ['qapplied'])
563 ... runcommand(server, ['qapplied'])
566 ...
564 ...
567 ... runcommand(server, ['qpop', '--all'])
565 ... runcommand(server, ['qpop', '--all'])
568 ... os.system('hg qqueue --create foo')
566 ... os.system('hg qqueue --create foo')
569 ... # repo.mq should be recreated to point to new queue
567 ... # repo.mq should be recreated to point to new queue
570 ... runcommand(server, ['qqueue', '--active'])
568 ... runcommand(server, ['qqueue', '--active'])
571 *** runcommand qapplied
569 *** runcommand qapplied
572 *** runcommand qapplied
570 *** runcommand qapplied
573 0.diff
571 0.diff
574 *** runcommand qpop --all
572 *** runcommand qpop --all
575 popping 0.diff
573 popping 0.diff
576 patch queue now empty
574 patch queue now empty
577 *** runcommand qqueue --active
575 *** runcommand qqueue --active
578 foo
576 foo
579
577
580 $ cat <<EOF > dbgui.py
578 $ cat <<EOF > dbgui.py
581 > import os, sys
579 > import os, sys
582 > from mercurial import cmdutil, commands
580 > from mercurial import cmdutil, commands
583 > cmdtable = {}
581 > cmdtable = {}
584 > command = cmdutil.command(cmdtable)
582 > command = cmdutil.command(cmdtable)
585 > @command("debuggetpass", norepo=True)
583 > @command("debuggetpass", norepo=True)
586 > def debuggetpass(ui):
584 > def debuggetpass(ui):
587 > ui.write("%s\\n" % ui.getpass())
585 > ui.write("%s\\n" % ui.getpass())
588 > @command("debugprompt", norepo=True)
586 > @command("debugprompt", norepo=True)
589 > def debugprompt(ui):
587 > def debugprompt(ui):
590 > ui.write("%s\\n" % ui.prompt("prompt:"))
588 > ui.write("%s\\n" % ui.prompt("prompt:"))
591 > @command("debugreadstdin", norepo=True)
589 > @command("debugreadstdin", norepo=True)
592 > def debugreadstdin(ui):
590 > def debugreadstdin(ui):
593 > ui.write("read: %r\n" % sys.stdin.read(1))
591 > ui.write("read: %r\n" % sys.stdin.read(1))
594 > @command("debugwritestdout", norepo=True)
592 > @command("debugwritestdout", norepo=True)
595 > def debugwritestdout(ui):
593 > def debugwritestdout(ui):
596 > os.write(1, "low-level stdout fd and\n")
594 > os.write(1, "low-level stdout fd and\n")
597 > sys.stdout.write("stdout should be redirected to /dev/null\n")
595 > sys.stdout.write("stdout should be redirected to /dev/null\n")
598 > sys.stdout.flush()
596 > sys.stdout.flush()
599 > EOF
597 > EOF
600 $ cat <<EOF >> .hg/hgrc
598 $ cat <<EOF >> .hg/hgrc
601 > [extensions]
599 > [extensions]
602 > dbgui = dbgui.py
600 > dbgui = dbgui.py
603 > EOF
601 > EOF
604
602
605 >>> from hgclient import readchannel, runcommand, check, stringio
603 >>> from hgclient import readchannel, runcommand, check, stringio
606 >>> @check
604 >>> @check
607 ... def getpass(server):
605 ... def getpass(server):
608 ... readchannel(server)
606 ... readchannel(server)
609 ... runcommand(server, ['debuggetpass', '--config',
607 ... runcommand(server, ['debuggetpass', '--config',
610 ... 'ui.interactive=True'],
608 ... 'ui.interactive=True'],
611 ... input=stringio('1234\n'))
609 ... input=stringio('1234\n'))
612 ... runcommand(server, ['debugprompt', '--config',
610 ... runcommand(server, ['debugprompt', '--config',
613 ... 'ui.interactive=True'],
611 ... 'ui.interactive=True'],
614 ... input=stringio('5678\n'))
612 ... input=stringio('5678\n'))
615 ... runcommand(server, ['debugreadstdin'])
613 ... runcommand(server, ['debugreadstdin'])
616 ... runcommand(server, ['debugwritestdout'])
614 ... runcommand(server, ['debugwritestdout'])
617 *** runcommand debuggetpass --config ui.interactive=True
615 *** runcommand debuggetpass --config ui.interactive=True
618 password: 1234
616 password: 1234
619 *** runcommand debugprompt --config ui.interactive=True
617 *** runcommand debugprompt --config ui.interactive=True
620 prompt: 5678
618 prompt: 5678
621 *** runcommand debugreadstdin
619 *** runcommand debugreadstdin
622 read: ''
620 read: ''
623 *** runcommand debugwritestdout
621 *** runcommand debugwritestdout
624
622
625
623
626 run commandserver in commandserver, which is silly but should work:
624 run commandserver in commandserver, which is silly but should work:
627
625
628 >>> from __future__ import print_function
626 >>> from __future__ import print_function
629 >>> from hgclient import readchannel, runcommand, check, stringio
627 >>> from hgclient import readchannel, runcommand, check, stringio
630 >>> @check
628 >>> @check
631 ... def nested(server):
629 ... def nested(server):
632 ... print('%c, %r' % readchannel(server))
630 ... print('%c, %r' % readchannel(server))
633 ... class nestedserver(object):
631 ... class nestedserver(object):
634 ... stdin = stringio('getencoding\n')
632 ... stdin = stringio('getencoding\n')
635 ... stdout = stringio()
633 ... stdout = stringio()
636 ... runcommand(server, ['serve', '--cmdserver', 'pipe'],
634 ... runcommand(server, ['serve', '--cmdserver', 'pipe'],
637 ... output=nestedserver.stdout, input=nestedserver.stdin)
635 ... output=nestedserver.stdout, input=nestedserver.stdin)
638 ... nestedserver.stdout.seek(0)
636 ... nestedserver.stdout.seek(0)
639 ... print('%c, %r' % readchannel(nestedserver)) # hello
637 ... print('%c, %r' % readchannel(nestedserver)) # hello
640 ... print('%c, %r' % readchannel(nestedserver)) # getencoding
638 ... print('%c, %r' % readchannel(nestedserver)) # getencoding
641 o, 'capabilities: getencoding runcommand\nencoding: *\npid: *' (glob)
639 o, 'capabilities: getencoding runcommand\nencoding: *\npid: *' (glob)
642 *** runcommand serve --cmdserver pipe
640 *** runcommand serve --cmdserver pipe
643 o, 'capabilities: getencoding runcommand\nencoding: *\npid: *' (glob)
641 o, 'capabilities: getencoding runcommand\nencoding: *\npid: *' (glob)
644 r, '*' (glob)
642 r, '*' (glob)
645
643
646
644
647 start without repository:
645 start without repository:
648
646
649 $ cd ..
647 $ cd ..
650
648
651 >>> from __future__ import print_function
649 >>> from __future__ import print_function
652 >>> from hgclient import readchannel, runcommand, check
650 >>> from hgclient import readchannel, runcommand, check
653 >>> @check
651 >>> @check
654 ... def hellomessage(server):
652 ... def hellomessage(server):
655 ... ch, data = readchannel(server)
653 ... ch, data = readchannel(server)
656 ... print('%c, %r' % (ch, data))
654 ... print('%c, %r' % (ch, data))
657 ... # run an arbitrary command to make sure the next thing the server
655 ... # run an arbitrary command to make sure the next thing the server
658 ... # sends isn't part of the hello message
656 ... # sends isn't part of the hello message
659 ... runcommand(server, ['id'])
657 ... runcommand(server, ['id'])
660 o, 'capabilities: getencoding runcommand\nencoding: *\npid: *' (glob)
658 o, 'capabilities: getencoding runcommand\nencoding: *\npid: *' (glob)
661 *** runcommand id
659 *** runcommand id
662 abort: there is no Mercurial repository here (.hg not found)
660 abort: there is no Mercurial repository here (.hg not found)
663 [255]
661 [255]
664
662
665 >>> from hgclient import readchannel, runcommand, check
663 >>> from hgclient import readchannel, runcommand, check
666 >>> @check
664 >>> @check
667 ... def startwithoutrepo(server):
665 ... def startwithoutrepo(server):
668 ... readchannel(server)
666 ... readchannel(server)
669 ... runcommand(server, ['init', 'repo2'])
667 ... runcommand(server, ['init', 'repo2'])
670 ... runcommand(server, ['id', '-R', 'repo2'])
668 ... runcommand(server, ['id', '-R', 'repo2'])
671 *** runcommand init repo2
669 *** runcommand init repo2
672 *** runcommand id -R repo2
670 *** runcommand id -R repo2
673 000000000000 tip
671 000000000000 tip
674
672
675
673
676 don't fall back to cwd if invalid -R path is specified (issue4805):
674 don't fall back to cwd if invalid -R path is specified (issue4805):
677
675
678 $ cd repo
676 $ cd repo
679 $ hg serve --cmdserver pipe -R ../nonexistent
677 $ hg serve --cmdserver pipe -R ../nonexistent
680 abort: repository ../nonexistent not found!
678 abort: repository ../nonexistent not found!
681 [255]
679 [255]
682 $ cd ..
680 $ cd ..
683
681
684
682
685 unix domain socket:
683 unix domain socket:
686
684
687 $ cd repo
685 $ cd repo
688 $ hg update -q
686 $ hg update -q
689
687
690 #if unix-socket unix-permissions
688 #if unix-socket unix-permissions
691
689
692 >>> from __future__ import print_function
690 >>> from __future__ import print_function
693 >>> from hgclient import unixserver, readchannel, runcommand, check, stringio
691 >>> from hgclient import unixserver, readchannel, runcommand, check, stringio
694 >>> server = unixserver('.hg/server.sock', '.hg/server.log')
692 >>> server = unixserver('.hg/server.sock', '.hg/server.log')
695 >>> def hellomessage(conn):
693 >>> def hellomessage(conn):
696 ... ch, data = readchannel(conn)
694 ... ch, data = readchannel(conn)
697 ... print('%c, %r' % (ch, data))
695 ... print('%c, %r' % (ch, data))
698 ... runcommand(conn, ['id'])
696 ... runcommand(conn, ['id'])
699 >>> check(hellomessage, server.connect)
697 >>> check(hellomessage, server.connect)
700 o, 'capabilities: getencoding runcommand\nencoding: *\npid: *' (glob)
698 o, 'capabilities: getencoding runcommand\nencoding: *\npid: *' (glob)
701 *** runcommand id
699 *** runcommand id
702 eff892de26ec tip bm1/bm2/bm3
700 eff892de26ec tip bm1/bm2/bm3
703 >>> def unknowncommand(conn):
701 >>> def unknowncommand(conn):
704 ... readchannel(conn)
702 ... readchannel(conn)
705 ... conn.stdin.write('unknowncommand\n')
703 ... conn.stdin.write('unknowncommand\n')
706 >>> check(unknowncommand, server.connect) # error sent to server.log
704 >>> check(unknowncommand, server.connect) # error sent to server.log
707 >>> def serverinput(conn):
705 >>> def serverinput(conn):
708 ... readchannel(conn)
706 ... readchannel(conn)
709 ... patch = """
707 ... patch = """
710 ... # HG changeset patch
708 ... # HG changeset patch
711 ... # User test
709 ... # User test
712 ... # Date 0 0
710 ... # Date 0 0
713 ... 2
711 ... 2
714 ...
712 ...
715 ... diff -r eff892de26ec -r 1ed24be7e7a0 a
713 ... diff -r eff892de26ec -r 1ed24be7e7a0 a
716 ... --- a/a
714 ... --- a/a
717 ... +++ b/a
715 ... +++ b/a
718 ... @@ -1,1 +1,2 @@
716 ... @@ -1,1 +1,2 @@
719 ... 1
717 ... 1
720 ... +2
718 ... +2
721 ... """
719 ... """
722 ... runcommand(conn, ['import', '-'], input=stringio(patch))
720 ... runcommand(conn, ['import', '-'], input=stringio(patch))
723 ... runcommand(conn, ['log', '-rtip', '-q'])
721 ... runcommand(conn, ['log', '-rtip', '-q'])
724 >>> check(serverinput, server.connect)
722 >>> check(serverinput, server.connect)
725 *** runcommand import -
723 *** runcommand import -
726 applying patch from stdin
724 applying patch from stdin
727 *** runcommand log -rtip -q
725 *** runcommand log -rtip -q
728 2:1ed24be7e7a0
726 2:1ed24be7e7a0
729 >>> server.shutdown()
727 >>> server.shutdown()
730
728
731 $ cat .hg/server.log
729 $ cat .hg/server.log
732 listening at .hg/server.sock
730 listening at .hg/server.sock
733 abort: unknown command unknowncommand
731 abort: unknown command unknowncommand
734 killed!
732 killed!
735 $ rm .hg/server.log
733 $ rm .hg/server.log
736
734
737 if server crashed before hello, traceback will be sent to 'e' channel as
735 if server crashed before hello, traceback will be sent to 'e' channel as
738 last ditch:
736 last ditch:
739
737
740 $ cat <<EOF >> .hg/hgrc
738 $ cat <<EOF >> .hg/hgrc
741 > [cmdserver]
739 > [cmdserver]
742 > log = inexistent/path.log
740 > log = inexistent/path.log
743 > EOF
741 > EOF
744 >>> from __future__ import print_function
742 >>> from __future__ import print_function
745 >>> from hgclient import unixserver, readchannel, check
743 >>> from hgclient import unixserver, readchannel, check
746 >>> server = unixserver('.hg/server.sock', '.hg/server.log')
744 >>> server = unixserver('.hg/server.sock', '.hg/server.log')
747 >>> def earlycrash(conn):
745 >>> def earlycrash(conn):
748 ... while True:
746 ... while True:
749 ... try:
747 ... try:
750 ... ch, data = readchannel(conn)
748 ... ch, data = readchannel(conn)
751 ... if not data.startswith(' '):
749 ... if not data.startswith(' '):
752 ... print('%c, %r' % (ch, data))
750 ... print('%c, %r' % (ch, data))
753 ... except EOFError:
751 ... except EOFError:
754 ... break
752 ... break
755 >>> check(earlycrash, server.connect)
753 >>> check(earlycrash, server.connect)
756 e, 'Traceback (most recent call last):\n'
754 e, 'Traceback (most recent call last):\n'
757 e, "IOError: *" (glob)
755 e, "IOError: *" (glob)
758 >>> server.shutdown()
756 >>> server.shutdown()
759
757
760 $ cat .hg/server.log | grep -v '^ '
758 $ cat .hg/server.log | grep -v '^ '
761 listening at .hg/server.sock
759 listening at .hg/server.sock
762 Traceback (most recent call last):
760 Traceback (most recent call last):
763 IOError: * (glob)
761 IOError: * (glob)
764 killed!
762 killed!
765 #endif
763 #endif
766 #if no-unix-socket
764 #if no-unix-socket
767
765
768 $ hg serve --cmdserver unix -a .hg/server.sock
766 $ hg serve --cmdserver unix -a .hg/server.sock
769 abort: unsupported platform
767 abort: unsupported platform
770 [255]
768 [255]
771
769
772 #endif
770 #endif
773
771
774 $ cd ..
772 $ cd ..
775
773
776 Test that accessing to invalid changelog cache is avoided at
774 Test that accessing to invalid changelog cache is avoided at
777 subsequent operations even if repo object is reused even after failure
775 subsequent operations even if repo object is reused even after failure
778 of transaction (see 0a7610758c42 also)
776 of transaction (see 0a7610758c42 also)
779
777
780 "hg log" after failure of transaction is needed to detect invalid
778 "hg log" after failure of transaction is needed to detect invalid
781 cache in repoview: this can't detect by "hg verify" only.
779 cache in repoview: this can't detect by "hg verify" only.
782
780
783 Combination of "finalization" and "empty-ness of changelog" (2 x 2 =
781 Combination of "finalization" and "empty-ness of changelog" (2 x 2 =
784 4) are tested, because '00changelog.i' are differently changed in each
782 4) are tested, because '00changelog.i' are differently changed in each
785 cases.
783 cases.
786
784
787 $ cat > $TESTTMP/failafterfinalize.py <<EOF
785 $ cat > $TESTTMP/failafterfinalize.py <<EOF
788 > # extension to abort transaction after finalization forcibly
786 > # extension to abort transaction after finalization forcibly
789 > from mercurial import commands, error, extensions, lock as lockmod
787 > from mercurial import commands, error, extensions, lock as lockmod
790 > def fail(tr):
788 > def fail(tr):
791 > raise error.Abort('fail after finalization')
789 > raise error.Abort('fail after finalization')
792 > def reposetup(ui, repo):
790 > def reposetup(ui, repo):
793 > class failrepo(repo.__class__):
791 > class failrepo(repo.__class__):
794 > def commitctx(self, ctx, error=False):
792 > def commitctx(self, ctx, error=False):
795 > if self.ui.configbool('failafterfinalize', 'fail'):
793 > if self.ui.configbool('failafterfinalize', 'fail'):
796 > # 'sorted()' by ASCII code on category names causes
794 > # 'sorted()' by ASCII code on category names causes
797 > # invoking 'fail' after finalization of changelog
795 > # invoking 'fail' after finalization of changelog
798 > # using "'cl-%i' % id(self)" as category name
796 > # using "'cl-%i' % id(self)" as category name
799 > self.currenttransaction().addfinalize('zzzzzzzz', fail)
797 > self.currenttransaction().addfinalize('zzzzzzzz', fail)
800 > return super(failrepo, self).commitctx(ctx, error)
798 > return super(failrepo, self).commitctx(ctx, error)
801 > repo.__class__ = failrepo
799 > repo.__class__ = failrepo
802 > EOF
800 > EOF
803
801
804 $ hg init repo3
802 $ hg init repo3
805 $ cd repo3
803 $ cd repo3
806
804
807 $ cat <<EOF >> $HGRCPATH
805 $ cat <<EOF >> $HGRCPATH
808 > [ui]
806 > [ui]
809 > logtemplate = {rev} {desc|firstline} ({files})\n
807 > logtemplate = {rev} {desc|firstline} ({files})\n
810 >
808 >
811 > [extensions]
809 > [extensions]
812 > failafterfinalize = $TESTTMP/failafterfinalize.py
810 > failafterfinalize = $TESTTMP/failafterfinalize.py
813 > EOF
811 > EOF
814
812
815 - test failure with "empty changelog"
813 - test failure with "empty changelog"
816
814
817 $ echo foo > foo
815 $ echo foo > foo
818 $ hg add foo
816 $ hg add foo
819
817
820 (failure before finalization)
818 (failure before finalization)
821
819
822 >>> from hgclient import readchannel, runcommand, check
820 >>> from hgclient import readchannel, runcommand, check
823 >>> @check
821 >>> @check
824 ... def abort(server):
822 ... def abort(server):
825 ... readchannel(server)
823 ... readchannel(server)
826 ... runcommand(server, ['commit',
824 ... runcommand(server, ['commit',
827 ... '--config', 'hooks.pretxncommit=false',
825 ... '--config', 'hooks.pretxncommit=false',
828 ... '-mfoo'])
826 ... '-mfoo'])
829 ... runcommand(server, ['log'])
827 ... runcommand(server, ['log'])
830 ... runcommand(server, ['verify', '-q'])
828 ... runcommand(server, ['verify', '-q'])
831 *** runcommand commit --config hooks.pretxncommit=false -mfoo
829 *** runcommand commit --config hooks.pretxncommit=false -mfoo
832 transaction abort!
830 transaction abort!
833 rollback completed
831 rollback completed
834 abort: pretxncommit hook exited with status 1
832 abort: pretxncommit hook exited with status 1
835 [255]
833 [255]
836 *** runcommand log
834 *** runcommand log
837 *** runcommand verify -q
835 *** runcommand verify -q
838
836
839 (failure after finalization)
837 (failure after finalization)
840
838
841 >>> from hgclient import readchannel, runcommand, check
839 >>> from hgclient import readchannel, runcommand, check
842 >>> @check
840 >>> @check
843 ... def abort(server):
841 ... def abort(server):
844 ... readchannel(server)
842 ... readchannel(server)
845 ... runcommand(server, ['commit',
843 ... runcommand(server, ['commit',
846 ... '--config', 'failafterfinalize.fail=true',
844 ... '--config', 'failafterfinalize.fail=true',
847 ... '-mfoo'])
845 ... '-mfoo'])
848 ... runcommand(server, ['log'])
846 ... runcommand(server, ['log'])
849 ... runcommand(server, ['verify', '-q'])
847 ... runcommand(server, ['verify', '-q'])
850 *** runcommand commit --config failafterfinalize.fail=true -mfoo
848 *** runcommand commit --config failafterfinalize.fail=true -mfoo
851 transaction abort!
849 transaction abort!
852 rollback completed
850 rollback completed
853 abort: fail after finalization
851 abort: fail after finalization
854 [255]
852 [255]
855 *** runcommand log
853 *** runcommand log
856 *** runcommand verify -q
854 *** runcommand verify -q
857
855
858 - test failure with "not-empty changelog"
856 - test failure with "not-empty changelog"
859
857
860 $ echo bar > bar
858 $ echo bar > bar
861 $ hg add bar
859 $ hg add bar
862 $ hg commit -mbar bar
860 $ hg commit -mbar bar
863
861
864 (failure before finalization)
862 (failure before finalization)
865
863
866 >>> from hgclient import readchannel, runcommand, check
864 >>> from hgclient import readchannel, runcommand, check
867 >>> @check
865 >>> @check
868 ... def abort(server):
866 ... def abort(server):
869 ... readchannel(server)
867 ... readchannel(server)
870 ... runcommand(server, ['commit',
868 ... runcommand(server, ['commit',
871 ... '--config', 'hooks.pretxncommit=false',
869 ... '--config', 'hooks.pretxncommit=false',
872 ... '-mfoo', 'foo'])
870 ... '-mfoo', 'foo'])
873 ... runcommand(server, ['log'])
871 ... runcommand(server, ['log'])
874 ... runcommand(server, ['verify', '-q'])
872 ... runcommand(server, ['verify', '-q'])
875 *** runcommand commit --config hooks.pretxncommit=false -mfoo foo
873 *** runcommand commit --config hooks.pretxncommit=false -mfoo foo
876 transaction abort!
874 transaction abort!
877 rollback completed
875 rollback completed
878 abort: pretxncommit hook exited with status 1
876 abort: pretxncommit hook exited with status 1
879 [255]
877 [255]
880 *** runcommand log
878 *** runcommand log
881 0 bar (bar)
879 0 bar (bar)
882 *** runcommand verify -q
880 *** runcommand verify -q
883
881
884 (failure after finalization)
882 (failure after finalization)
885
883
886 >>> from hgclient import readchannel, runcommand, check
884 >>> from hgclient import readchannel, runcommand, check
887 >>> @check
885 >>> @check
888 ... def abort(server):
886 ... def abort(server):
889 ... readchannel(server)
887 ... readchannel(server)
890 ... runcommand(server, ['commit',
888 ... runcommand(server, ['commit',
891 ... '--config', 'failafterfinalize.fail=true',
889 ... '--config', 'failafterfinalize.fail=true',
892 ... '-mfoo', 'foo'])
890 ... '-mfoo', 'foo'])
893 ... runcommand(server, ['log'])
891 ... runcommand(server, ['log'])
894 ... runcommand(server, ['verify', '-q'])
892 ... runcommand(server, ['verify', '-q'])
895 *** runcommand commit --config failafterfinalize.fail=true -mfoo foo
893 *** runcommand commit --config failafterfinalize.fail=true -mfoo foo
896 transaction abort!
894 transaction abort!
897 rollback completed
895 rollback completed
898 abort: fail after finalization
896 abort: fail after finalization
899 [255]
897 [255]
900 *** runcommand log
898 *** runcommand log
901 0 bar (bar)
899 0 bar (bar)
902 *** runcommand verify -q
900 *** runcommand verify -q
General Comments 0
You need to be logged in to leave comments. Login now