mercurial/hook.py
changeset 43077 687b865b95ad
parent 43076 2372284d9457
child 43089 c59eb1560c44
equal deleted inserted replaced
43076:2372284d9457 43077:687b865b95ad
    37 
    37 
    38     if callable(funcname):
    38     if callable(funcname):
    39         obj = funcname
    39         obj = funcname
    40         funcname = pycompat.sysbytes(obj.__module__ + r"." + obj.__name__)
    40         funcname = pycompat.sysbytes(obj.__module__ + r"." + obj.__name__)
    41     else:
    41     else:
    42         d = funcname.rfind('.')
    42         d = funcname.rfind(b'.')
    43         if d == -1:
    43         if d == -1:
    44             raise error.HookLoadError(
    44             raise error.HookLoadError(
    45                 _('%s hook is invalid: "%s" not in a module')
    45                 _(b'%s hook is invalid: "%s" not in a module')
    46                 % (hname, funcname)
    46                 % (hname, funcname)
    47             )
    47             )
    48         modname = funcname[:d]
    48         modname = funcname[:d]
    49         oldpaths = sys.path
    49         oldpaths = sys.path
    50         if procutil.mainfrozen():
    50         if procutil.mainfrozen():
    64                 except (ImportError, SyntaxError):
    64                 except (ImportError, SyntaxError):
    65                     e2 = sys.exc_info()
    65                     e2 = sys.exc_info()
    66                     if ui.tracebackflag:
    66                     if ui.tracebackflag:
    67                         ui.warn(
    67                         ui.warn(
    68                             _(
    68                             _(
    69                                 'exception from first failed import '
    69                                 b'exception from first failed import '
    70                                 'attempt:\n'
    70                                 b'attempt:\n'
    71                             )
    71                             )
    72                         )
    72                         )
    73                     ui.traceback(e1)
    73                     ui.traceback(e1)
    74                     if ui.tracebackflag:
    74                     if ui.tracebackflag:
    75                         ui.warn(
    75                         ui.warn(
    76                             _(
    76                             _(
    77                                 'exception from second failed import '
    77                                 b'exception from second failed import '
    78                                 'attempt:\n'
    78                                 b'attempt:\n'
    79                             )
    79                             )
    80                         )
    80                         )
    81                     ui.traceback(e2)
    81                     ui.traceback(e2)
    82 
    82 
    83                     if not ui.tracebackflag:
    83                     if not ui.tracebackflag:
    84                         tracebackhint = _(
    84                         tracebackhint = _(
    85                             'run with --traceback for stack trace'
    85                             b'run with --traceback for stack trace'
    86                         )
    86                         )
    87                     else:
    87                     else:
    88                         tracebackhint = None
    88                         tracebackhint = None
    89                     raise error.HookLoadError(
    89                     raise error.HookLoadError(
    90                         _('%s hook is invalid: import of "%s" failed')
    90                         _(b'%s hook is invalid: import of "%s" failed')
    91                         % (hname, modname),
    91                         % (hname, modname),
    92                         hint=tracebackhint,
    92                         hint=tracebackhint,
    93                     )
    93                     )
    94         sys.path = oldpaths
    94         sys.path = oldpaths
    95         try:
    95         try:
    96             for p in funcname.split('.')[1:]:
    96             for p in funcname.split(b'.')[1:]:
    97                 obj = getattr(obj, p)
    97                 obj = getattr(obj, p)
    98         except AttributeError:
    98         except AttributeError:
    99             raise error.HookLoadError(
    99             raise error.HookLoadError(
   100                 _('%s hook is invalid: "%s" is not defined') % (hname, funcname)
   100                 _(b'%s hook is invalid: "%s" is not defined')
       
   101                 % (hname, funcname)
   101             )
   102             )
   102         if not callable(obj):
   103         if not callable(obj):
   103             raise error.HookLoadError(
   104             raise error.HookLoadError(
   104                 _('%s hook is invalid: "%s" is not callable')
   105                 _(b'%s hook is invalid: "%s" is not callable')
   105                 % (hname, funcname)
   106                 % (hname, funcname)
   106             )
   107             )
   107 
   108 
   108     ui.note(_("calling hook %s: %s\n") % (hname, funcname))
   109     ui.note(_(b"calling hook %s: %s\n") % (hname, funcname))
   109     starttime = util.timer()
   110     starttime = util.timer()
   110 
   111 
   111     try:
   112     try:
   112         r = obj(ui=ui, repo=repo, hooktype=htype, **pycompat.strkwargs(args))
   113         r = obj(ui=ui, repo=repo, hooktype=htype, **pycompat.strkwargs(args))
   113     except Exception as exc:
   114     except Exception as exc:
   114         if isinstance(exc, error.Abort):
   115         if isinstance(exc, error.Abort):
   115             ui.warn(_('error: %s hook failed: %s\n') % (hname, exc.args[0]))
   116             ui.warn(_(b'error: %s hook failed: %s\n') % (hname, exc.args[0]))
   116         else:
   117         else:
   117             ui.warn(
   118             ui.warn(
   118                 _('error: %s hook raised an exception: ' '%s\n')
   119                 _(b'error: %s hook raised an exception: ' b'%s\n')
   119                 % (hname, stringutil.forcebytestr(exc))
   120                 % (hname, stringutil.forcebytestr(exc))
   120             )
   121             )
   121         if throw:
   122         if throw:
   122             raise
   123             raise
   123         if not ui.tracebackflag:
   124         if not ui.tracebackflag:
   124             ui.warn(_('(run with --traceback for stack trace)\n'))
   125             ui.warn(_(b'(run with --traceback for stack trace)\n'))
   125         ui.traceback()
   126         ui.traceback()
   126         return True, True
   127         return True, True
   127     finally:
   128     finally:
   128         duration = util.timer() - starttime
   129         duration = util.timer() - starttime
   129         ui.log(
   130         ui.log(
   130             'pythonhook',
   131             b'pythonhook',
   131             'pythonhook-%s: %s finished in %0.2f seconds\n',
   132             b'pythonhook-%s: %s finished in %0.2f seconds\n',
   132             htype,
   133             htype,
   133             funcname,
   134             funcname,
   134             duration,
   135             duration,
   135         )
   136         )
   136     if r:
   137     if r:
   137         if throw:
   138         if throw:
   138             raise error.HookAbort(_('%s hook failed') % hname)
   139             raise error.HookAbort(_(b'%s hook failed') % hname)
   139         ui.warn(_('warning: %s hook failed\n') % hname)
   140         ui.warn(_(b'warning: %s hook failed\n') % hname)
   140     return r, False
   141     return r, False
   141 
   142 
   142 
   143 
   143 def _exthook(ui, repo, htype, name, cmd, args, throw):
   144 def _exthook(ui, repo, htype, name, cmd, args, throw):
   144     starttime = util.timer()
   145     starttime = util.timer()
   147     # make in-memory changes visible to external process
   148     # make in-memory changes visible to external process
   148     if repo is not None:
   149     if repo is not None:
   149         tr = repo.currenttransaction()
   150         tr = repo.currenttransaction()
   150         repo.dirstate.write(tr)
   151         repo.dirstate.write(tr)
   151         if tr and tr.writepending():
   152         if tr and tr.writepending():
   152             env['HG_PENDING'] = repo.root
   153             env[b'HG_PENDING'] = repo.root
   153     env['HG_HOOKTYPE'] = htype
   154     env[b'HG_HOOKTYPE'] = htype
   154     env['HG_HOOKNAME'] = name
   155     env[b'HG_HOOKNAME'] = name
   155 
   156 
   156     for k, v in args.iteritems():
   157     for k, v in args.iteritems():
   157         if callable(v):
   158         if callable(v):
   158             v = v()
   159             v = v()
   159         if isinstance(v, (dict, list)):
   160         if isinstance(v, (dict, list)):
   160             v = stringutil.pprint(v)
   161             v = stringutil.pprint(v)
   161         env['HG_' + k.upper()] = v
   162         env[b'HG_' + k.upper()] = v
   162 
   163 
   163     if ui.configbool('hooks', 'tonative.%s' % name, False):
   164     if ui.configbool(b'hooks', b'tonative.%s' % name, False):
   164         oldcmd = cmd
   165         oldcmd = cmd
   165         cmd = procutil.shelltonative(cmd, env)
   166         cmd = procutil.shelltonative(cmd, env)
   166         if cmd != oldcmd:
   167         if cmd != oldcmd:
   167             ui.note(_('converting hook "%s" to native\n') % name)
   168             ui.note(_(b'converting hook "%s" to native\n') % name)
   168 
   169 
   169     ui.note(_("running hook %s: %s\n") % (name, cmd))
   170     ui.note(_(b"running hook %s: %s\n") % (name, cmd))
   170 
   171 
   171     if repo:
   172     if repo:
   172         cwd = repo.root
   173         cwd = repo.root
   173     else:
   174     else:
   174         cwd = encoding.getcwd()
   175         cwd = encoding.getcwd()
   175     r = ui.system(cmd, environ=env, cwd=cwd, blockedtag='exthook-%s' % (name,))
   176     r = ui.system(cmd, environ=env, cwd=cwd, blockedtag=b'exthook-%s' % (name,))
   176 
   177 
   177     duration = util.timer() - starttime
   178     duration = util.timer() - starttime
   178     ui.log(
   179     ui.log(
   179         'exthook',
   180         b'exthook',
   180         'exthook-%s: %s finished in %0.2f seconds\n',
   181         b'exthook-%s: %s finished in %0.2f seconds\n',
   181         name,
   182         name,
   182         cmd,
   183         cmd,
   183         duration,
   184         duration,
   184     )
   185     )
   185     if r:
   186     if r:
   186         desc = procutil.explainexit(r)
   187         desc = procutil.explainexit(r)
   187         if throw:
   188         if throw:
   188             raise error.HookAbort(_('%s hook %s') % (name, desc))
   189             raise error.HookAbort(_(b'%s hook %s') % (name, desc))
   189         ui.warn(_('warning: %s hook %s\n') % (name, desc))
   190         ui.warn(_(b'warning: %s hook %s\n') % (name, desc))
   190     return r
   191     return r
   191 
   192 
   192 
   193 
   193 # represent an untrusted hook command
   194 # represent an untrusted hook command
   194 _fromuntrusted = object()
   195 _fromuntrusted = object()
   211 
   212 
   212 
   213 
   213 def _hookitems(ui, _untrusted=False):
   214 def _hookitems(ui, _untrusted=False):
   214     """return all hooks items ready to be sorted"""
   215     """return all hooks items ready to be sorted"""
   215     hooks = {}
   216     hooks = {}
   216     for name, cmd in ui.configitems('hooks', untrusted=_untrusted):
   217     for name, cmd in ui.configitems(b'hooks', untrusted=_untrusted):
   217         if name.startswith('priority.') or name.startswith('tonative.'):
   218         if name.startswith(b'priority.') or name.startswith(b'tonative.'):
   218             continue
   219             continue
   219 
   220 
   220         priority = ui.configint('hooks', 'priority.%s' % name, 0)
   221         priority = ui.configint(b'hooks', b'priority.%s' % name, 0)
   221         hooks[name] = (-priority, len(hooks), name, cmd)
   222         hooks[name] = (-priority, len(hooks), name, cmd)
   222     return hooks
   223     return hooks
   223 
   224 
   224 
   225 
   225 _redirect = False
   226 _redirect = False
   233 def hashook(ui, htype):
   234 def hashook(ui, htype):
   234     """return True if a hook is configured for 'htype'"""
   235     """return True if a hook is configured for 'htype'"""
   235     if not ui.callhooks:
   236     if not ui.callhooks:
   236         return False
   237         return False
   237     for hname, cmd in _allhooks(ui):
   238     for hname, cmd in _allhooks(ui):
   238         if hname.split('.')[0] == htype and cmd:
   239         if hname.split(b'.')[0] == htype and cmd:
   239             return True
   240             return True
   240     return False
   241     return False
   241 
   242 
   242 
   243 
   243 def hook(ui, repo, htype, throw=False, **args):
   244 def hook(ui, repo, htype, throw=False, **args):
   244     if not ui.callhooks:
   245     if not ui.callhooks:
   245         return False
   246         return False
   246 
   247 
   247     hooks = []
   248     hooks = []
   248     for hname, cmd in _allhooks(ui):
   249     for hname, cmd in _allhooks(ui):
   249         if hname.split('.')[0] == htype and cmd:
   250         if hname.split(b'.')[0] == htype and cmd:
   250             hooks.append((hname, cmd))
   251             hooks.append((hname, cmd))
   251 
   252 
   252     res = runhooks(ui, repo, htype, hooks, throw=throw, **args)
   253     res = runhooks(ui, repo, htype, hooks, throw=throw, **args)
   253     r = False
   254     r = False
   254     for hname, cmd in hooks:
   255     for hname, cmd in hooks:
   277                     pass
   278                     pass
   278 
   279 
   279             if cmd is _fromuntrusted:
   280             if cmd is _fromuntrusted:
   280                 if throw:
   281                 if throw:
   281                     raise error.HookAbort(
   282                     raise error.HookAbort(
   282                         _('untrusted hook %s not executed') % hname,
   283                         _(b'untrusted hook %s not executed') % hname,
   283                         hint=_("see 'hg help config.trusted'"),
   284                         hint=_(b"see 'hg help config.trusted'"),
   284                     )
   285                     )
   285                 ui.warn(_('warning: untrusted hook %s not executed\n') % hname)
   286                 ui.warn(_(b'warning: untrusted hook %s not executed\n') % hname)
   286                 r = 1
   287                 r = 1
   287                 raised = False
   288                 raised = False
   288             elif callable(cmd):
   289             elif callable(cmd):
   289                 r, raised = pythonhook(ui, repo, htype, hname, cmd, args, throw)
   290                 r, raised = pythonhook(ui, repo, htype, hname, cmd, args, throw)
   290             elif cmd.startswith('python:'):
   291             elif cmd.startswith(b'python:'):
   291                 if cmd.count(':') >= 2:
   292                 if cmd.count(b':') >= 2:
   292                     path, cmd = cmd[7:].rsplit(':', 1)
   293                     path, cmd = cmd[7:].rsplit(b':', 1)
   293                     path = util.expandpath(path)
   294                     path = util.expandpath(path)
   294                     if repo:
   295                     if repo:
   295                         path = os.path.join(repo.root, path)
   296                         path = os.path.join(repo.root, path)
   296                     try:
   297                     try:
   297                         mod = extensions.loadpath(path, 'hghook.%s' % hname)
   298                         mod = extensions.loadpath(path, b'hghook.%s' % hname)
   298                     except Exception:
   299                     except Exception:
   299                         ui.write(_("loading %s hook failed:\n") % hname)
   300                         ui.write(_(b"loading %s hook failed:\n") % hname)
   300                         raise
   301                         raise
   301                     hookfn = getattr(mod, cmd)
   302                     hookfn = getattr(mod, cmd)
   302                 else:
   303                 else:
   303                     hookfn = cmd[7:].strip()
   304                     hookfn = cmd[7:].strip()
   304                 r, raised = pythonhook(
   305                 r, raised = pythonhook(