Fix up the console ui so that command-line options work again.. Also,

use the new UI class for the 'deluge-console' script.
This commit is contained in:
Andrew Resch 2009-05-18 21:35:16 +00:00
parent 56735452a8
commit c4a247018b
14 changed files with 141 additions and 54 deletions

View File

@ -22,3 +22,4 @@
# Boston, MA 02110-1301, USA.
#
UI_PATH = __path__[0]
from main import start

View File

@ -93,6 +93,17 @@ def replace_tabs(line):
line = line.replace("\t", " " * tab_length, 1)
return line
def strip_colors(line):
"""
Returns a string with the color formatting removed.
"""
# Remove all the color tags
while line.find("{!") != -1:
line = line[:line.find("{!")] + line[line.find("!}") + 2:]
return line
def get_line_length(line):
"""
Returns the string length without the color formatting.
@ -102,8 +113,7 @@ def get_line_length(line):
raise BadColorString("Number of {! is not equal to number of !}")
# Remove all the color tags
while line.find("{!") != -1:
line = line[:line.find("{!")] + line[line.find("!}") + 2:]
line = strip_colors(line)
# Replace tabs with the appropriate amount of spaces
line = replace_tabs(line)

View File

@ -22,6 +22,8 @@
# 51 Franklin Street, Fifth Floor
# Boston, MA 02110-1301, USA.
#
from twisted.internet import defer
from deluge.ui.console.main import BaseCommand
import deluge.ui.console.colors as colors
from deluge.ui.client import client
@ -47,6 +49,8 @@ class Command(BaseCommand):
if options["path"]:
t_options["download_location"] = options["path"]
# Keep a list of deferreds to make a DeferredList
deferreds = []
for arg in args:
if not os.path.isfile(arg):
self.console.write("{!error!}This is a directory!")
@ -60,7 +64,9 @@ class Command(BaseCommand):
def on_fail(result):
self.console.write("{!error!}Torrent was not added! %s" % result)
client.core.add_torrent_file(filename, filedump, t_options).addCallback(on_success).addErrback(on_fail)
deferreds.append(client.core.add_torrent_file(filename, filedump, t_options).addCallback(on_success).addErrback(on_fail))
return defer.DeferredList(deferreds)
def complete(self, line):
line = os.path.abspath(os.path.expanduser(line))

View File

@ -23,6 +23,8 @@
# Boston, MA 02110-1301, USA.
#
from twisted.internet import defer
from deluge.ui.console.main import BaseCommand
import deluge.ui.console.colors as colors
from deluge.ui.client import client
@ -63,7 +65,7 @@ def simple_eval(source):
taken from http://effbot.org/zone/simple-iterator-parser.htm"""
src = cStringIO.StringIO(source).readline
src = tokenize.generate_tokens(src)
src = (token for token in src if token[0] is not tokenize.NL)
src = (token for token in src if token[0] is not tokenize.NL37)
res = atom(src.next, src.next())
if src.next()[0] is not tokenize.ENDMARKER:
raise SyntaxError("bogus data after expression")
@ -83,13 +85,14 @@ class Command(BaseCommand):
def handle(self, *args, **options):
self.console = component.get("ConsoleUI")
if options['set']:
self._set_config(*args, **options)
return self._set_config(*args, **options)
else:
self._get_config(*args, **options)
return self._get_config(*args, **options)
def _get_config(self, *args, **options):
deferred = defer.Deferred()
def on_get_config(result):
config = component.get("CoreConfig")
keys = config.keys()
keys.sort()
s = ""
@ -113,8 +116,16 @@ class Command(BaseCommand):
s += " %s: %s%s\n" % (key, color, value)
self.console.write(s)
deferred.callback(True)
return config
# We need to ensure the config dict has been received first
component.get("CoreConfig").start_defer.addCallback(on_get_config)
return deferred
def _set_config(self, *args, **options):
deferred = defer.Deferred()
config = component.get("CoreConfig")
key = args[0]
if key not in config.keys():
@ -132,7 +143,10 @@ class Command(BaseCommand):
def on_set_config(result):
self.console.write("{!success!}Configuration value successfully updated.")
deferred.callback(True)
client.core.set_config({key: val}).addCallback(on_set_config)
return deferred
def complete(self, text):
return [ k for k in component.get("CoreConfig").keys() if k.startswith(text) ]

