Fix up some commands

This commit is contained in:
Andrew Resch 2009-04-21 02:43:20 +00:00
parent 9da95552f3
commit c17af41940
13 changed files with 222 additions and 160 deletions

View File

@ -50,6 +50,15 @@ schemes = {
"event": ("magenta", "black", "bold") "event": ("magenta", "black", "bold")
} }
# Colors for various torrent states
state_color = {
"Seeding": "{{blue,black,bold}}",
"Downloading": "{{green,black,bold}}",
"Paused": "{{white,black}}",
"Checking": "{{green,black}}",
"Queued": "{{yellow,black}}",
"Error": "{{red,black,bold}}"
}
def init_colors(): def init_colors():
# Create the color_pairs dict # Create the color_pairs dict
@ -65,6 +74,19 @@ def init_colors():
class BadColorString(Exception): class BadColorString(Exception):
pass pass
def get_line_length(line):
"""
Returns the string length without the color formatting.
"""
if line.count("{{") != line.count ("}}"):
raise BadColorString("Number of {{ does not equal number of }}")
while line.find("{{") != -1:
line = line[:line.find("{{")] + line[line.find("}}") + 2:]
return len(line)
def parse_color_string(s): def parse_color_string(s):
""" """
Parses a string and returns a list of 2-tuples (color, string). Parses a string and returns a list of 2-tuples (color, string).
@ -72,6 +94,9 @@ def parse_color_string(s):
:param s:, string to parse :param s:, string to parse
""" """
if s.count("{{") != s.count ("}}"):
raise BadColorString("Number of {{ does not equal number of }}")
ret = [] ret = []
# Keep track of where the strings # Keep track of where the strings
col_index = 0 col_index = 0

View File

@ -22,10 +22,11 @@
# 51 Franklin Street, Fifth Floor # 51 Franklin Street, Fifth Floor
# Boston, MA 02110-1301, USA. # Boston, MA 02110-1301, USA.
# #
from deluge.ui.console.main import BaseCommand, match_torrents from deluge.ui.console.main import BaseCommand
from deluge.ui.console import mapping
import deluge.ui.console.colors as colors import deluge.ui.console.colors as colors
from deluge.ui.client import client from deluge.ui.client import client
import deluge.component as component
from optparse import make_option from optparse import make_option
import os import os
import base64 import base64
@ -40,18 +41,20 @@ class Command(BaseCommand):
usage = "Usage: add [-p <save-location>] <torrent-file> [<torrent-file> ...]" usage = "Usage: add [-p <save-location>] <torrent-file> [<torrent-file> ...]"
def handle(self, *args, **options): def handle(self, *args, **options):
self.console = component.get("ConsoleUI")
t_options = {} t_options = {}
if options["path"]: if options["path"]:
t_options["download_location"] = options["path"] t_options["download_location"] = options["path"]
for arg in args: for arg in args:
self.write("{{info}}Attempting to add torrent: %s" % arg) self.console.write("{{info}}Attempting to add torrent: %s" % arg)
filename = os.path.split(arg)[-1] filename = os.path.split(arg)[-1]
filedump = base64.encodestring(open(arg).read()) filedump = base64.encodestring(open(arg).read())
def on_success(result): def on_success(result):
self.write("{{success}}Torrent added!") self.console.write("{{success}}Torrent added!")
def on_fail(result): def on_fail(result):
self.write("{{error}}Torrent was not added! %s" % 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) client.core.add_torrent_file(filename, filedump, t_options).addCallback(on_success).addErrback(on_fail)

View File

