eggs/mercurial-1.7.3-py2.6-linux-x86_64.egg/mercurial/hook.py
changeset 69 c6bca38c1cbf
equal deleted inserted replaced
68:5ff1fc726848 69:c6bca38c1cbf
       
     1 # hook.py - hook support for mercurial
       
     2 #
       
     3 # Copyright 2007 Matt Mackall <mpm@selenic.com>
       
     4 #
       
     5 # This software may be used and distributed according to the terms of the
       
     6 # GNU General Public License version 2 or any later version.
       
     7 
       
     8 from i18n import _
       
     9 import os, sys
       
    10 import extensions, util
       
    11 
       
    12 def _pythonhook(ui, repo, name, hname, funcname, args, throw):
       
    13     '''call python hook. hook is callable object, looked up as
       
    14     name in python module. if callable returns "true", hook
       
    15     fails, else passes. if hook raises exception, treated as
       
    16     hook failure. exception propagates if throw is "true".
       
    17 
       
    18     reason for "true" meaning "hook failed" is so that
       
    19     unmodified commands (e.g. mercurial.commands.update) can
       
    20     be run as hooks without wrappers to convert return values.'''
       
    21 
       
    22     ui.note(_("calling hook %s: %s\n") % (hname, funcname))
       
    23     obj = funcname
       
    24     if not hasattr(obj, '__call__'):
       
    25         d = funcname.rfind('.')
       
    26         if d == -1:
       
    27             raise util.Abort(_('%s hook is invalid ("%s" not in '
       
    28                                'a module)') % (hname, funcname))
       
    29         modname = funcname[:d]
       
    30         oldpaths = sys.path
       
    31         if hasattr(sys, "frozen"):
       
    32             # binary installs require sys.path manipulation
       
    33             modpath, modfile = os.path.split(modname)
       
    34             if modpath and modfile:
       
    35                 sys.path = sys.path[:] + [modpath]
       
    36                 modname = modfile
       
    37         try:
       
    38             obj = __import__(modname)
       
    39         except ImportError:
       
    40             e1 = sys.exc_type, sys.exc_value, sys.exc_traceback
       
    41             try:
       
    42                 # extensions are loaded with hgext_ prefix
       
    43                 obj = __import__("hgext_%s" % modname)
       
    44             except ImportError:
       
    45                 e2 = sys.exc_type, sys.exc_value, sys.exc_traceback
       
    46                 if ui.tracebackflag:
       
    47                     ui.warn(_('exception from first failed import attempt:\n'))
       
    48                 ui.traceback(e1)
       
    49                 if ui.tracebackflag:
       
    50                     ui.warn(_('exception from second failed import attempt:\n'))
       
    51                 ui.traceback(e2)
       
    52                 raise util.Abort(_('%s hook is invalid '
       
    53                                    '(import of "%s" failed)') %
       
    54                                  (hname, modname))
       
    55         sys.path = oldpaths
       
    56         try:
       
    57             for p in funcname.split('.')[1:]:
       
    58                 obj = getattr(obj, p)
       
    59         except AttributeError:
       
    60             raise util.Abort(_('%s hook is invalid '
       
    61                                '("%s" is not defined)') %
       
    62                              (hname, funcname))
       
    63         if not hasattr(obj, '__call__'):
       
    64             raise util.Abort(_('%s hook is invalid '
       
    65                                '("%s" is not callable)') %
       
    66                              (hname, funcname))
       
    67     try:
       
    68         r = obj(ui=ui, repo=repo, hooktype=name, **args)
       
    69     except KeyboardInterrupt:
       
    70         raise
       
    71     except Exception, exc:
       
    72         if isinstance(exc, util.Abort):
       
    73             ui.warn(_('error: %s hook failed: %s\n') %
       
    74                          (hname, exc.args[0]))
       
    75         else:
       
    76             ui.warn(_('error: %s hook raised an exception: '
       
    77                            '%s\n') % (hname, exc))
       
    78         if throw:
       
    79             raise
       
    80         ui.traceback()
       
    81         return True
       
    82     if r:
       
    83         if throw:
       
    84             raise util.Abort(_('%s hook failed') % hname)
       
    85         ui.warn(_('warning: %s hook failed\n') % hname)
       
    86     return r
       
    87 
       
    88 def _exthook(ui, repo, name, cmd, args, throw):
       
    89     ui.note(_("running hook %s: %s\n") % (name, cmd))
       
    90 
       
    91     env = {}
       
    92     for k, v in args.iteritems():
       
    93         if hasattr(v, '__call__'):
       
    94             v = v()
       
    95         env['HG_' + k.upper()] = v
       
    96 
       
    97     if repo:
       
    98         cwd = repo.root
       
    99     else:
       
   100         cwd = os.getcwd()
       
   101     if 'HG_URL' in env and env['HG_URL'].startswith('remote:http'):
       
   102         r = util.system(cmd, environ=env, cwd=cwd, out=ui)
       
   103     else:
       
   104         r = util.system(cmd, environ=env, cwd=cwd)
       
   105     if r:
       
   106         desc, r = util.explain_exit(r)
       
   107         if throw:
       
   108             raise util.Abort(_('%s hook %s') % (name, desc))
       
   109         ui.warn(_('warning: %s hook %s\n') % (name, desc))
       
   110     return r
       
   111 
       
   112 _redirect = False
       
   113 def redirect(state):
       
   114     global _redirect
       
   115     _redirect = state
       
   116 
       
   117 def hook(ui, repo, name, throw=False, **args):
       
   118     r = False
       
   119 
       
   120     oldstdout = -1
       
   121     if _redirect:
       
   122         stdoutno = sys.__stdout__.fileno()
       
   123         stderrno = sys.__stderr__.fileno()
       
   124         # temporarily redirect stdout to stderr, if possible
       
   125         if stdoutno >= 0 and stderrno >= 0:
       
   126             oldstdout = os.dup(stdoutno)
       
   127             os.dup2(stderrno, stdoutno)
       
   128 
       
   129     try:
       
   130         for hname, cmd in ui.configitems('hooks'):
       
   131             if hname.split('.')[0] != name or not cmd:
       
   132                 continue
       
   133             if hasattr(cmd, '__call__'):
       
   134                 r = _pythonhook(ui, repo, name, hname, cmd, args, throw) or r
       
   135             elif cmd.startswith('python:'):
       
   136                 if cmd.count(':') >= 2:
       
   137                     path, cmd = cmd[7:].rsplit(':', 1)
       
   138                     path = util.expandpath(path)
       
   139                     if repo:
       
   140                         path = os.path.join(repo.root, path)
       
   141                     mod = extensions.loadpath(path, 'hghook.%s' % hname)
       
   142                     hookfn = getattr(mod, cmd)
       
   143                 else:
       
   144                     hookfn = cmd[7:].strip()
       
   145                 r = _pythonhook(ui, repo, name, hname, hookfn, args, throw) or r
       
   146             else:
       
   147                 r = _exthook(ui, repo, hname, cmd, args, throw) or r
       
   148     finally:
       
   149         if _redirect and oldstdout >= 0:
       
   150             os.dup2(oldstdout, stdoutno)
       
   151             os.close(oldstdout)
       
   152 
       
   153     return r