mercurial/hook.py
author Martin von Zweigbergk <martinvonz@google.com>
Wed, 06 May 2020 11:40:17 -0700
changeset 44807 16596f5e1afa
parent 44652 3cbbfd0bfc17
child 44828 50416d3d4b65
child 44835 09da5cf44772
permissions -rw-r--r--
copy: give better error message when no source paths found with --at-rev The new error message matches what we show when marking copies in the working copy. Differential Revision: https://phab.mercurial-scm.org/D8496
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
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):
21797
b009dd135aa0 hook: restore use of callable() since it was readded in Python 3.2
Augie Fackler <raf@durin42.com>
parents: 20548
diff changeset
   161
        if callable(v):
7787
b8d750daadde Introduce HG_PREPEND to solve pretxn races
Matt Mackall <mpm@selenic.com>
parents: 7644
diff changeset
   162
            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
   163
        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
   164
            v = stringutil.pprint(v)
43077
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
   165
        env[b'HG_' + k.upper()] = v
7787
b8d750daadde Introduce HG_PREPEND to solve pretxn races
Matt Mackall <mpm@selenic.com>
parents: 7644
diff changeset
   166
43077
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
   167
    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
   168
        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
   169
        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
   170
        if cmd != oldcmd:
43077
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
   171
            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
   172
43077
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
   173
    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
   174
5869
2c565b9598b8 hooks: fix pre- and post- hooks specified in .hg/hgrc
Matt Mackall <mpm@selenic.com>
parents: 5833
diff changeset
   175
    if repo:
2c565b9598b8 hooks: fix pre- and post- hooks specified in .hg/hgrc
Matt Mackall <mpm@selenic.com>
parents: 5833
diff changeset
   176
        cwd = repo.root
2c565b9598b8 hooks: fix pre- and post- hooks specified in .hg/hgrc
Matt Mackall <mpm@selenic.com>
parents: 5833
diff changeset
   177
    else:
39818
24e493ec2229 py3: rename pycompat.getcwd() to encoding.getcwd() (API)
Matt Harbison <matt_harbison@yahoo.com>
parents: 38723
diff changeset
   178
        cwd = encoding.getcwd()
43077
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
   179
    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
   180
30975
22fbca1d11ed mercurial: switch to util.timer for all interval timings
Simon Farnsworth <simonfar@fb.com>
parents: 30519
diff changeset
   181
    duration = util.timer() - starttime
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 40971
diff changeset
   182
    ui.log(
43077
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
   183
        b'exthook',
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
   184
        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
   185
        name,
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 40971
diff changeset
   186
        cmd,
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 40971
diff changeset
   187
        duration,
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 40971
diff changeset
   188
    )
4622
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   189
    if r:
37463
bbd240f81ac5 procutil: make explainexit() simply return a message (API)
Yuya Nishihara <yuya@tcha.org>
parents: 37120
diff changeset
   190
        desc = procutil.explainexit(r)
4622
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   191
        if throw:
43077
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
   192
            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
   193
        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
   194
    return r
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   195
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 40971
diff changeset
   196
28938
ea1fec3e9aba hook: report untrusted hooks as failure (issue5110) (BC)
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents: 28937
diff changeset
   197
# 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
   198
_fromuntrusted = object()
ea1fec3e9aba hook: report untrusted hooks as failure (issue5110) (BC)
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents: 28937
diff changeset
   199
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 40971
diff changeset
   200
15896
30c34fde40cc hooks: prioritize run order of hooks
Matt Zuba <matt.zuba@goodwillaz.org>
parents: 15512
diff changeset
   201
def _allhooks(ui):
28937
3112c5e18835 hook: split config reading further
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents: 28936
diff changeset
   202
    """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
   203
    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
   204
    # 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
   205
    # 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
   206
    # 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
   207
    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
   208
    for name, value in untrustedhooks.items():
ea1fec3e9aba hook: report untrusted hooks as failure (issue5110) (BC)
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents: 28937
diff changeset
   209
        trustedvalue = hooks.get(name, (None, None, name, _fromuntrusted))
ea1fec3e9aba hook: report untrusted hooks as failure (issue5110) (BC)
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents: 28937
diff changeset
   210
        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
   211
            (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
   212
            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
   213
    # (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
   214
    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
   215
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 40971
diff changeset
   216
28938
ea1fec3e9aba hook: report untrusted hooks as failure (issue5110) (BC)
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents: 28937
diff changeset
   217
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
   218
    """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
   219
    hooks = {}