@ -1,4 +1,3 @@
#!/usr/bin/env python
# #
# connect.py # connect.py
# #
@ -25,17 +24,20 @@
from deluge.ui.console.main import BaseCommand from deluge.ui.console.main import BaseCommand
import deluge.ui.console.colors as colors import deluge.ui.console.colors as colors
from deluge.ui.client import client from deluge.ui.client import client
import deluge.component as component
class Command(BaseCommand): class Command(BaseCommand):
"""Connect to a new deluge server.""" """Connect to a new deluge server."""
def handle(self, host='localhost', port='58846', username="", password="", **options): def handle(self, host="", port="58846", username="", password="", **options):
self.console = component.get("ConsoleUI")
port = int(port) port = int(port)
d = client.connect(host, port, username, password) d = client.connect(host, port, username, password)
def on_connect(result): def on_connect(result):
print templates.SUCCESS('Connected to %s:%d!' % (host, port)) self.console.write("{{success}}Connected to %s:%s!" % (host, port))
def on_connect_fail(result): def on_connect_fail(result):
print templates.ERROR("Failed to connect to %s:%d!" % (host, port)) self.console.write("{{error}}Failed to connect to %s:%s!" % (host, port))
d.addCallback(on_connect) d.addCallback(on_connect)
d.addErrback(on_connect_fail) d.addErrback(on_connect_fail)

View File

@ -1,8 +1,8 @@
#!/usr/bin/env python
# #
# halt.py # halt.py
# #
# Copyright (C) 2008-2009 Ido Abramovich <ido.deluge@gmail.com> # Copyright (C) 2008-2009 Ido Abramovich <ido.deluge@gmail.com>
# Copyright (C) 2009 Andrew Resch <andrewresch@gmail.com>
# #
# Deluge is free software. # Deluge is free software.
# #
@ -22,12 +22,20 @@
# 51 Franklin Street, Fifth Floor # 51 Franklin Street, Fifth Floor
# Boston, MA 02110-1301, USA. # Boston, MA 02110-1301, USA.
# #
from deluge.ui.console.main import BaseCommand, match_torrents from deluge.ui.console.main import BaseCommand
from deluge.ui.console import mapping
import deluge.ui.console.colors as colors import deluge.ui.console.colors as colors
from deluge.ui.client import client from deluge.ui.client import client
import deluge.component as component
class Command(BaseCommand): class Command(BaseCommand):
"Shutdown the deluge server." "Shutdown the deluge server."
def handle(self, **options): def handle(self, **options):
client.daemon.shutdown(None) self.console = component.get("ConsoleUI")
def on_shutdown(result):
self.write("{{success}}Daemon was shutdown")
def on_shutdown_fail(reason):
self.write("{{error}}Unable to shutdown daemon: %s" % reason)
client.daemon.shutdown().addCallback(on_shutdown).addErrback(on_shutdown_fail)

View File

@ -1,8 +1,8 @@
#!/usr/bin/env python
# #
# help.py # help.py
# #
# Copyright (C) 2008-2009 Ido Abramovich <ido.deluge@gmail.com> # Copyright (C) 2008-2009 Ido Abramovich <ido.deluge@gmail.com>
# Copyright (C) 2009 Andrew Resch <andrewresch@gmail.com>
# #
# Deluge is free software. # Deluge is free software.
# #
@ -22,46 +22,44 @@
# 51 Franklin Street, Fifth Floor # 51 Franklin Street, Fifth Floor
# Boston, MA 02110-1301, USA. # Boston, MA 02110-1301, USA.
# #
from deluge.ui.console import UI_PATH from deluge.ui.console.main import BaseCommand
from deluge.ui.console.main import BaseCommand, load_commands
import deluge.ui.console.colors as colors import deluge.ui.console.colors as colors
#from deluge.ui.console.colors import templates import deluge.component as component
import os
class Command(BaseCommand): class Command(BaseCommand):
"""displays help on other commands""" """displays help on other commands"""
usage = "Usage: help [command]" usage = "Usage: help [command]"
def __init__(self): # def __init__(self):
BaseCommand.__init__(self) # BaseCommand.__init__(self)
# get a list of commands, exclude 'help' so we won't run into a recursive loop. # get a list of commands, exclude 'help' so we won't run into a recursive loop.
self._commands = load_commands(os.path.join(UI_PATH,'commands'), None, exclude=['help']) #self._commands = load_commands(os.path.join(UI_PATH,'commands'), None, exclude=['help'])
self._commands['help'] = self
# self._commands['help'] = self
def handle(self, *args, **options): def handle(self, *args, **options):
self.console = component.get("ConsoleUI")
self._commands = self.console._commands
if args: if args:
if len(args) > 1: if len(args) > 1:
#print usage #print usage
self.write(usage) self.console.write(usage)
return return
try: try:
cmd = self._commands[args[0]] cmd = self._commands[args[0]]
except KeyError: except KeyError:
#print templates.ERROR('unknown command %r' % args[0]) #print templates.ERROR('unknown command %r' % args[0])
self.write("{{error}}Unknown command %r" % args[0]) self.console.write("{{error}}Unknown command %r" % args[0])
return return
try: try:
parser = cmd.create_parser() parser = cmd.create_parser()
self.write(parser.format_help()) self.console.write(parser.format_help())
except AttributeError, e: except AttributeError, e:
self.write(cmd.__doc__ or 'No help for this command') self.console.write(cmd.__doc__ or 'No help for this command')
else: else:
max_length = max( len(k) for k in self._commands) max_length = max( len(k) for k in self._commands)
for cmd in sorted(self._commands): for cmd in sorted(self._commands):
self.write("{{info}}" + cmd + "{{input}} - " + self._commands[cmd].__doc__ or '') self.console.write("{{info}}" + cmd + "{{input}} - " + self._commands[cmd].__doc__ or '')
self.write("") self.console.write("")
self.write('For help on a specific command, use "<command> --help"') self.console.write('For help on a specific command, use "<command> --help"')
def complete(self, text, *args):
return [ x for x in self._commands.keys() if x.startswith(text) ]

