~abentley/bzrtools/bzrtools.dev

« back to all changes in this revision

Viewing changes to shell.py

  • Committer: Aaron Bentley
  • Date: 2005-10-27 04:05:17 UTC
  • Revision ID: aaron.bentley@utoronto.ca-20051027040517-5ba43a0b69ee0b0b
Initial import of Fai shell command

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2004, 2005 Aaron Bentley
2
 
# <aaron.bentley@utoronto.ca>
3
 
#
4
 
#    This program is free software; you can redistribute it and/or modify
5
 
#    it under the terms of the GNU General Public License as published by
6
 
#    the Free Software Foundation; either version 2 of the License, or
7
 
#    (at your option) any later version.
8
 
#
9
 
#    This program is distributed in the hope that it will be useful,
10
 
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
11
 
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
 
#    GNU General Public License for more details.
13
 
#
14
 
#    You should have received a copy of the GNU General Public License
15
 
#    along with this program; if not, write to the Free Software
16
 
#    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17
 
import cmd
18
 
import sys
19
 
import os
20
 
import terminal
21
 
import readline
22
 
import string
23
 
from itertools import chain
24
 
from bzrlib.errors import BzrError
25
 
from bzrlib.commands import get_cmd_object, get_all_cmds, get_alias
26
 
from bzrlib.branch import Branch
27
 
 
28
 
SHELL_BLACKLIST = set(['rm', 'ls'])
29
 
COMPLETION_BLACKLIST = set(['shell'])
30
 
 
31
 
class BlackListedCommand(BzrError):
32
 
    def __init__(self, command):
33
 
        BzrError.__init__(self, "The command %s is blacklisted for shell use" %
34
 
                          command)
35
 
 
36
 
class CompletionContext(object):
37
 
    def __init__(self, text, command=None, prev_opt=None, arg_pos=None):
38
 
        self.text = text
39
 
        self.command = command
40
 
        self.prev_opt = prev_opt
41
 
        self.arg_pos = None
42
 
 
43
 
    def get_completions(self):
44
 
        try:
45
 
            return self.get_completions_or_raise()
46
 
        except Exception, e:
47
 
            print e, type(e)
48
 
            return []
49
 
 
50
 
    def get_option_completions(self):
51
 
        try:
52
 
            command_obj = get_cmd_object(self.command)
53
 
        except BzrError:
54
 
            return []
55
 
        opts = [o+" " for o in iter_opt_completions(command_obj)]
56
 
        return list(filter_completions(opts, self.text))
57
 
 
58
 
    def get_completions_or_raise(self):
59
 
        if self.command is None:
60
 
            iter = (c+" " for c in iter_command_names() if
61
 
                    c not in COMPLETION_BLACKLIST)
62
 
            return list(filter_completions(iter, self.text))
63
 
        if self.prev_opt is None:
64
 
            completions = self.get_option_completions()
65
 
            if self.command == "cd":
66
 
                iter = iter_dir_completions(self.text)
67
 
                completions.extend(list(filter_completions(iter, self.text)))
68
 
            else:
69
 
                iter = iter_file_completions(self.text)
70
 
                completions.extend([f+" " for f in 
71
 
                                    filter_completions(iter, self.text)])
72
 
            return completions 
73
 
 
74
 
 
75
1
class PromptCmd(cmd.Cmd):
76
2
    def __init__(self):
77
3
        cmd.Cmd.__init__(self)
78
 
        self.prompt = "bzr> "
 
4
        self.prompt = "Fai> "
79
5
        try:
80
 
            self.tree = WorkingTree.open_containing('.')[0]
 
6
            self.tree = arch.tree_root(".")
81
7
        except:
82
8
            self.tree = None
83
9
        self.set_title()
84
10
        self.set_prompt()
 
11
        self.fake_aba = abacmds.AbaCmds()
85
12
        self.identchars += '-'
