28
26
displays no output.
35
import bzrlib.progress
38
class TextUIFactory(object):
39
def progress_bar(self):
41
# this in turn is abstract, and creates either a tty or dots
42
# bar depending on what we think of the terminal
43
return bzrlib.progress.ProgressBar()
46
class SilentUIFactory(object):
47
def progress_bar(self):
48
return bzrlib.progress.DummyProgress()
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.
108
def clear_term(self):
109
"""Prepare the terminal for output.
111
This will, for example, clear text progress bars, and leave the
112
cursor at the leftmost position.
116
def get_boolean(self, prompt):
117
"""Get a boolean question answered from the user.
119
:param prompt: a message to prompt the user with. Should be a single
120
line without terminating \n.
121
:return: True or False for y/yes or n/no.
123
raise NotImplementedError(self.get_boolean)
125
def recommend_upgrade(self,
128
# this should perhaps be in the TextUIFactory and the default can do
130
trace.warning("%s is deprecated "
131
"and a better format is available.\n"
132
"It is recommended that you upgrade by "
133
"running the command\n"
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
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
159
def get_boolean(self, prompt):
160
# FIXME: make a regexp and handle case variations as well.
162
self.prompt(prompt + "? [y/n]: ")
163
line = self.stdin.readline()
164
if line in ('y\n', 'yes\n'):
166
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]
184
def get_password(self, prompt='', **kwargs):
185
"""Prompt the user for a password.
187
:param prompt: The prompt to present the user
188
:param kwargs: Arguments which will be expanded into the prompt.
189
This lets front ends display different things if
191
:return: The password string, return None if the user
192
canceled the request.
195
self.prompt(prompt, **kwargs)
196
# There's currently no way to say 'i decline to enter a password'
197
# 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):
220
"""Emit prompt on the CLI.
222
:param kwargs: Dictionary of arguments to insert into the prompt,
223
to allow UIs to reformat the prompt.
226
# See <https://launchpad.net/bugs/365891>
227
prompt = prompt % kwargs
228
prompt = prompt.encode(osutils.get_terminal_encoding(), 'replace')
230
self.stdout.write(prompt)
233
"""Write an already-formatted message."""
234
self.stdout.write(msg + '\n')
237
class SilentUIFactory(CLIUIFactory):
238
"""A UI Factory which never prints anything.
240
This is the default UI, if another one is never registered.
244
CLIUIFactory.__init__(self)
246
def get_password(self, prompt='', **kwargs):
249
def get_username(self, prompt='', **kwargs):
252
def prompt(self, prompt, **kwargs):
259
def clear_decorator(func, *args, **kwargs):
260
"""Decorator that clears the term"""
261
ui_factory.clear_term()
262
func(*args, **kwargs)
51
265
ui_factory = SilentUIFactory()
266
"""IMPORTANT: never import this symbol directly. ONLY ever access it as
270
def make_ui_for_terminal(stdin, stdout, stderr):
271
"""Construct and return a suitable UIFactory for a text mode program.
273
If stdout is a smart terminal, this gets a smart UIFactory with
274
progress indicators, etc. If it's a dumb terminal, just plain text output.
277
isatty = getattr(stdin, 'isatty', None)
282
elif os.environ.get('TERM') in ('dumb', ''):
283
# e.g. emacs compile window
285
# User may know better, otherwise default to TextUIFactory
286
if ( os.environ.get('BZR_USE_TEXT_UI', None) is not None
288
from bzrlib.ui.text import TextUIFactory
290
return cls(stdin=stdin, stdout=stdout, stderr=stderr)