View File

@ -1,8 +1,8 @@
#!/usr/bin/env python
# #
# info.py # info.py
# #
# Copyright (C) 2008-2009 Ido Abramovich <ido.deluge@gmail.com> # Copyright (C) 2008-2009 Ido Abramovich <ido.deluge@gmail.com>
# Copyright (C) 2009 Andrew Resch <andrewresch@gmail.com>
# #
# Deluge is free software. # Deluge is free software.
# #
@ -23,13 +23,13 @@
# Boston, MA 02110-1301, USA. # Boston, MA 02110-1301, USA.
# #
from deluge.ui.console.main import BaseCommand, match_torrents from optparse import make_option
from deluge.ui.console import mapping
from deluge.ui.console.main import BaseCommand
import deluge.ui.console.colors as colors import deluge.ui.console.colors as colors
#from deluge.ui.console.colors import templates
from deluge.ui.client import client from deluge.ui.client import client
import deluge.common as common import deluge.common as common
from optparse import make_option import deluge.component as component
status_keys = ["state", status_keys = ["state",
"save_path", "save_path",
@ -73,25 +73,58 @@ class Command(BaseCommand):
def handle(self, *args, **options): def handle(self, *args, **options):
def on_to_ids(result): self.console = component.get("ConsoleUI")
def on_match_torrents(torrents): # Compile a list of torrent_ids to request the status of
for torrent in torrents: torrent_ids = []
self.show_info(torrent, options.get("verbose")) for arg in args:
torrent_ids.extend(self.console.match_torrent(arg))
match_torrents(result).addCallback(on_match_torrents) def on_torrents_status(status):
mapping.to_ids(args).addCallback(on_to_ids) # Print out the information for each torrent
for key, value in status.items():
self.show_info(key, value, options["verbose"])
# def complete(self, text, *args): def on_torrents_status_fail(reason):
# torrents = match_torrents() self.console.write("{{error}}Error getting torrent info: %s" % reason)
# names = mapping.get_names(torrents)
# return [ x[1] for x in names if x[1].startswith(text) ]
def show_info(self, torrent, verbose): d = client.core.get_torrents_status({"id": torrent_ids}, status_keys)
d.addCallback(on_torrents_status)
d.addErrback(on_torrents_status_fail)
def show_info(self, torrent_id, status, verbose=False):
"""
Writes out the torrents information to the screen.
:param torrent_id: str, the torrent_id
:param status: dict, the torrents status, this should have the same keys
as status_keys
:param verbose: bool, if true, we print out more information about the
the torrent
"""
self.console.write(" ")
self.console.write("{{info}}Name: {{input}}%s" % (status["name"]))
self.console.write("{{info}}ID: {{input}}%s" % (torrent_id))
s = "{{info}}State: %s%s" % (colors.state_color[status["state"]], status["state"])
# Only show speed if active
if status["state"] in ("Seeding", "Downloading"):
if status["state"] != "Seeding":
s += " {{info}}Down Speed: {{input}}%s" % common.fspeed(status["download_payload_rate"])
s += " {{info}}Up Speed: {{input}}%s" % common.fspeed(status["upload_payload_rate"])
if common.ftime(status["eta"]):
s += " {{info}}ETA: {{input}}%s" % common.ftime(status["eta"])
self.console.write(s)
s = "{{info}}Seeds: {{input}}%s (%s)" % (status["num_seeds"], status["total_seeds"])
s += " {{info}}Peers: {{input}}%s (%s)" % (status["num_peers"], status["total_peers"])
s += " {{info}}Ratio: {{input}}%.3f" % status["ratio"]
s += " {{info}}Availibility: {{input}}%.2f" % status["distributed_copies"]
self.console.write(s)
""" def __show_info(self, torrent, verbose):
def _got_torrent_status(state): def _got_torrent_status(state):
print templates.info_general('ID', torrent)
print templates.info_general('Name', state['name'])
#self._mapping[state['name']] = torrent # update mapping
print templates.info_general('Path', state['save_path'])
if verbose or not state['is_seed']: if verbose or not state['is_seed']:
print templates.info_transfers("Completed", common.fsize(state['total_done']) + "/" + common.fsize(state['total_size'])) print templates.info_transfers("Completed", common.fsize(state['total_done']) + "/" + common.fsize(state['total_size']))
@ -129,3 +162,4 @@ class Command(BaseCommand):
str(common.fspeed(peer['up_speed'])), str(common.fspeed(peer['down_speed']))) str(common.fspeed(peer['up_speed'])), str(common.fspeed(peer['down_speed'])))
print "" print ""
client.core.get_torrent_status(torrent, status_keys).addCallback(_got_torrent_status) client.core.get_torrent_status(torrent, status_keys).addCallback(_got_torrent_status)
"""

View File

@ -1,8 +1,8 @@
#!/usr/bin/env python
# #
# pause.py # pause.py
# #
# Copyright (C) 2008-2009 Ido Abramovich <ido.deluge@gmail.com> # Copyright (C) 2008-2009 Ido Abramovich <ido.deluge@gmail.com>
# Copyright (C) 2009 Andrew Resch <andrewresch@gmail.com>
# #
# Deluge is free software. # Deluge is free software.
# #
@ -22,30 +22,27 @@
# 51 Franklin Street, Fifth Floor # 51 Franklin Street, Fifth Floor
# Boston, MA 02110-1301, USA. # Boston, MA 02110-1301, USA.
# #
from deluge.ui.console.main import BaseCommand, match_torrents from deluge.ui.console.main import BaseCommand
from deluge.ui.console import mapping
from deluge.ui.client import client from deluge.ui.client import client
import deluge.ui.console.colors as colors import deluge.ui.console.colors as colors
import deluge.component as component
class Command(BaseCommand): class Command(BaseCommand):
"""Pause a torrent""" """Pause a torrent"""
usage = "Usage: pause [ all | <torrent-id> [<torrent-id> ...] ]" usage = "Usage: pause [ * | <torrent-id> [<torrent-id> ...] ]"
def handle(self, *args, **options): def handle(self, *args, **options):
if len(args) == 0: self.console = component.get("ConsoleUI")
print self.usage
return
if len(args) == 1 and args[0] == 'all':
args = tuple() # empty tuple means everything
try:
args = mapping.to_ids(args)
torrents = match_torrents(args)
client.pause_torrent(torrents)
except Exception, msg:
print templates.ERROR(str(msg))
else:
print templates.SUCCESS('torrent%s successfully paused' % ('s' if len(args) > 1 else ''))
def complete(self, text, *args): if len(args) == 0:
torrents = match_torrents() self.console.write(self.usage)
names = mapping.get_names(torrents) return
return [ x[1] for x in names if x[1].startswith(text) ] if len(args) > 0 and args[0].lower() == '*':
client.core.pause_all_torrents()
return
torrent_ids = []
for arg in args:
torrent_ids.extend(self.console.match_torrent(arg))
if torrent_ids:
client.core.pause_torrent(torrent_ids)

View File

@ -34,3 +34,5 @@ class Command(BaseCommand):
def on_disconnect(result): def on_disconnect(result):
reactor.stop() reactor.stop()
client.disconnect().addCallback(on_disconnect) client.disconnect().addCallback(on_disconnect)
else:
reactor.stop()

View File

@ -1,8 +1,8 @@
#!/usr/bin/env python
# #
# resume.py # resume.py
# #
# Copyright (C) 2008-2009 Ido Abramovich <ido.deluge@gmail.com> # Copyright (C) 2008-2009 Ido Abramovich <ido.deluge@gmail.com>
# Copyright (C) 2009 Andrew Resch <andrewresch@gmail.com>
# #
# Deluge is free software. # Deluge is free software.
# #
@ -22,30 +22,27 @@
# 51 Franklin Street, Fifth Floor # 51 Franklin Street, Fifth Floor
# Boston, MA 02110-1301, USA. # Boston, MA 02110-1301, USA.
# #
from deluge.ui.console.main import BaseCommand, match_torrents from deluge.ui.console.main import BaseCommand
from deluge.ui.console import mapping
from deluge.ui.client import client from deluge.ui.client import client
import deluge.ui.console.colors as colors import deluge.ui.console.colors as colors
import deluge.component as component
class Command(BaseCommand): class Command(BaseCommand):
"""Resume a torrent""" """Resume a torrent"""
usage = "Usage: resume [ all | <torrent-id> [<torrent-id> ...] ]" usage = "Usage: resume [ * | <torrent-id> [<torrent-id> ...] ]"
def handle(self, *args, **options): def handle(self, *args, **options):
if len(args) == 0: self.console = component.get("ConsoleUI")
print self.usage
return
if len(args) == 1 and args[0] == 'all':
args = tuple() # empty tuple means everything
try:
args = mapping.to_ids(args)
torrents = match_torrents(args)
client.resume_torrent(torrents)
except Exception, msg:
print templates.ERROR(str(msg))
else:
print templates.SUCCESS('torrent%s successfully resumed' % ('s' if len(args) > 1 else ''))
def complete(self, text, *args): if len(args) == 0:
torrents = match_torrents() self.console.write(self.usage)
names = mapping.get_names(torrents) return
return [ x[1] for x in names if x[1].startswith(text) ] if len(args) > 0 and args[0] == '*':
client.core.resume_all_torrents()
return
torrent_ids = []
for arg in args:
torrent_ids.extend(self.console.match_torrent(arg))
if torrent_ids:
client.core.resume_torrent(torrent_ids)

View File

@ -1,8 +1,8 @@
#!/usr/bin/env python
# #
# rm.py # rm.py
# #
# Copyright (C) 2008-2009 Ido Abramovich <ido.deluge@gmail.com> # Copyright (C) 2008-2009 Ido Abramovich <ido.deluge@gmail.com>
# Copyright (C) 2009 Andrew Resch <andrewresch@gmail.com>
# #
# Deluge is free software. # Deluge is free software.
# #
@ -22,12 +22,13 @@
# 51 Franklin Street, Fifth Floor # 51 Franklin Street, Fifth Floor
# Boston, MA 02110-1301, USA. # Boston, MA 02110-1301, USA.
# #
from deluge.ui.console.main import BaseCommand, match_torrents from deluge.ui.console.main import BaseCommand
from deluge.ui.console import mapping
import deluge.ui.console.colors as colors import deluge.ui.console.colors as colors
from deluge.ui.client import client from deluge.ui.client import client
import deluge.component as component
from optparse import make_option from optparse import make_option
import os
class Command(BaseCommand): class Command(BaseCommand):
"""Remove a torrent""" """Remove a torrent"""
@ -40,14 +41,12 @@ class Command(BaseCommand):
) )
def handle(self, *args, **options): def handle(self, *args, **options):
try: self.console = component.get("ConsoleUI")
args = mapping.to_ids(args) if len(args) == 0:
torrents = match_torrents(args) self.console.write(usage)
client.remove_torrent(torrents, options['remove_data'])
except Exception, msg:
print template.ERROR(str(msg))
def complete(self, text, *args): torrent_ids = []
torrents = match_torrents() for arg in args:
names = mapping.get_names(torrents) torrent_ids.extend(self.console.match_torrent(arg))
return [ x[1] for x in names if x[1].startswith(text) ]
client.core.remove_torrent(torrent_ids, options['remove_data'])

