annotate mercurial/hook.py @ 45095:8e04607023e5

procutil: ensure that procutil.std{out,err}.write() writes all bytes Python 3 offers different kind of streams and it’s not guaranteed for all of them that calling write() writes all bytes. When Python is started in unbuffered mode, sys.std{out,err}.buffer are instances of io.FileIO, whose write() can write less bytes for platform-specific reasons (e.g. Linux has a 0x7ffff000 bytes maximum and could write less if interrupted by a signal; when writing to Windows consoles, it’s limited to 32767 bytes to avoid the "not enough space" error). This can lead to silent loss of data, both when using sys.std{out,err}.buffer (which may in fact not be a buffered stream) and when using the text streams sys.std{out,err} (I’ve created a CPython bug report for that: https://bugs.python.org/issue41221). Python may fix the problem at some point. For now, we implement our own wrapper for procutil.std{out,err} that calls the raw stream’s write() method until all bytes have been written. We don’t use sys.std{out,err} for larger writes, so I think it’s not worth the effort to patch them.
author Manuel Jacob <me@manueljacob.de>
date Fri, 10 Jul 2020 12:27:58 +0200
parents fd3b94f1712d
children b3e8d8e4a40d
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
4622
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
1 # hook.py - hook support for mercurial
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
2 #
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
3 # Copyright 2007 Matt Mackall <mpm@selenic.com>
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
4 #
8225
46293a0c7e9f updated license to be explicit about GPL version 2
Martin Geisler <mg@lazybytes.net>
parents: 8209
diff changeset
5 # This software may be used and distributed according to the terms of the
10263
25e572394f5c Update license to GPLv2+
Matt Mackall <mpm@selenic.com>
parents: 10103
diff changeset
6 # GNU General Public License version 2 or any later version.
4622
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
7
25953
d15b279ddade hook: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25660
diff changeset
8 from __future__ import absolute_import
d15b279ddade hook: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25660
diff changeset
9
44652
3cbbfd0bfc17 hook: move stdio redirection to context manager
Gregory Szorc <gregory.szorc@gmail.com>
parents: 43671
diff changeset
10 import contextlib
25953
d15b279ddade hook: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25660
diff changeset
11 import os
d15b279ddade hook: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25660
diff changeset
12 import sys
d15b279ddade hook: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25660
diff changeset
13
d15b279ddade hook: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25660
diff changeset
14 from .i18n import _
43089
c59eb1560c44 py3: manually import getattr where it is needed
Gregory Szorc <gregory.szorc@gmail.com>
parents: 43077
diff changeset
15 from .pycompat import getattr
25953
d15b279ddade hook: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25660
diff changeset
16 from . import (
d15b279ddade hook: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25660
diff changeset
17 demandimport,
32642
c032e137e494 py3: convert exception to bytes to pass into ui.warn()
Pulkit Goyal <7895pulkit@gmail.com>
parents: 32614
diff changeset
18 encoding,
25953
d15b279ddade hook: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25660
diff changeset
19 error,
d15b279ddade hook: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25660
diff changeset
20 extensions,
30519
20a42325fdef py3: use pycompat.getcwd() instead of os.getcwd()
Pulkit Goyal <7895pulkit@gmail.com>
parents: 30473
diff changeset
21 pycompat,
25953
d15b279ddade hook: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25660
diff changeset
22 util,
d15b279ddade hook: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25660
diff changeset
23 )
37119
d4a2e0d5d042 procutil: bulk-replace util.std* to point to new module
Yuya Nishihara <yuya@tcha.org>
parents: 36841
diff changeset
24 from .utils import (
d4a2e0d5d042 procutil: bulk-replace util.std* to point to new module
Yuya Nishihara <yuya@tcha.org>
parents: 36841
diff changeset
25 procutil,
43671
664e24207728 procutil: move mainfrozen() to new resourceutil.py
Martin von Zweigbergk <martinvonz@google.com>
parents: 43503
diff changeset
26 resourceutil,
37751
483de34f23b1 hook: use stringutil.pprint instead of reinventing it
Augie Fackler <augie@google.com>
parents: 37463
diff changeset
27 stringutil,
37119
d4a2e0d5d042 procutil: bulk-replace util.std* to point to new module
Yuya Nishihara <yuya@tcha.org>
parents: 36841
diff changeset
28 )
4622
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
29
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 40971
diff changeset
30
38041
242eb5132203 filemerge: support specifying a python function to custom merge-tools
hindlemail <tom_hindle@sil.org>
parents: 37942
diff changeset
31 def pythonhook(ui, repo, htype, hname, funcname, args, throw):
4622
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
32 '''call python hook. hook is callable object, looked up as
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
33 name in python module. if callable returns "true", hook
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
34 fails, else passes. if hook raises exception, treated as
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
35 hook failure. exception propagates if throw is "true".
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
36
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
37 reason for "true" meaning "hook failed" is so that
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
38 unmodified commands (e.g. mercurial.commands.update) can
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
39 be run as hooks without wrappers to convert return values.'''
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
40
21797
b009dd135aa0 hook: restore use of callable() since it was readded in Python 3.2
Augie Fackler <raf@durin42.com>
parents: 20548
diff changeset
41 if callable(funcname):
20548
5bd6a9fec103 hooks: for python hooks, consistently use __name__ etc as name, not the repr
Mads Kiilerich <madski@unity3d.com>
parents: 20547
diff changeset
42 obj = funcname
43503
313e3a279828 cleanup: remove pointless r-prefixes on double-quoted strings
Augie Fackler <augie@google.com>
parents: 43117
diff changeset
43 funcname = pycompat.sysbytes(obj.__module__ + "." + obj.__name__)
20548
5bd6a9fec103 hooks: for python hooks, consistently use __name__ etc as name, not the repr
Mads Kiilerich <madski@unity3d.com>
parents: 20547
diff changeset
44 else:
43077
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
45 d = funcname.rfind(b'.')
4622
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
46 if d == -1:
26692
8d1cfd77b64f hook: raise a separate exception for when loading a hook fails
Siddharth Agarwal <sid0@fb.com>
parents: 26587
diff changeset
47 raise error.HookLoadError(
43077
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
48 _(b'%s hook is invalid: "%s" not in a module')
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 40971
diff changeset
49 % (hname, funcname)
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 40971
diff changeset
50 )
4622
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
51 modname = funcname[:d]
10103
37679dbf2ee3 hook: fix bug (reuse of variable) introduced in 872d49dd577a
Sune Foldager <cryo@cyanite.org>
parents: 9851
diff changeset
52 oldpaths = sys.path
43671
664e24207728 procutil: move mainfrozen() to new resourceutil.py
Martin von Zweigbergk <martinvonz@google.com>
parents: 43503
diff changeset
53 if resourceutil.mainfrozen():
9332
872d49dd577a hook: fix full path imports on Windows (issue1779)
Steve Borho <steve@borho.org>
parents: 8366
diff changeset
54 # binary installs require sys.path manipulation
10103
37679dbf2ee3 hook: fix bug (reuse of variable) introduced in 872d49dd577a
Sune Foldager <cryo@cyanite.org>
parents: 9851
diff changeset
55 modpath, modfile = os.path.split(modname)
37679dbf2ee3 hook: fix bug (reuse of variable) introduced in 872d49dd577a
Sune Foldager <cryo@cyanite.org>
parents: 9851
diff changeset
56 if modpath and modfile:
37679dbf2ee3 hook: fix bug (reuse of variable) introduced in 872d49dd577a
Sune Foldager <cryo@cyanite.org>
parents: 9851
diff changeset
57 sys.path = sys.path[:] + [modpath]
37679dbf2ee3 hook: fix bug (reuse of variable) introduced in 872d49dd577a
Sune Foldager <cryo@cyanite.org>
parents: 9851
diff changeset
58 modname = modfile
25328
2cfb0bbf83a1 hooks: replace if-try-finally with a "with" statement
Jordi Gutiérrez Hermoso <jordigh@octave.org>
parents: 25184
diff changeset
59 with demandimport.deactivated():
4622
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
60 try:
36108
c4146cf4dd20 py3: use system strings when calling __import__
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35357
diff changeset
61 obj = __import__(pycompat.sysstr(modname))
28109
b892e424f88c hook: don't crash on syntax errors in python hooks
Siddharth Agarwal <sid0@fb.com>
parents: 28108
diff changeset
62 except (ImportError, SyntaxError):
28078
2058e1a894f2 hook: use sys.exc_info rather than the deprecated equivalents
Siddharth Agarwal <sid0@fb.com>
parents: 27228
diff changeset
63 e1 = sys.exc_info()
25328
2cfb0bbf83a1 hooks: replace if-try-finally with a "with" statement
Jordi Gutiérrez Hermoso <jordigh@octave.org>
parents: 25184
diff changeset
64 try:
2cfb0bbf83a1 hooks: replace if-try-finally with a "with" statement
Jordi Gutiérrez Hermoso <jordigh@octave.org>
parents: 25184
diff changeset
65 # extensions are loaded with hgext_ prefix
43503
313e3a279828 cleanup: remove pointless r-prefixes on double-quoted strings
Augie Fackler <augie@google.com>
parents: 43117
diff changeset
66 obj = __import__("hgext_%s" % pycompat.sysstr(modname))
28109
b892e424f88c hook: don't crash on syntax errors in python hooks
Siddharth Agarwal <sid0@fb.com>
parents: 28108
diff changeset
67 except (ImportError, SyntaxError):
28078
2058e1a894f2 hook: use sys.exc_info rather than the deprecated equivalents
Siddharth Agarwal <sid0@fb.com>
parents: 27228
diff changeset
68 e2 = sys.exc_info()
25328
2cfb0bbf83a1 hooks: replace if-try-finally with a "with" statement
Jordi Gutiérrez Hermoso <jordigh@octave.org>
parents: 25184
diff changeset
69 if ui.tracebackflag:
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 40971
diff changeset
70 ui.warn(
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 40971
diff changeset
71 _(
43077
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
72 b'exception from first failed import '
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
73 b'attempt:\n'
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 40971
diff changeset
74 )
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 40971
diff changeset
75 )
25328
2cfb0bbf83a1 hooks: replace if-try-finally with a "with" statement
Jordi Gutiérrez Hermoso <jordigh@octave.org>
parents: 25184
diff changeset
76 ui.traceback(e1)
2cfb0bbf83a1 hooks: replace if-try-finally with a "with" statement
Jordi Gutiérrez Hermoso <jordigh@octave.org>
parents: 25184
diff changeset
77 if ui.tracebackflag:
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 40971
diff changeset
78 ui.warn(
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 40971
diff changeset
79 _(
43077
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
80 b'exception from second failed import '
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
81 b'attempt:\n'
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 40971
diff changeset
82 )
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 40971
diff changeset
83 )
25328
2cfb0bbf83a1 hooks: replace if-try-finally with a "with" statement
Jordi Gutiérrez Hermoso <jordigh@octave.org>
parents: 25184
diff changeset
84 ui.traceback(e2)
28080
37b818cad146 hook: for python hook ImportErrors, add note to run with --traceback
Siddharth Agarwal <sid0@fb.com>
parents: 28079
diff changeset
85
37b818cad146 hook: for python hook ImportErrors, add note to run with --traceback
Siddharth Agarwal <sid0@fb.com>
parents: 28079
diff changeset
86 if not ui.tracebackflag:
37b818cad146 hook: for python hook ImportErrors, add note to run with --traceback
Siddharth Agarwal <sid0@fb.com>
parents: 28079
diff changeset
87 tracebackhint = _(
43077
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
88 b'run with --traceback for stack trace'
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 40971
diff changeset
89 )
28080
37b818cad146 hook: for python hook ImportErrors, add note to run with --traceback
Siddharth Agarwal <sid0@fb.com>
parents: 28079
diff changeset
90 else:
37b818cad146 hook: for python hook ImportErrors, add note to run with --traceback
Siddharth Agarwal <sid0@fb.com>
parents: 28079
diff changeset
91 tracebackhint = None
26692
8d1cfd77b64f hook: raise a separate exception for when loading a hook fails
Siddharth Agarwal <sid0@fb.com>
parents: 26587
diff changeset
92 raise error.HookLoadError(
43077
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
93 _(b'%s hook is invalid: import of "%s" failed')
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 40971
diff changeset
94 % (hname, modname),
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 40971
diff changeset
95 hint=tracebackhint,
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 40971
diff changeset
96 )
9332
872d49dd577a hook: fix full path imports on Windows (issue1779)
Steve Borho <steve@borho.org>
parents: 8366
diff changeset
97 sys.path = oldpaths
4622
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
98 try:
43077
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
99 for p in funcname.split(b'.')[1:]:
4622
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
100 obj = getattr(obj, p)
7280
810ca383da9c remove unused variables
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 6762
diff changeset
101 except AttributeError:
26692
8d1cfd77b64f hook: raise a separate exception for when loading a hook fails
Siddharth Agarwal <sid0@fb.com>
parents: 26587
diff changeset
102 raise error.HookLoadError(
43077
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
103 _(b'%s hook is invalid: "%s" is not defined')
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
104 % (hname, funcname)
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 40971
diff changeset
105 )
21797
b009dd135aa0 hook: restore use of callable() since it was readded in Python 3.2
Augie Fackler <raf@durin42.com>
parents: 20548
diff changeset
106 if not callable(obj):
26692
8d1cfd77b64f hook: raise a separate exception for when loading a hook fails
Siddharth Agarwal <sid0@fb.com>
parents: 26587
diff changeset
107 raise error.HookLoadError(
43077
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
108 _(b'%s hook is invalid: "%s" is not callable')
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 40971
diff changeset
109 % (hname, funcname)
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 40971
diff changeset
110 )
20547
9d9f8ccffead hooks: move logging of hook name to after we have found the hook
Mads Kiilerich <madski@unity3d.com>
parents: 20422
diff changeset
111
43077
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
112 ui.note(_(b"calling hook %s: %s\n") % (hname, funcname))
30975
22fbca1d11ed mercurial: switch to util.timer for all interval timings
Simon Farnsworth <simonfar@fb.com>
parents: 30519
diff changeset
113 starttime = util.timer()
20547
9d9f8ccffead hooks: move logging of hook name to after we have found the hook
Mads Kiilerich <madski@unity3d.com>
parents: 20422
diff changeset
114
4622
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
115 try:
35357
056a9c8813aa py3: handle keyword arguments correctly in hook.py
Pulkit Goyal <7895pulkit@gmail.com>
parents: 34687
diff changeset
116 r = obj(ui=ui, repo=repo, hooktype=htype, **pycompat.strkwargs(args))
25660
328739ea70c3 global: mass rewrite to use modern exception syntax
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25328
diff changeset
117 except Exception as exc:
26587
56b2bcea2529 error: get Abort from 'error' instead of 'util'
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 25953
diff changeset
118 if isinstance(exc, error.Abort):
43077
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
119 ui.warn(_(b'error: %s hook failed: %s\n') % (hname, exc.args[0]))
25084
7046c7e7fcb4 hooks: use try/except/finally
Matt Mackall <mpm@selenic.com>
parents: 24716
diff changeset
120 else:
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 40971
diff changeset
121 ui.warn(
43117
8ff1ecfadcd1 cleanup: join string literals that are already on one line
Martin von Zweigbergk <martinvonz@google.com>
parents: 43106
diff changeset
122 _(b'error: %s hook raised an exception: %s\n')
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 40971
diff changeset
123 % (hname, stringutil.forcebytestr(exc))
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 40971
diff changeset
124 )
25084
7046c7e7fcb4 hooks: use try/except/finally
Matt Mackall <mpm@selenic.com>
parents: 24716
diff changeset
125 if throw:
4622
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
126 raise
28108
2a71d9483199 hook: for python hook exceptions, add note to run with --traceback
Siddharth Agarwal <sid0@fb.com>
parents: 28106
diff changeset
127 if not ui.tracebackflag:
43077
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
128 ui.warn(_(b'(run with --traceback for stack trace)\n'))
25084
7046c7e7fcb4 hooks: use try/except/finally
Matt Mackall <mpm@selenic.com>
parents: 24716
diff changeset
129 ui.traceback()
26739
8429369eeb85 hook: for python hooks, also return whether an exception was raised
Siddharth Agarwal <sid0@fb.com>
parents: 26738
diff changeset
130 return True, True
14889
a59058fd074a hooks: redirect stdout/err/in to the ui descriptors when calling python hooks
Idan Kamara <idankk86@gmail.com>
parents: 14711
diff changeset
131 finally:
30975
22fbca1d11ed mercurial: switch to util.timer for all interval timings
Simon Farnsworth <simonfar@fb.com>
parents: 30519
diff changeset
132 duration = util.timer() - starttime
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 40971
diff changeset
133 ui.log(
43077
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
134 b'pythonhook',
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
135 b'pythonhook-%s: %s finished in %0.2f seconds\n',
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 40971
diff changeset
136 htype,
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 40971
diff changeset
137 funcname,
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 40971
diff changeset
138 duration,
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 40971
diff changeset
139 )
4622
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
140 if r:
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
141 if throw:
43077
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
142 raise error.HookAbort(_(b'%s hook failed') % hname)
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
143 ui.warn(_(b'warning: %s hook failed\n') % hname)
26739
8429369eeb85 hook: for python hooks, also return whether an exception was raised
Siddharth Agarwal <sid0@fb.com>
parents: 26738
diff changeset
144 return r, False
4622
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
145
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 40971
diff changeset
146
31746
0fa30fbccc34 hook: provide hook type information to external hook
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents: 31745
diff changeset
147 def _exthook(ui, repo, htype, name, cmd, args, throw):
30975
22fbca1d11ed mercurial: switch to util.timer for all interval timings
Simon Farnsworth <simonfar@fb.com>
parents: 30519
diff changeset
148 starttime = util.timer()
7787
b8d750daadde Introduce HG_PREPEND to solve pretxn races
Matt Mackall <mpm@selenic.com>
parents: 7644
diff changeset
149 env = {}
26751
520defbc0335 hook: centralize passing HG_PENDING to external hook process
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 26739
diff changeset
150
520defbc0335 hook: centralize passing HG_PENDING to external hook process
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 26739
diff changeset
151 # make in-memory changes visible to external process
27228
10695f8f3323 dirstate: don't write repo.currenttransaction to repo.dirstate if repo
Sietse Brouwer <sbbrouwer@gmail.com>
parents: 26861
diff changeset
152 if repo is not None:
10695f8f3323 dirstate: don't write repo.currenttransaction to repo.dirstate if repo
Sietse Brouwer <sbbrouwer@gmail.com>
parents: 26861
diff changeset
153 tr = repo.currenttransaction()
10695f8f3323 dirstate: don't write repo.currenttransaction to repo.dirstate if repo
Sietse Brouwer <sbbrouwer@gmail.com>
parents: 26861
diff changeset
154 repo.dirstate.write(tr)
10695f8f3323 dirstate: don't write repo.currenttransaction to repo.dirstate if repo
Sietse Brouwer <sbbrouwer@gmail.com>
parents: 26861
diff changeset
155 if tr and tr.writepending():
43077
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
156 env[b'HG_PENDING'] = repo.root
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
157 env[b'HG_HOOKTYPE'] = htype
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
158 env[b'HG_HOOKNAME'] = name
26751
520defbc0335 hook: centralize passing HG_PENDING to external hook process
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 26739
diff changeset
159
43106
d783f945a701 py3: finish porting iteritems() to pycompat and remove source transformer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 43089
diff changeset
160 for k, v in pycompat.iteritems(args):
44835
09da5cf44772 hooks: provide access to transaction changes for internal hooks
Joerg Sonnenberger <joerg@bec.de>
parents: 44652
diff changeset
161 # transaction changes can accumulate MBs of data, so skip it
09da5cf44772 hooks: provide access to transaction changes for internal hooks
Joerg Sonnenberger <joerg@bec.de>
parents: 44652
diff changeset
162 # for external hooks
09da5cf44772 hooks: provide access to transaction changes for internal hooks
Joerg Sonnenberger <joerg@bec.de>
parents: 44652
diff changeset
163 if k == b'changes':
09da5cf44772 hooks: provide access to transaction changes for internal hooks
Joerg Sonnenberger <joerg@bec.de>
parents: 44652
diff changeset
164 continue
21797
b009dd135aa0 hook: restore use of callable() since it was readded in Python 3.2
Augie Fackler <raf@durin42.com>
parents: 20548
diff changeset
165 if callable(v):
7787
b8d750daadde Introduce HG_PREPEND to solve pretxn races
Matt Mackall <mpm@selenic.com>
parents: 7644
diff changeset
166 v = v()
37752
63b7415e37a5 hook: also use pprint on lists for stable output on py2/3
Augie Fackler <augie@google.com>
parents: 37751
diff changeset
167 if isinstance(v, (dict, list)):
37942
32bc3815efae stringutil: flip the default of pprint() to bprefix=False
Yuya Nishihara <yuya@tcha.org>
parents: 37752
diff changeset
168 v = stringutil.pprint(v)
43077
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
169 env[b'HG_' + k.upper()] = v
7787
b8d750daadde Introduce HG_PREPEND to solve pretxn races
Matt Mackall <mpm@selenic.com>
parents: 7644
diff changeset
170
43077
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
171 if ui.configbool(b'hooks', b'tonative.%s' % name, False):
38723
f9b2d996ffa5 hook: only print the note about native cmd translation if it actually changes
Matt Harbison <matt_harbison@yahoo.com>
parents: 38722
diff changeset
172 oldcmd = cmd
38629
38dfd308fe9d hook: add support for disabling the shell to native command translation
Matt Harbison <matt_harbison@yahoo.com>
parents: 38628
diff changeset
173 cmd = procutil.shelltonative(cmd, env)
38723
f9b2d996ffa5 hook: only print the note about native cmd translation if it actually changes
Matt Harbison <matt_harbison@yahoo.com>
parents: 38722
diff changeset
174 if cmd != oldcmd:
43077
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
175 ui.note(_(b'converting hook "%s" to native\n') % name)
38484
e9e61fbac787 hooks: allow Unix style environment variables on external Windows hooks
Matt Harbison <matt_harbison@yahoo.com>
parents: 38041
diff changeset
176
43077
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
177 ui.note(_(b"running hook %s: %s\n") % (name, cmd))
38484
e9e61fbac787 hooks: allow Unix style environment variables on external Windows hooks
Matt Harbison <matt_harbison@yahoo.com>
parents: 38041
diff changeset
178
5869
2c565b9598b8 hooks: fix pre- and post- hooks specified in .hg/hgrc
Matt Mackall <mpm@selenic.com>
parents: 5833
diff changeset
179 if repo:
2c565b9598b8 hooks: fix pre- and post- hooks specified in .hg/hgrc
Matt Mackall <mpm@selenic.com>
parents: 5833
diff changeset
180 cwd = repo.root
2c565b9598b8 hooks: fix pre- and post- hooks specified in .hg/hgrc
Matt Mackall <mpm@selenic.com>
parents: 5833
diff changeset
181 else:
39818
24e493ec2229 py3: rename pycompat.getcwd() to encoding.getcwd() (API)
Matt Harbison <matt_harbison@yahoo.com>
parents: 38723
diff changeset
182 cwd = encoding.getcwd()
43077
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
183 r = ui.system(cmd, environ=env, cwd=cwd, blockedtag=b'exthook-%s' % (name,))
18671
1c305128e5b9 blackbox: logs python and extension hooks via ui.log()
Durham Goode <durham@fb.com>
parents: 18111
diff changeset
184
30975
22fbca1d11ed mercurial: switch to util.timer for all interval timings
Simon Farnsworth <simonfar@fb.com>
parents: 30519
diff changeset
185 duration = util.timer() - starttime
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 40971
diff changeset
186 ui.log(
43077
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
187 b'exthook',
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
188 b'exthook-%s: %s finished in %0.2f seconds\n',
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 40971
diff changeset
189 name,
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 40971
diff changeset
190 cmd,
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 40971
diff changeset
191 duration,
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 40971
diff changeset
192 )
4622
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
193 if r:
37463
bbd240f81ac5 procutil: make explainexit() simply return a message (API)
Yuya Nishihara <yuya@tcha.org>
parents: 37120
diff changeset
194 desc = procutil.explainexit(r)
4622
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
195 if throw:
43077
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
196 raise error.HookAbort(_(b'%s hook %s') % (name, desc))
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
197 ui.warn(_(b'warning: %s hook %s\n') % (name, desc))
4622
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
198 return r
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
199
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 40971
diff changeset
200
28938
ea1fec3e9aba hook: report untrusted hooks as failure (issue5110) (BC)
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents: 28937
diff changeset
201 # represent an untrusted hook command
ea1fec3e9aba hook: report untrusted hooks as failure (issue5110) (BC)
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents: 28937
diff changeset
202 _fromuntrusted = object()
ea1fec3e9aba hook: report untrusted hooks as failure (issue5110) (BC)
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents: 28937
diff changeset
203
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 40971
diff changeset
204
15896
30c34fde40cc hooks: prioritize run order of hooks
Matt Zuba <matt.zuba@goodwillaz.org>
parents: 15512
diff changeset
205 def _allhooks(ui):
28937
3112c5e18835 hook: split config reading further
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents: 28936
diff changeset
206 """return a list of (hook-id, cmd) pairs sorted by priority"""
3112c5e18835 hook: split config reading further
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents: 28936
diff changeset
207 hooks = _hookitems(ui)
28938
ea1fec3e9aba hook: report untrusted hooks as failure (issue5110) (BC)
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents: 28937
diff changeset
208 # Be careful in this section, propagating the real commands from untrusted
ea1fec3e9aba hook: report untrusted hooks as failure (issue5110) (BC)
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents: 28937
diff changeset
209 # sources would create a security vulnerability, make sure anything altered
ea1fec3e9aba hook: report untrusted hooks as failure (issue5110) (BC)
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents: 28937
diff changeset
210 # in that section uses "_fromuntrusted" as its command.
ea1fec3e9aba hook: report untrusted hooks as failure (issue5110) (BC)
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents: 28937
diff changeset
211 untrustedhooks = _hookitems(ui, _untrusted=True)
ea1fec3e9aba hook: report untrusted hooks as failure (issue5110) (BC)
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents: 28937
diff changeset
212 for name, value in untrustedhooks.items():
44828
50416d3d4b65 py3: change default priority and length used for sorting hooks to be compatible with python 3
Charles Chamberlain <cchamberlain@janestreet.com>
parents: 44652
diff changeset
213 trustedvalue = hooks.get(name, ((), (), name, _fromuntrusted))
28938
ea1fec3e9aba hook: report untrusted hooks as failure (issue5110) (BC)
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents: 28937
diff changeset
214 if value != trustedvalue:
ea1fec3e9aba hook: report untrusted hooks as failure (issue5110) (BC)
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents: 28937
diff changeset
215 (lp, lo, lk, lv) = trustedvalue
ea1fec3e9aba hook: report untrusted hooks as failure (issue5110) (BC)
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents: 28937
diff changeset
216 hooks[name] = (lp, lo, lk, _fromuntrusted)
ea1fec3e9aba hook: report untrusted hooks as failure (issue5110) (BC)
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents: 28937
diff changeset
217 # (end of the security sensitive section)
28937
3112c5e18835 hook: split config reading further
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents: 28936
diff changeset
218 return [(k, v) for p, o, k, v in sorted(hooks.values())]
3112c5e18835 hook: split config reading further
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents: 28936
diff changeset
219
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 40971
diff changeset
220
28938
ea1fec3e9aba hook: report untrusted hooks as failure (issue5110) (BC)
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents: 28937
diff changeset
221 def _hookitems(ui, _untrusted=False):
28937
3112c5e18835 hook: split config reading further
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents: 28936
diff changeset
222 """return all hooks items ready to be sorted"""
28936
44bd37af54e5 hook: small refactor to store hooks as dict instead of list
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents: 28109
diff changeset
223 hooks = {}
43077
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
224 for name, cmd in ui.configitems(b'hooks', untrusted=_untrusted):
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
225 if name.startswith(b'priority.') or name.startswith(b'tonative.'):
38629
38dfd308fe9d hook: add support for disabling the shell to native command translation
Matt Harbison <matt_harbison@yahoo.com>
parents: 38628
diff changeset
226 continue
38dfd308fe9d hook: add support for disabling the shell to native command translation
Matt Harbison <matt_harbison@yahoo.com>
parents: 38628
diff changeset
227
43077
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
228 priority = ui.configint(b'hooks', b'priority.%s' % name, 0)
44828
50416d3d4b65 py3: change default priority and length used for sorting hooks to be compatible with python 3
Charles Chamberlain <cchamberlain@janestreet.com>
parents: 44652
diff changeset
229 hooks[name] = ((-priority,), (len(hooks),), name, cmd)
28937
3112c5e18835 hook: split config reading further
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents: 28936
diff changeset
230 return hooks
15896
30c34fde40cc hooks: prioritize run order of hooks
Matt Zuba <matt.zuba@goodwillaz.org>
parents: 15512
diff changeset
231
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 40971
diff changeset
232
5833
323b9c55b328 hook: redirect stdout to stderr for ssh and http servers
Matt Mackall <mpm@selenic.com>
parents: 4622
diff changeset
233 _redirect = False
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 40971
diff changeset
234
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 40971
diff changeset
235
5833
323b9c55b328 hook: redirect stdout to stderr for ssh and http servers
Matt Mackall <mpm@selenic.com>
parents: 4622
diff changeset
236 def redirect(state):
6266
9f76df0edb7d hook.py: fix redirections introduced by 323b9c55b328
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 5869
diff changeset
237 global _redirect
5833
323b9c55b328 hook: redirect stdout to stderr for ssh and http servers
Matt Mackall <mpm@selenic.com>
parents: 4622
diff changeset
238 _redirect = state
323b9c55b328 hook: redirect stdout to stderr for ssh and http servers
Matt Mackall <mpm@selenic.com>
parents: 4622
diff changeset
239
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 40971
diff changeset
240
34687
e79b6300d97c hook: add a 'hashook' function to test for hook existence
Boris Feld <boris.feld@octobus.net>
parents: 32897
diff changeset
241 def hashook(ui, htype):
e79b6300d97c hook: add a 'hashook' function to test for hook existence
Boris Feld <boris.feld@octobus.net>
parents: 32897
diff changeset
242 """return True if a hook is configured for 'htype'"""
e79b6300d97c hook: add a 'hashook' function to test for hook existence
Boris Feld <boris.feld@octobus.net>
parents: 32897
diff changeset
243 if not ui.callhooks:
e79b6300d97c hook: add a 'hashook' function to test for hook existence
Boris Feld <boris.feld@octobus.net>
parents: 32897
diff changeset
244 return False
e79b6300d97c hook: add a 'hashook' function to test for hook existence
Boris Feld <boris.feld@octobus.net>
parents: 32897
diff changeset
245 for hname, cmd in _allhooks(ui):
43077
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
246 if hname.split(b'.')[0] == htype and cmd:
34687
e79b6300d97c hook: add a 'hashook' function to test for hook existence
Boris Feld <boris.feld@octobus.net>
parents: 32897
diff changeset
247 return True
e79b6300d97c hook: add a 'hashook' function to test for hook existence
Boris Feld <boris.feld@octobus.net>
parents: 32897
diff changeset
248 return False
e79b6300d97c hook: add a 'hashook' function to test for hook existence
Boris Feld <boris.feld@octobus.net>
parents: 32897
diff changeset
249
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 40971
diff changeset
250
31745
33504b54863e hook: use 'htype' in 'hook'
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents: 31744
diff changeset
251 def hook(ui, repo, htype, throw=False, **args):
17048
15d4d475de9e ui: add a variable to control whether hooks should be called
Idan Kamara <idankk86@gmail.com>
parents: 15896
diff changeset
252 if not ui.callhooks:
15d4d475de9e ui: add a variable to control whether hooks should be called
Idan Kamara <idankk86@gmail.com>
parents: 15896
diff changeset
253 return False
15d4d475de9e ui: add a variable to control whether hooks should be called
Idan Kamara <idankk86@gmail.com>
parents: 15896
diff changeset
254
26737
a930d66a04af hook: factor out determination of hooks from running them
Siddharth Agarwal <sid0@fb.com>
parents: 26692
diff changeset
255 hooks = []
a930d66a04af hook: factor out determination of hooks from running them
Siddharth Agarwal <sid0@fb.com>
parents: 26692
diff changeset
256 for hname, cmd in _allhooks(ui):
43077
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
257 if hname.split(b'.')[0] == htype and cmd:
26737
a930d66a04af hook: factor out determination of hooks from running them
Siddharth Agarwal <sid0@fb.com>
parents: 26692
diff changeset
258 hooks.append((hname, cmd))
a930d66a04af hook: factor out determination of hooks from running them
Siddharth Agarwal <sid0@fb.com>
parents: 26692
diff changeset
259
31745
33504b54863e hook: use 'htype' in 'hook'
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents: 31744
diff changeset
260 res = runhooks(ui, repo, htype, hooks, throw=throw, **args)
26738
9abc2c921bbd hook.runhooks: return a dict of result values
Siddharth Agarwal <sid0@fb.com>
parents: 26737
diff changeset
261 r = False
9abc2c921bbd hook.runhooks: return a dict of result values
Siddharth Agarwal <sid0@fb.com>
parents: 26737
diff changeset
262 for hname, cmd in hooks:
26739
8429369eeb85 hook: for python hooks, also return whether an exception was raised
Siddharth Agarwal <sid0@fb.com>
parents: 26738
diff changeset
263 r = res[hname][0] or r
26738
9abc2c921bbd hook.runhooks: return a dict of result values
Siddharth Agarwal <sid0@fb.com>
parents: 26737
diff changeset
264 return r
26737
a930d66a04af hook: factor out determination of hooks from running them
Siddharth Agarwal <sid0@fb.com>
parents: 26692
diff changeset
265
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 40971
diff changeset
266
44652
3cbbfd0bfc17 hook: move stdio redirection to context manager
Gregory Szorc <gregory.szorc@gmail.com>
parents: 43671
diff changeset
267 @contextlib.contextmanager
3cbbfd0bfc17 hook: move stdio redirection to context manager
Gregory Szorc <gregory.szorc@gmail.com>
parents: 43671
diff changeset
268 def redirect_stdio():
3cbbfd0bfc17 hook: move stdio redirection to context manager
Gregory Szorc <gregory.szorc@gmail.com>
parents: 43671
diff changeset
269 """Redirects stdout to stderr, if possible."""
3cbbfd0bfc17 hook: move stdio redirection to context manager
Gregory Szorc <gregory.szorc@gmail.com>
parents: 43671
diff changeset
270
3cbbfd0bfc17 hook: move stdio redirection to context manager
Gregory Szorc <gregory.szorc@gmail.com>
parents: 43671
diff changeset
271 oldstdout = -1
3cbbfd0bfc17 hook: move stdio redirection to context manager
Gregory Szorc <gregory.szorc@gmail.com>
parents: 43671
diff changeset
272 try:
3cbbfd0bfc17 hook: move stdio redirection to context manager
Gregory Szorc <gregory.szorc@gmail.com>
parents: 43671
diff changeset
273 if _redirect:
3cbbfd0bfc17 hook: move stdio redirection to context manager
Gregory Szorc <gregory.szorc@gmail.com>
parents: 43671
diff changeset
274 try:
3cbbfd0bfc17 hook: move stdio redirection to context manager
Gregory Szorc <gregory.szorc@gmail.com>
parents: 43671
diff changeset
275 stdoutno = procutil.stdout.fileno()
3cbbfd0bfc17 hook: move stdio redirection to context manager
Gregory Szorc <gregory.szorc@gmail.com>
parents: 43671
diff changeset
276 stderrno = procutil.stderr.fileno()
3cbbfd0bfc17 hook: move stdio redirection to context manager
Gregory Szorc <gregory.szorc@gmail.com>
parents: 43671
diff changeset
277 # temporarily redirect stdout to stderr, if possible
3cbbfd0bfc17 hook: move stdio redirection to context manager
Gregory Szorc <gregory.szorc@gmail.com>
parents: 43671
diff changeset
278 if stdoutno >= 0 and stderrno >= 0:
3cbbfd0bfc17 hook: move stdio redirection to context manager
Gregory Szorc <gregory.szorc@gmail.com>
parents: 43671
diff changeset
279 procutil.stdout.flush()
3cbbfd0bfc17 hook: move stdio redirection to context manager
Gregory Szorc <gregory.szorc@gmail.com>
parents: 43671
diff changeset
280 oldstdout = os.dup(stdoutno)
3cbbfd0bfc17 hook: move stdio redirection to context manager
Gregory Szorc <gregory.szorc@gmail.com>
parents: 43671
diff changeset
281 os.dup2(stderrno, stdoutno)
3cbbfd0bfc17 hook: move stdio redirection to context manager
Gregory Szorc <gregory.szorc@gmail.com>
parents: 43671
diff changeset
282 except (OSError, AttributeError):
3cbbfd0bfc17 hook: move stdio redirection to context manager
Gregory Szorc <gregory.szorc@gmail.com>
parents: 43671
diff changeset
283 # files seem to be bogus, give up on redirecting (WSGI, etc)
3cbbfd0bfc17 hook: move stdio redirection to context manager
Gregory Szorc <gregory.szorc@gmail.com>
parents: 43671
diff changeset
284 pass
3cbbfd0bfc17 hook: move stdio redirection to context manager
Gregory Szorc <gregory.szorc@gmail.com>
parents: 43671
diff changeset
285
3cbbfd0bfc17 hook: move stdio redirection to context manager
Gregory Szorc <gregory.szorc@gmail.com>
parents: 43671
diff changeset
286 yield
3cbbfd0bfc17 hook: move stdio redirection to context manager
Gregory Szorc <gregory.szorc@gmail.com>
parents: 43671
diff changeset
287
3cbbfd0bfc17 hook: move stdio redirection to context manager
Gregory Szorc <gregory.szorc@gmail.com>
parents: 43671
diff changeset
288 finally:
3cbbfd0bfc17 hook: move stdio redirection to context manager
Gregory Szorc <gregory.szorc@gmail.com>
parents: 43671
diff changeset
289 # The stderr is fully buffered on Windows when connected to a pipe.
3cbbfd0bfc17 hook: move stdio redirection to context manager
Gregory Szorc <gregory.szorc@gmail.com>
parents: 43671
diff changeset
290 # A forcible flush is required to make small stderr data in the
3cbbfd0bfc17 hook: move stdio redirection to context manager
Gregory Szorc <gregory.szorc@gmail.com>
parents: 43671
diff changeset
291 # remote side available to the client immediately.
3cbbfd0bfc17 hook: move stdio redirection to context manager
Gregory Szorc <gregory.szorc@gmail.com>
parents: 43671
diff changeset
292 procutil.stderr.flush()
3cbbfd0bfc17 hook: move stdio redirection to context manager
Gregory Szorc <gregory.szorc@gmail.com>
parents: 43671
diff changeset
293
3cbbfd0bfc17 hook: move stdio redirection to context manager
Gregory Szorc <gregory.szorc@gmail.com>
parents: 43671
diff changeset
294 if _redirect and oldstdout >= 0:
3cbbfd0bfc17 hook: move stdio redirection to context manager
Gregory Szorc <gregory.szorc@gmail.com>
parents: 43671
diff changeset
295 procutil.stdout.flush() # write hook output to stderr fd
3cbbfd0bfc17 hook: move stdio redirection to context manager
Gregory Szorc <gregory.szorc@gmail.com>
parents: 43671
diff changeset
296 os.dup2(oldstdout, stdoutno)
3cbbfd0bfc17 hook: move stdio redirection to context manager
Gregory Szorc <gregory.szorc@gmail.com>
parents: 43671
diff changeset
297 os.close(oldstdout)
3cbbfd0bfc17 hook: move stdio redirection to context manager
Gregory Szorc <gregory.szorc@gmail.com>
parents: 43671
diff changeset
298
3cbbfd0bfc17 hook: move stdio redirection to context manager
Gregory Szorc <gregory.szorc@gmail.com>
parents: 43671
diff changeset
299
31744
5678496659e9 hook: use 'htype' in 'runhooks'
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents: 31743
diff changeset
300 def runhooks(ui, repo, htype, hooks, throw=False, **args):
32897
799db2af824c py3: convert keys of kwargs back to bytes using pycompat.byteskwargs()
Pulkit Goyal <7895pulkit@gmail.com>
parents: 32642
diff changeset
301 args = pycompat.byteskwargs(args)
26738
9abc2c921bbd hook.runhooks: return a dict of result values
Siddharth Agarwal <sid0@fb.com>
parents: 26737
diff changeset
302 res = {}
5833
323b9c55b328 hook: redirect stdout to stderr for ssh and http servers
Matt Mackall <mpm@selenic.com>
parents: 4622
diff changeset
303
44652
3cbbfd0bfc17 hook: move stdio redirection to context manager
Gregory Szorc <gregory.szorc@gmail.com>
parents: 43671
diff changeset
304 with redirect_stdio():
26737
a930d66a04af hook: factor out determination of hooks from running them
Siddharth Agarwal <sid0@fb.com>
parents: 26692
diff changeset
305 for hname, cmd in hooks:
28938
ea1fec3e9aba hook: report untrusted hooks as failure (issue5110) (BC)
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents: 28937
diff changeset
306 if cmd is _fromuntrusted:
ea1fec3e9aba hook: report untrusted hooks as failure (issue5110) (BC)
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents: 28937
diff changeset
307 if throw:
ea1fec3e9aba hook: report untrusted hooks as failure (issue5110) (BC)
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents: 28937
diff changeset
308 raise error.HookAbort(
43077
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
309 _(b'untrusted hook %s not executed') % hname,
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
310 hint=_(b"see 'hg help config.trusted'"),
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 40971
diff changeset
311 )
43077
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
312 ui.warn(_(b'warning: untrusted hook %s not executed\n') % hname)
28938
ea1fec3e9aba hook: report untrusted hooks as failure (issue5110) (BC)
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents: 28937
diff changeset
313 r = 1
ea1fec3e9aba hook: report untrusted hooks as failure (issue5110) (BC)
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents: 28937
diff changeset
314 raised = False
ea1fec3e9aba hook: report untrusted hooks as failure (issue5110) (BC)
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents: 28937
diff changeset
315 elif callable(cmd):
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 40971
diff changeset
316 r, raised = pythonhook(ui, repo, htype, hname, cmd, args, throw)
43077
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
317 elif cmd.startswith(b'python:'):
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
318 if cmd.count(b':') >= 2:
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
319 path, cmd = cmd[7:].rsplit(b':', 1)
13118
789e0fa2fcea hook: assume relative path to hook is given from repo root
Alexander Solovyov <alexander@solovyov.net>
parents: 11469
diff changeset
320 path = util.expandpath(path)
13119
ecf7d6e0eef0 hook: fix import path handling for repo=None
Matt Mackall <mpm@selenic.com>
parents: 13118
diff changeset
321 if repo:
ecf7d6e0eef0 hook: fix import path handling for repo=None
Matt Mackall <mpm@selenic.com>
parents: 13118
diff changeset
322 path = os.path.join(repo.root, path)
17217
1b2b727a885f hooks: print out more information when loading a python hook fails
Simon Heimberg <simohe@besonet.ch>
parents: 17048
diff changeset
323 try:
43077
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
324 mod = extensions.loadpath(path, b'hghook.%s' % hname)
17217
1b2b727a885f hooks: print out more information when loading a python hook fails
Simon Heimberg <simohe@besonet.ch>
parents: 17048
diff changeset
325 except Exception:
43077
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
326 ui.write(_(b"loading %s hook failed:\n") % hname)
17217
1b2b727a885f hooks: print out more information when loading a python hook fails
Simon Heimberg <simohe@besonet.ch>
parents: 17048
diff changeset
327 raise
7916
f779e1996e23 ability to load hooks from arbitrary python module
Alexander Solovyov <piranha@piranha.org.ua>
parents: 7787
diff changeset
328 hookfn = getattr(mod, cmd)
f779e1996e23 ability to load hooks from arbitrary python module
Alexander Solovyov <piranha@piranha.org.ua>
parents: 7787
diff changeset
329 else:
f779e1996e23 ability to load hooks from arbitrary python module
Alexander Solovyov <piranha@piranha.org.ua>
parents: 7787
diff changeset
330 hookfn = cmd[7:].strip()
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 40971
diff changeset
331 r, raised = pythonhook(
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 40971
diff changeset
332 ui, repo, htype, hname, hookfn, args, throw
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 40971
diff changeset
333 )
7416
196b05a548d0 hooks: restore io correctly on exception
Jesse Long <jesse@virtualpostman.co.za>
parents: 7280
diff changeset
334 else:
31746
0fa30fbccc34 hook: provide hook type information to external hook
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents: 31745
diff changeset
335 r = _exthook(ui, repo, htype, hname, cmd, args, throw)
26739
8429369eeb85 hook: for python hooks, also return whether an exception was raised
Siddharth Agarwal <sid0@fb.com>
parents: 26738
diff changeset
336 raised = False
26738
9abc2c921bbd hook.runhooks: return a dict of result values
Siddharth Agarwal <sid0@fb.com>
parents: 26737
diff changeset
337
26739
8429369eeb85 hook: for python hooks, also return whether an exception was raised
Siddharth Agarwal <sid0@fb.com>
parents: 26738
diff changeset
338 res[hname] = r, raised
6266
9f76df0edb7d hook.py: fix redirections introduced by 323b9c55b328
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 5869
diff changeset
339
26738
9abc2c921bbd hook.runhooks: return a dict of result values
Siddharth Agarwal <sid0@fb.com>
parents: 26737
diff changeset
340 return res