14
14
# You should have received a copy of the GNU General Public License
15
15
# along with this program; if not, write to the Free Software
16
16
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19
from itertools import chain
32
from bzrlib import osutils, trace
33
from bzrlib.branch import Branch
34
from bzrlib.config import config_dir, ensure_config_dir_exists
35
from bzrlib.commands import get_cmd_object, all_command_names, get_alias
36
23
from bzrlib.errors import BzrError
37
from bzrlib.workingtree import WorkingTree
42
SHELL_BLACKLIST = set(['rm', 'ls'])
43
COMPLETION_BLACKLIST = set(['shell'])
46
class BlackListedCommand(BzrError):
47
def __init__(self, command):
48
BzrError.__init__(self, "The command %s is blacklisted for shell use" %
52
class CompletionContext(object):
53
def __init__(self, text, command=None, prev_opt=None, arg_pos=None):
55
self.command = command
56
self.prev_opt = prev_opt
59
def get_completions(self):
61
return self.get_completions_or_raise()
66
def get_option_completions(self):
68
command_obj = get_cmd_object(self.command)
71
opts = [o+" " for o in iter_opt_completions(command_obj)]
72
return list(filter_completions(opts, self.text))
74
def get_completions_or_raise(self):
75
if self.command is None:
77
iter = iter_executables(self.text)
79
iter = (c+" " for c in iter_command_names() if
80
c not in COMPLETION_BLACKLIST)
81
return list(filter_completions(iter, self.text))
82
if self.prev_opt is None:
83
completions = self.get_option_completions()
84
if self.command == "cd":
85
iter = iter_dir_completions(self.text)
86
completions.extend(list(filter_completions(iter, self.text)))
88
iter = iter_file_completions(self.text)
89
completions.extend(filter_completions(iter, self.text))
24
from bzrlib.commands import get_cmd_object
93
26
class PromptCmd(cmd.Cmd):
95
27
def __init__(self):
96
28
cmd.Cmd.__init__(self)
97
29
self.prompt = "bzr> "
99
self.tree = WorkingTree.open_containing('.')[0]
31
self.tree = arch.tree_root(".")
104
36
self.identchars += '-'
105
ensure_config_dir_exists()
106
self.history_file = osutils.pathjoin(config_dir(), 'shell-history')
107
whitespace = ''.join(c for c in string.whitespace if c < chr(127))
109
readline.set_completer_delims(whitespace)
110
if os.access(self.history_file, os.R_OK) and \
111
os.path.isfile(self.history_file):
112
readline.read_history_file(self.history_file)
37
self.history_file = os.path.expanduser("~/.bazaar/shell-history")
38
readline.set_completer_delims(string.whitespace)
39
if os.access(self.history_file, os.R_OK) and \
40
os.path.isfile(self.history_file):
41
readline.read_history_file(self.history_file)
113
42
self.cwd = os.getcwd()
115
44
def write_history(self):
117
readline.write_history_file(self.history_file)
45
readline.write_history_file(self.history_file)
119
47
def do_quit(self, args):
120
48
self.write_history()
123
51
def do_exit(self, args):
124
52
self.do_quit(args)
168
98
except Exception, e:
171
self.tree = WorkingTree.open_containing(".")[0]
101
self.tree = arch.tree_root(".")
175
105
def do_help(self, line):
176
self.default("help "+line)
178
108
def default(self, line):
180
args = shlex.split(line)
181
except ValueError, e:
182
print 'Parse error:', e
185
alias_args = get_alias(args[0])
186
if alias_args is not None:
187
args[0] = alias_args.pop(0)
189
110
commandname = args.pop(0)
190
for char in ('|', '<', '>'):
191
commandname = commandname.split(char)[0]
192
if commandname[-1] in ('|', '<', '>'):
193
commandname = commandname[:-1]
195
if commandname in SHELL_BLACKLIST:
196
raise BlackListedCommand(commandname)
197
112
cmd_obj = get_cmd_object(commandname)
198
except (BlackListedCommand, BzrError):
199
114
return os.system(line)
202
is_qbzr = cmd_obj.__module__.startswith('bzrlib.plugins.qbzr.')
203
if too_complicated(line) or is_qbzr:
204
return os.system("bzr "+line)
206
return (cmd_obj.run_argv_aliases(args, alias_args) or 0)
118
return (cmd_obj.run_argv(args) or 0)
207
119
except BzrError, e:
208
trace.log_exception_quietly()
210
121
except KeyboardInterrupt, e:
211
122
print "Interrupted"
212
123
except Exception, e:
213
trace.log_exception_quietly()
124
# print "Unhandled error:\n%s" % errors.exception_str(e)
214
125
print "Unhandled error:\n%s" % (e)
217
128
def completenames(self, text, line, begidx, endidx):
218
return CompletionContext(text).get_completions()
130
iter = iter_command_names(self.fake_aba)
133
arg = line.split()[-1]
136
iter = cmdutil.iter_munged_completions(iter, arg, text)
220
141
def completedefault(self, text, line, begidx, endidx):
221
142
"""Perform completion for native commands.
223
144
:param text: The text to complete
225
146
:param line: The entire line to complete
229
150
:param endidx: The end of the text in the line
230
151
:type endidx: int
232
(cmd, args, foo) = self.parseline(line)
235
return CompletionContext(text, command=cmd).get_completions()
238
def run_shell(directory=None):
154
(cmd, args, foo) = self.parseline(line)
155
command_obj=find_command(cmd)
156
if command_obj is not None:
157
return command_obj.complete(args.split(), text)
158
elif not self.fake_aba.is_command(cmd) and \
159
cmdutil.is_tla_command(cmd):
160
iter = cmdutil.iter_supported_switches(cmd)
162
arg = args.split()[-1]
165
if arg.startswith("-"):
166
return list(cmdutil.iter_munged_completions(iter, arg,
169
return list(cmdutil.iter_munged_completions(
170
cmdutil.iter_file_completions(arg), arg, text))
175
arg = args.split()[-1]
178
iter = cmdutil.iter_dir_completions(arg)
179
iter = cmdutil.iter_munged_completions(iter, arg, text)
182
arg = args.split()[-1]
183
iter = cmdutil.iter_file_completions(arg)
184
return list(cmdutil.iter_munged_completions(iter, arg, text))
186
return self.completenames(text, line, begidx, endidx)
240
if not directory is None:
247
except KeyboardInterrupt:
250
prompt.write_history()
251
except StopIteration:
255
def iter_opt_completions(command_obj):
256
for option_name, option in command_obj.options().items():
257
yield "--" + option_name
258
short_name = option.short_name()
260
yield "-" + short_name
195
prompt.write_history()
263
197
def iter_file_completions(arg, only_dirs = False):
264
198
"""Generate an iterator that iterates through filename completions.
300
234
return iter_file_completions(arg, True)
303
def iter_command_names(hidden=False):
304
for real_cmd_name in all_command_names():
305
cmd_obj = get_cmd_object(real_cmd_name)
306
if not hidden and cmd_obj.hidden:
308
for name in [real_cmd_name] + cmd_obj.aliases:
309
# Don't complete on aliases that are prefixes of the canonical name
310
if name == real_cmd_name or not real_cmd_name.startswith(name):
314
def iter_executables(path):
315
dirname, partial = os.path.split(path)
316
for filename in os.listdir(dirname):
317
if not filename.startswith(partial):
319
fullpath = os.path.join(dirname, filename)
320
mode=os.lstat(fullpath)[stat.ST_MODE]
321
if stat.S_ISREG(mode) and 0111 & mode:
325
def filter_completions(iter, arg):
326
return (c for c in iter if c.startswith(arg))
329
def iter_munged_completions(iter, arg, text):
330
for completion in iter:
331
completion = str(completion)
332
if completion.startswith(arg):
333
yield completion[len(arg)-len(text):]+" "
336
def too_complicated(line):