43077
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
   220
    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
   221
        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
   222
            continue
38dfd308fe9d hook: add support for disabling the shell to native command translation
Matt Harbison <matt_harbison@yahoo.com>
parents: 38628
diff changeset
   223
43077
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
   224
        priority = ui.configint(b'hooks', b'priority.%s' % name, 0)
38629
38dfd308fe9d hook: add support for disabling the shell to native command translation
Matt Harbison <matt_harbison@yahoo.com>
parents: 38628
diff changeset
   225
        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
   226
    return hooks
15896
30c34fde40cc hooks: prioritize run order of hooks
Matt Zuba <matt.zuba@goodwillaz.org>
parents: 15512
diff changeset
   227
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 40971
diff changeset
   228
5833
323b9c55b328 hook: redirect stdout to stderr for ssh and http servers
Matt Mackall <mpm@selenic.com>
parents: 4622
diff changeset
   229
_redirect = False
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 40971
diff changeset
   230
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 40971
diff changeset
   231
5833
323b9c55b328 hook: redirect stdout to stderr for ssh and http servers
Matt Mackall <mpm@selenic.com>
parents: 4622
diff changeset
   232
def redirect(state):
6266
9f76df0edb7d hook.py: fix redirections introduced by 323b9c55b328
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 5869
diff changeset
   233
    global _redirect
5833
323b9c55b328 hook: redirect stdout to stderr for ssh and http servers
Matt Mackall <mpm@selenic.com>
parents: 4622
diff changeset
   234
    _redirect = state
323b9c55b328 hook: redirect stdout to stderr for ssh and http servers
Matt Mackall <mpm@selenic.com>
parents: 4622
diff changeset
   235
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 40971
diff changeset
   236
