# -*- 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 utils import chmod # ignore these plugin configs, mainly because plugins were wiped out IGNORE = ( "FreakshareNet", "SpeedManager", "ArchiveTo", "ShareCx", ('hooks', 'UnRar'), 'EasyShareCom', 'FlyshareCz' ) CONF_VERSION = 1 class ConfigParser: """ 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() self.deleteOldPlugins() def checkVersion(self, n=0): """determines if config need to be copied""" try: if not exists("pyload.conf"): copy(join(pypath, "module", "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, "module", "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: if n < 3: sleep(0.3) self.checkVersion(n + 1) else: raise def readConfig(self): """reads the config file""" self.config = self.parseConfig(join(pypath, "module", "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, e: 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 type(data["value"]) in (str, unicode): 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"], value.encode("utf8"))) def cast(self, typ, value): """cast value to given format""" if type(value) not in (str, unicode): return value elif typ == "int": return int(value) elif typ == "bool": return True if value.lower() in ("1", "true", "on", "an", "yes") else False elif typ == "time": if not value: value = "0:00" if not ":" in value: value += ":00" return value elif typ in ("str", "file", "folder"): try: return value.encode("utf8") except: return 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""" val = self.config[section][option]["value"] try: if type(val) in (str, unicode): return val.decode("utf8") else: return val except: return val 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""" val = self.plugin[plugin][option]["value"] try: if type(val) in (str, unicode): return val.decode("utf8") else: return val except: return val 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] def deleteOldPlugins(self): """ remove old plugins from config """ for name in IGNORE: if name in self.plugin: del self.plugin[name] class Section: """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) if __name__ == "__main__": pypath = "" from time import time a = time() c = ConfigParser() b = time() print "sec", b - a print c.config c.saveConfig(c.config, "user.conf")