View File

@ -42,3 +42,4 @@ class Command(BaseCommand):
d.addCallback(on_connect)
d.addErrback(on_connect_fail)
return d

View File

@ -22,6 +22,9 @@
# 51 Franklin Street, Fifth Floor
# Boston, MA 02110-1301, USA.
#
from twisted.internet import defer
from deluge.ui.console.main import BaseCommand
from deluge.ui.client import client
import deluge.ui.console.colors as colors
@ -39,5 +42,7 @@ class Command(BaseCommand):
else:
component.get("ConsoleUI").write("{!error!}%s" % usage)
return defer.succeed(True)
def complete(self, text):
return [x for x in ['on', 'off'] if x.startswith(text)]

View File

@ -38,4 +38,4 @@ class Command(BaseCommand):
def on_shutdown_fail(reason):
self.write("{!error!}Unable to shutdown daemon: %s" % reason)
client.daemon.shutdown().addCallback(on_shutdown).addErrback(on_shutdown_fail)
return client.daemon.shutdown().addCallback(on_shutdown).addErrback(on_shutdown_fail)

View File

@ -1,4 +1,3 @@
#
# help.py
#
# Copyright (C) 2008-2009 Ido Abramovich <ido.deluge@gmail.com>
@ -22,6 +21,9 @@
# 51 Franklin Street, Fifth Floor
# Boston, MA 02110-1301, USA.
#
from twisted.internet import defer
from deluge.ui.console.main import BaseCommand
import deluge.ui.console.colors as colors
import deluge.component as component
@ -34,15 +36,16 @@ class Command(BaseCommand):
def handle(self, *args, **options):
self.console = component.get("ConsoleUI")
self._commands = self.console._commands
deferred = defer.succeed(True)
if args:
if len(args) > 1:
self.console.write(usage)
return
return deferred
try:
cmd = self._commands[args[0]]
except KeyError:
self.console.write("{!error!}Unknown command %r" % args[0])
return
return deferred
try:
parser = cmd.create_parser()
self.console.write(parser.format_help())
@ -55,5 +58,7 @@ class Command(BaseCommand):
self.console.write(" ")
self.console.write('For help on a specific command, use "<command> --help"')
return deferred
def complete(self, line):
return [x for x in component.get("ConsoleUI")._commands if x.startswith(line)]

View File