86
 
        self.history_file = os.path.expanduser("~/.bazaar/shell-history")
 
13
        self.history_file = os.path.expanduser("~/.fai-history")
87
14
        readline.set_completer_delims(string.whitespace)
88
15
        if os.access(self.history_file, os.R_OK) and \
89
16
            os.path.isfile(self.history_file):
95
22
 
96
23
    def do_quit(self, args):
97
24
        self.write_history()
98
 
        raise StopIteration
 
25
        sys.exit(0)
99
26
 
100
27
    def do_exit(self, args):
101
28
        self.do_quit(args)
111
38
    def set_prompt(self):
112
39
        if self.tree is not None:
113
40
            try:
114
 
                prompt_data = (self.tree.branch.nick, self.tree.branch.revno(), 
115
 
                               self.tree.branch.relpath('.'))
116
 
                prompt = " %s:%d/%s" % prompt_data
 
41
                prompt = pylon.alias_or_version(self.tree.tree_version, 
 
42
                                                self.tree, 
 
43
                                                full=False)
 
44
                if prompt is not None:
 
45
                    prompt = " " + prompt +":"+ pylon.tree_cwd(self.tree)
117
46
            except:
118
47
                prompt = ""
119
48
        else:
120
49
            prompt = ""
121
 
        self.prompt = "bzr%s> " % prompt
 
50
        self.prompt = "Fai%s> " % prompt
122
51
 
123
52
    def set_title(self, command=None):
124
53
        try:
125
 
            b = Branch.open_containing('.')[0]
126
 
            version = "%s:%d" % (b.nick, b.revno())
 
54
            version = pylon.alias_or_version(self.tree.tree_version, self.tree, 
 
55
                                             full=False)
127
56
        except:
128
57
            version = "[no version]"
129
58
        if command is None:
130
59
            command = ""
131
 
        sys.stdout.write(terminal.term_title("bzr %s %s" % (command, version)))
 
60
        sys.stdout.write(terminal.term_title("Fai %s %s" % (command, version)))
132
61
 
133
62
    def do_cd(self, line):
134
63
        if line == "":
145
74
        except Exception, e:
146
75
            print e
147
76
        try:
148
 
            self.tree = WorkingTree.open_containing(".")[0]
 
77
            self.tree = arch.tree_root(".")
149
78
        except:
150
79
            self.tree = None
151
80
 
152
81
    def do_help(self, line):
153
 
        self.default("help "+line)
 
82
        Help()(line)
154
83
 
155
84
    def default(self, line):
156
85
        args = line.split()
157
 
        alias_args = get_alias(args[0])
158
 
        if alias_args is not None:
159
 
            args[0] = alias_args.pop(0)
160
 
            
161
 
        commandname = args.pop(0)
162
 
        for char in ('|', '<', '>'):
163
 
            commandname = commandname.split(char)[0]
164
 
        if commandname[-1] in ('|', '<', '>'):
165
 
            commandname = commandname[:-1]
166
 
        try:
167
 
            if commandname in SHELL_BLACKLIST:
168
 
                raise BlackListedCommand(commandname)
169
 
            cmd_obj = get_cmd_object(commandname)
170
 
        except (BlackListedCommand, BzrError):
171
 
            return os.system(line)
172
 
 
173
 
        try:
174
 
            if too_complicated(line):
175
 
                return os.system("bzr "+line)
176
 
            else:
177
 
                return (cmd_obj.run_argv_aliases(args, alias_args) or 0)
178
 
        except BzrError, e:
179
 
            print e
180
 
        except KeyboardInterrupt, e:
181
 
            print "Interrupted"
182
 
        except Exception, e:
183
 
#            print "Unhandled error:\n%s" % errors.exception_str(e)
184
 
            print "Unhandled error:\n%s" % (e)
185
 
 
 
86
        if find_command(args[0]):
 
87
            try:
 
88
                find_command(args[0]).do_command(args[1:])
 