34687
e79b6300d97c hook: add a 'hashook' function to test for hook existence
Boris Feld <boris.feld@octobus.net>
parents: 32897
diff changeset
   237
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
   238
    """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
   239
    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
   240
        return False
e79b6300d97c hook: add a 'hashook' function to test for hook existence
Boris Feld <boris.feld@octobus.net>
parents: 32897
diff changeset
   241
    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
   242
        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
   243
            return True
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
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 40971
diff changeset
   246
31745
33504b54863e hook: use 'htype' in 'hook'
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents: 31744
diff changeset
   247
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
   248
    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
   249
        return False
15d4d475de9e ui: add a variable to control whether hooks should be called
Idan Kamara <idankk86@gmail.com>
parents: 15896
diff changeset
   250
26737
a930d66a04af hook: factor out determination of hooks from running them
Siddharth Agarwal <sid0@fb.com>
parents: 26692
diff changeset
   251
    hooks = []
a930d66a04af hook: factor out determination of hooks from running them
Siddharth Agarwal <sid0@fb.com>
parents: 26692
diff changeset
   252
    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
   253
        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
   254
            hooks.append((hname, cmd))
a930d66a04af hook: factor out determination of hooks from running them
Siddharth Agarwal <sid0@fb.com>
parents: 26692
diff changeset
   255
31745
33504b54863e hook: use 'htype' in 'hook'
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents: 31744
diff changeset
   256
    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
   257
    r = False
9abc2c921bbd hook.runhooks: return a dict of result values
Siddharth Agarwal <sid0@fb.com>
parents: 26737
diff changeset
   258
    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
   259
        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
   260
    return r
26737
a930d66a04af hook: factor out determination of hooks from running them
Siddharth Agarwal <sid0@fb.com>
parents: 26692
diff changeset
   261
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 40971
diff changeset
   262
44652
3cbbfd0bfc17 hook: move stdio redirection to context manager
Gregory Szorc <gregory.szorc@gmail.com>
parents: 43671
diff changeset
   263
@contextlib.contextmanager
3cbbfd0bfc17 hook: move stdio redirection to context manager
Gregory Szorc <gregory.szorc@gmail.com>
parents: 43671
diff changeset
   264
def redirect_stdio():
3cbbfd0bfc17 hook: move stdio redirection to context manager
Gregory Szorc <gregory.szorc@gmail.com>
parents: 43671
diff changeset
   265
    """Redirects stdout to stderr, if possible."""
3cbbfd0bfc17 hook: move stdio redirection to context manager
Gregory Szorc <gregory.szorc@gmail.com>
parents: 43671
diff changeset
   266
3cbbfd0bfc17 hook: move stdio redirection to context manager
Gregory Szorc <gregory.szorc@gmail.com>
parents: 43671
diff changeset
   267
    oldstdout = -1
3cbbfd0bfc17 hook: move stdio redirection to context manager
Gregory Szorc <gregory.szorc@gmail.com>
parents: 43671
diff changeset
   268
    try:
3cbbfd0bfc17 hook: move stdio redirection to context manager
Gregory Szorc <gregory.szorc@gmail.com>
parents: 43671
diff changeset
   269
        if _redirect:
3cbbfd0bfc17 hook: move stdio redirection to context manager
Gregory Szorc <gregory.szorc@gmail.com>
parents: 43671
diff changeset
   270
            try:
3cbbfd0bfc17 hook: move stdio redirection to context manager
Gregory Szorc <gregory.szorc@gmail.com>
parents: 43671
diff changeset
   271
                stdoutno = procutil.stdout.fileno()
3cbbfd0bfc17 hook: move stdio redirection to context manager
Gregory Szorc <gregory.szorc@gmail.com>
parents: 43671
diff changeset
   272
                stderrno = procutil.stderr.fileno()
3cbbfd0bfc17 hook: move stdio redirection to context manager
Gregory Szorc <gregory.szorc@gmail.com>
parents: 43671
diff changeset
   273
                # 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
   274
                if stdoutno >= 0 and stderrno >= 0:
3cbbfd0bfc17 hook: move stdio redirection to context manager
Gregory Szorc <gregory.szorc@gmail.com>
parents: 43671
diff changeset
   275
                    procutil.stdout.flush()
3cbbfd0bfc17 hook: move stdio redirection to context manager
Gregory Szorc <gregory.szorc@gmail.com>
parents: 43671
diff changeset
   276
                    oldstdout = os.dup(stdoutno)
3cbbfd0bfc17 hook: move stdio redirection to context manager
Gregory Szorc <gregory.szorc@gmail.com>
parents: 43671
diff changeset
   277
                    os.dup2(stderrno, stdoutno)
3cbbfd0bfc17 hook: move stdio redirection to context manager
Gregory Szorc <gregory.szorc@gmail.com>
parents: 43671
diff changeset
   278
            except (OSError, AttributeError):
3cbbfd0bfc17 hook: move stdio redirection to context manager
Gregory Szorc <gregory.szorc@gmail.com>
parents: 43671
diff changeset
   279
                # 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
   280
                pass
3cbbfd0bfc17 hook: move stdio redirection to context manager
Gregory Szorc <gregory.szorc@gmail.com>
parents: 43671
diff changeset
   281
3cbbfd0bfc17 hook: move stdio redirection to context manager
Gregory Szorc <gregory.szorc@gmail.com>
parents: 43671
diff changeset
   282
        yield
3cbbfd0bfc17 hook: move stdio redirection to context manager
Gregory Szorc <gregory.szorc@gmail.com>
parents: 43671
diff changeset
   283
3cbbfd0bfc17 hook: move stdio redirection to context manager
Gregory Szorc <gregory.szorc@gmail.com>
parents: 43671
diff changeset
   284
    finally:
3cbbfd0bfc17 hook: move stdio redirection to context manager
Gregory Szorc <gregory.szorc@gmail.com>
parents: 43671
diff changeset
   285
        # 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
   286
        # 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
   287
        # 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
   288
        procutil.stderr.flush()
3cbbfd0bfc17 hook: move stdio redirection to context manager
Gregory Szorc <gregory.szorc@gmail.com>
parents: 43671
diff changeset
   289
3cbbfd0bfc17 hook: move stdio redirection to context manager
Gregory Szorc <gregory.szorc@gmail.com>
parents: 43671
diff changeset
   290
        if _redirect and oldstdout >= 0:
3cbbfd0bfc17 hook: move stdio redirection to context manager
Gregory Szorc <gregory.szorc@gmail.com>
parents: 43671
diff changeset
   291
            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
   292
            os.dup2(oldstdout, stdoutno)
3cbbfd0bfc17 hook: move stdio redirection to context manager
Gregory Szorc <gregory.szorc@gmail.com>
parents: 43671
diff changeset
   293
            os.close(oldstdout)
3cbbfd0bfc17 hook: move stdio redirection to context manager
Gregory Szorc <gregory.szorc@gmail.com>
parents: 43671
diff changeset
   294
3cbbfd0bfc17 hook: move stdio redirection to context manager
Gregory Szorc <gregory.szorc@gmail.com>
parents: 43671
diff changeset
   295
31744
5678496659e9 hook: use 'htype' in 'runhooks'
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents: 31743
diff changeset
   296
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
   297
    args = pycompat.byteskwargs(args)
26738
9abc2c921bbd hook.runhooks: return a dict of result values
Siddharth Agarwal <sid0@fb.com>
parents: 26737
diff changeset
   298
    res = {}
5833
323b9c55b328 hook: redirect stdout to stderr for ssh and http servers
Matt Mackall <mpm@selenic.com>
parents: 4622
diff changeset
   299
44652
3cbbfd0bfc17 hook: move stdio redirection to context manager
Gregory Szorc <gregory.szorc@gmail.com>
parents: 43671
diff changeset
   300
    with redirect_stdio():
26737
a930d66a04af hook: factor out determination of hooks from running them
Siddharth Agarwal <sid0@fb.com>
parents: 26692
diff changeset
   301
        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
   302
            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
   303
                if throw:
ea1fec3e9aba hook: report untrusted hooks as failure (issue5110) (BC)
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents: 28937
diff changeset
   304
                    raise error.HookAbort(
43077
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
   305
                        _(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
   306
                        hint=_(b"see 'hg help config.trusted'"),
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 40971
diff changeset
   307
                    )
43077
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
   308
                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
   309
                r = 1
ea1fec3e9aba hook: report untrusted hooks as failure (issue5110) (BC)
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents: 28937
diff changeset
   310
                raised = False
ea1fec3e9aba hook: report untrusted hooks as failure (issue5110) (BC)
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents: 28937
diff changeset
   311
            elif callable(cmd):
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 40971
diff changeset
   312
                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
   313
            elif cmd.startswith(b'python:'):
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
   314
                if cmd.count(b':') >= 2:
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
   315
                    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
   316
                    path = util.expandpath(path)
13119
ecf7d6e0eef0 hook: fix import path handling for repo=None
Matt Mackall <mpm@selenic.com>
parents: 13118
diff changeset
   317
                    if repo:
ecf7d6e0eef0 hook: fix import path handling for repo=None
Matt Mackall <mpm@selenic.com>
parents: 13118
diff changeset
   318
                        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
   319
                    try:
43077
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
   320
                        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
   321
                    except Exception:
43077
687b865b95ad formatting: byteify all mercurial/ and hgext/ string literals
Augie Fackler <augie@google.com>
parents: 43076
diff changeset
   322
                        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
   323
                        raise
7916
f779e1996e23 ability to load hooks from arbitrary python module
Alexander Solovyov <piranha@piranha.org.ua>
parents: 7787
diff changeset
   324
                    hookfn = getattr(mod, cmd)
f779e1996e23 ability to load hooks from arbitrary python module
Alexander Solovyov <piranha@piranha.org.ua>
parents: 7787
diff changeset
   325
                else:
f779e1996e23 ability to load hooks from arbitrary python module
Alexander Solovyov <piranha@piranha.org.ua>
parents: 7787
diff changeset
   326
                    hookfn = cmd[7:].strip()
43076
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 40971
diff changeset
   327
                r, raised = pythonhook(
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 40971
diff changeset
   328
                    ui, repo, htype, hname, hookfn, args, throw
2372284d9457 formatting: blacken the codebase
Augie Fackler <augie@google.com>
parents: 40971
diff changeset
   329
                )
7416
196b05a548d0 hooks: restore io correctly on exception
Jesse Long <jesse@virtualpostman.co.za>
parents: 7280
diff changeset
   330
            else:
31746
0fa30fbccc34 hook: provide hook type information to external hook
Pierre-Yves David <pierre-yves.david@ens-lyon.org>
parents: 31745
diff changeset
   331
                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
   332
                raised = False
26738
9abc2c921bbd hook.runhooks: return a dict of result values
Siddharth Agarwal <sid0@fb.com>
parents: 26737
diff changeset
   333
26739
8429369eeb85 hook: for python hooks, also return whether an exception was raised
Siddharth Agarwal <sid0@fb.com>
parents: 26738
diff changeset
   334
            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
   335
26738
9abc2c921bbd hook.runhooks: return a dict of result values
Siddharth Agarwal <sid0@fb.com>
parents: 26737
diff changeset
   336
    return res