X-Git-Url: http://mj.ucw.cz/gitweb/?a=blobdiff_plain;f=t%2Fmoe%2Fconfig.py;h=a96fdb6207e2dea03870934573b26f39fcff001e;hb=0208316ef336f906abff8f2516f08b40e8fdf348;hp=7c41fa2e774d31772e0f676f84f1a74330ad1a5d;hpb=962213ada3cb8db462ea772ce5ebd3b9a0bd5d8f;p=eval.git diff --git a/t/moe/config.py b/t/moe/config.py index 7c41fa2..a96fdb6 100644 --- a/t/moe/config.py +++ b/t/moe/config.py @@ -2,56 +2,68 @@ import re import sys +import moe -key_pattern = re.compile('^[A-Za-z0-9_-]+$') -ref_pattern = re.compile('^[A-Za-z0-9_-]+') +key_pattern = re.compile("^[A-Za-z0-9_-]+$") +ref_pattern = re.compile("^[A-Za-z0-9_-]+") -class MoeConfigInvalid(Exception): +class MoeConfigInvalid(moe.MoeError): pass -class MoeConfigEvalErr(Exception): +class MoeConfigEvalError(moe.MoeError): pass class MoeConfig: - """Moe configuration file.""" + """Moe configuration file. Should be immutable once a part of a stack.""" - def __init__(self, file=None, name=None): - self.cfg = {} + def __init__(self, file=None, name=None, type=""): + self.vars = {} + self.type = type if file is not None: self.load(file) elif name is not None: self.name = name - self.load(open(name, 'r')) + try: + file = open(name, "r") + except IOError, err: + raise MoeConfigInvalid, "Cannot open configuration file %s: %s" % (name, err.strerror) + else: + self.load(file) + + def set(self, k, v): + self.vars[k] = [("s", v)] def parse_line(self, x): x = x.rstrip("\n").lstrip(" \t") - if x=='' or x.startswith('#'): + if x=="" or x.startswith("#"): pass else: - sep = x.find('=') + 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','')]; + if not self.vars.has_key(k): + self.vars[k] = [("a","")]; + else: + self.vars[k] += [("s"," ")] else: - self.cfg[k] = [] + self.vars[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])) + self.vars[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]) + self.parse_interpolated(self.vars[k], v[:-1]) else: - self.cfg[k].append(('s', v)) + self.parse_interpolated(self.vars[k], v) else: raise MoeConfigInvalid, "Parse error" @@ -62,17 +74,17 @@ class MoeConfig: try: self.parse_line(x) except MoeConfigInvalid, x: - msg = x.message + ' at line ' + str(lino) - if hasattr(self, 'name'): - msg += ' of ' + self.name + msg = x.message + " at line " + str(lino) + if hasattr(self, "name"): + msg += " of " + self.name raise MoeConfigInvalid, msg def parse_interpolated(self, list, s): - while s<>'': - if s.startswith('$'): + while s<>"": + if s.startswith("$"): s = s[1:] - if s.startswith('{'): - p = s.find('}') + if s.startswith("{"): + p = s.find("}") if not p: raise MoeConfigInvalid, "Unbalanced braces" k, s = s[1:p], s[p+1:] @@ -84,25 +96,26 @@ class MoeConfig: k, s = s[:m.end()], s[m.end():] else: raise MoeConfigInvalid, "Invalid variable reference" - list.append(('i', k)) + list.append(("i", k)) else: - p = s.find('$') + p = s.find("$") if p < 0: p = len(s) - list.append(('s', s[:p])) + list.append(("s", s[:p])) s = s[p:] - def dump(self, file=sys.stdout): - for k,v in self.cfg.items(): + def dump(self, file=sys.stdout, prefix=""): + for k,v in self.vars.items(): + file.write(prefix) file.write(k) - if len(v) > 0 and v[0][0] == 'a': - file.write('+') + if len(v) > 0 and v[0][0] == "a": + file.write("+") v = v[1:] - file.write('=') + file.write("=") for t,w in v: - if t == 's': + if t == "s": file.write("'" + w + "'") - elif t == 'i': + elif t == "i": file.write('"$' + w + '"') file.write("\n") @@ -110,7 +123,6 @@ class MoeConfigStack: """Stack of configuration files.""" def __init__(self, base=None): - ## FIXME: Do we need to duplicate the config files themselves? if base: self.stk = base.stk[:] else: @@ -122,7 +134,7 @@ class MoeConfigStack: def __getitem__(self, k): if self.in_progress.has_key(k): - raise MoeConfigEvalErr, "Definition of $%s is recursive" % k; + raise MoeConfigEvalError, "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] @@ -131,17 +143,69 @@ class MoeConfigStack: 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': + if cfg.vars.has_key(k): + new = cfg.vars[k] + if len(new) > 0 and new[0][0] == "a": v = self.do_get(k, pos-1) + if v != "" and not v.endswith(" "): + v += " " else: - v = '' + v = "" for op,arg in new: - if op == 's': + if op == "s": v = v + arg - elif op == 'i': + elif op == "i": v = v + self[arg] return v pos -= 1 - return '' + return "" + + def keys(self): + seen = {} + for cfg in self.stk: + for k in cfg.vars.keys(): + seen[k] = None + return seen.keys() + + def dump(self, file=sys.stdout, prefix=""): + for k in sorted(self.keys()): + v = self[k] + file.write("%s%s=%s\n" % (prefix,k,v)) + + def dump_defs(self, file=sys.stdout, prefix=""): + level = 0 + for cfg in self.stk: + level += 1 + file.write("%s(level %d: %s)\n" % (prefix,level,cfg.type)) + cfg.dump(file, prefix + "\t") + file.write("%s(end)\n" % prefix) + + def apply_overrides(self, prefix): + newstk = [] + for cfg in self.stk: + over = MoeConfig(type = cfg.type + '-overrides') + changed = False + for k in cfg.vars.keys(): + if k.startswith(prefix): + over.vars[k[len(prefix):]] = cfg.vars[k] + changed = True + if changed: + clean = MoeConfig(type = cfg.type) + for k in cfg.vars.keys(): + if not k.startswith(prefix): + clean.vars[k] = cfg.vars[k] + newstk.append(clean) + newstk.append(over) + else: + newstk.append(cfg) + self.stk = newstk + +def parse_overrides(argv): + cfg = None + argv0 = argv.pop(0) + while len(argv) > 0 and argv[0].find("=") >= 0: + if cfg is None: + cfg = MoeConfig(type='cmdline') + cfg.parse_line(argv.pop(0)) + argv.insert(0, argv0) + return cfg