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