diff --git a/src/python/recoll/recoll/rclconfig.py b/src/python/recoll/recoll/rclconfig.py new file mode 100755 index 00000000..a2f79709 --- /dev/null +++ b/src/python/recoll/recoll/rclconfig.py @@ -0,0 +1,187 @@ +#!/usr/bin/env python + +import locale +import re +import os +import sys +import base64 + +class ConfSimple: + """A ConfSimple class reads a recoll configuration file, which is a typical + ini file (see the Recoll manual). It's a dictionary of dictionaries which + lets you retrieve named values from the top level or a subsection""" + + def __init__(self, confname, tildexp = False): + f = open(confname, 'r') + self.dotildexpand = tildexp + self.submaps = {} + + self.parseinput(f) + + def parseinput(self, f): + appending = False + line = '' + submapkey = '' + for cline in f: + cline = cline.rstrip("\r\n") + if appending: + line = line + cline + else: + line = cline + line = line.strip() + if line == '' or line[0] == '#': + continue + + if line[len(line)-1] == '\\': + line = line[0:len(line)-1] + appending = True + continue + appending = False + #print line + if line[0] == '[': + line = line.strip('[]') + if self.dotildexpand: + submapkey = os.path.expanduser(line) + else: + submapkey = line + #print "Submapkey:", submapkey + continue + nm, sep, value = line.partition('=') + if sep == '': + continue + nm = nm.strip() + value = value.strip() + #print "Name:", nm, "Value:", value + + if not self.submaps.has_key(submapkey): + self.submaps[submapkey] = {} + self.submaps[submapkey][nm] = value + + def get(self, nm, sk = ''): + '''Returns None if not found, empty string if found empty''' + if not self.submaps.has_key(sk): + return None + if not self.submaps[sk].has_key(nm): + return None + return self.submaps[sk][nm] + + def getNames(self, sk = ''): + if not self.submaps.has_key(sk): + return None + return self.submaps[sk].keys() + +class ConfTree(ConfSimple): + """A ConfTree adds path-hierarchical interpretation of the section keys, + which should be '/'-separated values. When a value is requested for a + given path, it will also be searched in the sections corresponding to + the ancestors. E.g. get(name, '/a/b') will also look in sections '/a' and + '/' or '' (the last 2 are equivalent""" + def get(self, nm, sk = ''): + if sk == '' or sk[0] != '/': + return ConfSimple.get(self, nm, sk) + + if sk[len(sk)-1] != '/': + sk = sk + '/' + + # Try all sk ancestors as submaps (/a/b/c-> /a/b/c, /a/b, /a, '') + while sk.find('/') != -1: + val = ConfSimple.get(self, nm, sk) + if val is not None: + return val + i = sk.rfind('/') + if i == -1: + break + sk = sk[:i] + + return ConfSimple.get(self, nm) + +class ConfStack: + """ A ConfStack manages the superposition of a list of Configuration + objects. Values are looked for in each object from the list until found. + This typically provides for defaults overriden by sparse values in the + topmost file.""" + + def __init__(self, nm, dirs, tp = 'simple'): + fnames = [] + for dir in dirs: + fnm = os.path.join(dir, nm) + fnames.append(fnm) + self._construct(tp, fnames) + + def _construct(self, tp, fnames): + self.confs = [] + for fname in fnames: + if tp.lower() == 'simple': + conf = ConfSimple(fname) + else: + conf = ConfTree(fname) + self.confs.append(conf) + + def get(self, nm, sk = ''): + for conf in self.confs: + value = conf.get(nm, sk) + if value is not None: + return value + return None + +class RclDynConf: + def __init__(self, fname): + self.data = ConfSimple(fname) + + def getStringList(self, sk): + nms = self.data.getNames(sk) + out = [] + if nms is not None: + for nm in nms: + out.append(base64.b64decode(self.data.get(nm, sk))) + return out + +class RclConfig: + def __init__(self, argcnf = None): + # Find configuration directory + if argcnf is not None: + self.confdir = os.path.abspath(argcnf) + elif os.environ.has_key("RECOLL_CONFDIR"): + self.confdir = os.environ["RECOLL_CONFDIR"] + else: + self.confdir = os.path.expanduser("~/.recoll") + #print "Confdir: [%s]" % self.confdir + # Also find datadir. This is trickier because this is set by + # "configure" in the C code. We can only do our best. Have to + # choose a preference order. Use RECOLL_DATADIR if the order is wrong + self.datadir = None + if os.environ.has_key("RECOLL_DATADIR"): + self.datadir = os.environ["RECOLL_DATADIR"] + else: + dirs = ("/opt/local", "/usr", "/usr/local") + for dir in dirs: + dd = os.path.join(dir, "share/recoll") + if os.path.exists(dd): + self.datadir = dd + if self.datadir is None: + self.datadir = "/usr/share/recoll" + #print "Datadir: [%s]" % self.datadir + self.cdirs = [self.confdir,] + self.cdirs.append(os.path.join(self.datadir, "examples")) + #print self.cdirs + self.config = ConfStack("recoll.conf", self.cdirs) + self.keydir = '' + + def getConfDir(self): + return self.confdir + + def setKeyDir(self, dir): + self.keydir = dir + + def getConfParam(self, nm): + return self.config.get(nm, self.keydir) + +class RclExtraDbs: + def __init__(self, config): + self.config = config + + def getActDbs(self): + dyncfile = os.path.join(self.config.getConfDir(), "history") + dync = RclDynConf(dyncfile) + return dync.getStringList("actExtDbs") +