Do not use stdout instead of stderr
[stgit] / stgit / out.py
1 # -*- coding: utf-8 -*-
2
3 __copyright__ = """
4 Copyright (C) 2007, Karl Hasselström <kha@treskal.com>
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License version 2 as
8 published by the Free Software Foundation.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 """
19
20 import sys, textwrap
21
22 class MessagePrinter(object):
23 def __init__(self, file = None):
24 class Output(object):
25 def __init__(self, write, flush):
26 self.write = write
27 self.flush = flush
28 self.at_start_of_line = True
29 self.level = 0
30 def new_line(self):
31 """Ensure that we're at the beginning of a line."""
32 if not self.at_start_of_line:
33 self.write('\n')
34 self.at_start_of_line = True
35 def single_line(self, msg, print_newline = True,
36 need_newline = True):
37 """Write a single line. Newline before and after are
38 separately configurable."""
39 if need_newline:
40 self.new_line()
41 if self.at_start_of_line:
42 self.write(' '*self.level)
43 self.write(msg)
44 if print_newline:
45 self.write('\n')
46 self.at_start_of_line = True
47 else:
48 self.flush()
49 self.at_start_of_line = False
50 def tagged_lines(self, tag, lines):
51 tag += ': '
52 width = 79 - 2*self.level - len(tag)
53 lines = [wl for line in lines
54 for wl in textwrap.wrap(line, width,
55 break_long_words = False)]
56 for line in lines:
57 self.single_line(tag + line)
58 tag = ' '*len(tag)
59 def write_line(self, line):
60 """Write one line of text on a lines of its own, not
61 indented."""
62 self.new_line()
63 self.write('%s\n' % line)
64 self.at_start_of_line = True
65 def write_raw(self, string):
66 """Write an arbitrary string, possibly containing
67 newlines."""
68 self.new_line()
69 self.write(string)
70 self.at_start_of_line = string.endswith('\n')
71 if file:
72 self.__stdout = self.__stderr = Output(file.write, file.flush)
73 else:
74 self.__stdout = Output(sys.stdout.write, sys.stdout.flush)
75 self.__stderr = Output(sys.stderr.write, sys.stderr.flush)
76 if file or sys.stdout.isatty():
77 self.__out = self.__stdout
78 else:
79 self.__out = Output(lambda msg: None, lambda: None)
80 self.__err = self.__stderr
81 def stdout(self, line):
82 """Write a line to stdout."""
83 self.__stdout.write_line(line)
84 def stdout_raw(self, string):
85 """Write a string possibly containing newlines to stdout."""
86 self.__stdout.write_raw(string)
87 def err_raw(self, string):
88 """Write a string possibly containing newlines to the error
89 output."""
90 self.__err.write_raw(string)
91 def info(self, *msgs):
92 for msg in msgs:
93 self.__out.single_line(msg)
94 def note(self, *msgs, **kw):
95 self.__out.tagged_lines(kw.get('title', 'Notice'), msgs)
96 def warn(self, *msgs, **kw):
97 self.__err.tagged_lines(kw.get('title', 'Warning'), msgs)
98 def error(self, *msgs, **kw):
99 self.__err.tagged_lines(kw.get('title', 'Error'), msgs)
100 def start(self, msg):
101 """Start a long-running operation."""
102 self.__out.single_line('%s ... ' % msg, print_newline = False)
103 self.__out.level += 1
104 def done(self, extramsg = None):
105 """Finish long-running operation."""
106 self.__out.level -= 1
107 if extramsg:
108 msg = 'done (%s)' % extramsg
109 else:
110 msg = 'done'
111 self.__out.single_line(msg, need_newline = False)
112
113 out = MessagePrinter()