89
            except cmdutil.BadCommandOption, e:
 
90
                print e
 
91
            except cmdutil.GetHelp, e:
 
92
                find_command(args[0]).help()
 
93
            except CommandFailed, e:
 
94
                print e
 
95
            except arch.errors.ArchiveNotRegistered, e:
 
96
                print e
 
97
            except KeyboardInterrupt, e:
 
98
                print "Interrupted"
 
99
            except arch.util.ExecProblem, e:
 
100
                print e.proc.error.rstrip('\n')
 
101
            except cmdutil.CantDetermineVersion, e:
 
102
                print e
 
103
            except cmdutil.CantDetermineRevision, e:
 
104
                print e
 
105
            except Exception, e:
 
106
                print "Unhandled error:\n%s" % errors.exception_str(e)
 
107
 
 
108
        elif suggestions.has_key(args[0]):
 
109
            print suggestions[args[0]]
 
110
 
 
111
        elif self.fake_aba.is_command(args[0]):
 
112
            tree = None
 
113
            try:
 
114
                tree = arch.tree_root(".")
 
115
            except arch.errors.TreeRootError:
 
116
                pass
 
117
            cmd = self.fake_aba.is_command(args[0])
 
118
            try:
 
119
                args = cmdutil.expand_prefix_alias(args[1:], tree)
 
120
            except Exception, e:
 
121
                print e
 
122
                return
 
123
            try:
 
124
                cmd.run(args)
 
125
            except KeyboardInterrupt, e:
 
126
                print "Interrupted"
 
127
 
 
128
        elif options.tla_fallthrough and args[0] != "rm" and \
 
129
            cmdutil.is_tla_command(args[0]):
 
130
            try:
 
131
                tree = None
 
132
                try:
 
133
                    tree = arch.tree_root(".")
 
134
                except arch.errors.TreeRootError:
 
135
                    pass
 
136
                try:
 
137
                    args = cmdutil.expand_prefix_alias(args, tree)
 
138
                except Exception, e:
 
139
                    print e
 
140
                    return
 
141
                arch.util.exec_safe('tla', args, stderr=sys.stderr,
 
142
                                    stdout=sys.stdout, expected=(0, 1))
 
143
            except arch.util.ExecProblem, e:
 
144
                pass
 
145
            except KeyboardInterrupt, e:
 
146
                print "Interrupted"
 
147
        else:
 
148
            try:
 
149
                try:
 
150
                    tree = arch.tree_root(".")
 
151
                except arch.errors.TreeRootError:
 
152
                    tree = None
 
153
                args=line.split()
 
154
                try:
 
155
                    args = cmdutil.expand_prefix_alias(args, tree)
 
156
                except Exception, e:
 
157
                    print e
 
158
                    return
 
159
                os.system(" ".join(args))
 
160
            except KeyboardInterrupt, e:
 
161
                print "Interrupted"
186
162
 
187
163
    def completenames(self, text, line, begidx, endidx):
188
 
        return CompletionContext(text).get_completions()
 
164
        completions = []
 
165
        iter = iter_command_names(self.fake_aba)
 
166
        try:
 
167
            if len(line) > 0:
 
168
                arg = line.split()[-1]
 
169
            else:
 
170
                arg = ""
 
171
            iter = cmdutil.iter_munged_completions(iter, arg, text)
 
172
        except Exception, e:
 
173
            print e
 
174
        return list(iter)
189
175
 
190
176
    def completedefault(self, text, line, begidx, endidx):
191
177
        """Perform completion for native commands.
199
185
        :param endidx: The end of the text in the line
200
186
        :type endidx: int
201
187
        """
202
 
        (cmd, args, foo) = self.parseline(line)
203
 
        if cmd == "bzr":
204
 
            cmd = None
205
 
        return CompletionContext(text, command=cmd).get_completions()
 
188
        try:
 
189
            (cmd, args, foo) = self.parseline(line)
 
