mercurial/hook.py
author Thomas De Schampheleire <thomas.de.schampheleire@gmail.com>
Wed, 16 Nov 2011 08:34:36 +0100
branchstable
changeset 15512 8b011ededfb2
parent 14999 f6a737357195
child 15896 30c34fde40cc
permissions -rw-r--r--
hook: flush stdout before redirecting to stderr When hook output redirection is enabled (e.g. when cloning over ssh), hook output on stdout is redirected to stderr, to prevent the repository data on stdout from being corrupted. In certain cases, the redirection could cause part of the repository data to end up on stderr as well. In case of a clone, this causes: "abort: consistency error in delta!" This was seen with a clone over ssh, an outgoing hook present (any non-python type, e.g. 'pwd'), on certain repositories only, probably depending on the distribution of the sent data) This patch updates the hook redirection code to flush stdout before redirecting, removing the problem.
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
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
     8
from i18n import _
8312
b87a50b7125c separate import lines from mercurial and general python modules
Simon Heimberg <simohe@besonet.ch>
parents: 8225
diff changeset
     9
import os, sys
b87a50b7125c separate import lines from mercurial and general python modules
Simon Heimberg <simohe@besonet.ch>
parents: 8225
diff changeset
    10
import extensions, util
4622
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    11
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    12
def _pythonhook(ui, repo, name, hname, funcname, args, throw):
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    13
    '''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
    14
    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
    15
    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
    16
    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
    17
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    18
    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
    19
    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
    20
    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
    21
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    22
    ui.note(_("calling hook %s: %s\n") % (hname, funcname))
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    23
    obj = funcname
14943
d3bb825ddae3 globally: use safehasattr(x, '__call__') instead of hasattr(x, '__call__')
Augie Fackler <durin42@gmail.com>
parents: 14941
diff changeset
    24
    if not util.safehasattr(obj, '__call__'):
4622
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    25
        d = funcname.rfind('.')
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    26
        if d == -1:
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    27
            raise util.Abort(_('%s hook is invalid ("%s" not in '
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    28
                               'a module)') % (hname, funcname))
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    29
        modname = funcname[:d]
10103
37679dbf2ee3 hook: fix bug (reuse of variable) introduced in 872d49dd577a
Sune Foldager <cryo@cyanite.org>
parents: 9851
diff changeset
    30
        oldpaths = sys.path
14941
4a28cb4df1f8 windows: check util.mainfrozen() instead of ad-hoc checks everywhere
Augie Fackler <durin42@gmail.com>
parents: 14916
diff changeset
    31
        if util.mainfrozen():
9332
872d49dd577a hook: fix full path imports on Windows (issue1779)
Steve Borho <steve@borho.org>
parents: 8366
diff changeset
    32
            # 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
    33
            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
    34
            if modpath and modfile:
37679dbf2ee3 hook: fix bug (reuse of variable) introduced in 872d49dd577a
Sune Foldager <cryo@cyanite.org>
parents: 9851
diff changeset
    35
                sys.path = sys.path[:] + [modpath]
37679dbf2ee3 hook: fix bug (reuse of variable) introduced in 872d49dd577a
Sune Foldager <cryo@cyanite.org>
parents: 9851
diff changeset
    36
                modname = modfile
4622
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    37
        try:
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    38
            obj = __import__(modname)
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    39
        except ImportError:
9851
9e7b2c49d25d Make it possible to debug failed hook imports via use of --traceback
Bryan O'Sullivan <bos@serpentine.com>
parents: 9658
diff changeset
    40
            e1 = sys.exc_type, sys.exc_value, sys.exc_traceback
4622
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    41
            try:
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    42
                # extensions are loaded with hgext_ prefix
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    43
                obj = __import__("hgext_%s" % modname)
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    44
            except ImportError:
9851
9e7b2c49d25d Make it possible to debug failed hook imports via use of --traceback
Bryan O'Sullivan <bos@serpentine.com>
parents: 9658
diff changeset
    45
                e2 = sys.exc_type, sys.exc_value, sys.exc_traceback
9e7b2c49d25d Make it possible to debug failed hook imports via use of --traceback
Bryan O'Sullivan <bos@serpentine.com>
parents: 9658
diff changeset
    46
                if ui.tracebackflag:
9e7b2c49d25d Make it possible to debug failed hook imports via use of --traceback
Bryan O'Sullivan <bos@serpentine.com>
parents: 9658
diff changeset
    47
                    ui.warn(_('exception from first failed import attempt:\n'))
9e7b2c49d25d Make it possible to debug failed hook imports via use of --traceback
Bryan O'Sullivan <bos@serpentine.com>
parents: 9658
diff changeset
    48
                ui.traceback(e1)
9e7b2c49d25d Make it possible to debug failed hook imports via use of --traceback
Bryan O'Sullivan <bos@serpentine.com>
parents: 9658
diff changeset
    49
                if ui.tracebackflag:
9e7b2c49d25d Make it possible to debug failed hook imports via use of --traceback
Bryan O'Sullivan <bos@serpentine.com>
parents: 9658
diff changeset
    50
                    ui.warn(_('exception from second failed import attempt:\n'))
9e7b2c49d25d Make it possible to debug failed hook imports via use of --traceback
Bryan O'Sullivan <bos@serpentine.com>
parents: 9658
diff changeset
    51
                ui.traceback(e2)
4622
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    52
                raise util.Abort(_('%s hook is invalid '
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    53
                                   '(import of "%s" failed)') %
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    54
                                 (hname, modname))
9332
872d49dd577a hook: fix full path imports on Windows (issue1779)
Steve Borho <steve@borho.org>
parents: 8366
diff changeset
    55
        sys.path = oldpaths
4622
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    56
        try:
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    57
            for p in funcname.split('.')[1:]:
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    58
                obj = getattr(obj, p)
7280
810ca383da9c remove unused variables
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 6762
diff changeset
    59
        except AttributeError:
4622
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    60
            raise util.Abort(_('%s hook is invalid '
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    61
                               '("%s" is not defined)') %
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    62
                             (hname, funcname))
14943
d3bb825ddae3 globally: use safehasattr(x, '__call__') instead of hasattr(x, '__call__')
Augie Fackler <durin42@gmail.com>
parents: 14941
diff changeset
    63
        if not util.safehasattr(obj, '__call__'):
4622
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    64
            raise util.Abort(_('%s hook is invalid '
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    65
                               '("%s" is not callable)') %
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    66
                             (hname, funcname))
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    67
    try:
14916
58f97dcbd550 hooks: use python 2.4 compatible exception handling
Lee Cantey <lcantey@gmail.com>
parents: 14889
diff changeset
    68
        try:
58f97dcbd550 hooks: use python 2.4 compatible exception handling
Lee Cantey <lcantey@gmail.com>
parents: 14889
diff changeset
    69
            # redirect IO descriptors the the ui descriptors so hooks
58f97dcbd550 hooks: use python 2.4 compatible exception handling
Lee Cantey <lcantey@gmail.com>
parents: 14889
diff changeset
    70
            # that write directly to these don't mess up the command
58f97dcbd550 hooks: use python 2.4 compatible exception handling
Lee Cantey <lcantey@gmail.com>
parents: 14889
diff changeset
    71
            # protocol when running through the command server
58f97dcbd550 hooks: use python 2.4 compatible exception handling
Lee Cantey <lcantey@gmail.com>
parents: 14889
diff changeset
    72
            old = sys.stdout, sys.stderr, sys.stdin
58f97dcbd550 hooks: use python 2.4 compatible exception handling
Lee Cantey <lcantey@gmail.com>
parents: 14889
diff changeset
    73
            sys.stdout, sys.stderr, sys.stdin = ui.fout, ui.ferr, ui.fin
14889
a59058fd074a hooks: redirect stdout/err/in to the ui descriptors when calling python hooks
Idan Kamara <idankk86@gmail.com>
parents: 14711
diff changeset
    74
14916
58f97dcbd550 hooks: use python 2.4 compatible exception handling
Lee Cantey <lcantey@gmail.com>
parents: 14889
diff changeset
    75
            r = obj(ui=ui, repo=repo, hooktype=name, **args)
58f97dcbd550 hooks: use python 2.4 compatible exception handling
Lee Cantey <lcantey@gmail.com>
parents: 14889
diff changeset
    76
        except KeyboardInterrupt:
4622
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    77
            raise
14916
58f97dcbd550 hooks: use python 2.4 compatible exception handling
Lee Cantey <lcantey@gmail.com>
parents: 14889
diff changeset
    78
        except Exception, exc:
58f97dcbd550 hooks: use python 2.4 compatible exception handling
Lee Cantey <lcantey@gmail.com>
parents: 14889
diff changeset
    79
            if isinstance(exc, util.Abort):
58f97dcbd550 hooks: use python 2.4 compatible exception handling
Lee Cantey <lcantey@gmail.com>
parents: 14889
diff changeset
    80
                ui.warn(_('error: %s hook failed: %s\n') %
58f97dcbd550 hooks: use python 2.4 compatible exception handling
Lee Cantey <lcantey@gmail.com>
parents: 14889
diff changeset
    81
                             (hname, exc.args[0]))
58f97dcbd550 hooks: use python 2.4 compatible exception handling
Lee Cantey <lcantey@gmail.com>
parents: 14889
diff changeset
    82
            else:
58f97dcbd550 hooks: use python 2.4 compatible exception handling
Lee Cantey <lcantey@gmail.com>
parents: 14889
diff changeset
    83
                ui.warn(_('error: %s hook raised an exception: '
58f97dcbd550 hooks: use python 2.4 compatible exception handling
Lee Cantey <lcantey@gmail.com>
parents: 14889
diff changeset
    84
                               '%s\n') % (hname, exc))
58f97dcbd550 hooks: use python 2.4 compatible exception handling
Lee Cantey <lcantey@gmail.com>
parents: 14889
diff changeset
    85
            if throw:
58f97dcbd550 hooks: use python 2.4 compatible exception handling
Lee Cantey <lcantey@gmail.com>
parents: 14889
diff changeset
    86
                raise
58f97dcbd550 hooks: use python 2.4 compatible exception handling
Lee Cantey <lcantey@gmail.com>
parents: 14889
diff changeset
    87
            ui.traceback()
58f97dcbd550 hooks: use python 2.4 compatible exception handling
Lee Cantey <lcantey@gmail.com>
parents: 14889
diff changeset
    88
            return 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
    89
    finally:
a59058fd074a hooks: redirect stdout/err/in to the ui descriptors when calling python hooks
Idan Kamara <idankk86@gmail.com>
parents: 14711
diff changeset
    90
        sys.stdout, sys.stderr, sys.stdin = old
4622
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    91
    if r:
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    92
        if throw:
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    93
            raise util.Abort(_('%s hook failed') % hname)
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    94
        ui.warn(_('warning: %s hook failed\n') % hname)
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    95
    return r
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    96
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    97
def _exthook(ui, repo, name, cmd, args, throw):
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    98
    ui.note(_("running hook %s: %s\n") % (name, cmd))
7787
b8d750daadde Introduce HG_PREPEND to solve pretxn races
Matt Mackall <mpm@selenic.com>
parents: 7644
diff changeset
    99
b8d750daadde Introduce HG_PREPEND to solve pretxn races
Matt Mackall <mpm@selenic.com>
parents: 7644
diff changeset
   100
    env = {}
b8d750daadde Introduce HG_PREPEND to solve pretxn races
Matt Mackall <mpm@selenic.com>
parents: 7644
diff changeset
   101
    for k, v in args.iteritems():
14943
d3bb825ddae3 globally: use safehasattr(x, '__call__') instead of hasattr(x, '__call__')
Augie Fackler <durin42@gmail.com>
parents: 14941
diff changeset
   102
        if util.safehasattr(v, '__call__'):
7787
b8d750daadde Introduce HG_PREPEND to solve pretxn races
Matt Mackall <mpm@selenic.com>
parents: 7644
diff changeset
   103
            v = v()
13207
1775382ff833 hooks: sort any dictionaries set in the environment
Dan Villiom Podlaski Christiansen <danchr@gmail.com>
parents: 13119
diff changeset
   104
        if isinstance(v, dict):
1775382ff833 hooks: sort any dictionaries set in the environment
Dan Villiom Podlaski Christiansen <danchr@gmail.com>
parents: 13119
diff changeset
   105
            # make the dictionary element order stable across Python
1775382ff833 hooks: sort any dictionaries set in the environment
Dan Villiom Podlaski Christiansen <danchr@gmail.com>
parents: 13119
diff changeset
   106
            # implementations
1775382ff833 hooks: sort any dictionaries set in the environment
Dan Villiom Podlaski Christiansen <danchr@gmail.com>
parents: 13119
diff changeset
   107
            v = ('{' +
1775382ff833 hooks: sort any dictionaries set in the environment
Dan Villiom Podlaski Christiansen <danchr@gmail.com>
parents: 13119
diff changeset
   108
                 ', '.join('%r: %r' % i for i in sorted(v.iteritems())) +
1775382ff833 hooks: sort any dictionaries set in the environment
Dan Villiom Podlaski Christiansen <danchr@gmail.com>
parents: 13119
diff changeset
   109
                 '}')
7787
b8d750daadde Introduce HG_PREPEND to solve pretxn races
Matt Mackall <mpm@selenic.com>
parents: 7644
diff changeset
   110
        env['HG_' + k.upper()] = v
b8d750daadde Introduce HG_PREPEND to solve pretxn races
Matt Mackall <mpm@selenic.com>
parents: 7644
diff changeset
   111
5869
2c565b9598b8 hooks: fix pre- and post- hooks specified in .hg/hgrc
Matt Mackall <mpm@selenic.com>
parents: 5833
diff changeset
   112
    if repo:
2c565b9598b8 hooks: fix pre- and post- hooks specified in .hg/hgrc
Matt Mackall <mpm@selenic.com>
parents: 5833
diff changeset
   113
        cwd = repo.root
2c565b9598b8 hooks: fix pre- and post- hooks specified in .hg/hgrc
Matt Mackall <mpm@selenic.com>
parents: 5833
diff changeset
   114
    else:
2c565b9598b8 hooks: fix pre- and post- hooks specified in .hg/hgrc
Matt Mackall <mpm@selenic.com>
parents: 5833
diff changeset
   115
        cwd = os.getcwd()
11469
c37f35d7f2f5 http: deliver hook output to client
Maxim Khitrov <mkhitrov@gmail.com>
parents: 10263
diff changeset
   116
    if 'HG_URL' in env and env['HG_URL'].startswith('remote:http'):
c37f35d7f2f5 http: deliver hook output to client
Maxim Khitrov <mkhitrov@gmail.com>
parents: 10263
diff changeset
   117
        r = util.system(cmd, environ=env, cwd=cwd, out=ui)
c37f35d7f2f5 http: deliver hook output to client
Maxim Khitrov <mkhitrov@gmail.com>
parents: 10263
diff changeset
   118
    else:
14711
ac70f8d5987c hook: write hook output to ui fout descriptor
Idan Kamara <idankk86@gmail.com>
parents: 14234
diff changeset
   119
        r = util.system(cmd, environ=env, cwd=cwd, out=ui.fout)
4622
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   120
    if r:
14234
600e64004eb5 rename explain_exit to explainexit
Adrian Buehlmann <adrian@cadifra.com>
parents: 13207
diff changeset
   121
        desc, r = util.explainexit(r)
4622
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   122
        if throw:
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   123
            raise util.Abort(_('%s hook %s') % (name, desc))
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   124
        ui.warn(_('warning: %s hook %s\n') % (name, desc))
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   125
    return r
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   126
5833
323b9c55b328 hook: redirect stdout to stderr for ssh and http servers
Matt Mackall <mpm@selenic.com>
parents: 4622
diff changeset
   127
_redirect = False
323b9c55b328 hook: redirect stdout to stderr for ssh and http servers
Matt Mackall <mpm@selenic.com>
parents: 4622
diff changeset
   128
def redirect(state):
6266
9f76df0edb7d hook.py: fix redirections introduced by 323b9c55b328
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 5869
diff changeset
   129
    global _redirect
5833
323b9c55b328 hook: redirect stdout to stderr for ssh and http servers
Matt Mackall <mpm@selenic.com>
parents: 4622
diff changeset
   130
    _redirect = state
323b9c55b328 hook: redirect stdout to stderr for ssh and http servers
Matt Mackall <mpm@selenic.com>
parents: 4622
diff changeset
   131
4622
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   132
def hook(ui, repo, name, throw=False, **args):
fff50306e6dd hooks: separate hook code into a separate module
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   133
    r = False
5833
323b9c55b328 hook: redirect stdout to stderr for ssh and http servers
Matt Mackall <mpm@selenic.com>
parents: 4622
diff changeset
   134
9658
852b1f3032d2 hook: only redirect stdout if it and stderr are valid files
Sune Foldager <cryo@cyanite.org>
parents: 9332
diff changeset
   135
    oldstdout = -1
5833
323b9c55b328 hook: redirect stdout to stderr for ssh and http servers
Matt Mackall <mpm@selenic.com>
parents: 4622
diff changeset
   136
    if _redirect:
14993
e5b2ee5157ae hook: be prepared for __stdout/err__ not having fileno()
Idan Kamara <idankk86@gmail.com>
parents: 14916
diff changeset
   137
        try:
e5b2ee5157ae hook: be prepared for __stdout/err__ not having fileno()
Idan Kamara <idankk86@gmail.com>
parents: 14916
diff changeset
   138
            stdoutno = sys.__stdout__.fileno()
e5b2ee5157ae hook: be prepared for __stdout/err__ not having fileno()
Idan Kamara <idankk86@gmail.com>
parents: 14916
diff changeset
   139
            stderrno = sys.__stderr__.fileno()
e5b2ee5157ae hook: be prepared for __stdout/err__ not having fileno()
Idan Kamara <idankk86@gmail.com>
parents: 14916
diff changeset
   140
            # temporarily redirect stdout to stderr, if possible
e5b2ee5157ae hook: be prepared for __stdout/err__ not having fileno()
Idan Kamara <idankk86@gmail.com>
parents: 14916
diff changeset
   141
            if stdoutno >= 0 and stderrno >= 0:
15512
8b011ededfb2 hook: flush stdout before redirecting to stderr
Thomas De Schampheleire <thomas.de.schampheleire@gmail.com>
parents: 14999
diff changeset
   142
                sys.__stdout__.flush()
14993
e5b2ee5157ae hook: be prepared for __stdout/err__ not having fileno()
Idan Kamara <idankk86@gmail.com>
parents: 14916
diff changeset
   143
                oldstdout = os.dup(stdoutno)
e5b2ee5157ae hook: be prepared for __stdout/err__ not having fileno()
Idan Kamara <idankk86@gmail.com>
parents: 14916
diff changeset
   144
                os.dup2(stderrno, stdoutno)
e5b2ee5157ae hook: be prepared for __stdout/err__ not having fileno()
Idan Kamara <idankk86@gmail.com>
parents: 14916
diff changeset
   145
        except AttributeError:
e5b2ee5157ae hook: be prepared for __stdout/err__ not having fileno()
Idan Kamara <idankk86@gmail.com>
parents: 14916
diff changeset
   146
            # __stdout/err__ doesn't have fileno(), it's not a real file
e5b2ee5157ae hook: be prepared for __stdout/err__ not having fileno()
Idan Kamara <idankk86@gmail.com>
parents: 14916
diff changeset
   147
            pass
5833
323b9c55b328 hook: redirect stdout to stderr for ssh and http servers
Matt Mackall <mpm@selenic.com>
parents: 4622
diff changeset
   148
7416
196b05a548d0 hooks: restore io correctly on exception
Jesse Long <jesse@virtualpostman.co.za>
parents: 7280
diff changeset
   149
    try:
8209
a1a5a57efe90 replace util.sort with sorted built-in
Matt Mackall <mpm@selenic.com>
parents: 8206
diff changeset
   150
        for hname, cmd in ui.configitems('hooks'):
7416
196b05a548d0 hooks: restore io correctly on exception
Jesse Long <jesse@virtualpostman.co.za>
parents: 7280
diff changeset
   151
            if hname.split('.')[0] != name or not cmd:
196b05a548d0 hooks: restore io correctly on exception
Jesse Long <jesse@virtualpostman.co.za>
parents: 7280
diff changeset
   152
                continue
14943
d3bb825ddae3 globally: use safehasattr(x, '__call__') instead of hasattr(x, '__call__')
Augie Fackler <durin42@gmail.com>
parents: 14941
diff changeset
   153
            if util.safehasattr(cmd, '__call__'):
7416
196b05a548d0 hooks: restore io correctly on exception
Jesse Long <jesse@virtualpostman.co.za>
parents: 7280
diff changeset
   154
                r = _pythonhook(ui, repo, name, hname, cmd, args, throw) or r
196b05a548d0 hooks: restore io correctly on exception
Jesse Long <jesse@virtualpostman.co.za>
parents: 7280
diff changeset
   155
            elif cmd.startswith('python:'):
9332
872d49dd577a hook: fix full path imports on Windows (issue1779)
Steve Borho <steve@borho.org>
parents: 8366
diff changeset
   156
                if cmd.count(':') >= 2:
872d49dd577a hook: fix full path imports on Windows (issue1779)
Steve Borho <steve@borho.org>
parents: 8366
diff changeset
   157
                    path, cmd = cmd[7:].rsplit(':', 1)
13118
789e0fa2fcea hook: assume relative path to hook is given from repo root
Alexander Solovyov <alexander@solovyov.net>
parents: 11469
diff changeset
   158
                    path = util.expandpath(path)
13119
ecf7d6e0eef0 hook: fix import path handling for repo=None
Matt Mackall <mpm@selenic.com>
parents: 13118
diff changeset
   159
                    if repo:
ecf7d6e0eef0 hook: fix import path handling for repo=None
Matt Mackall <mpm@selenic.com>
parents: 13118
diff changeset
   160
                        path = os.path.join(repo.root, path)
ecf7d6e0eef0 hook: fix import path handling for repo=None
Matt Mackall <mpm@selenic.com>
parents: 13118
diff changeset
   161
                    mod = extensions.loadpath(path, 'hghook.%s' % hname)
7916
f779e1996e23 ability to load hooks from arbitrary python module
Alexander Solovyov <piranha@piranha.org.ua>
parents: 7787
diff changeset
   162
                    hookfn = getattr(mod, cmd)
f779e1996e23 ability to load hooks from arbitrary python module
Alexander Solovyov <piranha@piranha.org.ua>
parents: 7787
diff changeset
   163
                else:
f779e1996e23 ability to load hooks from arbitrary python module
Alexander Solovyov <piranha@piranha.org.ua>
parents: 7787
diff changeset
   164
                    hookfn = cmd[7:].strip()
f779e1996e23 ability to load hooks from arbitrary python module
Alexander Solovyov <piranha@piranha.org.ua>
parents: 7787
diff changeset
   165
                r = _pythonhook(ui, repo, name, hname, hookfn, args, throw) or r
7416
196b05a548d0 hooks: restore io correctly on exception
Jesse Long <jesse@virtualpostman.co.za>
parents: 7280
diff changeset
   166
            else:
196b05a548d0 hooks: restore io correctly on exception
Jesse Long <jesse@virtualpostman.co.za>
parents: 7280
diff changeset
   167
                r = _exthook(ui, repo, hname, cmd, args, throw) or r
196b05a548d0 hooks: restore io correctly on exception
Jesse Long <jesse@virtualpostman.co.za>
parents: 7280
diff changeset
   168
    finally:
9658
852b1f3032d2 hook: only redirect stdout if it and stderr are valid files
Sune Foldager <cryo@cyanite.org>
parents: 9332
diff changeset
   169
        if _redirect and oldstdout >= 0:
852b1f3032d2 hook: only redirect stdout if it and stderr are valid files
Sune Foldager <cryo@cyanite.org>
parents: 9332
diff changeset
   170
            os.dup2(oldstdout, stdoutno)
7416
196b05a548d0 hooks: restore io correctly on exception
Jesse Long <jesse@virtualpostman.co.za>
parents: 7280
diff changeset
   171
            os.close(oldstdout)
6266
9f76df0edb7d hook.py: fix redirections introduced by 323b9c55b328
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 5869
diff changeset
   172
9f76df0edb7d hook.py: fix redirections introduced by 323b9c55b328
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 5869
diff changeset
   173
    return r