View File

@ -25,6 +25,7 @@
import deluge.component as component import deluge.component as component
import deluge.common import deluge.common
import colors
from deluge.ui.client import client from deluge.ui.client import client
from deluge.log import LOG as log from deluge.log import LOG as log
@ -58,16 +59,8 @@ class EventLog(component.Component):
def on_torrent_state_changed_event(self, torrent_id, state): def on_torrent_state_changed_event(self, torrent_id, state):
log.debug("on_torrent_state_changed_event!") log.debug("on_torrent_state_changed_event!")
# Modify the state string color # Modify the state string color
state_color = { if state in colors.state_color:
"Seeding": "{{blue,black,bold}}", state = colors.state_color[state] + state
"Downloading": "{{green,black,bold}}",
"Paused": "{{white,black}}",
"Checking": "{{green,black}}",
"Queued": "{{yellow,black}}",
"Error": "{{red,black,bold}}"
}
if state in state_color:
state = state_color[state] + state
self.console.write("{{event}}* TorrentStateChanged: %s {{info}}%s (%s)" % self.console.write("{{event}}* TorrentStateChanged: %s {{info}}%s (%s)" %
(state, self.console.get_torrent_name(torrent_id), torrent_id)) (state, self.console.get_torrent_name(torrent_id), torrent_id))