190
            command_obj=find_command(cmd)
 
191
            if command_obj is not None:
 
192
                return command_obj.complete(args.split(), text)
 
193
            elif not self.fake_aba.is_command(cmd) and \
 
194
                cmdutil.is_tla_command(cmd):
 
195
                iter = cmdutil.iter_supported_switches(cmd)
 
196
                if len(args) > 0:
 
197
                    arg = args.split()[-1]
 
198
                else:
 
199
                    arg = ""
 
200
                if arg.startswith("-"):
 
201
                    return list(cmdutil.iter_munged_completions(iter, arg, 
 
202
                                                                text))
 
203
                else:
 
204
                    return list(cmdutil.iter_munged_completions(
 
205
                        cmdutil.iter_file_completions(arg), arg, text))
 
206
 
 
207
 
 
208
            elif cmd == "cd":
 
209
                if len(args) > 0:
 
210
                    arg = args.split()[-1]
 
211
                else:
 
212
                    arg = ""
 
213
                iter = cmdutil.iter_dir_completions(arg)
 
214
                iter = cmdutil.iter_munged_completions(iter, arg, text)
 
215
                return list(iter)
 
216
            elif len(args)>0:
 
217
                arg = args.split()[-1]
 
218
                iter = cmdutil.iter_file_completions(arg)
 
219
                return list(cmdutil.iter_munged_completions(iter, arg, text))
 
220
            else:
 
221
                return self.completenames(text, line, begidx, endidx)
 
222
        except Exception, e:
 
223
            print e
206
224
 
207
225
def run_shell():
 
226
    if len(cmdargs)!=0:
 
227
        raise cmdutil.GetHelp
 
228
    prompt = PromptCmd()
208
229
    try:
209
 
        prompt = PromptCmd()
210
 
        try:
211
 
            prompt.cmdloop()
212
 
        finally:
213
 
            prompt.write_history()
214
 
    except StopIteration:
215
 
        pass
216
 
 
217
 
def iter_opt_completions(command_obj):
218
 
    for option_name, option in command_obj.options().items():
219
 
        yield "--" + option_name
220
 
        short_name = option.short_name()
221
 
        if short_name:
222
 
            yield "-" + short_name
 
230
        prompt.cmdloop()
 
231
    finally:
 
232
        prompt.write_history()
223
233
 
224
234
def iter_file_completions(arg, only_dirs = False):
225
235
    """Generate an iterator that iterates through filename completions.
239
249
        listingdir = os.path.expanduser(dir)
240
250
    else:
241
251
        listingdir = cwd
242
 
    for file in chain(os.listdir(listingdir), extras):
 
252
    for file in iter_combine([os.listdir(listingdir), extras]):
243
253
        if dir != "":
244
254
            userfile = dir+'/'+file
245
255
        else:
259
269
    :type arg: str
260
270
    """
261
271
    return iter_file_completions(arg, True)
262
 
 
263
 
def iter_command_names(hidden=False):
264
 
    for real_cmd_name, cmd_class in get_all_cmds():
265
 
        if not hidden and cmd_class.hidden:
266
 
            continue
267
 
        for name in [real_cmd_name] + cmd_class.aliases:
268
 
            # Don't complete on aliases that are prefixes of the canonical name
269
 
            if name == real_cmd_name or not real_cmd_name.startswith(name):
270
 
                yield name
271
 
 
272
 
def filter_completions(iter, arg):
273
 
    return (c for c in iter if c.startswith(arg))
274
 
 
275
 
def iter_munged_completions(iter, arg, text):
276
 
    for completion in iter:
277
 
        completion = str(completion)
278
 
        if completion.startswith(arg):
279
 
            yield completion[len(arg)-len(text):]+" "
280
 
 
281
 
def too_complicated(line):
282
 
    for char in '|<>"\"*?':
283
 
        if char in line:
284
 
            return True
285
 
    return False