1
# Copyright (C) 2005, 2006, 2007 Canonical Ltd
1
# Copyright (C) 2005, 2006, 2007, 2008, 2009 Canonical Ltd
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
13
13
# You should have received a copy of the GNU General Public License
14
14
# along with this program; if not, write to the Free Software
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
53
53
def __init__(self):
54
super(UIFactory, self).__init__()
55
self._progress_bar_stack = None
57
@deprecated_method(zero_eight)
58
def progress_bar(self):
59
"""See UIFactory.nested_progress_bar()."""
60
raise NotImplementedError(self.progress_bar)
62
56
def get_password(self, prompt='', **kwargs):
63
57
"""Prompt the user for a password.
80
74
When the bar has been finished with, it should be released by calling
83
raise NotImplementedError(self.nested_progress_bar)
78
t = progress.ProgressTask(self._task_stack[-1], self)
80
t = progress.ProgressTask(None, self)
81
self._task_stack.append(t)
84
def _progress_finished(self, task):
85
"""Called by the ProgressTask when it finishes"""
86
if not self._task_stack:
87
warnings.warn("%r finished but nothing is active"
89
elif task != self._task_stack[-1]:
90
warnings.warn("%r is not the active task %r"
91
% (task, self._task_stack[-1]))
93
del self._task_stack[-1]
94
if not self._task_stack:
95
self._progress_all_finished()
97
def _progress_all_finished(self):
98
"""Called when the top-level progress task finished"""
101
def _progress_updated(self, task):
102
"""Called by the ProgressTask when it changes.
104
Should be specialized to draw the progress.
85
108
def clear_term(self):
86
109
"""Prepare the terminal for output.
88
111
This will, for example, clear text progress bars, and leave the
89
cursor at the leftmost position."""
90
raise NotImplementedError(self.clear_term)
112
cursor at the leftmost position.
92
116
def get_boolean(self, prompt):
93
"""Get a boolean question answered from the user.
117
"""Get a boolean question answered from the user.
95
119
:param prompt: a message to prompt the user with. Should be a single
96
120
line without terminating \n.
111
135
current_format_name,
138
def report_transport_activity(self, transport, byte_count, direction):
139
"""Called by transports as they do IO.
141
This may update a progress bar, spinner, or similar display.
142
By default it does nothing.
115
148
class CLIUIFactory(UIFactory):
116
"""Common behaviour for command line UI factories."""
119
super(CLIUIFactory, self).__init__()
120
self.stdin = sys.stdin
149
"""Common behaviour for command line UI factories.
151
This is suitable for dumb terminals that can't repaint existing text."""
153
def __init__(self, stdin=None, stdout=None, stderr=None):
154
UIFactory.__init__(self)
155
self.stdin = stdin or sys.stdin
156
self.stdout = stdout or sys.stdout
157
self.stderr = stderr or sys.stderr
122
159
def get_boolean(self, prompt):
124
160
# FIXME: make a regexp and handle case variations as well.
126
162
self.prompt(prompt + "? [y/n]: ")
130
166
if line in ('n\n', 'no\n'):
133
def get_non_echoed_password(self, prompt):
134
return getpass.getpass(prompt)
169
def get_non_echoed_password(self):
170
isatty = getattr(self.stdin, 'isatty', None)
171
if isatty is not None and isatty():
172
# getpass() ensure the password is not echoed and other
173
# cross-platform niceties
174
password = getpass.getpass('')
176
# echo doesn't make sense without a terminal
177
password = self.stdin.readline()
180
elif password[-1] == '\n':
181
password = password[:-1]
136
184
def get_password(self, prompt='', **kwargs):
137
185
"""Prompt the user for a password.
140
188
:param kwargs: Arguments which will be expanded into the prompt.
141
189
This lets front ends display different things if
143
:return: The password string, return None if the user
191
:return: The password string, return None if the user
144
192
canceled the request.
147
prompt = (prompt % kwargs).encode(sys.stdout.encoding, 'replace')
195
self.prompt(prompt, **kwargs)
148
196
# There's currently no way to say 'i decline to enter a password'
149
197
# as opposed to 'my password is empty' -- does it matter?
150
return self.get_non_echoed_password(prompt)
152
def prompt(self, prompt):
198
return self.get_non_echoed_password()
200
def get_username(self, prompt, **kwargs):
201
"""Prompt the user for a username.
203
:param prompt: The prompt to present the user
204
:param kwargs: Arguments which will be expanded into the prompt.
205
This lets front ends display different things if
207
:return: The username string, return None if the user
208
canceled the request.
211
self.prompt(prompt, **kwargs)
212
username = self.stdin.readline()
215
elif username[-1] == '\n':
216
username = username[:-1]
219
def prompt(self, prompt, **kwargs):
153
220
"""Emit prompt on the CLI."""
221
prompt = prompt % kwargs
222
prompt = prompt.encode(osutils.get_terminal_encoding(), 'replace')
224
self.stdout.write(prompt)
227
"""Write an already-formatted message."""
228
self.stdout.write(msg + '\n')
156
231
class SilentUIFactory(CLIUIFactory):
159
234
This is the default UI, if another one is never registered.
162
@deprecated_method(zero_eight)
163
def progress_bar(self):
164
"""See UIFactory.nested_progress_bar()."""
165
return progress.DummyProgress()
238
CLIUIFactory.__init__(self)
167
240
def get_password(self, prompt='', **kwargs):
170
def nested_progress_bar(self):
171
if self._progress_bar_stack is None:
172
self._progress_bar_stack = progress.ProgressBarStack(
173
klass=progress.DummyProgress)
174
return self._progress_bar_stack.get_nested()
243
def get_username(self, prompt='', **kwargs):
176
def clear_term(self):
246
def prompt(self, prompt, **kwargs):
179
def recommend_upgrade(self, *args):
189
259
ui_factory = SilentUIFactory()
190
"""IMPORTANT: never import this symbol directly. ONLY ever access it as
260
"""IMPORTANT: never import this symbol directly. ONLY ever access it as
191
261
ui.ui_factory."""
264
def make_ui_for_terminal(stdin, stdout, stderr):
265
"""Construct and return a suitable UIFactory for a text mode program.
267
If stdout is a smart terminal, this gets a smart UIFactory with
268
progress indicators, etc. If it's a dumb terminal, just plain text output.
271
isatty = getattr(stdin, 'isatty', None)
276
elif os.environ.get('TERM') in ('dumb', ''):
277
# e.g. emacs compile window
279
# User may know better, otherwise default to TextUIFactory
280
if ( os.environ.get('BZR_USE_TEXT_UI', None) is not None
282
from bzrlib.ui.text import TextUIFactory
284
return cls(stdin=stdin, stdout=stdout, stderr=stderr)