def save(self, attributes=[]): target = {} if attributes: for key in attributes: target[key] = self[key] else: target = cpy(self) targetfile = getdatadir() + os.sep + "containers" + os.sep + str(self.createtime) + "_" + stripname(self.origin) p = Persist(targetfile) p.data = getjson().dumps(target) p.save()
def savealiases(ddir=None): """ return global aliases. """ global aliases if aliases: logging.warn("saving aliases") from tl.lib.persist import Persist from tl.utils.lazydict import LazyDict d = ddir or getdatadir() p = Persist(d + os.sep + "run" + os.sep + "aliases") p.data = aliases p.save() return aliases
class Config(LazyDict): """ config class is a dict containing json strings. is writable to file and human editable. """ def __init__(self, filename, verbose=False, input={}, ddir=None, nolog=False, *args, **kwargs): assert filename if ddir: ddir = normdir(ddir) if input: LazyDict.__init__(self, input, *args, **kwargs) else: LazyDict.__init__(self, *args, **kwargs) self.filename = filename self.setcfile(ddir, filename) if not self._comments: self._comments = {} logging.info("%s from %s" % (self._logname, whichmodule(2))) self.fromfile(self._cfile) self.cid = get_cid(self) self.init() if self.owner: logging.info("owner is %s" % self.owner) if "uuid" not in self: self.setuuid() if not self._origdir in self._cfile: raise WrongFileName("%s not in %s" % (self._origdir, self._cfile)) def setcfile(self, ddir, filename): self._origname = filename self._logname = "config" + os.sep + filename self._origdir = ddir or getdatadir() self._filename = filename or 'mainconfig' self._datadir = ddir or getdatadir() if self._datadir[-1] != os.sep: self._datadir += os.sep self._dir = self._datadir + 'config' self._cfile = self._dir + os.sep + self._filename logging.debug("self._cfile is %s" % self._cfile) self.cfile = self._cfile def setuuid(self, save=True): logging.debug("setting uuid") self.uuid = str(uuid.uuid4()) if save: self.save() def __deepcopy__(self, a): """ accessor function. """ cfg = Config(self._filename, input=self, nolog=True) return cfg def __getitem__(self, item): """ accessor function. """ if item not in self: return None else: return LazyDict.__getitem__(self, item) def merge(self, cfg): """ merge in another cfg. """ self.update(cfg) def set(self, item, value): """ set item to value. """ LazyDict.__setitem__(self, item, value) def fromdb(self): """ read config from database. """ from tl.lib.persist import Persist tmp = Persist(self._cfile) logging.debug("fromdb - %s - %s" % (self._cfile, tmp.data.tojson())) self.update(tmp.data) def todb(self): """ save config to database. """ cp = dict(self) del cp['jsondb'] if not self.jsondb: from tl.lib.persist import Persist self.jsondb = Persist(self._cfile) self.jsondb.data = cp self.jsondb.save() def fromfile(self, filename=None): """ read config object from filename. """ curline = "" fname = filename or self._cfile if not fname: raise Exception("no name found - %s - %s" % (self._cfile, self.dump())) if not os.path.exists(fname): logging.warn("config file %s doesn't exist yet" % fname) ; return False comment = "" for line in open(fname, 'r'): curline = line curline = curline.strip() if curline == "": continue if curline.startswith('#'): comment = curline; continue if True: try: key, value = curline.split('=', 1) kkey = key.strip() self[kkey] = json.loads(str(value.strip())) if comment: if not self._comments: self._comments = {} self._comments[kkey] = comment comment = "" except ValueError: logging.error("skipping line - unable to parse: %s" % line) #self.cfile = fname return def tofile(self, filename=None, stdout=False): """ save config object to file. """ if not filename: filename = self._cfile if not filename: raise Exception("no cfile found - %s" % whichmodule(3)) logging.warn("%s saved" % self._logname) if filename.startswith(os.sep): d = [os.sep,] else: d = [] for p in filename.split(os.sep)[:-1]: if not p: continue d.append(p) ddir = os.sep.join(d) if not os.path.isdir(ddir): logging.debug("persist - creating %s dir" % ddir) try: os.mkdir(ddir) except OSError as ex: logging.error("persist - not saving - failed to make %s - %s" % (ddir, str(ex))) return written = [] curitem = None later = [] try: if stdout: configtmp = sys.stdout else: configtmp = open(filename + '.tmp', 'w') configtmp.write('# ===========================================================\n#\n') configtmp.write("# T I M E L I N E CONFIGURATION FILE - %s\n" % filename) configtmp.write("#\n") configtmp.write('# last changed on %s\n#\n' % time.ctime(time.time())) configtmp.write("# This file contains configration data for the T I M E L I N E.\n") configtmp.write('# Variables are defined by "name = json value" pairs.\n') configtmp.write('# Make sure to use " in strings.\n#\n') configtmp.write('# The bot can edit this file!.\n#\n') configtmp.write('# ===========================================================\n\n') teller = 0 keywords = list(self.keys()) keywords.sort() for keyword in keywords: value = self[keyword] if keyword in written: continue if keyword.startswith("_"): continue if keyword in ['origdir', 'origname', 'issaved', 'blacklist', 'whitelist', 'followlist', 'uuid', 'whitelist', 'datadir', 'name', 'createdfrom', 'cfile', 'filename', 'dir', 'isdb']: later.append(keyword) ; continue if keyword == 'jsondb': continue if keyword == 'optionslist': continue if keyword == 'gatekeeper': continue if keyword == "_comments": continue if self._comments and keyword in self._comments: configtmp.write(self._comments[keyword] + "\n") curitem = keyword try: configtmp.write('%s = %s\n' % (keyword, json.dumps(value))) except TypeError: logging.error("%s - can't serialize %s" % (filename, keyword)) ; continue teller += 1 #configtmp.write("\n") configtmp.write('\n\n# ============================================================\n#\n') configtmp.write("# bot generated stuff.\n#\n") configtmp.write('# ============================================================\n\n') for keyword in later: if self._comments and keyword in self._comments: configtmp.write(self._comments[keyword] + "\n") curitem = keyword value = self[keyword] try: configtmp.write(keyword + " = " + json.dumps(value) + "\n") except TypeError: logging.error("%s - can't serialize %s" % (filename, keyword)) ; continue teller += 1 #configtmp.write("\n") if not "mainconfig" in filename and self._comments: try: configtmp.write('\n\n# ============================================================\n#\n') configtmp.write("# possible other config variables.\n#\n") configtmp.write('# ============================================================\n\n') items = list(self._comments.keys()) keys = list(self.keys()) do = [] for var in items: if var not in keys: do.append(var) do.sort() for var in do: configtmp.write("# %s -=- %s\n" % (var, self._comments[var])) configtmp.write("\n\n") except Exception as ex: handle_exception() else: configtmp.write("\n\n# tl can run multiple bots at once. see %s/config/fleet for their configurations.\n\n" % self.origdir) if not stdout: configtmp.close() os.rename(filename + '.tmp', filename) return teller except Exception as ex: handle_exception() logging.error("ERROR WRITING %s CONFIG FILE: %s .. %s" % (filename, str(ex), curitem)) @savelocked def save(self): """ save the config. """ logging.info("save called from %s" % calledfrom(sys._getframe(2))) self.issaved = True if self.isdb: self.todb() else: self.tofile(self._cfile) def load_config(self, verbose=False): """ load the config file. """ if self.isdb: self.fromdb() else: self.fromfile(self._filename) self.init() if verbose: logging.debug('%s' % self.dump()) def init(self): """ initialize the config object. """ if not self._comments: self._comments = {} if self._filename == 'mainconfig': self._comments["whitelist"] = "# - whitelist used to allow ips .. bot maintains this" self.setdefault("whitelist", []) self._comments["blacklist"] = "# - blacklist used to deny ips .. bot maintains this" self.setdefault("blacklist", []) self.setdefault('owner', []) self._comments["loglist"] = "# - loglist .. maintained by the bot." self.setdefault('loglist', []) self._comments["loglevel"] = "# - loglevel of all bots" self.setdefault('loglevel', "warn") self._comments["loadlist"] = "# - loadlist .. not used yet." self.setdefault('loadlist', []) self._comments["quitmsg"] = "# - message to send on quit" self.setdefault('quitmsg', "http://github.com/feedbackflow/tl") self._comments["dotchars"] = "# - characters to used as seperator." self.setdefault('dotchars', ", ") self._comments["floodallow"] = "# - whether the bot is allowed to flood." self.setdefault('floodallow', 1) self._comments["auto_register"] = "# - enable automatic registration of new users." self.setdefault('auto_register', 0) self._comments["guestasuser"] = "******" self.setdefault('guestasuser', 0) self._comments["globalcc"] = "# - global control character" self.setdefault('globalcc', "") self._comments["app_id"] = "# - application id used by appengine." self.setdefault('app_id', "tl") self._comments["appname"] = "# - application name as used by the bot." self.setdefault('appname', "T I M E L I N E") self._comments["domain"] = "# - domain .. used for WAVE." self.setdefault('domain', "") self._comments["color"] = "# - color used in the webconsole." self.setdefault('color', "") self._comments["colors"] = "# - enable colors in logging." self.setdefault('colors', "") self._comments["memcached"] = "# - enable memcached." self.setdefault('memcached', 0) self._comments["allowrc"] = "# - allow execution of rc files." self.setdefault('allowrc', 0) self._comments["allowremoterc"] = "# - allow execution of remote rc files." self.setdefault('allowremoterc', 0) self._comments['dbenable'] = "# - enable database support" self.setdefault('dbenable', 1) self._comments['dbtype'] = "# - type of database .. sqlite or mysql at this time." self.setdefault('dbtype', 'sqlite') self._comments['dbname'] = "# - database name" self.setdefault('dbname', "main.db") self._comments['dbhost'] = "# - database hostname" self.setdefault('dbhost', "localhost") self._comments['dbuser'] = "******" self.setdefault('dbuser', "bart") self._comments['dbpasswd'] = "# - database password" self.setdefault('dbpasswd', "mekker2") self._comments['ticksleep'] = "# - nr of seconds to sleep before creating a TICK event." self.setdefault('ticksleep', 1) self._comments['bindhost'] = "# - host to bind to" self.setdefault("bindhost", "") self['createdfrom'] = whichmodule() if 'xmpp' in self._cfile: self.setdefault('fulljids', 1) if 'fleet' in self._cfile: self.setdefault('nick', "timeliner") self.setdefault('disable', 1) self.setdefault("owner", []) self.setdefault("user", "") self.setdefault("host", "") self.setdefault("server", "") self.setdefault("ssl", 0) self.setdefault("ipv6", 0) self.setdefault("channels", []) self.setdefault("port", "") self.setdefault("password", "") self._comments['datadir'] = "# - directory to store bot data in." self._comments["owner"] = "# - owner of the bot." self._comments["uuid"] = "# - bot generated uuid for this config file." self._comments["user"] = "******" self._comments["host"] = "# - host part of the user, derived from user var." self._comments["server"] = "# - server to connect to (only when different from users host)." self._comments["password"] = "******" self._comments["port"] = "# - port to connect to (IRC)." self._comments["ssl"] = "# - whether to enable ssl (set to 1 to enable)." self._comments["ipv6"] = "# - whether to enable ssl (set to 1 to enable)." self._comments["name"] = "# - the name of the bot." self._comments["disable"] = "# - set this to 0 to enable the bot." self._comments["followlist"] = "# - who to follow on the bot .. bot maintains this list." self._comments["networkname"] = "# - networkname .. not used right now." self._comments["type"] = "# - the bot's type." self._comments["nick"] = "# - the bot's nick." self._comments["channels"] = "# - channels to join." self._comments["cfile"] = "# - filename of this config file. edit this when you move this file." self._comments["createdfrom"] = "# - function that created this config file. bot generated" self._comments["dir"] = "# - directory in which this config file lives." self._comments["isdb"] = "# - whether this config file lives in the database and not on file." self._comments["filename"] = "# - filename of this config file." self._comments["username"] = "******" self._comments["fulljids"] = "# - use fulljids of bot users (used in non anonymous conferences." self._comments["servermodes"] = "# - string of modes to send to the server after connect." self._comments["realname"] = "# - name used in the ident of the bot." self._comments["onconnect"] = "# - string to send to server after connect." self._comments["onconnectmode"] = "# - MODE string to send to server after connect." self._comments["realname"] = "# - mode string to send to the server after connect." self._comments["issaved"] = "# - whether this config file has been saved. " self._comments["origdir"] = "# - original datadir for this configfile. " self._comments["origname"] = "# - displayable name of the config file name. " return self def reload(self): """ reload the config file. """ self.load_config() return self
def save(self): """ save the hubbub items data. """ Persist.save(self) self.itemslists.save() self.markup.save()