control: tags -1 +patch > Reportbug is not designed to cope with arbitrary encodings of > configuration files, but relies on the user to use consistent encoding > in files and environment.
We can and should still prevent reportbug from simply crashing in such cases. So here is a patch. It applies on top of the patch that I sent to #695887. Besides #877650, it should also fix #868022 and #883577.
>From c238cf242a8713ccd8bd9a36319e1bd1d8c72bb6 Mon Sep 17 00:00:00 2001 From: Nis Martensen <nis.marten...@web.de> Date: Tue, 5 Dec 2017 21:40:03 +0100 Subject: [PATCH 2/2] Prevent Unicode(De|En)codeError with most open() calls We are still getting new bugreports with Unicode(De|En)codingError-Crashes. While users can often fix that by fixing their locale setup, we should prevent crashes where we can. --- bin/reportbug | 35 ++++++++++++++++++----------------- reportbug/debbugs.py | 2 +- reportbug/submit.py | 5 ++--- reportbug/tempfiles.py | 4 ++-- reportbug/ui/gtk2_ui.py | 5 ++--- reportbug/ui/text_ui.py | 4 ++-- reportbug/utils.py | 15 ++++++++------- 7 files changed, 35 insertions(+), 35 deletions(-) diff --git a/bin/reportbug b/bin/reportbug index 6a554b6..dff93c2 100755 --- a/bin/reportbug +++ b/bin/reportbug @@ -142,11 +142,10 @@ def include_file_in_report(message, message_filename, """ if inline: try: - fp = open(include_filename) - message += '\n*** %s\n%s' % ( - include_filename, - fp.read()) - fp.close() + with open(include_filename, errors='backslashreplace') as fp: + message += '\n*** {}\n{}'.format( + include_filename, + fp.read()) fp, temp_filename = TempFile( prefix=tempfile_prefix(package_name), dir=draftpath) fp.write(message) @@ -192,7 +191,8 @@ def handle_editing(filename, dmessage, options, sendto, attachments, package, stopmsg(filename) sys.exit(1) - message = open(filename).read() + with open(filename, errors='backslashreplace') as f: + message = f.read() changed = True prompt = 'Submit this report on %s (e to edit)' % package @@ -365,7 +365,8 @@ def handle_editing(filename, dmessage, options, sendto, attachments, package, if 'patch' in newtaglist: patch = True message = message.replace(oldtags, newtags) - open(filename, 'w').write(message) + with open(filename, 'w', errors='backslashreplace') as f: + f.write(message) elif x == 's': skip_editing = True ccemail = ui.get_string( @@ -391,7 +392,7 @@ def handle_editing(filename, dmessage, options, sendto, attachments, package, else: break - return open(filename).read(), patch, justsave + return open(filename, errors='backslashreplace').read(), patch, justsave def find_package_for(filename, notatty=False, pathonly=False): @@ -670,7 +671,7 @@ def offer_configuration(options): 'home directory. Please fix this before using ' 'reportbug again.\n', utils.USERFILE) - fp = os.fdopen(fd, 'w') + fp = os.fdopen(fd, 'w', errors='backslashreplace') print('# reportbug preferences file', file=fp) print('# character encoding: %s' % charset, file=fp) print('# Version of reportbug this preferences file was written by', file=fp) @@ -1168,7 +1169,8 @@ class UI(object): 'reduce its size else the report cannot be sent' % ( self.options.bodyfile, self.options.max_attachment_size)) raise Exception - body = open(self.options.bodyfile).read() + with open(self.options.bodyfile, errors='backslashreplace') as bf: + body = bf.read() except: efail('Unable to read body from file %s.\n', self.options.bodyfile) @@ -1351,11 +1353,8 @@ class UI(object): if self.options.include: for f in self.options.include: if os.path.exists(f): - fp = open(f) - incfiles = '%s\n*** %s\n%s' % ( - incfiles, f, - fp.read()) - fp.close() + with open(f, errors='backslashreplace') as fp: + incfiles += '\n*** {}\n{}'.format(f, fp.read()) else: ewrite("Can't find %s to include!\n", f) sys.exit(1) @@ -1864,7 +1863,8 @@ For more details, please see: http://www.debian.org/devel/wnpp/''') ewrite('\n') prompted = False if interactive and not (self.options.kudos or exinfo) and presubj: - ui.display_report(open(presubj).read() + '\n', presubj=True) + with open(presubj, errors='backslashreplace') as f: + ui.display_report(f.read() + '\n', presubj=True) if self.options.kudos: subject = subject or ('Thanks for packaging %s!' % package) @@ -2094,7 +2094,8 @@ For more details, please see: http://www.debian.org/devel/wnpp/''') if not mua: SIGFILE = os.path.join(HOMEDIR, '.signature') try: - message = "\n\n-- \n" + open(SIGFILE).read() + with open(SIGFILE, errors='backslashreplace') as sf: + message = "\n\n-- \n" + sf.read() except IOError: pass else: diff --git a/reportbug/debbugs.py b/reportbug/debbugs.py index 1c65075..a8d24eb 100644 --- a/reportbug/debbugs.py +++ b/reportbug/debbugs.py @@ -930,7 +930,7 @@ def parse_bts_url(url): # Dynamically add any additional systems found for origin in glob.glob('/etc/dpkg/origins/*'): try: - fp = open(origin) + fp = open(origin, errors='backslashreplace') system = os.path.basename(origin) SYSTEMS[system] = SYSTEMS.get(system, {'otherpkgs': {}, 'query-dpkg': True, diff --git a/reportbug/submit.py b/reportbug/submit.py index ea613cb..7454188 100644 --- a/reportbug/submit.py +++ b/reportbug/submit.py @@ -88,9 +88,8 @@ def sign_message(body, fromaddr, package='x', pgp_addr=None, sign='gpg', draftpa try: os.system(signcmd) - x = open(file2, 'r') - signedbody = x.read() - x.close() + with open(file2, 'r', errors='backslashreplace') as x: + signedbody = x.read() if os.path.exists(file1): os.unlink(file1) diff --git a/reportbug/tempfiles.py b/reportbug/tempfiles.py index bfa1208..7ca6622 100644 --- a/reportbug/tempfiles.py +++ b/reportbug/tempfiles.py @@ -61,7 +61,7 @@ def open_write_safe(filename, mode='w+b', bufsize=-1): fd = os.open(filename, _text_openflags, 0o600) try: - return os.fdopen(fd, mode, bufsize) + return os.fdopen(fd, mode, bufsize, errors='backslashreplace') except: os.close(fd) raise @@ -72,7 +72,7 @@ def open_write_safe(filename, mode='w+b', bufsize=-1): def TempFile(suffix="", prefix=template, dir=None, text=True, mode="w+", bufsize=-1): fh, filename = tempfile.mkstemp(suffix, prefix, dir, text) - fd = os.fdopen(fh, mode, bufsize) + fd = os.fdopen(fh, mode, bufsize, errors='backslashreplace') return (fd, filename) diff --git a/reportbug/ui/gtk2_ui.py b/reportbug/ui/gtk2_ui.py index fe97201..80b7d3d 100644 --- a/reportbug/ui/gtk2_ui.py +++ b/reportbug/ui/gtk2_ui.py @@ -1350,9 +1350,8 @@ class EditorPage(Page): global report_message _assert_context(ui_context) report_message = self.get_value()[0] - f = open(self.filename, "w") - f.write(report_message) - f.close() + with open(self.filename, "w", errors='backslashreplace') as f: + f.write(report_message) def connect_signals(self): _assert_context(ui_context) diff --git a/reportbug/ui/text_ui.py b/reportbug/ui/text_ui.py index 4a60ff8..eeaae63 100644 --- a/reportbug/ui/text_ui.py +++ b/reportbug/ui/text_ui.py @@ -1023,7 +1023,7 @@ def spawn_editor(message, filename, editor, charset='utf-8'): # Move the cursor for lazy buggers like me; add your editor here... ourline = 0 - with open(filename) as f: + with open(filename, errors='backslashreplace') as f: for (lineno, line) in enumerate(f): if line == '\n' and not ourline: ourline = lineno + 2 @@ -1062,7 +1062,7 @@ def spawn_editor(message, filename, editor, charset='utf-8'): if '&' in editor: return (None, 1) - with open(filename) as f: + with open(filename, errors='backslashreplace') as f: newmessage = f.read() if newmessage == message: diff --git a/reportbug/utils.py b/reportbug/utils.py index 8139668..450673d 100644 --- a/reportbug/utils.py +++ b/reportbug/utils.py @@ -246,7 +246,7 @@ def find_rewritten(username): for filename in ['/etc/email-addresses']: if os.path.exists(filename): try: - fp = open(filename) + fp = open(filename, errors='backslashreplace') except IOError: continue for line in fp: @@ -714,7 +714,7 @@ def get_changed_config_files(conffiles, nocompress=False): changed = [] for (filename, md5sum) in conffiles: try: - fp = open(filename) + fp = open(filename, errors='backslashreplace') except IOError as msg: confinfo[filename] = msg continue @@ -769,9 +769,8 @@ def get_debian_release_info(): debvers = dists[0][1] try: - fob = open('/etc/debian_version') - verfile = fob.readline().strip() - fob.close() + with open('/etc/debian_version', errors='backslashreplace') as fob: + verfile = fob.readline().strip() except IOError: print('Unable to open /etc/debian_version', file=sys.stderr) @@ -961,7 +960,9 @@ def mua_exists(mua): output = '/dev/null' if os.path.exists(output): try: - returnvalue = subprocess.call(MUAVERSION[mua_tmp], stdout=open(output, 'w'), stderr=subprocess.STDOUT, + returnvalue = subprocess.call(MUAVERSION[mua_tmp], + stdout=open(output, 'w', errors='backslashreplace'), + stderr=subprocess.STDOUT, shell=True) except (IOError, OSError): returnvalue = subprocess.call(MUAVERSION[mua_tmp], shell=True) @@ -1084,7 +1085,7 @@ def parse_bug_control_file(filename): submitas = submitto = None reportwith = [] supplemental = [] - fh = open(filename) + fh = open(filename, errors='backslashreplace') for line in fh: line = line.strip() parts = line.split(': ') -- 2.11.0