1
# Copyright (C) 2005, 2006, 2007, 2008, 2009 Canonical Ltd
3
# This program is free software; you can redistribute it and/or modify
4
# it under the terms of the GNU General Public License as published by
5
# the Free Software Foundation; either version 2 of the License, or
6
# (at your option) any later version.
8
# This program is distributed in the hope that it will be useful,
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
# GNU General Public License for more details.
13
# You should have received a copy of the GNU General Public License
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
19
This tells the library how to display things to the user. Through this
20
layer different applications can choose the style of UI.
22
At the moment this layer is almost trivial: the application can just
23
choose the style of progress bar.
25
Set the ui_factory member to define the behaviour. The default
33
from bzrlib.lazy_import import lazy_import
34
lazy_import(globals(), """
46
class UIFactory(object):
49
This tells the library how to display things to the user. Through this
50
layer different applications can choose the style of UI.
56
def get_password(self, prompt='', **kwargs):
57
"""Prompt the user for a password.
59
:param prompt: The prompt to present the user
60
:param kwargs: Arguments which will be expanded into the prompt.
61
This lets front ends display different things if
64
:return: The password string, return None if the user canceled the
65
request. Note that we do not touch the encoding, users may
66
have whatever they see fit and the password should be
69
raise NotImplementedError(self.get_password)
71
def nested_progress_bar(self):
72
"""Return a nested progress bar.
74
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."""
107
def clear_term(self):
108
"""Prepare the terminal for output.
110
This will, for example, clear text progress bars, and leave the
111
cursor at the leftmost position."""
114
def get_boolean(self, prompt):
115
"""Get a boolean question answered from the user.
117
:param prompt: a message to prompt the user with. Should be a single
118
line without terminating \n.
119
:return: True or False for y/yes or n/no.
121
raise NotImplementedError(self.get_boolean)
123
def recommend_upgrade(self,
126
# this should perhaps be in the TextUIFactory and the default can do
128
trace.warning("%s is deprecated "
129
"and a better format is available.\n"
130
"It is recommended that you upgrade by "
131
"running the command\n"
136
def report_transport_activity(self, transport, byte_count, direction):
137
"""Called by transports as they do IO.
139
This may update a progress bar, spinner, or similar display.
140
By default it does nothing.
146
class CLIUIFactory(UIFactory):
147
"""Common behaviour for command line UI factories.
149
This is suitable for dumb terminals that can't repaint existing text."""
151
def __init__(self, stdin=None, stdout=None, stderr=None):
152
UIFactory.__init__(self)
153
self.stdin = stdin or sys.stdin
154
self.stdout = stdout or sys.stdout
155
self.stderr = stderr or sys.stderr
157
def get_boolean(self, prompt):
159
# FIXME: make a regexp and handle case variations as well.
161
self.prompt(prompt + "? [y/n]: ")
162
line = self.stdin.readline()
163
if line in ('y\n', 'yes\n'):
165
if line in ('n\n', 'no\n'):
168
def get_non_echoed_password(self, prompt):
169
if not sys.stdin.isatty():
170
raise errors.NotATerminal()
171
encoding = osutils.get_terminal_encoding()
172
return getpass.getpass(prompt.encode(encoding, 'replace'))
174
def get_password(self, prompt='', **kwargs):
175
"""Prompt the user for a password.
177
:param prompt: The prompt to present the user
178
:param kwargs: Arguments which will be expanded into the prompt.
179
This lets front ends display different things if
181
:return: The password string, return None if the user
182
canceled the request.
185
prompt = (prompt % kwargs)
186
# There's currently no way to say 'i decline to enter a password'
187
# as opposed to 'my password is empty' -- does it matter?
188
return self.get_non_echoed_password(prompt)
190
def prompt(self, prompt):
191
"""Emit prompt on the CLI."""
194
class SilentUIFactory(CLIUIFactory):
195
"""A UI Factory which never prints anything.
197
This is the default UI, if another one is never registered.
201
CLIUIFactory.__init__(self)
203
def get_password(self, prompt='', **kwargs):
210
def clear_decorator(func, *args, **kwargs):
211
"""Decorator that clears the term"""
212
ui_factory.clear_term()
213
func(*args, **kwargs)
216
ui_factory = SilentUIFactory()
217
"""IMPORTANT: never import this symbol directly. ONLY ever access it as
221
def make_ui_for_terminal(stdin, stdout, stderr):
222
"""Construct and return a suitable UIFactory for a text mode program.
224
If stdout is a smart terminal, this gets a smart UIFactory with
225
progress indicators, etc. If it's a dumb terminal, just plain text output.
227
isatty = getattr(stdin, 'isatty', None)
232
elif os.environ.get('TERM') in (None, 'dumb', ''):
233
# e.g. emacs compile window
236
from bzrlib.ui.text import TextUIFactory
238
return cls(stdin=stdin, stdout=stdout, stderr=stderr)