stg import now extracts Message-ID header
[stgit.git] / stgit / out.py
blobd140d8dac95315f0f809deffb19740cb0ad34057
1 import io
2 import sys
3 import textwrap
5 __copyright__ = """
6 Copyright (C) 2007, Karl Hasselström <kha@treskal.com>
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License version 2 as
10 published by the Free Software Foundation.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, see http://www.gnu.org/licenses/.
19 """
22 class Output:
23 def __init__(self, file):
24 if file is not None:
25 self.write = file.write
26 self.write_bytes = file.buffer.write
27 self.flush = file.flush
28 else:
29 self.write = self.write_bytes = lambda s: None
30 self.flush = lambda: None
31 self.at_start_of_line = True
32 self.level = 0
34 def new_line(self):
35 """Ensure that we're at the beginning of a line."""
36 if not self.at_start_of_line:
37 self.write('\n')
38 self.at_start_of_line = True
40 def single_line(self, msg, print_newline=True, need_newline=True):
41 """Write a single line. Newline before and after are
42 separately configurable."""
43 if need_newline:
44 self.new_line()
45 if self.at_start_of_line:
46 self.write(' ' * self.level)
47 self.write(msg)
48 if print_newline:
49 self.write('\n')
50 self.at_start_of_line = True
51 else:
52 self.flush()
53 self.at_start_of_line = False
55 def tagged_lines(self, tag, lines):
56 tag += ': '
57 width = 79 - (2 * self.level) - len(tag)
58 lines = [
60 for line in lines
61 for wl in textwrap.wrap(line, width, break_long_words=False)
63 for line in lines:
64 self.single_line(tag + line)
65 tag = ' ' * len(tag)
67 def write_line(self, line):
68 """Write one line of text on a lines of its own, not
69 indented."""
70 self.new_line()
71 self.write('%s\n' % line)
72 self.at_start_of_line = True
75 class MessagePrinter:
76 def __init__(self, file=None):
77 if file:
78 self._stdout = self._stderr = Output(file)
79 self.isatty = False
80 else:
81 self._stdout = Output(
82 io.open(sys.stdout.fileno(), 'w', buffering=1, encoding='utf-8')
84 self._stderr = Output(
85 io.open(sys.stderr.fileno(), 'w', buffering=1, encoding='utf-8')
87 self.isatty = sys.stdout.isatty()
89 def stdout(self, line):
90 """Write a line to stdout."""
91 self._stdout.write_line(line)
93 def stdout_bytes(self, byte_data):
94 self._stdout.write_bytes(byte_data)
95 self._stdout.flush()
97 def err(self, line):
98 """Write a line to stderr."""
99 self._stderr.write_line(line)
101 def err_bytes(self, byte_data):
102 """Write encoded byte data to the error output."""
103 self._stderr.write_bytes(byte_data)
104 self._stderr.flush()
106 def info(self, *msgs):
107 for msg in msgs:
108 self._stderr.single_line(msg)
110 def warn(self, *msgs, **kw):
111 self._stderr.tagged_lines(kw.get('title', 'Warning'), msgs)
113 def error(self, *msgs, **kw):
114 self._stderr.tagged_lines(kw.get('title', 'Error'), msgs)
116 def start(self, msg):
117 """Start a long-running operation."""
118 self._stderr.single_line('%s ... ' % msg, print_newline=False)
119 self._stderr.level += 1
121 def done(self, extramsg=None):
122 """Finish long-running operation."""
123 self._stderr.level -= 1
124 if extramsg:
125 msg = 'done (%s)' % extramsg
126 else:
127 msg = 'done'
128 self._stderr.single_line(msg, need_newline=False)
131 out = MessagePrinter()