32
32
In principle apport can run on any platform though as of Feb 2010 there seem
33
33
to be some portability bugs.
35
To force this off in brz turn set APPORT_DISABLE in the environment or
35
To force this off in bzr turn set APPORT_DISABLE in the environment or
39
# for interactive testing, try the 'brz assert-fail' command
39
from __future__ import absolute_import
41
# for interactive testing, try the 'bzr assert-fail' command
40
42
# or see http://code.launchpad.net/~mbp/bzr/bzr-fail
42
44
# to test with apport it's useful to set
43
45
# export APPORT_IGNORE_OBSOLETE_PACKAGES=1
45
from io import StringIO
52
from StringIO import StringIO
62
64
def report_bug(exc_info, stderr):
63
65
if ('no_apport' in debug.debug_flags) or \
64
os.environ.get('APPORT_DISABLE', None):
66
os.environ.get('APPORT_DISABLE', None):
65
67
return report_bug_legacy(exc_info, stderr)
67
69
if report_bug_to_apport(exc_info, stderr):
68
70
# wrote a file; if None then report the old way
70
except ImportError as e:
72
except ImportError, e:
71
73
trace.mutter("couldn't find apport bug-reporting library: %s" % e)
72
except Exception as e:
73
75
# this should only happen if apport is installed but it didn't
74
76
# work, eg because of an io error writing the crash file
75
trace.mutter("brz: failed to report crash using apport: %r" % e)
77
trace.mutter("bzr: failed to report crash using apport: %r" % e)
76
78
trace.log_exception_quietly()
77
79
return report_bug_legacy(exc_info, stderr)
82
84
trace.print_exception(exc_info, err_file)
83
85
err_file.write('\n')
86
87
def print_wrapped(l):
87
err_file.write(textwrap.fill(
88
l, width=78, subsequent_indent=' ') + '\n')
89
print_wrapped('brz %s on python %s (%s)\n' %
91
breezy._format_version_tuple(sys.version_info),
92
platform.platform(aliased=1)))
88
err_file.write(textwrap.fill(l,
89
width=78, subsequent_indent=' ') + '\n')
90
print_wrapped('bzr %s on python %s (%s)\n' % \
92
bzrlib._format_version_tuple(sys.version_info),
93
platform.platform(aliased=1)))
93
94
print_wrapped('arguments: %r\n' % sys.argv)
94
95
print_wrapped(textwrap.fill(
95
96
'plugins: ' + plugin.format_concise_plugin_list(),
106
107
"*** Bazaar has encountered an internal error. This probably indicates a\n"
107
108
" bug in Bazaar. You can help us fix it by filing a bug report at\n"
108
" https://bugs.launchpad.net/brz/+filebug\n"
109
" https://bugs.launchpad.net/bzr/+filebug\n"
109
110
" including this traceback and a description of the problem.\n"
121
122
# This import is apparently not used, but we're doing it so that if the
122
123
# import fails, the exception will be caught at a higher level and we'll
123
124
# report the error by other means.
124
import apport # noqa: F401
126
127
crash_filename = _write_apport_report_to_file(exc_info)
128
129
if crash_filename is None:
129
130
stderr.write("\n"
130
"apport is set to ignore crashes in this version of brz.\n"
131
"apport is set to ignore crashes in this version of bzr.\n"
133
134
trace.print_exception(exc_info, stderr)
134
135
stderr.write("\n"
135
"You can report this problem to Bazaar's developers by running\n"
137
"if a bug-reporting window does not automatically appear.\n"
136
"You can report this problem to Bazaar's developers by running\n"
138
"if a bug-reporting window does not automatically appear.\n"
139
140
# XXX: on Windows, Mac, and other platforms where we might have the
140
141
# apport libraries but not have an apport always running, we could
141
142
# synchronously file now
158
159
pr.add_user_info()
160
161
# Package and SourcePackage are needed so that apport will report about even
161
# non-packaged versions of brz; also this reports on their packaged
162
# non-packaged versions of bzr; also this reports on their packaged
162
163
# dependencies which is useful.
163
pr['SourcePackage'] = 'brz'
164
pr['Package'] = 'brz'
164
pr['SourcePackage'] = 'bzr'
165
pr['Package'] = 'bzr'
166
167
pr['CommandLine'] = pprint.pformat(sys.argv)
167
pr['BrzVersion'] = breezy.__version__
168
pr['PythonVersion'] = breezy._format_version_tuple(sys.version_info)
168
pr['BzrVersion'] = bzrlib.__version__
169
pr['PythonVersion'] = bzrlib._format_version_tuple(sys.version_info)
169
170
pr['Platform'] = platform.platform(aliased=1)
170
171
pr['UserEncoding'] = osutils.get_user_encoding()
171
172
pr['FileSystemEncoding'] = sys.getfilesystemencoding()
172
173
pr['Locale'] = os.environ.get('LANG', 'C')
173
pr['BrzPlugins'] = _format_plugin_list()
174
pr['BzrPlugins'] = _format_plugin_list()
174
175
pr['PythonLoadedModules'] = _format_module_list()
175
pr['BrzDebugFlags'] = pprint.pformat(debug.debug_flags)
176
pr['BzrDebugFlags'] = pprint.pformat(debug.debug_flags)
177
178
# actually we'd rather file directly against the upstream product, but
178
179
# apport does seem to count on there being one in there; we might need to
179
180
# redirect it elsewhere anyhow
180
pr['SourcePackage'] = 'brz'
181
pr['Package'] = 'brz'
181
pr['SourcePackage'] = 'bzr'
182
pr['Package'] = 'bzr'
183
# tell apport to file directly against the brz package using
184
# tell apport to file directly against the bzr package using
184
185
# <https://bugs.launchpad.net/bzr/+bug/391015>
186
187
# XXX: unfortunately apport may crash later if the crashdb definition
187
188
# file isn't present
188
pr['CrashDb'] = 'brz'
189
pr['CrashDb'] = 'bzr'
190
191
tb_file = StringIO()
191
192
traceback.print_exception(exc_type, exc_object, exc_tb, file=tb_file)
194
195
_attach_log_tail(pr)
196
# We want to use the 'brz' crashdb so that it gets sent directly upstream,
197
# We want to use the 'bzr' crashdb so that it gets sent directly upstream,
197
198
# which is a reasonable default for most internal errors. However, if we
198
199
# set it here then apport will crash later if it doesn't know about that
199
# crashdb. Instead, we rely on the brz package installing both a
200
# crashdb. Instead, we rely on the bzr package installing both a
200
201
# source hook telling crashes to go to this crashdb, and a crashdb
201
202
# configuration describing it.
203
204
# these may contain some sensitive info (smtp_passwords)
204
205
# TODO: strip that out and attach the rest
206
# attach_file_if_exists(report,
207
# os.path.join(dot_brz, 'breezy.conf', 'BrzConfig')
208
# attach_file_if_exists(report,
209
# os.path.join(dot_brz, 'locations.conf', 'BrzLocations')
207
#attach_file_if_exists(report,
208
# os.path.join(dot_bzr, 'bazaar.conf', 'BzrConfig')
209
#attach_file_if_exists(report,
210
# os.path.join(dot_bzr, 'locations.conf', 'BzrLocations')
211
212
# strip username, hostname, etc
224
225
def _attach_log_tail(pr):
226
brz_log = open(trace._get_brz_log_filename(), 'rt')
227
except (IOError, OSError) as e:
228
pr['BrzLogTail'] = repr(e)
227
bzr_log = open(trace._get_bzr_log_filename(), 'rt')
228
except (IOError, OSError), e:
229
pr['BzrLogTail'] = repr(e)
231
lines = brz_log.readlines()
232
pr['BrzLogTail'] = ''.join(lines[-40:])
232
lines = bzr_log.readlines()
233
pr['BzrLogTail'] = ''.join(lines[-40:])
237
238
def _open_crash_file():
238
crash_dir = bedding.crash_dir()
239
crash_dir = config.crash_dir()
239
240
if not osutils.isdir(crash_dir):
240
241
# on unix this should be /var/crash and should already exist; on
241
242
# Windows or if it's manually configured it might need to be created,
242
243
# and then it should be private
243
os.makedirs(crash_dir, mode=0o600)
244
os.makedirs(crash_dir, mode=0600)
244
245
date_string = time.strftime('%Y-%m-%dT%H:%M', time.gmtime())
245
246
# XXX: getuid doesn't work on win32, but the crash directory is per-user
246
247
if sys.platform == 'win32':
249
250
user_part = '.%d' % os.getuid()
250
251
filename = osutils.pathjoin(
255
256
# be careful here that people can't play tmp-type symlink mischief in the
256
257
# world-writable directory
257
258
return filename, os.fdopen(
259
os.O_WRONLY | os.O_CREAT | os.O_EXCL,
260
os.O_WRONLY|os.O_CREAT|os.O_EXCL,