1
# Copyright (C) 2005, 2006, 2007, 2008, 2009 Canonical Ltd
1
# Copyright (C) 2005, 2006, 2007 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
53
54
def __init__(self):
55
super(UIFactory, self).__init__()
56
self._progress_bar_stack = None
58
@deprecated_method(zero_eight)
59
def progress_bar(self):
60
"""See UIFactory.nested_progress_bar()."""
61
raise NotImplementedError(self.progress_bar)
56
63
def get_password(self, prompt='', **kwargs):
57
64
"""Prompt the user for a password.
74
81
When the bar has been finished with, it should be released by calling
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.
84
raise NotImplementedError(self.nested_progress_bar)
108
86
def clear_term(self):
109
87
"""Prepare the terminal for output.
111
89
This will, for example, clear text progress bars, and leave the
112
cursor at the leftmost position.
90
cursor at the leftmost position."""
91
raise NotImplementedError(self.clear_term)
116
93
def get_boolean(self, prompt):
117
"""Get a boolean question answered from the user.
94
"""Get a boolean question answered from the user.
119
96
:param prompt: a message to prompt the user with. Should be a single
120
97
line without terminating \n.
135
112
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.
148
116
class CLIUIFactory(UIFactory):
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
117
"""Common behaviour for command line UI factories."""
120
super(CLIUIFactory, self).__init__()
121
self.stdin = sys.stdin
159
123
def get_boolean(self, prompt):
160
125
# FIXME: make a regexp and handle case variations as well.
162
127
self.prompt(prompt + "? [y/n]: ")
166
131
if line in ('n\n', 'no\n'):
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]
134
def get_non_echoed_password(self, prompt):
135
encoding = osutils.get_terminal_encoding()
136
return getpass.getpass(prompt.encode(encoding, 'replace'))
184
138
def get_password(self, prompt='', **kwargs):
185
139
"""Prompt the user for a password.
188
142
:param kwargs: Arguments which will be expanded into the prompt.
189
143
This lets front ends display different things if
191
:return: The password string, return None if the user
145
:return: The password string, return None if the user
192
146
canceled the request.
195
self.prompt(prompt, **kwargs)
149
prompt = (prompt % kwargs)
196
150
# There's currently no way to say 'i decline to enter a password'
197
151
# as opposed to 'my password is empty' -- does it matter?
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):
152
return self.get_non_echoed_password(prompt)
154
def prompt(self, prompt):
220
155
"""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')
231
158
class SilentUIFactory(CLIUIFactory):
234
161
This is the default UI, if another one is never registered.
238
CLIUIFactory.__init__(self)
164
@deprecated_method(zero_eight)
165
def progress_bar(self):
166
"""See UIFactory.nested_progress_bar()."""
167
return progress.DummyProgress()
240
169
def get_password(self, prompt='', **kwargs):
243
def get_username(self, prompt='', **kwargs):
172
def nested_progress_bar(self):
173
if self._progress_bar_stack is None:
174
self._progress_bar_stack = progress.ProgressBarStack(
175
klass=progress.DummyProgress)
176
return self._progress_bar_stack.get_nested()
246
def prompt(self, prompt, **kwargs):
178
def clear_term(self):
181
def recommend_upgrade(self, *args):
259
191
ui_factory = SilentUIFactory()
260
"""IMPORTANT: never import this symbol directly. ONLY ever access it as
192
"""IMPORTANT: never import this symbol directly. ONLY ever access it as
261
193
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)