From 4574d9c6b1e2e9425f1919233a03a123b38a5e70 Mon Sep 17 00:00:00 2001 From: Martin Mares Date: Sat, 8 Aug 2009 16:23:44 +0200 Subject: [PATCH] Added a prototype of the configuration module. --- t/moe/config.py | 131 ++++++++++++++++++++++++++++++++++++++++++++++-- t/test.py | 19 +++++-- 2 files changed, 143 insertions(+), 7 deletions(-) diff --git a/t/moe/config.py b/t/moe/config.py index 3075d80..3280283 100644 --- a/t/moe/config.py +++ b/t/moe/config.py @@ -1,13 +1,136 @@ #!/usr/bin/env python +import re +import sys + +key_pattern = re.compile('^[A-Za-z0-9_-]+$') +ref_pattern = re.compile('^[A-Za-z0-9_-]+') + +class MoeConfigInvalid(Exception): + pass + +class MoeConfigEvalErr(Exception): + pass + class MoeConfig: """Moe configuration file.""" - def __init__(self): - cfg = { 'XYZZY' : 'brum' } + def __init__(self, file=None, name=None): + self.cfg = {} + if file is not None: + self.load(file) + elif name is not None: + self.load(open(name, 'r')) + + def load(self, file): + for x in file.readlines(): + x = x.rstrip("\n").lstrip(" \t") + if x=='' or x.startswith('#'): + pass + else: + sep = x.find('=') + if sep >= 0: + k = x[:sep] + v = x[sep+1:] + if k.endswith("+"): + k = k[:-1] + if not self.cfg.has_key(k): + self.cfg[k] = [('a','')]; + else: + self.cfg[k] = [] + if not key_pattern.match(k): + raise MoeConfigInvalid, "Malformed name of configuration variable" + if v.startswith("'"): + v=v[1:] + if not v.endswith("'"): + raise MoeConfigInvalid, "Misquoted string" + self.cfg[k].append(('s', v[:-1])) + elif v.startswith('"'): + v=v[1:] + if not v.endswith('"'): + raise MoeConfigInvalid, "Misquoted string" + self.parse_interpolated(self.cfg[k], v[:-1]) + else: + self.cfg[k].append(('s', v)) + else: + ## FIXME: Report line numbers + raise MoeConfigInvalid, "Parse error" + + def parse_interpolated(self, list, s): + while s<>'': + if s.startswith('$'): + s = s[1:] + if s.startswith('{'): + p = s.find('}') + if not p: + raise MoeConfigInvalid, "Unbalanced braces" + k, s = s[1:p], s[p+1:] + if not key_pattern.match(k): + raise MoeConfigInvalid, "Invalid variable name" + else: + m = ref_pattern.match(s) + if m: + k, s = s[:m.end()], s[m.end():] + else: + raise MoeConfigInvalid, "Invalid variable reference" + list.append(('i', k)) + else: + p = s.find('$') + if p < 0: + p = len(s) + list.append(('s', s[:p])) + s = s[p:] + + def dump(self, file=sys.stdout): + for k,v in self.cfg.items(): + file.write(k) + if len(v) > 0 and v[0][0] == 'a': + file.write('+') + v = v[1:] + file.write('=') + for t,w in v: + if t == 's': + file.write("'" + w + "'") + elif t == 'i': + file.write('"$' + w + '"') + file.write("\n") class MoeConfigStack: """Stack of configuration files.""" - def __init__(self): - stk = [] + def __init__(self, base=None): + ## FIXME: Do we need to duplicate the config files themselves? + if base: + self.stk = base.stk[:] + else: + self.stk = [] + self.in_progress = {} + + def push(self, cfg): + self.stk.append(cfg) + + def __getitem__(self, k): + if self.in_progress.has_key(k): + raise MoeConfigEvalErr, "Definition of $%s is recursive" % k; + self.in_progress[k] = 1; + v = self.do_get(k, len(self.stk)-1) + del self.in_progress[k] + return v + + def do_get(self, k, pos): + while pos >= 0: + cfg = self.stk[pos] + if cfg.cfg.has_key(k): + new = cfg.cfg[k] + if new[0][0] == 'a': + v = self.do_get(k, pos-1) + else: + v = '' + for op,arg in new: + if op == 's': + v = v + arg + elif op == 'i': + v = v + self[arg] + return v + pos -= 1 + return '' diff --git a/t/test.py b/t/test.py index e928214..2460a21 100755 --- a/t/test.py +++ b/t/test.py @@ -4,7 +4,20 @@ import sys sys.path.append('.') import moe.meta +import moe.config -m = moe.meta.MoeMeta() -m['a'] = '1' -m.write() +#m = moe.meta.MoeMeta() +#m['a'] = '1' +#m.write() + +c = moe.config.MoeConfig(name='/dev/stdin') +c.dump() + +d = moe.config.MoeConfig(name='/dev/stdin') +d.dump() + +s = moe.config.MoeConfigStack() +s.push(c) +s.push(d) + +print s['a'] -- 2.39.5