View File

@ -25,6 +25,10 @@
import os, sys import os, sys
import optparse import optparse
import shlex
from twisted.internet import defer, reactor
from deluge.ui.console import UI_PATH from deluge.ui.console import UI_PATH
import deluge.component as component import deluge.component as component
from deluge.ui.client import client from deluge.ui.client import client
@ -32,14 +36,14 @@ import deluge.common
from deluge.ui.coreconfig import CoreConfig from deluge.ui.coreconfig import CoreConfig
from deluge.ui.console.statusbars import StatusBars from deluge.ui.console.statusbars import StatusBars
from deluge.ui.console.eventlog import EventLog from deluge.ui.console.eventlog import EventLog
import deluge.ui.console.screen as screen
from twisted.internet import defer, reactor import deluge.ui.console.colors as colors
import shlex
import screen
import colors
from deluge.log import LOG as log from deluge.log import LOG as log
# XXX: Remove when the commands are all fixed up
def match_torrents(a=[]):
pass
class OptionParser(optparse.OptionParser): class OptionParser(optparse.OptionParser):
"""subclass from optparse.OptionParser so exit() won't exit.""" """subclass from optparse.OptionParser so exit() won't exit."""
def exit(self, status=0, msg=None): def exit(self, status=0, msg=None):
@ -62,7 +66,6 @@ class BaseCommand(object):
option_list = tuple() option_list = tuple()
aliases = [] aliases = []
def complete(self, text, *args): def complete(self, text, *args):
return [] return []
def handle(self, *args, **options): def handle(self, *args, **options):
@ -85,24 +88,7 @@ class BaseCommand(object):
epilog = self.epilog, epilog = self.epilog,
option_list = self.option_list) option_list = self.option_list)
def load_commands(command_dir, exclude=[]):
def match_torrents(array=[]):
# Make sure we don't have any duplicates
array = set(array)
# We return this defer and it will be fired once we received the session
# state and intersect the data.
d = defer.Deferred()
def _got_session_state(tors):
if not array:
d.callback(tors)
d.callback(list(tors.intersection(array)))
client.core.get_session_state().addCallback(_got_session_state)
return d
def load_commands(command_dir, write_func, exclude=[]):
def get_command(name): def get_command(name):
return getattr(__import__('deluge.ui.console.commands.%s' % name, {}, {}, ['Command']), 'Command')() return getattr(__import__('deluge.ui.console.commands.%s' % name, {}, {}, ['Command']), 'Command')()
@ -112,8 +98,6 @@ def load_commands(command_dir, write_func, exclude=[]):
if filename.split('.')[0] in exclude or filename.startswith('_') or not filename.endswith('.py'): if filename.split('.')[0] in exclude or filename.startswith('_') or not filename.endswith('.py'):
continue continue
cmd = get_command(filename[:-3]) cmd = get_command(filename[:-3])
# Hack to give the commands a write function
cmd.write = write_func
aliases = [ filename[:-3] ] aliases = [ filename[:-3] ]
aliases.extend(cmd.aliases) aliases.extend(cmd.aliases)
for a in aliases: for a in aliases:
@ -126,7 +110,7 @@ class ConsoleUI(component.Component):
def __init__(self, args=None): def __init__(self, args=None):
component.Component.__init__(self, "ConsoleUI", 2) component.Component.__init__(self, "ConsoleUI", 2)
# Load all the commands # Load all the commands
self._commands = load_commands(os.path.join(UI_PATH, 'commands'), self.write) self._commands = load_commands(os.path.join(UI_PATH, 'commands'))
# Try to connect to the localhost daemon # Try to connect to the localhost daemon
def on_connect(result): def on_connect(result):
@ -236,10 +220,11 @@ class ConsoleUI(component.Component):
if not getattr(options, '_exit', False): if not getattr(options, '_exit', False):
try: try:
self._commands[cmd].handle(*args, **options.__dict__) self._commands[cmd].handle(*args, **options.__dict__)
except StopIteration, e:
raise
except Exception, e: except Exception, e:
self.write("{{error}}" + str(e)) self.write("{{error}}" + str(e))
log.exception(e)
import traceback
self.write("%s" % traceback.format_exc())
def tab_completer(self, line, cursor, second_hit): def tab_completer(self, line, cursor, second_hit):
""" """
@ -330,9 +315,27 @@ class ConsoleUI(component.Component):
return None return None
def match_torrent(self, string):
"""
Returns a list of torrent_id matches for the string. It will search both
torrent_ids and torrent names, but will only return torrent_ids.
:param string: str, the string to match on
:returns: list of matching torrent_ids. Will return an empty list if
no matches are found.
"""
ret = []
for tid, name in self.torrents:
if tid.startswith(string) or name.startswith(string):
ret.append(tid)
return ret
def on_torrent_added_event(self, torrent_id): def on_torrent_added_event(self, torrent_id):
def on_torrent_status(status): def on_torrent_status(status):
self.torrents.append(torrent_id, status["name"]) self.torrents.append((torrent_id, status["name"]))
client.get_torrent_status(torrent_id, ["name"]).addCallback(on_torrent_status) client.get_torrent_status(torrent_id, ["name"]).addCallback(on_torrent_status)
def on_torrent_removed_event(self, torrent_id): def on_torrent_removed_event(self, torrent_id):

