57
60
:param kwargs: Arguments which will be expanded into the prompt.
58
61
This lets front ends display different things if
60
:return: The password string, return None if the user
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
63
69
raise NotImplementedError(self.get_password)
65
71
def nested_progress_bar(self):
66
72
"""Return a nested progress bar.
68
When the bar has been finished with, it should be released bu calling
74
When the bar has been finished with, it should be released by calling
71
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.
73
108
def clear_term(self):
74
109
"""Prepare the terminal for output.
76
111
This will, for example, clear text progress bars, and leave the
77
cursor at the leftmost position."""
78
raise NotImplementedError(self.clear_term)
112
cursor at the leftmost position.
80
116
def get_boolean(self, prompt):
81
"""Get a boolean question answered from the user.
117
"""Get a boolean question answered from the user.
83
119
:param prompt: a message to prompt the user with. Should be a single
84
120
line without terminating \n.
87
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.
90
148
class CLIUIFactory(UIFactory):
91
"""Common behaviour for command line UI factories."""
94
super(CLIUIFactory, self).__init__()
95
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
97
159
def get_boolean(self, prompt):
99
# FIXME: make a regexp and handle case variations as well.
161
self.prompt(prompt + "? [y/n]: ")
102
162
line = self.stdin.readline()
103
164
if line in ('y\n', 'yes\n'):
105
166
if line in ('n\n', 'no\n'):
108
def prompt(self, prompt):
109
"""Emit prompt on the CLI."""
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.stderr.write(prompt)
233
"""Write an already-formatted message."""
234
self.stdout.write(msg + '\n')
112
237
class SilentUIFactory(CLIUIFactory):
115
240
This is the default UI, if another one is never registered.
118
@deprecated_method(zero_eight)
119
def progress_bar(self):
120
"""See UIFactory.nested_progress_bar()."""
121
return bzrlib.progress.DummyProgress()
244
CLIUIFactory.__init__(self)
123
246
def get_password(self, prompt='', **kwargs):
126
def nested_progress_bar(self):
127
if self._progress_bar_stack is None:
128
self._progress_bar_stack = bzrlib.progress.ProgressBarStack(
129
klass=bzrlib.progress.DummyProgress)
130
return self._progress_bar_stack.get_nested()
132
def clear_term(self):
249
def get_username(self, prompt='', **kwargs):
252
def prompt(self, prompt, **kwargs):
142
265
ui_factory = SilentUIFactory()
143
"""IMPORTANT: never import this symbol directly. ONLY ever access it as
266
"""IMPORTANT: never import this symbol directly. ONLY ever access it as
144
267
ui.ui_factory."""
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)