diff options
Diffstat (limited to 'module/config/Parser.py')
-rw-r--r-- | module/config/Parser.py | 353 |
1 files changed, 353 insertions, 0 deletions
diff --git a/module/config/Parser.py b/module/config/Parser.py new file mode 100644 index 000000000..e21eaba9f --- /dev/null +++ b/module/config/Parser.py @@ -0,0 +1,353 @@ +# -*- coding: utf-8 -*- + +from __future__ import with_statement + +from time import sleep +from os.path import exists, join +from shutil import copy + +from traceback import print_exc +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"): + copy(join(pypath, "pyload", "config", "default.conf"), "pyload.conf") + + if not exists("plugin.conf"): + f = open("plugin.conf", "wb") + f.write("version: " + str(CONF_VERSION)) + f.close() + + f = open("pyload.conf", "rb") + v = f.readline() + f.close() + v = v[v.find(":") + 1:].strip() + + if not v or int(v) < CONF_VERSION: + copy(join(pypath, "pyload", "config", "default.conf"), "pyload.conf") + print "Old version of config was replaced" + + f = open("plugin.conf", "rb") + v = f.readline() + f.close() + v = v[v.find(":") + 1:].strip() + + if not v or int(v) < CONF_VERSION: + f = open("plugin.conf", "wb") + f.write("version: " + str(CONF_VERSION)) + f.close() + 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" + print_exc() + + + def parseConfig(self, config): + """parses a given configfile""" + + f = open(config) + + 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} + + + else: + content, none, value = line.partition("=") + + content, none, desc = content.partition(":") + + desc = desc.replace('"', "").strip() + + typ, none, option = content.strip().rpartition(" ") + + value = value.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} + + except Exception, e: + print "Config Warning" + print_exc() + + f.close() + 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 config[section].iteritems(): + 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 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]) + } + + 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) |