1
# Copyright (C) 2005, 2006, 2007, 2008 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
if task != self._task_stack[-1]:
86
warnings.warn("%r is not currently active" % (task,))
88
del self._task_stack[-1]
91
"""Prepare the terminal for output.
93
This will, for example, clear text progress bars, and leave the
94
cursor at the leftmost position."""
95
raise NotImplementedError(self.clear_term)
97
def get_boolean(self, prompt):
98
"""Get a boolean question answered from the user.
100
:param prompt: a message to prompt the user with. Should be a single
101
line without terminating \n.
102
:return: True or False for y/yes or n/no.
104
raise NotImplementedError(self.get_boolean)
106
def recommend_upgrade(self,
109
# this should perhaps be in the TextUIFactory and the default can do
111
trace.warning("%s is deprecated "
112
"and a better format is available.\n"
113
"It is recommended that you upgrade by "
114
"running the command\n"
119
def report_transport_activity(self, transport, byte_count, direction):
120
"""Called by transports as they do IO.
122
This may update a progress bar, spinner, or similar display.
123
By default it does nothing.
129
class CLIUIFactory(UIFactory):
130
"""Common behaviour for command line UI factories.
132
This is suitable for dumb terminals that can't repaint existing text."""
134
def __init__(self, stdin=None, stdout=None, stderr=None):
135
UIFactory.__init__(self)
136
self.stdin = stdin or sys.stdin
137
self.stdout = stdout or sys.stdout
138
self.stderr = stderr or sys.stderr
140
def get_boolean(self, prompt):
142
# FIXME: make a regexp and handle case variations as well.
144
self.prompt(prompt + "? [y/n]: ")
145
line = self.stdin.readline()
146
if line in ('y\n', 'yes\n'):
148
if line in ('n\n', 'no\n'):
151
def get_non_echoed_password(self, prompt):
152
if not sys.stdin.isatty():
153
raise errors.NotATerminal()
154
encoding = osutils.get_terminal_encoding()
155
return getpass.getpass(prompt.encode(encoding, 'replace'))
157
def get_password(self, prompt='', **kwargs):
158
"""Prompt the user for a password.
160
:param prompt: The prompt to present the user
161
:param kwargs: Arguments which will be expanded into the prompt.
162
This lets front ends display different things if
164
:return: The password string, return None if the user
165
canceled the request.
168
prompt = (prompt % kwargs)
169
# There's currently no way to say 'i decline to enter a password'
170
# as opposed to 'my password is empty' -- does it matter?
171
return self.get_non_echoed_password(prompt)
173
def prompt(self, prompt):
174
"""Emit prompt on the CLI."""
176
def clear_term(self):
179
def show_progress(self, task):
182
def progress_finished(self, task):
186
class SilentUIFactory(CLIUIFactory):
187
"""A UI Factory which never prints anything.
189
This is the default UI, if another one is never registered.
193
CLIUIFactory.__init__(self)
195
def get_password(self, prompt='', **kwargs):
203
def clear_decorator(func, *args, **kwargs):
204
"""Decorator that clears the term"""
205
ui_factory.clear_term()
206
func(*args, **kwargs)
209
ui_factory = SilentUIFactory()
210
"""IMPORTANT: never import this symbol directly. ONLY ever access it as
214
def make_ui_for_terminal(stdin, stdout, stderr):
215
"""Construct and return a suitable UIFactory for a text mode program.
217
If stdout is a smart terminal, this gets a smart UIFactory with
218
progress indicators, etc. If it's a dumb terminal, just plain text output.
220
isatty = getattr(stdin, 'isatty', None)
225
elif os.environ.get('TERM') in (None, 'dumb', ''):
226
# e.g. emacs compile window
229
from bzrlib.ui.text import TextUIFactory
231
return cls(stdin=stdin, stdout=stdout, stderr=stderr)