Quick re-review requested; here's the incremental diff === modified file 'bzrlib/builtins.py' --- bzrlib/builtins.py 2009-11-04 22:32:13 +0000 +++ bzrlib/builtins.py 2009-12-08 09:06:02 +0000 @@ -2323,7 +2323,10 @@ # Build the log formatter if log_format is None: log_format = log.log_formatter_registry.get_default(b) + # Make a non-encoding output to include the diffs - bug 328007 + unencoded_output = ui.ui_factory.make_output_stream(encoding_type='exact') lf = log_format(show_ids=show_ids, to_file=self.outf, + to_exact_file=unencoded_output, show_timezone=timezone, delta_format=get_verbosity_level(), levels=levels, === modified file 'bzrlib/log.py' --- bzrlib/log.py 2009-10-29 03:32:42 +0000 +++ bzrlib/log.py 2009-12-08 09:17:21 +0000 @@ -1291,10 +1291,13 @@ preferred_levels = 0 def __init__(self, to_file, show_ids=False, show_timezone='original', - delta_format=None, levels=None, show_advice=False): + delta_format=None, levels=None, show_advice=False, + to_exact_file=None): """Create a LogFormatter. :param to_file: the file to output to + :param to_exact_file: if set, gives an output stream to which + non-Unicode diffs are written. :param show_ids: if True, revision-ids are to be displayed :param show_timezone: the timezone to use :param delta_format: the level of delta information to display @@ -1307,7 +1310,13 @@ self.to_file = to_file # 'exact' stream used to show diff, it should print content 'as is' # and should not try to decode/encode it to unicode to avoid bug #328007 - self.to_exact_file = getattr(to_file, 'stream', to_file) + if to_exact_file is not None: + self.to_exact_file = to_exact_file + else: + # XXX: somewhat hacky; this assumes it's a codec writer; it's better + # for code that expects to get diffs to pass in the exact file + # stream + self.to_exact_file = getattr(to_file, 'stream', to_file) self.show_ids = show_ids self.show_timezone = show_timezone if delta_format is None: @@ -1463,9 +1472,11 @@ short_status=False) if revision.diff is not None: to_file.write(indent + 'diff:\n') + to_file.flush() # Note: we explicitly don't indent the diff (relative to the # revision information) so that the output can be fed to patch -p0 self.show_diff(self.to_exact_file, revision.diff, indent) + self.to_exact_file.flush() def get_advice_separator(self): """Get the text separating the log from the closing advice.""" === modified file 'bzrlib/ui/__init__.py' --- bzrlib/ui/__init__.py 2009-11-16 02:56:00 +0000 +++ bzrlib/ui/__init__.py 2009-12-08 08:40:11 +0000 @@ -146,12 +146,7 @@ encoding = osutils.get_terminal_encoding() if encoding_type is None: encoding_type = 'replace' - # For whatever reason codecs.getwriter() does not advertise its encoding - # it just returns the encoding of the wrapped file, which is completely - # bogus. So set the attribute, so we can find the correct encoding later. out_stream = self._make_output_stream_explicit(encoding, encoding_type) - if not getattr(out_stream, 'encoding', None): - out_stream.encoding = encoding return out_stream def _make_output_stream_explicit(self, encoding, encoding_type): === modified file 'bzrlib/ui/text.py' --- bzrlib/ui/text.py 2009-11-16 02:56:18 +0000 +++ bzrlib/ui/text.py 2009-12-08 09:17:34 +0000 @@ -161,6 +161,10 @@ else: encoded_stdout = codecs.getwriter(encoding)(self.stdout, errors=encoding_type) + # For whatever reason codecs.getwriter() does not advertise its encoding + # it just returns the encoding of the wrapped file, which is completely + # bogus. So set the attribute, so we can find the correct encoding later. + encoded_stdout.encoding = encoding return TextUIOutputStream(self, encoded_stdout) def note(self, msg): @@ -400,6 +404,10 @@ def __init__(self, ui_factory, wrapped_stream): self.ui_factory = ui_factory self.wrapped_stream = wrapped_stream + # this does no transcoding, but it must expose the underlying encoding + # because some callers need to know what can be written - see for + # example unescape_for_display. + self.encoding = wrapped_stream.encoding def flush(self): self.ui_factory.clear_term()