diff options
Diffstat (limited to 'pyload/config/Parser.py')
-rw-r--r-- | pyload/config/Parser.py | 358 |
1 files changed, 358 insertions, 0 deletions
diff --git a/pyload/config/Parser.py b/pyload/config/Parser.py new file mode 100644 index 000000000..d74238007 --- /dev/null +++ b/pyload/config/Parser.py @@ -0,0 +1,358 @@ +# -*- coding: utf-8 -*- + +from __future__ import with_statement + +import shutil +import traceback + +from os.path import exists, join +from time import sleep + +from pyload.utils import chmod, encode, decode + + +CONF_VERSION = 1 + + +class ConfigParser(object): + """ + holds and manage the configuration + + current dict layout: + + { + + section: { + option: { + value: + type: + desc: + } + desc: + + } + """ + + def __init__(self): + """Constructor""" + self.config = {} #: the config values + self.plugin = {} #: the config for plugins + self.oldRemoteData = {} + + self.pluginCB = None #: callback when plugin config value is changed + + self.checkVersion() + + self.readConfig() + + + def checkVersion(self, n=0): + """determines if config need to be copied""" + try: + if not exists("pyload.conf"): + shutil.copy(join(pypath, "pyload", "config", "default.conf"), "pyload.conf") + + if not exists("plugin.conf"): + with open("plugin.conf", "wb") as f: + f.write("version: " + str(CONF_VERSION)) + + with open("pyload.conf", "rb") as f: + v = f.readline() + v = v[v.find(":") + 1:].strip() + + if not v or int(v) < CONF_VERSION: + shutil.copy(join(pypath, "pyload", "config", "default.conf"), "pyload.conf") + print "Old version of config was replaced" + + with open("plugin.conf", "rb") as f: + v = f.readline() + v = v[v.find(":") + 1:].strip() + + if not v or int(v) < CONF_VERSION: + with open("plugin.conf", "wb") as f: + f.write("version: " + str(CONF_VERSION)) + print "Old version of plugin-config replaced" + + except Exception: + if n >= 3: + raise + sleep(0.3) + self.checkVersion(n + 1) + + + def readConfig(self): + """reads the config file""" + self.config = self.parseConfig(join(pypath, "pyload", "config", "default.conf")) + self.plugin = self.parseConfig("plugin.conf") + + try: + homeconf = self.parseConfig("pyload.conf") + if "username" in homeconf['remote']: + if "password" in homeconf['remote']: + self.oldRemoteData = {"username": homeconf['remote']['username']['value'], + "password": homeconf['remote']['username']['value']} + del homeconf['remote']['password'] + del homeconf['remote']['username'] + self.updateValues(homeconf, self.config) + except Exception: + print "Config Warning" + traceback.print_exc() + + + def parseConfig(self, config): + """parses a given configfile""" + + with open(config) as f: + config = f.read() + + config = config.splitlines()[1:] + + conf = {} + + section, option, value, typ, desc = "", "", "", "", "" + + listmode = False + + for line in config: + comment = line.rfind("#") + if line.find(":", comment) < 0 > line.find("=", comment) and comment > 0 and line[comment - 1].isspace(): + line = line.rpartition("#") #: removes comments + if line[1]: + line = line[0] + else: + line = line[2] + + line = line.strip() + + try: + if line == "": + continue + elif line.endswith(":"): + section, none, desc = line[:-1].partition('-') + section = section.strip() + desc = desc.replace('"', "").strip() + conf[section] = {"desc": desc} + else: + if listmode: + if line.endswith("]"): + listmode = False + line = line.replace("]", "") + + value += [self.cast(typ, x.strip()) for x in line.split(",") if x] + + if not listmode: + conf[section][option] = {"desc": desc, + "type": typ, + "value": value, + "idx": len(conf[section])} + + + else: + content, none, value = line.partition("=") + + content, none, desc = content.partition(":") + + desc = desc.replace('"', "").strip() + + typ, none, option = content.strip().rpartition(" ") + + value = value.strip() + typ = typ.strip() + + if value.startswith("["): + if value.endswith("]"): + listmode = False + value = value[:-1] + else: + listmode = True + + value = [self.cast(typ, x.strip()) for x in value[1:].split(",") if x] + else: + value = self.cast(typ, value) + + if not listmode: + conf[section][option] = {"desc": desc, + "type": typ, + "value": value, + "idx": len(conf[section])} + + except Exception, e: + print "Config Warning" + traceback.print_exc() + + return conf + + + def updateValues(self, config, dest): + """sets the config values from a parsed config file to values in destination""" + + for section in config.iterkeys(): + if section in dest: + for option in config[section].iterkeys(): + if option in ("desc", "outline"): + continue + + if option in dest[section]: + dest[section][option]['value'] = config[section][option]['value'] + + # else: + # dest[section][option] = config[section][option] + + + # else: + # dest[section] = config[section] + + + def saveConfig(self, config, filename): + """saves config to filename""" + with open(filename, "wb") as f: + chmod(filename, 0600) + f.write("version: %i \n" % CONF_VERSION) + for section in config.iterkeys(): + f.write('\n%s - "%s":\n' % (section, config[section]['desc'])) + + for option, data in sorted(config[section].items(), key=lambda i: i[1]['idx'] if i[0] not in ("desc", "outline") else 0): + if option in ("desc", "outline"): + continue + + if isinstance(data['value'], list): + value = "[ \n" + for x in data['value']: + value += "\t\t" + str(x) + ",\n" + value += "\t\t]\n" + else: + if isinstance(data['value'], basestring): + value = data['value'] + "\n" + else: + value = str(data['value']) + "\n" + try: + f.write('\t%s %s : "%s" = %s' % (data['type'], option, data['desc'], value)) + except UnicodeEncodeError: + f.write('\t%s %s : "%s" = %s' % (data['type'], option, data['desc'], encode(value))) + + + def cast(self, typ, value): + """cast value to given format""" + if not isinstance(value, basestring): + return value + + elif typ == "int": + return int(value) + elif typ == "bool": + return value.lower() in ("1", "true", "on", "an", "yes") + elif typ == "time": + if not value: + value = "0:00" + if not ":" in value: + value += ":00" + return value + elif typ in ("str", "file", "folder"): + return encode(value) + else: + return value + + + def save(self): + """saves the configs to disk""" + self.saveConfig(self.config, "pyload.conf") + self.saveConfig(self.plugin, "plugin.conf") + + + def __getitem__(self, section): + """provides dictonary like access: c['section']['option']""" + return Section(self, section) + + + def get(self, section, option): + """get value""" + value = self.config[section][option]['value'] + return decode(value) + + + def set(self, section, option, value): + """set value""" + value = self.cast(self.config[section][option]['type'], value) + self.config[section][option]['value'] = value + self.save() + + + def getPlugin(self, plugin, option): + """gets a value for a plugin""" + value = self.plugin[plugin][option]['value'] + return encode(value) + + + def setPlugin(self, plugin, option, value): + """sets a value for a plugin""" + + value = self.cast(self.plugin[plugin][option]['type'], value) + + if self.pluginCB: self.pluginCB(plugin, option, value) + + self.plugin[plugin][option]['value'] = value + self.save() + + + def removeDeletedPlugins(self, plugins): + for name in self.plugin.keys(): + if not name in plugins: + del self.plugin[name] + + + def getMetaData(self, section, option): + """ get all config data for an option """ + return self.config[section][option] + + + def addPluginConfig(self, name, config, outline=""): + """adds config options with tuples (name, type, desc, default)""" + if name not in self.plugin: + conf = {"desc": name, + "outline": outline} + self.plugin[name] = conf + else: + conf = self.plugin[name] + conf['outline'] = outline + + for item in config: + if item[0] in conf: + conf[item[0]]['type'] = item[1] + conf[item[0]]['desc'] = item[2] + else: + conf[item[0]] = { + "desc": item[2], + "type": item[1], + "value": self.cast(item[1], item[3]), + "idx": len(conf) + } + + values = [x[0] for x in config] + ["desc", "outline"] + # delete old values + for item in conf.keys(): + if item not in values: + del conf[item] + + + def deleteConfig(self, name): + """Removes a plugin config""" + if name in self.plugin: + del self.plugin[name] + + +class Section(object): + """provides dictionary like access for configparser""" + + def __init__(self, parser, section): + """Constructor""" + self.parser = parser + self.section = section + + + def __getitem__(self, item): + """getitem""" + return self.parser.get(self.section, item) + + + def __setitem__(self, item, value): + """setitem""" + self.parser.set(self.section, item, value) |