Ticket #1974: 0001-Decouple-GUI-selection-from-core.patch

File 0001-Decouple-GUI-selection-from-core.patch, 17.6 KB (added by jumentous, 12 years ago)
  • deluge/main.py

    From 3227bdc65af97bb74d383333a32eb6153c065eda Mon Sep 17 00:00:00 2001
    From: Jamie Lennox <jamielennox@gmail.com>
    Date: Sat, 19 Nov 2011 20:20:43 +1100
    Subject: [PATCH] Decouple GUI selection from core.
    
    Add EntryPoints into setup for each of the UIs and then use this information
    to determine which client UI to run.
    ---
     deluge/main.py                |   34 +++++------
     deluge/ui/console/__init__.py |    5 +-
     deluge/ui/console/console.py  |  128 +++++++++++++++++++++++++++++++++++++++++
     deluge/ui/console/main.py     |   91 -----------------------------
     deluge/ui/gtkui/__init__.py   |   18 ++++++-
     deluge/ui/gtkui/gtkui.py      |   15 -----
     deluge/ui/web/__init__.py     |    5 +-
     deluge/ui/web/web.py          |    1 +
     setup.py                      |    7 ++-
     9 files changed, 174 insertions(+), 130 deletions(-)
     create mode 100644 deluge/ui/console/console.py
    
    diff --git a/deluge/main.py b/deluge/main.py
    index 5797251..4b429e7 100644
    a b  
    4444import sys 
    4545import optparse 
    4646import logging 
     47import pkg_resources  
    4748 
    4849import deluge.log 
    4950import deluge.error 
    def start_ui(): 
    6263    parser = CommonOptionParser() 
    6364    group = optparse.OptionGroup (parser, _("Default Options")) 
    6465 
    65     group.add_option("-u", "--ui", dest="ui", 
    66         help="""The UI that you wish to launch.  The UI choices are:\n 
    67         \t gtk -- A GTK-based graphical user interface (default)\n 
    68         \t web -- A web-based interface (http://localhost:8112)\n 
    69         \t console -- A console or command-line interface""", action="store", type="str") 
     66    ui_entrypoints = dict([(entrypoint.name, entrypoint.load()) 
     67        for entrypoint in pkg_resources.iter_entry_points('deluge.ui')]) 
     68 
     69    cmd_help = ['The UI that you wish to launch.  The UI choices are:'] 
     70    cmd_help.extend(["%s -- %s" % (k, getattr(v, 'cmdline', "")) for k,v in ui_entrypoints.iteritems()]) 
     71 
     72    parser.add_option("-u", "--ui", dest="ui",  
     73        choices = ui_entrypoints.keys(), help="\n\t ".join(cmd_help), action="store") 
    7074    group.add_option("-a", "--args", dest="args", 
    7175        help="Arguments to pass to UI, -a '--option args'", action="store", type="str") 
    7276    group.add_option("-s", "--set-default-ui", dest="default_ui", 
    def start_ui(): 
    106110    client_args.extend(args) 
    107111 
    108112    try: 
    109         if selected_ui == "gtk": 
    110             log.info("Starting GtkUI..") 
    111             from deluge.ui.gtkui.gtkui import Gtk 
    112             ui = Gtk(skip_common = True) 
    113             ui.start(client_args) 
    114         elif selected_ui == "web": 
    115             log.info("Starting WebUI..") 
    116             from deluge.ui.web.web import Web 
    117             ui = Web(skip_common = True) 
    118             ui.start(client_args) 
    119         elif selected_ui == "console": 
    120             log.info("Starting ConsoleUI..") 
    121             from deluge.ui.console.main import Console 
    122             ui = Console(skip_common = True) 
    123             ui.start(client_args) 
     113        ui = ui_entrypoints[selected_ui](skip_common = True) 
     114    except KeyError, e:  
     115        log.error("Unable to find the requested UI: %s. Please select a different UI with the '-u' option or alternatively use the '-s' option to select a different default UI.", selected_ui) 
    124116    except ImportError, e: 
    125117        import sys 
    126118        import traceback 
    def start_ui(): 
    134126            log.error("There was an error whilst launching the request UI: %s", selected_ui) 
    135127            log.error("Look at the traceback above for more information.") 
    136128        sys.exit(1) 
     129    else:  
     130        ui.start(client_args) 
    137131 
    138132def start_daemon(): 
    139133    """Entry point for daemon script""" 
  • deluge/ui/console/__init__.py

    diff --git a/deluge/ui/console/__init__.py b/deluge/ui/console/__init__.py
    index 0747fac..09b2438 100644
    a b  
    3333# 
    3434# 
    3535UI_PATH = __path__[0] 
    36 from main import start 
     36from console import Console 
     37 
     38def start():  
     39    Console().start() 
  • new file deluge/ui/console/console.py

    diff --git a/deluge/ui/console/console.py b/deluge/ui/console/console.py
    new file mode 100644
    index 0000000..139e789
    - +  
     1# 
     2# main.py 
     3# 
     4# Copyright (C) 2008-2009 Ido Abramovich <ido.deluge@gmail.com> 
     5# Copyright (C) 2009 Andrew Resch <andrewresch@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 os 
     38import sys 
     39import optparse  
     40from deluge.ui.ui import _UI 
     41from deluge.ui.console import UI_PATH 
     42 
     43def load_commands(command_dir, exclude=[]): 
     44    def get_command(name): 
     45        return getattr(__import__('deluge.ui.console.commands.%s' % name, {}, {}, ['Command']), 'Command')() 
     46 
     47    try: 
     48        commands = [] 
     49        for filename in os.listdir(command_dir): 
     50            if filename.split('.')[0] in exclude or filename.startswith('_'): 
     51                continue 
     52            if not (filename.endswith('.py') or filename.endswith('.pyc')): 
     53                continue 
     54            cmd = get_command(filename.split('.')[len(filename.split('.')) - 2]) 
     55            aliases = [ filename.split('.')[len(filename.split('.')) - 2] ] 
     56            aliases.extend(cmd.aliases) 
     57            for a in aliases: 
     58                commands.append((a, cmd)) 
     59        return dict(commands) 
     60    except OSError, e: 
     61        return {} 
     62 
     63class Console(_UI): 
     64 
     65    help = """Starts the Deluge console interface""" 
     66    cmdline = """A console or command-line interface""" 
     67 
     68    def __init__(self, *args, **kwargs): 
     69        super(Console, self).__init__("console", *args, **kwargs) 
     70        group = optparse.OptionGroup(self.parser, "Console Options","These options control how " 
     71                                     "the console connects to the daemon.  These options will be " 
     72                                     "used if you pass a command, or if you have autoconnect " 
     73                                     "enabled for the console ui.") 
     74 
     75        group.add_option("-d","--daemon",dest="daemon_addr", 
     76                         action="store",type="str",default="127.0.0.1", 
     77                         help="Set the address of the daemon to connect to." 
     78                              " [default: %default]") 
     79        group.add_option("-p","--port",dest="daemon_port", 
     80                         help="Set the port to connect to the daemon on. [default: %default]", 
     81                         action="store",type="int",default=58846) 
     82        group.add_option("-u","--username",dest="daemon_user", 
     83                         help="Set the username to connect to the daemon with. [default: %default]", 
     84                         action="store",type="string") 
     85        group.add_option("-P","--password",dest="daemon_pass", 
     86                         help="Set the password to connect to the daemon with. [default: %default]", 
     87                         action="store",type="string") 
     88        self.parser.add_option_group(group) 
     89 
     90        self.cmds = load_commands(os.path.join(UI_PATH, 'commands')) 
     91        class CommandOptionGroup(optparse.OptionGroup): 
     92            def __init__(self, parser, title, description=None, cmds = None): 
     93                optparse.OptionGroup.__init__(self,parser,title,description) 
     94                self.cmds = cmds 
     95 
     96            def format_help(self, formatter): 
     97                result = formatter.format_heading(self.title) 
     98                formatter.indent() 
     99                if self.description: 
     100                    result += "%s\n"%formatter.format_description(self.description) 
     101                for cname in self.cmds: 
     102                    cmd = self.cmds[cname] 
     103                    if cmd.interactive_only or cname in cmd.aliases: continue 
     104                    allnames = [cname] 
     105                    allnames.extend(cmd.aliases) 
     106                    cname = "/".join(allnames) 
     107                    result += formatter.format_heading(" - ".join([cname,cmd.__doc__])) 
     108                    formatter.indent() 
     109                    result += "%*s%s\n" % (formatter.current_indent, "", cmd.usage) 
     110                    formatter.dedent() 
     111                formatter.dedent() 
     112                return result 
     113        cmd_group = CommandOptionGroup(self.parser, "Console Commands", 
     114                                       description="The following commands can be issued at the " 
     115                                       "command line.  Commands should be quoted, so, for example, " 
     116                                       "to pause torrent with id 'abc' you would run: '%s " 
     117                                       "\"pause abc\"'"%os.path.basename(sys.argv[0]), 
     118                                       cmds=self.cmds) 
     119        self.parser.add_option_group(cmd_group) 
     120 
     121    def start(self, args = None): 
     122        from main import ConsoleUI 
     123        super(Console, self).start(args) 
     124        ConsoleUI(self.args,self.cmds,(self.options.daemon_addr, 
     125                  self.options.daemon_port,self.options.daemon_user, 
     126                  self.options.daemon_pass)) 
     127 
     128 
  • deluge/ui/console/main.py

    diff --git a/deluge/ui/console/main.py b/deluge/ui/console/main.py
    index 1f0467e..bbe5a24 100644
    a b  
    3434# 
    3535# 
    3636 
    37 import os 
    3837import sys 
    3938import logging 
    4039import optparse 
     
    5150from deluge.ui.console.statusbars import StatusBars 
    5251from deluge.ui.console.eventlog import EventLog 
    5352import colors 
    54 from deluge.ui.ui import _UI 
    55 from deluge.ui.console import UI_PATH 
    56  
    5753 
    5854log = logging.getLogger(__name__) 
    5955 
    60 class Console(_UI): 
    61  
    62     help = """Starts the Deluge console interface""" 
    63  
    64     def __init__(self, *args, **kwargs): 
    65         super(Console, self).__init__("console", *args, **kwargs) 
    66         group = optparse.OptionGroup(self.parser, "Console Options","These options control how " 
    67                                      "the console connects to the daemon.  These options will be " 
    68                                      "used if you pass a command, or if you have autoconnect " 
    69                                      "enabled for the console ui.") 
    70  
    71         group.add_option("-d","--daemon",dest="daemon_addr", 
    72                          action="store",type="str",default="127.0.0.1", 
    73                          help="Set the address of the daemon to connect to." 
    74                               " [default: %default]") 
    75         group.add_option("-p","--port",dest="daemon_port", 
    76                          help="Set the port to connect to the daemon on. [default: %default]", 
    77                          action="store",type="int",default=58846) 
    78         group.add_option("-u","--username",dest="daemon_user", 
    79                          help="Set the username to connect to the daemon with. [default: %default]", 
    80                          action="store",type="string") 
    81         group.add_option("-P","--password",dest="daemon_pass", 
    82                          help="Set the password to connect to the daemon with. [default: %default]", 
    83                          action="store",type="string") 
    84         self.parser.add_option_group(group) 
    85  
    86         self.cmds = load_commands(os.path.join(UI_PATH, 'commands')) 
    87         class CommandOptionGroup(optparse.OptionGroup): 
    88             def __init__(self, parser, title, description=None, cmds = None): 
    89                 optparse.OptionGroup.__init__(self,parser,title,description) 
    90                 self.cmds = cmds 
    91  
    92             def format_help(self, formatter): 
    93                 result = formatter.format_heading(self.title) 
    94                 formatter.indent() 
    95                 if self.description: 
    96                     result += "%s\n"%formatter.format_description(self.description) 
    97                 for cname in self.cmds: 
    98                     cmd = self.cmds[cname] 
    99                     if cmd.interactive_only or cname in cmd.aliases: continue 
    100                     allnames = [cname] 
    101                     allnames.extend(cmd.aliases) 
    102                     cname = "/".join(allnames) 
    103                     result += formatter.format_heading(" - ".join([cname,cmd.__doc__])) 
    104                     formatter.indent() 
    105                     result += "%*s%s\n" % (formatter.current_indent, "", cmd.usage) 
    106                     formatter.dedent() 
    107                 formatter.dedent() 
    108                 return result 
    109         cmd_group = CommandOptionGroup(self.parser, "Console Commands", 
    110                                        description="The following commands can be issued at the " 
    111                                        "command line.  Commands should be quoted, so, for example, " 
    112                                        "to pause torrent with id 'abc' you would run: '%s " 
    113                                        "\"pause abc\"'"%os.path.basename(sys.argv[0]), 
    114                                        cmds=self.cmds) 
    115         self.parser.add_option_group(cmd_group) 
    116  
    117     def start(self, args = None): 
    118         super(Console, self).start(args) 
    119         ConsoleUI(self.args,self.cmds,(self.options.daemon_addr, 
    120                   self.options.daemon_port,self.options.daemon_user, 
    121                   self.options.daemon_pass)) 
    122  
    123 def start(): 
    124     Console().start() 
    125  
    12656class OptionParser(optparse.OptionParser): 
    12757    """subclass from optparse.OptionParser so exit() won't exit.""" 
    12858    def exit(self, status=0, msg=None): 
    def create_parser(self): 
    172102                            option_list = self.option_list) 
    173103 
    174104 
    175 def load_commands(command_dir, exclude=[]): 
    176     def get_command(name): 
    177         return getattr(__import__('deluge.ui.console.commands.%s' % name, {}, {}, ['Command']), 'Command')() 
    178  
    179     try: 
    180         commands = [] 
    181         for filename in os.listdir(command_dir): 
    182             if filename.split('.')[0] in exclude or filename.startswith('_'): 
    183                 continue 
    184             if not (filename.endswith('.py') or filename.endswith('.pyc')): 
    185                 continue 
    186             cmd = get_command(filename.split('.')[len(filename.split('.')) - 2]) 
    187             aliases = [ filename.split('.')[len(filename.split('.')) - 2] ] 
    188             aliases.extend(cmd.aliases) 
    189             for a in aliases: 
    190                 commands.append((a, cmd)) 
    191         return dict(commands) 
    192     except OSError, e: 
    193         return {} 
    194  
    195  
    196105class ConsoleUI(component.Component): 
    197106    def __init__(self, args=None, cmds = None, daemon = None): 
    198107        component.Component.__init__(self, "ConsoleUI", 2) 
  • deluge/ui/gtkui/__init__.py

    diff --git a/deluge/ui/gtkui/__init__.py b/deluge/ui/gtkui/__init__.py
    index c5a539a..5b3edba 100644
    a b  
    1 from gtkui import start 
     1from deluge.ui.ui import _UI 
     2 
     3class Gtk(_UI): 
     4 
     5    help = """Starts the Deluge GTK+ interface""" 
     6    cmdline = """A GTK-based graphical user interface""" 
     7 
     8    def __init__(self, *args, **kwargs): 
     9        super(Gtk, self).__init__("gtk", *args, **kwargs) 
     10 
     11    def start(self, args = None): 
     12        from gtkui import GtkUI 
     13        super(Gtk, self).start(args) 
     14        GtkUI(self.args) 
     15 
     16def start(): 
     17    Gtk().start() 
  • deluge/ui/gtkui/gtkui.py

    diff --git a/deluge/ui/gtkui/gtkui.py b/deluge/ui/gtkui/gtkui.py
    index 634c266..22f55c2 100644
    a b  
    7171import deluge.common 
    7272import deluge.error 
    7373 
    74 from deluge.ui.ui import _UI 
    75  
    76 class Gtk(_UI): 
    77  
    78     help = """Starts the Deluge GTK+ interface""" 
    79  
    80     def __init__(self, *args, **kwargs): 
    81         super(Gtk, self).__init__("gtk", *args, **kwargs) 
    82  
    83     def start(self, args = None): 
    84         super(Gtk, self).start(args) 
    85         GtkUI(self.args) 
    86  
    87 def start(): 
    88     Gtk().start() 
    8974 
    9075DEFAULT_PREFS = { 
    9176    "classic_mode": True, 
  • deluge/ui/web/__init__.py

    diff --git a/deluge/ui/web/__init__.py b/deluge/ui/web/__init__.py
    index 28f53f2..a1ad237 100644
    a b  
    1 from web import start 
    2  No newline at end of file 
     1from web import Web 
     2 
     3def start():  
     4    Web().start() 
  • deluge/ui/web/web.py

    diff --git a/deluge/ui/web/web.py b/deluge/ui/web/web.py
    index 6ecbdfc..f862ebf 100644
    a b def __init__(self, args): 
    4848class Web(_UI): 
    4949 
    5050    help = """Starts the Deluge web interface""" 
     51    cmdline = """A web-based interface (http://localhost:8112)""" 
    5152 
    5253    def __init__(self, *args, **kwargs): 
    5354        super(Web, self).__init__("web", *args, **kwargs) 
  • setup.py

    diff --git a/setup.py b/setup.py
    index 5a55d42..6960ac4 100644
    a b def run(self): 
    515515    "gui_scripts": [ 
    516516        "deluge = deluge.main:start_ui", 
    517517        "deluge-gtk = deluge.ui.gtkui:start" 
    518     ] 
     518    ],  
     519    "deluge.ui" : [ 
     520        "console = deluge.ui.console:Console",  
     521        "web = deluge.ui.web:Web",  
     522        "gtk = deluge.ui.gtkui:Gtk",  
     523    ], 
    519524} 
    520525 
    521526