@ -110,6 +110,7 @@ class Command(BaseCommand):
d = client.core.get_torrents_status({"id": torrent_ids}, status_keys)
d.addCallback(on_torrents_status)
d.addErrback(on_torrents_status_fail)
return d
def show_info(self, torrent_id, status, verbose=False):
"""

View File

@ -45,7 +45,7 @@ class Command(BaseCommand):
torrent_ids.extend(self.console.match_torrent(arg))
if torrent_ids:
client.core.pause_torrent(torrent_ids)
return client.core.pause_torrent(torrent_ids)
def complete(self, line):
# We use the ConsoleUI torrent tab complete method

View File

@ -33,6 +33,6 @@ class Command(BaseCommand):
if client.connected():
def on_disconnect(result):
reactor.stop()
client.disconnect().addCallback(on_disconnect)
return client.disconnect().addCallback(on_disconnect)
else:
reactor.stop()

View File

@ -22,6 +22,7 @@
# 51 Franklin Street, Fifth Floor
# Boston, MA 02110-1301, USA.
#
from deluge.ui.console.main import BaseCommand
from deluge.ui.client import client
import deluge.ui.console.colors as colors
@ -45,7 +46,7 @@ class Command(BaseCommand):
torrent_ids.extend(self.console.match_torrent(arg))
if torrent_ids:
client.core.resume_torrent(torrent_ids)
return client.core.resume_torrent(torrent_ids)
def complete(self, line):
# We use the ConsoleUI torrent tab complete method

View File

@ -49,7 +49,7 @@ class Command(BaseCommand):
for arg in args:
torrent_ids.extend(self.console.match_torrent(arg))
client.core.remove_torrent(torrent_ids, options['remove_data'])
return client.core.remove_torrent(torrent_ids, options['remove_data'])
def complete(self, line):
# We use the ConsoleUI torrent tab complete method

View File

@ -36,9 +36,30 @@ import deluge.common
from deluge.ui.coreconfig import CoreConfig
from deluge.ui.console.statusbars import StatusBars
from deluge.ui.console.eventlog import EventLog
import deluge.ui.console.screen as screen
import deluge.ui.console.colors as colors
import screen
import colors
from deluge.log import LOG as log
from deluge.ui.ui import _UI
class Console(_UI):
help = """Starts the Deluge console interface"""
def __init__(self):
super(Console, self).__init__("console")
cmds = load_commands(os.path.join(UI_PATH, 'commands'))
group = optparse.OptionGroup(self.parser, "Console Commands",
"\n".join(cmds.keys()))
self.parser.add_option_group(group)
def start(self):
super(Console, self).start()
ConsoleUI(self.args)
def start():
Console().start()
class OptionParser(optparse.OptionParser):
"""subclass from optparse.OptionParser so exit() won't exit."""
@ -108,27 +129,42 @@ class ConsoleUI(component.Component):
# Load all the commands
self._commands = load_commands(os.path.join(UI_PATH, 'commands'))
# Try to connect to the localhost daemon
def on_connect(result):
component.start()
client.connect().addCallback(on_connect)
# Set the interactive flag to indicate where we should print the output
self.interactive = True
if args:
args = args[0]
self.interactive = False
# Try to connect to the localhost daemon
def on_connect(result):
component.start()
if not self.interactive:
def on_started(result):
deferreds = []
# If we have args, lets process them and quit
# allow multiple commands split by ";"
for arg in args.split(";"):
self.do_command(arg)
sys.exit(0)
deferreds.append(self.do_command(arg.strip()))
def on_complete(result):
self.do_command("quit")
dl = defer.DeferredList(deferreds).addCallback(on_complete)
# We need to wait for the rpcs in start() to finish before processing
# any of the commands.
self.started_deferred.addCallback(on_started)
client.connect().addCallback(on_connect)
self.coreconfig = CoreConfig()
if self.interactive:
# We use the curses.wrapper function to prevent the console from getting
# messed up if an uncaught exception is experienced.
import curses.wrapper
curses.wrapper(self.run)
else:
reactor.run()
def run(self, stdscr):
"""
@ -157,12 +193,16 @@ class ConsoleUI(component.Component):
reactor.run()
def start(self):
# This gets fired once we have received the torrents list from the core
self.started_deferred = defer.Deferred()
# Maintain a list of (torrent_id, name) for use in tab completion
self.torrents = []
def on_session_state(result):
def on_torrents_status(torrents):
for torrent_id, status in torrents.items():
self.torrents.append((torrent_id, status["name"]))
self.started_deferred.callback(True)
client.core.get_torrents_status({"id": result}, ["name"]).addCallback(on_torrents_status)
client.core.get_session_state().addCallback(on_session_state)
@ -184,7 +224,7 @@ class ConsoleUI(component.Component):
if self.interactive:
self.screen.add_line(line)
else:
print(line)
print(colors.strip_colors(line))
def do_command(self, cmd):
"""
@ -215,12 +255,15 @@ class ConsoleUI(component.Component):
options, args = parser.parse_args(args)
if not getattr(options, '_exit', False):
try:
self._commands[cmd].handle(*args, **options.__dict__)
ret = self._commands[cmd].handle(*args, **options.__dict__)
except Exception, e:
self.write("{!error!}" + str(e))
log.exception(e)
import traceback
self.write("%s" % traceback.format_exc())
return defer.succeed(True)
else:
return ret
def tab_completer(self, line, cursor, second_hit):
"""