Ticket #897: main.py

File main.py, 7.6 KB (added by greeklegend, 15 years ago)

modified deluge.ui.console.main

Line 
1#!/usr/bin/env python
2#
3# main.py
4#
5# Copyright (C) 2008-2009 Ido Abramovich <ido.deluge@gmail.com>
6#
7# Deluge is free software.
8#
9# You may redistribute it and/or modify it under the terms of the
10# GNU General Public License, as published by the Free Software
11# Foundation; either version 3 of the License, or (at your option)
12# any later version.
13#
14# deluge is distributed in the hope that it will be useful,
15# but WITHOUT ANY WARRANTY; without even the implied warranty of
16# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
17# See the GNU General Public License for more details.
18#
19# You should have received a copy of the GNU General Public License
20# along with deluge.    If not, write to:
21#       The Free Software Foundation, Inc.,
22#       51 Franklin Street, Fifth Floor
23#       Boston, MA  02110-1301, USA.
24#
25#    In addition, as a special exception, the copyright holders give
26#    permission to link the code of portions of this program with the OpenSSL
27#    library.
28#    You must obey the GNU General Public License in all respects for all of
29#    the code used other than OpenSSL. If you modify file(s) with this
30#    exception, you may extend this exception to your version of the file(s),
31#    but you are not obligated to do so. If you do not wish to do so, delete
32#    this exception statement from your version. If you delete this exception
33#    statement from all source files in the program, then also delete it here.
34#
35
36#
37import logging
38logging.disable(logging.ERROR)
39import os, sys
40import optparse
41from deluge.ui.console import UI_PATH
42from deluge.ui.console.colors import Template, make_style, templates, default_style as style
43from deluge.ui.client import aclient as client
44from deluge.ui.common import get_localhost_auth_uri
45import shlex
46
47
48class OptionParser(optparse.OptionParser):
49    """subclass from optparse.OptionParser so exit() won't exit."""
50    def exit(self, status=0, msg=None):
51        self.values._exit = True
52        if msg:
53            print msg
54
55    def error(self, msg):
56        """error(msg : string)
57
58           Print a usage message incorporating 'msg' to stderr and exit.
59           If you override this in a subclass, it should not return -- it
60           should either exit or raise an exception.
61        """
62        raise
63
64
65class BaseCommand(object):
66
67    usage = 'usage'
68    option_list = tuple()
69    aliases = []
70
71
72    def complete(self, text, *args):
73        return []
74    def handle(self, *args, **options):
75        pass
76
77    @property
78    def name(self):
79        return 'base'
80
81    @property
82    def epilog(self):
83        return self.__doc__
84
85    def split(self, text):
86        return shlex.split(text)
87
88    def create_parser(self):
89        return OptionParser(prog = self.name,
90                            usage = self.usage,
91                            epilog = self.epilog,
92                            option_list = self.option_list)
93
94def match_torrents(array=None):
95    global torrents
96    if array is None:
97        array = list()
98    torrents = []
99    array = set(array)
100    def _got_session_state(tors):
101        if not array:
102            torrents.extend(tors)
103            return
104        tors = set(tors)
105        torrents.extend(list(tors.intersection(array)))
106        return
107    client.get_session_state(_got_session_state)
108    client.force_call()
109    return torrents
110
111def load_commands(command_dir, exclude=[]):
112    def get_command(name):
113        return getattr(__import__('deluge.ui.console.commands.%s' % name, {}, {}, ['Command']), 'Command')()
114
115    try:
116        commands = []
117        for filename in os.listdir(command_dir):
118            if filename.split('.')[0] in exclude or filename.startswith('_'):
119                continue
120            if not (filename.endswith('.pyc') or filename.endswith('.py')):
121                continue
122            cmd = get_command(filename.split('.')[len(filename.split('.')) - 2])
123            aliases = [ filename.split('.')[len(filename.split('.')) - 2] ]
124            aliases.extend(cmd.aliases)
125            for a in aliases:
126                commands.append((a, cmd))
127        return dict(commands)
128    except OSError, e:
129        return {}
130
131class ConsoleUI(object):
132    prompt = '>>> '
133
134    def __init__(self, args=None):
135        client.set_core_uri(get_localhost_auth_uri("http://localhost:58846"))
136        self._commands = load_commands(os.path.join(UI_PATH, 'commands'))
137        if args:
138            self.precmd()
139            #allow multiple commands split by ";"
140            for arg in args.split(";"):
141                self.onecmd(arg)
142                self.postcmd()
143            sys.exit(0)
144
145    def completedefault(self, *ignored):
146        """Method called to complete an input line when no command-specific
147        method is available.
148
149        By default, it returns an empty list.
150
151        """
152        return []
153
154    def completenames(self, text, *ignored):
155        return [n for n in self._commands.keys() if n.startswith(text)]
156
157    def complete(self, text, state):
158        """Return the next possible completion for 'text'.
159        If a command has not been entered, then complete against command list.
160        Otherwise try to call complete_<command> to get list of completions.
161        """
162        if state == 0:
163            import readline
164            origline = readline.get_line_buffer()
165            line = origline.lstrip()
166            stripped = len(origline) - len(line)
167            begidx = readline.get_begidx() - stripped
168            endidx = readline.get_endidx() - stripped
169            if begidx>0:
170                cmd = line.split()[0]
171                if cmd == '':
172                    compfunc = self.completedefault
173                else:
174                    try:
175                        compfunc = getattr(self._commands[cmd], 'complete')
176                    except AttributeError:
177                        compfunc = self.completedefault
178            else:
179                compfunc = self.completenames
180            self.completion_matches = compfunc(text, line, begidx, endidx)
181        try:
182            return self.completion_matches[state]
183        except IndexError:
184            return None
185
186    def preloop(self):
187        pass
188
189    def postloop(self):
190        pass
191
192    def precmd(self):
193        pass
194
195    def onecmd(self, line):
196        if not line:
197            return
198        cmd, _, line = line.partition(' ')
199        try:
200            parser = self._commands[cmd].create_parser()
201        except KeyError:
202            print templates.ERROR('unknown command: %s' % cmd)
203            return
204        args = self._commands[cmd].split(line)
205        options, args = parser.parse_args(args)
206        if not getattr(options, '_exit', False):
207            try:
208                self._commands[cmd].handle(*args, **options.__dict__)
209            except StopIteration, e:
210                raise
211            except Exception, e:
212                print templates.ERROR(str(e))
213
214    def postcmd(self):
215        client.force_call()
216
217    def cmdloop(self):
218        self.preloop()
219        try:
220            import readline
221            self.old_completer = readline.get_completer()
222            readline.set_completer(self.complete)
223            readline.parse_and_bind("tab: complete")
224        except ImportError:
225            pass
226
227        while True:
228            try:
229                line = raw_input(templates.prompt(self.prompt)).strip()
230            except EOFError:
231                break
232            except Exception, e:
233                print e
234                continue
235            try:
236                self.precmd()
237                self.onecmd(line)
238                self.postcmd()
239            except StopIteration:
240                break
241        self.postloop()
242        print
243    run = cmdloop
244
245if __name__ == '__main__':
246    ui = ConsoleUI()
247    ui.precmd()
248    ui.onecmd(' '.join(sys.argv[1:]))
249    ui.postcmd()