- Preparation work for using six or future module for Py2/3 compat. The code will be written in Python 3 with Python 2 fallbacks. - Added some Py3 imports with Py2 fallbacks to make it easier to remove Py2 code in future. - Replace xrange with range (sort out import as top of files in future). - Workaround Py2to3 basestring issue with inline if in instances. This means every usage of basestring is more considered. - Replace iteritems and itervalues for items and values. There might be a performance penalty on Py2 so might need to revisit this change.
145 lines
4.9 KiB
Python
145 lines
4.9 KiB
Python
# -*- coding: utf-8 -*-
|
|
#
|
|
# Copyright (C) 2008-2009 Ido Abramovich <ido.deluge@gmail.com>
|
|
# Copyright (C) 2009 Andrew Resch <andrewresch@gmail.com>
|
|
#
|
|
# This file is part of Deluge and is licensed under GNU General Public License 3.0, or later, with
|
|
# the additional special exception to link portions of this program with the OpenSSL library.
|
|
# See LICENSE for more details.
|
|
#
|
|
|
|
from __future__ import unicode_literals
|
|
|
|
import cStringIO
|
|
import logging
|
|
import tokenize
|
|
|
|
import deluge.component as component
|
|
import deluge.ui.console.utils.colors as colors
|
|
from deluge.ui.client import client
|
|
|
|
from . import BaseCommand
|
|
|
|
log = logging.getLogger(__name__)
|
|
|
|
|
|
def atom(src, token):
|
|
"""taken with slight modifications from http://effbot.org/zone/simple-iterator-parser.htm"""
|
|
if token[1] == '(':
|
|
out = []
|
|
token = next(src)
|
|
while token[1] != ')':
|
|
out.append(atom(src, token))
|
|
token = next(src)
|
|
if token[1] == ',':
|
|
token = next(src)
|
|
return tuple(out)
|
|
elif token[0] is tokenize.NUMBER or token[1] == '-':
|
|
try:
|
|
if token[1] == '-':
|
|
return int(token[-1], 0)
|
|
else:
|
|
return int(token[1], 0)
|
|
except ValueError:
|
|
try:
|
|
return float(token[-1])
|
|
except ValueError:
|
|
return str(token[-1])
|
|
elif token[1].lower() == 'true':
|
|
return True
|
|
elif token[1].lower() == 'false':
|
|
return False
|
|
elif token[0] is tokenize.STRING or token[1] == '/':
|
|
return token[-1].decode('string-escape')
|
|
|
|
raise SyntaxError('malformed expression (%s)' % token[1])
|
|
|
|
|
|
def simple_eval(source):
|
|
""" evaluates the 'source' string into a combination of primitive python objects
|
|
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)
|
|
res = atom(src, next(src))
|
|
return res
|
|
|
|
|
|
class Command(BaseCommand):
|
|
"""Show and set configuration values"""
|
|
|
|
usage = _('Usage: config [--set <key> <value>] [<key> [<key>...] ]')
|
|
|
|
def add_arguments(self, parser):
|
|
set_group = parser.add_argument_group('setting a value')
|
|
set_group.add_argument('-s', '--set', action='store', metavar='<key>', help=_('set value for this key'))
|
|
set_group.add_argument('values', metavar='<value>', nargs='+', help=_('Value to set'))
|
|
get_group = parser.add_argument_group('getting values')
|
|
get_group.add_argument('keys', metavar='<keys>', nargs='*', help=_('one or more keys separated by space'))
|
|
|
|
def handle(self, options):
|
|
self.console = component.get('ConsoleUI')
|
|
if options.set:
|
|
return self._set_config(options)
|
|
else:
|
|
return self._get_config(options)
|
|
|
|
def _get_config(self, options):
|
|
def _on_get_config(config):
|
|
keys = sorted(config.keys())
|
|
s = ''
|
|
for key in keys:
|
|
if key not in options.values:
|
|
continue
|
|
color = '{!white,black,bold!}'
|
|
value = config[key]
|
|
try:
|
|
color = colors.type_color[type(value)]
|
|
except KeyError:
|
|
pass
|
|
|
|
# We need to format dicts for printing
|
|
if isinstance(value, dict):
|
|
import pprint
|
|
value = pprint.pformat(value, 2, 80)
|
|
new_value = []
|
|
for line in value.splitlines():
|
|
new_value.append('%s%s' % (color, line))
|
|
value = '\n'.join(new_value)
|
|
|
|
s += '%s: %s%s\n' % (key, color, value)
|
|
self.console.write(s.strip())
|
|
|
|
return client.core.get_config().addCallback(_on_get_config)
|
|
|
|
def _set_config(self, options):
|
|
config = component.get('CoreConfig')
|
|
key = options.set
|
|
val = ' '.join(options.values)
|
|
|
|
try:
|
|
val = simple_eval(val)
|
|
except SyntaxError as ex:
|
|
self.console.write('{!error!}%s' % ex)
|
|
return
|
|
|
|
if key not in list(config.keys()):
|
|
self.console.write('{!error!}Invalid key: %s' % key)
|
|
return
|
|
|
|
if not isinstance(config[key], type(val)):
|
|
try:
|
|
val = type(config[key])(val)
|
|
except TypeError:
|
|
self.config.write('{!error!}Configuration value provided has incorrect type.')
|
|
return
|
|
|
|
def on_set_config(result):
|
|
self.console.write('{!success!}Configuration value successfully updated.')
|
|
|
|
self.console.write('Setting "%s" to: %s' % (key, val))
|
|
return client.core.set_config({key: val}).addCallback(on_set_config)
|
|
|
|
def complete(self, text):
|
|
return [k for k in component.get('CoreConfig').keys() if k.startswith(text)]
|