##// END OF EJS Templates
hook.py: fix redirections introduced by 323b9c55b328...
Alexis S. L. Carvalho -
r6266:9f76df0e default
parent child Browse files
Show More
@@ -1,113 +1,115
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
5 # This software may be used and distributed according to the terms
6 # of the GNU General Public License, incorporated herein by reference.
6 # of the GNU General Public License, incorporated herein by reference.
7
7
8 from i18n import _
8 from i18n import _
9 import util, os, sys
9 import util, os, sys
10
10
11 def _pythonhook(ui, repo, name, hname, funcname, args, throw):
11 def _pythonhook(ui, repo, name, hname, funcname, args, throw):
12 '''call python hook. hook is callable object, looked up as
12 '''call python hook. hook is callable object, looked up as
13 name in python module. if callable returns "true", hook
13 name in python module. if callable returns "true", hook
14 fails, else passes. if hook raises exception, treated as
14 fails, else passes. if hook raises exception, treated as
15 hook failure. exception propagates if throw is "true".
15 hook failure. exception propagates if throw is "true".
16
16
17 reason for "true" meaning "hook failed" is so that
17 reason for "true" meaning "hook failed" is so that
18 unmodified commands (e.g. mercurial.commands.update) can
18 unmodified commands (e.g. mercurial.commands.update) can
19 be run as hooks without wrappers to convert return values.'''
19 be run as hooks without wrappers to convert return values.'''
20
20
21 ui.note(_("calling hook %s: %s\n") % (hname, funcname))
21 ui.note(_("calling hook %s: %s\n") % (hname, funcname))
22 obj = funcname
22 obj = funcname
23 if not callable(obj):
23 if not callable(obj):
24 d = funcname.rfind('.')
24 d = funcname.rfind('.')
25 if d == -1:
25 if d == -1:
26 raise util.Abort(_('%s hook is invalid ("%s" not in '
26 raise util.Abort(_('%s hook is invalid ("%s" not in '
27 'a module)') % (hname, funcname))
27 'a module)') % (hname, funcname))
28 modname = funcname[:d]
28 modname = funcname[:d]
29 try:
29 try:
30 obj = __import__(modname)
30 obj = __import__(modname)
31 except ImportError:
31 except ImportError:
32 try:
32 try:
33 # extensions are loaded with hgext_ prefix
33 # extensions are loaded with hgext_ prefix
34 obj = __import__("hgext_%s" % modname)
34 obj = __import__("hgext_%s" % modname)
35 except ImportError:
35 except ImportError:
36 raise util.Abort(_('%s hook is invalid '
36 raise util.Abort(_('%s hook is invalid '
37 '(import of "%s" failed)') %
37 '(import of "%s" failed)') %
38 (hname, modname))
38 (hname, modname))
39 try:
39 try:
40 for p in funcname.split('.')[1:]:
40 for p in funcname.split('.')[1:]:
41 obj = getattr(obj, p)
41 obj = getattr(obj, p)
42 except AttributeError, err:
42 except AttributeError, err:
43 raise util.Abort(_('%s hook is invalid '
43 raise util.Abort(_('%s hook is invalid '
44 '("%s" is not defined)') %
44 '("%s" is not defined)') %
45 (hname, funcname))
45 (hname, funcname))
46 if not callable(obj):
46 if not callable(obj):
47 raise util.Abort(_('%s hook is invalid '
47 raise util.Abort(_('%s hook is invalid '
48 '("%s" is not callable)') %
48 '("%s" is not callable)') %
49 (hname, funcname))
49 (hname, funcname))
50 try:
50 try:
51 r = obj(ui=ui, repo=repo, hooktype=name, **args)
51 r = obj(ui=ui, repo=repo, hooktype=name, **args)
52 except (KeyboardInterrupt, util.SignalInterrupt):
52 except (KeyboardInterrupt, util.SignalInterrupt):
53 raise
53 raise
54 except Exception, exc:
54 except Exception, exc:
55 if isinstance(exc, util.Abort):
55 if isinstance(exc, util.Abort):
56 ui.warn(_('error: %s hook failed: %s\n') %
56 ui.warn(_('error: %s hook failed: %s\n') %
57 (hname, exc.args[0]))
57 (hname, exc.args[0]))
58 else:
58 else:
59 ui.warn(_('error: %s hook raised an exception: '
59 ui.warn(_('error: %s hook raised an exception: '
60 '%s\n') % (hname, exc))
60 '%s\n') % (hname, exc))
61 if throw:
61 if throw:
62 raise
62 raise
63 ui.print_exc()
63 ui.print_exc()
64 return True
64 return True
65 if r:
65 if r:
66 if throw:
66 if throw:
67 raise util.Abort(_('%s hook failed') % hname)
67 raise util.Abort(_('%s hook failed') % hname)
68 ui.warn(_('warning: %s hook failed\n') % hname)
68 ui.warn(_('warning: %s hook failed\n') % hname)
69 return r
69 return r
70
70
71 def _exthook(ui, repo, name, cmd, args, throw):
71 def _exthook(ui, repo, name, cmd, args, throw):
72 ui.note(_("running hook %s: %s\n") % (name, cmd))
72 ui.note(_("running hook %s: %s\n") % (name, cmd))
73 env = dict([('HG_' + k.upper(), v) for k, v in args.iteritems()])
73 env = dict([('HG_' + k.upper(), v) for k, v in args.iteritems()])
74 if repo:
74 if repo:
75 cwd = repo.root
75 cwd = repo.root
76 else:
76 else:
77 cwd = os.getcwd()
77 cwd = os.getcwd()
78 r = util.system(cmd, environ=env, cwd=cwd)
78 r = util.system(cmd, environ=env, cwd=cwd)
79 if r:
79 if r:
80 desc, r = util.explain_exit(r)
80 desc, r = util.explain_exit(r)
81 if throw:
81 if throw:
82 raise util.Abort(_('%s hook %s') % (name, desc))
82 raise util.Abort(_('%s hook %s') % (name, desc))
83 ui.warn(_('warning: %s hook %s\n') % (name, desc))
83 ui.warn(_('warning: %s hook %s\n') % (name, desc))
84 return r
84 return r
85
85
86 _redirect = False
86 _redirect = False
87 def redirect(state):
87 def redirect(state):
88 global _redirect
88 _redirect = state
89 _redirect = state
89
90
90 def hook(ui, repo, name, throw=False, **args):
91 def hook(ui, repo, name, throw=False, **args):
91 r = False
92 r = False
92
93
93 if _redirect:
94 if _redirect:
94 # temporarily redirect stdout to stderr
95 # temporarily redirect stdout to stderr
95 oldstdout = os.dup(sys.stdout.fileno())
96 oldstdout = os.dup(sys.__stdout__.fileno())
96 os.dup2(sys.stderr.fileno(), sys.stdout.fileno())
97 os.dup2(sys.__stderr__.fileno(), sys.__stdout__.fileno())
97
98
98 hooks = [(hname, cmd) for hname, cmd in ui.configitems("hooks")
99 hooks = [(hname, cmd) for hname, cmd in ui.configitems("hooks")
99 if hname.split(".", 1)[0] == name and cmd]
100 if hname.split(".", 1)[0] == name and cmd]
100 hooks.sort()
101 hooks.sort()
101 for hname, cmd in hooks:
102 for hname, cmd in hooks:
102 if callable(cmd):
103 if callable(cmd):
103 r = _pythonhook(ui, repo, name, hname, cmd, args, throw) or r
104 r = _pythonhook(ui, repo, name, hname, cmd, args, throw) or r
104 elif cmd.startswith('python:'):
105 elif cmd.startswith('python:'):
105 r = _pythonhook(ui, repo, name, hname, cmd[7:].strip(),
106 r = _pythonhook(ui, repo, name, hname, cmd[7:].strip(),
106 args, throw) or r
107 args, throw) or r
107 else:
108 else:
108 r = _exthook(ui, repo, hname, cmd, args, throw) or r
109 r = _exthook(ui, repo, hname, cmd, args, throw) or r
109 return r
110
110
111 if _redirect:
111 if _redirect:
112 os.dup2(oldstdout, sys.stdout.fileno())
112 os.dup2(oldstdout, sys.__stdout__.fileno())
113 os.close(oldstdout)
113 os.close(oldstdout)
114
115 return r
@@ -1,111 +1,111
1 #!/bin/sh
1 #!/bin/sh
2
2
3 cp "$TESTDIR"/printenv.py .
3 cp "$TESTDIR"/printenv.py .
4
4
5 # This test tries to exercise the ssh functionality with a dummy script
5 # This test tries to exercise the ssh functionality with a dummy script
6
6
7 cat <<EOF > dummyssh
7 cat <<EOF > dummyssh
8 import sys
8 import sys
9 import os
9 import os
10
10
11 os.chdir(os.path.dirname(sys.argv[0]))
11 os.chdir(os.path.dirname(sys.argv[0]))
12 if sys.argv[1] != "user@dummy":
12 if sys.argv[1] != "user@dummy":
13 sys.exit(-1)
13 sys.exit(-1)
14
14
15 if not os.path.exists("dummyssh"):
15 if not os.path.exists("dummyssh"):
16 sys.exit(-1)
16 sys.exit(-1)
17
17
18 os.environ["SSH_CLIENT"] = "127.0.0.1 1 2"
18 os.environ["SSH_CLIENT"] = "127.0.0.1 1 2"
19
19
20 log = open("dummylog", "ab")
20 log = open("dummylog", "ab")
21 log.write("Got arguments")
21 log.write("Got arguments")
22 for i, arg in enumerate(sys.argv[1:]):
22 for i, arg in enumerate(sys.argv[1:]):
23 log.write(" %d:%s" % (i+1, arg))
23 log.write(" %d:%s" % (i+1, arg))
24 log.write("\n")
24 log.write("\n")
25 log.close()
25 log.close()
26 r = os.system(sys.argv[2])
26 r = os.system(sys.argv[2])
27 sys.exit(bool(r))
27 sys.exit(bool(r))
28 EOF
28 EOF
29
29
30 cat <<EOF > badhook
30 cat <<EOF > badhook
31 import sys
31 import sys
32 sys.stdout.write("KABOOM")
32 sys.stdout.write("KABOOM\n")
33 EOF
33 EOF
34
34
35 echo "# creating 'remote'"
35 echo "# creating 'remote'"
36 hg init remote
36 hg init remote
37 cd remote
37 cd remote
38 echo this > foo
38 echo this > foo
39 echo this > fooO
39 echo this > fooO
40 hg ci -A -m "init" -d "1000000 0" foo fooO
40 hg ci -A -m "init" -d "1000000 0" foo fooO
41 echo '[server]' > .hg/hgrc
41 echo '[server]' > .hg/hgrc
42 echo 'uncompressed = True' >> .hg/hgrc
42 echo 'uncompressed = True' >> .hg/hgrc
43 echo '[hooks]' >> .hg/hgrc
43 echo '[hooks]' >> .hg/hgrc
44 echo 'changegroup = python ../printenv.py changegroup-in-remote 0 ../dummylog' >> .hg/hgrc
44 echo 'changegroup = python ../printenv.py changegroup-in-remote 0 ../dummylog' >> .hg/hgrc
45
45
46 cd ..
46 cd ..
47
47
48 echo "# repo not found error"
48 echo "# repo not found error"
49 hg clone -e "python ./dummyssh" ssh://user@dummy/nonexistent local
49 hg clone -e "python ./dummyssh" ssh://user@dummy/nonexistent local
50
50
51 echo "# clone remote via stream"
51 echo "# clone remote via stream"
52 hg clone -e "python ./dummyssh" --uncompressed ssh://user@dummy/remote local-stream 2>&1 | \
52 hg clone -e "python ./dummyssh" --uncompressed ssh://user@dummy/remote local-stream 2>&1 | \
53 sed -e 's/[0-9][0-9.]*/XXX/g' -e 's/[KM]\(B\/sec\)/X\1/'
53 sed -e 's/[0-9][0-9.]*/XXX/g' -e 's/[KM]\(B\/sec\)/X\1/'
54 cd local-stream
54 cd local-stream
55 hg verify
55 hg verify
56 cd ..
56 cd ..
57
57
58 echo "# clone remote via pull"
58 echo "# clone remote via pull"
59 hg clone -e "python ./dummyssh" ssh://user@dummy/remote local
59 hg clone -e "python ./dummyssh" ssh://user@dummy/remote local
60
60
61 echo "# verify"
61 echo "# verify"
62 cd local
62 cd local
63 hg verify
63 hg verify
64
64
65 echo '[hooks]' >> .hg/hgrc
65 echo '[hooks]' >> .hg/hgrc
66 echo 'changegroup = python ../printenv.py changegroup-in-local 0 ../dummylog' >> .hg/hgrc
66 echo 'changegroup = python ../printenv.py changegroup-in-local 0 ../dummylog' >> .hg/hgrc
67
67
68 echo "# empty default pull"
68 echo "# empty default pull"
69 hg paths
69 hg paths
70 hg pull -e "python ../dummyssh"
70 hg pull -e "python ../dummyssh"
71
71
72 echo "# local change"
72 echo "# local change"
73 echo bleah > foo
73 echo bleah > foo
74 hg ci -m "add" -d "1000000 0"
74 hg ci -m "add" -d "1000000 0"
75
75
76 echo "# updating rc"
76 echo "# updating rc"
77 echo "default-push = ssh://user@dummy/remote" >> .hg/hgrc
77 echo "default-push = ssh://user@dummy/remote" >> .hg/hgrc
78 echo "[ui]" >> .hg/hgrc
78 echo "[ui]" >> .hg/hgrc
79 echo "ssh = python ../dummyssh" >> .hg/hgrc
79 echo "ssh = python ../dummyssh" >> .hg/hgrc
80
80
81 echo "# find outgoing"
81 echo "# find outgoing"
82 hg out ssh://user@dummy/remote
82 hg out ssh://user@dummy/remote
83
83
84 echo "# find incoming on the remote side"
84 echo "# find incoming on the remote side"
85 hg incoming -R ../remote -e "python ../dummyssh" ssh://user@dummy/local
85 hg incoming -R ../remote -e "python ../dummyssh" ssh://user@dummy/local
86
86
87 echo "# push"
87 echo "# push"
88 hg push
88 hg push
89
89
90 cd ../remote
90 cd ../remote
91
91
92 echo "# check remote tip"
92 echo "# check remote tip"
93 hg tip
93 hg tip
94 hg verify
94 hg verify
95 hg cat -r tip foo
95 hg cat -r tip foo
96
96
97 echo z > z
97 echo z > z
98 hg ci -A -m z -d '1000001 0' z
98 hg ci -A -m z -d '1000001 0' z
99 # a bad, evil hook that prints to stdout
99 # a bad, evil hook that prints to stdout
100 echo 'changegroup.stdout = python ../badhook' >> .hg/hgrc
100 echo 'changegroup.stdout = python ../badhook' >> .hg/hgrc
101
101
102 cd ../local
102 cd ../local
103 echo r > r
103 echo r > r
104 hg ci -A -m z -d '1000002 0' r
104 hg ci -A -m z -d '1000002 0' r
105
105
106 echo "# push should succeed even though it has an unexpected response"
106 echo "# push should succeed even though it has an unexpected response"
107 hg push
107 hg push
108 hg -R ../remote heads
108 hg -R ../remote heads
109
109
110 cd ..
110 cd ..
111 cat dummylog
111 cat dummylog
@@ -1,105 +1,104
1 # creating 'remote'
1 # creating 'remote'
2 # repo not found error
2 # repo not found error
3 remote: abort: There is no Mercurial repository here (.hg not found)!
3 remote: abort: There is no Mercurial repository here (.hg not found)!
4 abort: no suitable response from remote hg!
4 abort: no suitable response from remote hg!
5 # clone remote via stream
5 # clone remote via stream
6 streaming all changes
6 streaming all changes
7 XXX files to transfer, XXX bytes of data
7 XXX files to transfer, XXX bytes of data
8 transferred XXX bytes in XXX seconds (XXX XB/sec)
8 transferred XXX bytes in XXX seconds (XXX XB/sec)
9 XXX files updated, XXX files merged, XXX files removed, XXX files unresolved
9 XXX files updated, XXX files merged, XXX files removed, XXX files unresolved
10 checking changesets
10 checking changesets
11 checking manifests
11 checking manifests
12 crosschecking files in changesets and manifests
12 crosschecking files in changesets and manifests
13 checking files
13 checking files
14 2 files, 1 changesets, 2 total revisions
14 2 files, 1 changesets, 2 total revisions
15 # clone remote via pull
15 # clone remote via pull
16 requesting all changes
16 requesting all changes
17 adding changesets
17 adding changesets
18 adding manifests
18 adding manifests
19 adding file changes
19 adding file changes
20 added 1 changesets with 2 changes to 2 files
20 added 1 changesets with 2 changes to 2 files
21 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
21 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
22 # verify
22 # verify
23 checking changesets
23 checking changesets
24 checking manifests
24 checking manifests
25 crosschecking files in changesets and manifests
25 crosschecking files in changesets and manifests
26 checking files
26 checking files
27 2 files, 1 changesets, 2 total revisions
27 2 files, 1 changesets, 2 total revisions
28 # empty default pull
28 # empty default pull
29 default = ssh://user@dummy/remote
29 default = ssh://user@dummy/remote
30 pulling from ssh://user@dummy/remote
30 pulling from ssh://user@dummy/remote
31 searching for changes
31 searching for changes
32 no changes found
32 no changes found
33 # local change
33 # local change
34 # updating rc
34 # updating rc
35 # find outgoing
35 # find outgoing
36 comparing with ssh://user@dummy/remote
36 comparing with ssh://user@dummy/remote
37 searching for changes
37 searching for changes
38 changeset: 1:572896fe480d
38 changeset: 1:572896fe480d
39 tag: tip
39 tag: tip
40 user: test
40 user: test
41 date: Mon Jan 12 13:46:40 1970 +0000
41 date: Mon Jan 12 13:46:40 1970 +0000
42 summary: add
42 summary: add
43
43
44 # find incoming on the remote side
44 # find incoming on the remote side
45 comparing with ssh://user@dummy/local
45 comparing with ssh://user@dummy/local
46 searching for changes
46 searching for changes
47 changeset: 1:572896fe480d
47 changeset: 1:572896fe480d
48 tag: tip
48 tag: tip
49 user: test
49 user: test
50 date: Mon Jan 12 13:46:40 1970 +0000
50 date: Mon Jan 12 13:46:40 1970 +0000
51 summary: add
51 summary: add
52
52
53 # push
53 # push
54 pushing to ssh://user@dummy/remote
54 pushing to ssh://user@dummy/remote
55 searching for changes
55 searching for changes
56 remote: adding changesets
56 remote: adding changesets
57 remote: adding manifests
57 remote: adding manifests
58 remote: adding file changes
58 remote: adding file changes
59 remote: added 1 changesets with 1 changes to 1 files
59 remote: added 1 changesets with 1 changes to 1 files
60 # check remote tip
60 # check remote tip
61 changeset: 1:572896fe480d
61 changeset: 1:572896fe480d
62 tag: tip
62 tag: tip
63 user: test
63 user: test
64 date: Mon Jan 12 13:46:40 1970 +0000
64 date: Mon Jan 12 13:46:40 1970 +0000
65 summary: add
65 summary: add
66
66
67 checking changesets
67 checking changesets
68 checking manifests
68 checking manifests
69 crosschecking files in changesets and manifests
69 crosschecking files in changesets and manifests
70 checking files
70 checking files
71 2 files, 2 changesets, 3 total revisions
71 2 files, 2 changesets, 3 total revisions
72 bleah
72 bleah
73 # push should succeed even though it has an unexpected response
73 # push should succeed even though it has an unexpected response
74 pushing to ssh://user@dummy/remote
74 pushing to ssh://user@dummy/remote
75 searching for changes
75 searching for changes
76 note: unsynced remote changes!
76 note: unsynced remote changes!
77 remote: adding changesets
77 remote: adding changesets
78 remote: adding manifests
78 remote: adding manifests
79 remote: adding file changes
79 remote: adding file changes
80 remote: added 1 changesets with 1 changes to 1 files
80 remote: added 1 changesets with 1 changes to 1 files
81 abort: unexpected response:
81 remote: KABOOM
82 'KABOOM1\n'
83 changeset: 3:ac7448082955
82 changeset: 3:ac7448082955
84 tag: tip
83 tag: tip
85 parent: 1:572896fe480d
84 parent: 1:572896fe480d
86 user: test
85 user: test
87 date: Mon Jan 12 13:46:42 1970 +0000
86 date: Mon Jan 12 13:46:42 1970 +0000
88 summary: z
87 summary: z
89
88
90 changeset: 2:187c6caa0d1e
89 changeset: 2:187c6caa0d1e
91 parent: 0:e34318c26897
90 parent: 0:e34318c26897
92 user: test
91 user: test
93 date: Mon Jan 12 13:46:41 1970 +0000
92 date: Mon Jan 12 13:46:41 1970 +0000
94 summary: z
93 summary: z
95
94
96 Got arguments 1:user@dummy 2:hg -R nonexistent serve --stdio
95 Got arguments 1:user@dummy 2:hg -R nonexistent serve --stdio
97 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
96 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
98 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
97 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
99 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
98 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
100 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
99 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
101 Got arguments 1:user@dummy 2:hg -R local serve --stdio
100 Got arguments 1:user@dummy 2:hg -R local serve --stdio
102 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
101 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
103 changegroup-in-remote hook: HG_NODE=572896fe480d7581849806ee402175c49cb20037 HG_SOURCE=serve HG_URL=remote:ssh:127.0.0.1
102 changegroup-in-remote hook: HG_NODE=572896fe480d7581849806ee402175c49cb20037 HG_SOURCE=serve HG_URL=remote:ssh:127.0.0.1
104 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
103 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
105 changegroup-in-remote hook: HG_NODE=ac7448082955a0b2ff5cb4512c1e061c779bbc79 HG_SOURCE=serve HG_URL=remote:ssh:127.0.0.1
104 changegroup-in-remote hook: HG_NODE=ac7448082955a0b2ff5cb4512c1e061c779bbc79 HG_SOURCE=serve HG_URL=remote:ssh:127.0.0.1
General Comments 0
You need to be logged in to leave comments. Login now