View File

@ -116,15 +116,6 @@ class Screen(CursesStdIO):
""" """
log.debug("adding line: %s", text) log.debug("adding line: %s", text)
def get_line_length(line):
"""
Returns the string length without the color formatting.
"""
while line.find("{{") != -1:
line = line[:line.find("{{")] + line[line.find("}}") + 2:]
return len(line)
def get_line_chunks(line): def get_line_chunks(line):
""" """
@ -155,7 +146,12 @@ class Screen(CursesStdIO):
for line in text.splitlines(): for line in text.splitlines():
# We need to check for line lengths here and split as necessary # We need to check for line lengths here and split as necessary
line_length = get_line_length(line) try:
line_length = colors.get_line_length(line)
except colors.BadColorString:
log.error("Passed a bad colored string..")
line_length = len(line)
if line_length >= (self.cols - 1): if line_length >= (self.cols - 1):
s = "" s = ""
# The length of the text without the color tags # The length of the text without the color tags
@ -198,7 +194,12 @@ class Screen(CursesStdIO):
""" """
col = 0 col = 0
parsed = colors.parse_color_string(string) try:
parsed = colors.parse_color_string(string)
except colors.BadColorString:
log.error("Cannot add bad color string: %s", string)
return
for index, (color, s) in enumerate(parsed): for index, (color, s) in enumerate(parsed):
if index + 1 == len(parsed): if index + 1 == len(parsed):
# This is the last string so lets append some " " to it # This is the last string so lets append some " " to it