2 from __future__ import absolute_import, print_function
3 from array import array
4 from binascii import hexlify
5 from traceback import print_exception
8 # Please see CODINGSTYLE for important exception handling guidelines
9 # and the rationale behind add_ex_tb(), add_ex_ctx(), etc.
11 py_maj = sys.version_info[0]
16 from os import environb as environ
18 lc_ctype = environ.get(b'LC_CTYPE')
19 if lc_ctype and lc_ctype.lower() != b'iso-8859-1':
20 # Because of argv, options.py, pwd, grp, and any number of other issues
21 print('error: bup currently only works with ISO-8859-1, not LC_CTYPE=%s'
24 print('error: this should already have been arranged, so indicates a bug',
28 from os import fsdecode, fsencode
29 from shlex import quote
36 """Return hex string (not bytes as with hexlify) representation of b."""
40 raise ex.with_traceback(sys.exc_info()[2])
43 """Do nothing (already handled by Python 3 infrastructure)."""
46 def add_ex_ctx(ex, context_ex):
47 """Do nothing (already handled by Python 3 infrastructure)."""
54 """Return the original bytes passed to main() for an argv argument."""
57 def bytes_from_uint(i):
60 def bytes_from_byte(b): # python > 2: b[3] returns ord('x'), not b'x'
63 byte_int = lambda x: x
65 def buffer(object, offset=None, size=None):
67 assert offset is not None
68 return memoryview(object)[offset:offset + size]
70 return memoryview(object)[offset:]
71 return memoryview(object)
73 def join_bytes(*items):
74 """Return the concatenated bytes or memoryview arguments as bytes."""
75 return b''.join(items)
78 return fsencode(os.getcwd())
88 from pipes import quote
89 from os import environ, getcwd
91 from bup.py2raise import reraise
96 int_types = (int, long)
101 """Add a traceback to ex if it doesn't already have one. Return ex.
104 if not getattr(ex, '__traceback__', None):
105 ex.__traceback__ = sys.exc_info()[2]
108 def add_ex_ctx(ex, context_ex):
109 """Make context_ex the __context__ of ex (unless it already has one).
114 if not getattr(ex, '__context__', None):
115 ex.__context__ = context_ex
118 def dump_traceback(ex):
120 next_ex = getattr(ex, '__context__', None)
122 stack.append(next_ex)
123 next_ex = getattr(next_ex, '__context__', None)
124 stack = reversed(stack)
126 tb = getattr(ex, '__traceback__', None)
127 print_exception(type(ex), ex, tb)
129 print('\nDuring handling of the above exception, another exception occurred:\n',
131 tb = getattr(ex, '__traceback__', None)
132 print_exception(type(ex), ex, tb)
138 """Return the original bytes passed to main() for an argv argument."""
141 def bytes_from_uint(i):
144 def bytes_from_byte(b):
151 def join_bytes(x, y):
152 """Return the concatenated bytes or buffer arguments as bytes."""
153 if type(x) == buffer:
154 assert type(y) in (bytes, buffer)
156 assert type(x) == bytes
158 return b''.join((x, y))
159 assert type(y) in (bytes, buffer)
163 def restore_lc_env():
164 # Once we're up and running with iso-8859-1, undo the bup-python
165 # LC_CTYPE hackery, so we don't affect unrelated subprocesses.
166 bup_lc_all = environ.get(b'BUP_LC_ALL')
168 del environ[b'LC_COLLATE']
169 del environ[b'LC_CTYPE']
170 del environ[b'LC_MONETARY']
171 del environ[b'LC_NUMERIC']
172 del environ[b'LC_TIME']
173 del environ[b'LC_MESSAGES']
174 del environ[b'LC_MESSAGES']
175 environ[b'LC_ALL'] = bup_lc_all
177 bup_lc_ctype = environ.get(b'BUP_LC_CTYPE')
179 environ[b'LC_CTYPE'] = bup_lc_ctype
182 """Run main() and raise a SystemExit with the return value if it
183 returns, pass along any SystemExit it raises, convert
184 KeyboardInterrupts into exit(130), and print a Python 3 style
185 contextual backtrace for other exceptions in both Python 2 and
189 except KeyboardInterrupt as ex:
191 except SystemExit as ex:
193 except BaseException as ex:
201 # Excepting wrap_main() in the traceback, these should produce similar output:
202 # python2 lib/bup/compat.py
203 # python3 lib/bup/compat.py
205 # diff -u <(python2 lib/bup/compat.py 2>&1) <(python3 lib/bup/compat.py 2>&1)
207 # Though the python3 output for 'second' will include a stacktrace
208 # starting from wrap_main, rather than from outer().
210 if __name__ == '__main__':
213 raise Exception('first')
218 except Exception as ex:
221 raise Exception('second')
222 except Exception as ex2:
223 raise add_ex_ctx(add_ex_tb(ex2), ex)