|
1 # logexceptions.py - Write files containing info about Mercurial exceptions |
|
2 # |
|
3 # Copyright 2017 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 __future__ import absolute_import |
|
9 |
|
10 import inspect |
|
11 import os |
|
12 import sys |
|
13 import traceback |
|
14 import uuid |
|
15 |
|
16 from mercurial import ( |
|
17 dispatch, |
|
18 extensions, |
|
19 ) |
|
20 |
|
21 def handleexception(orig, ui): |
|
22 res = orig(ui) |
|
23 |
|
24 if not ui.environ.get(b'HGEXCEPTIONSDIR'): |
|
25 return res |
|
26 |
|
27 dest = os.path.join(ui.environ[b'HGEXCEPTIONSDIR'], |
|
28 str(uuid.uuid4()).encode('ascii')) |
|
29 |
|
30 exc_type, exc_value, exc_tb = sys.exc_info() |
|
31 |
|
32 stack = [] |
|
33 tb = exc_tb |
|
34 while tb: |
|
35 stack.append(tb) |
|
36 tb = tb.tb_next |
|
37 stack.reverse() |
|
38 |
|
39 hgframe = 'unknown' |
|
40 hgline = 'unknown' |
|
41 |
|
42 # Find the first Mercurial frame in the stack. |
|
43 for tb in stack: |
|
44 mod = inspect.getmodule(tb) |
|
45 if not mod.__name__.startswith(('hg', 'mercurial')): |
|
46 continue |
|
47 |
|
48 frame = tb.tb_frame |
|
49 |
|
50 try: |
|
51 with open(inspect.getsourcefile(tb), 'r') as fh: |
|
52 hgline = fh.readlines()[frame.f_lineno - 1].strip() |
|
53 except (IndexError, OSError): |
|
54 pass |
|
55 |
|
56 hgframe = '%s:%d' % (frame.f_code.co_filename, frame.f_lineno) |
|
57 break |
|
58 |
|
59 primary = traceback.extract_tb(exc_tb)[-1] |
|
60 primaryframe = '%s:%d' % (primary.filename, primary.lineno) |
|
61 |
|
62 with open(dest, 'wb') as fh: |
|
63 parts = [ |
|
64 str(exc_value), |
|
65 primaryframe, |
|
66 hgframe, |
|
67 hgline, |
|
68 ] |
|
69 fh.write(b'\0'.join(p.encode('utf-8', 'replace') for p in parts)) |
|
70 |
|
71 def extsetup(ui): |
|
72 extensions.wrapfunction(dispatch, 'handlecommandexception', |
|
73 handleexception) |