6 key_pattern = re.compile("^[A-Za-z0-9_-]+$")
7 ref_pattern = re.compile("^[A-Za-z0-9_-]+")
9 class MoeConfigInvalid(Exception):
12 class MoeConfigEvalErr(Exception):
16 """Moe configuration file. Should be immutable once a part of a stack."""
18 def __init__(self, file=None, name=None):
22 elif name is not None:
25 file = open(name, "r")
27 raise MoeConfigInvalid, "Cannot open configuration file %s: %s" % (name, err.strerror)
32 self.vars[k] = [("s", v)]
34 def parse_line(self, x):
35 x = x.rstrip("\n").lstrip(" \t")
36 if x=="" or x.startswith("#"):
45 if not self.vars.has_key(k):
46 self.vars[k] = [("a","")];
49 if not key_pattern.match(k):
50 raise MoeConfigInvalid, "Malformed name of configuration variable"
53 if not v.endswith("'"):
54 raise MoeConfigInvalid, "Misquoted string"
55 self.vars[k].append(("s", v[:-1]))
56 elif v.startswith('"'):
58 if not v.endswith('"'):
59 raise MoeConfigInvalid, "Misquoted string"
60 self.parse_interpolated(self.vars[k], v[:-1])
62 self.parse_interpolated(self.vars[k], v)
64 raise MoeConfigInvalid, "Parse error"
68 for x in file.readlines():
72 except MoeConfigInvalid, x:
73 msg = x.message + " at line " + str(lino)
74 if hasattr(self, "name"):
75 msg += " of " + self.name
76 raise MoeConfigInvalid, msg
78 def parse_interpolated(self, list, s):
85 raise MoeConfigInvalid, "Unbalanced braces"
86 k, s = s[1:p], s[p+1:]
87 if not key_pattern.match(k):
88 raise MoeConfigInvalid, "Invalid variable name"
90 m = ref_pattern.match(s)
92 k, s = s[:m.end()], s[m.end():]
94 raise MoeConfigInvalid, "Invalid variable reference"
100 list.append(("s", s[:p]))
103 def dump(self, file=sys.stdout):
104 for k,v in self.vars.items():
106 if len(v) > 0 and v[0][0] == "a":
112 file.write("'" + w + "'")
114 file.write('"$' + w + '"')
117 class MoeConfigStack:
118 """Stack of configuration files."""
120 def __init__(self, base=None):
121 ## FIXME: Do we need to duplicate the config files themselves?
123 self.stk = base.stk[:]
126 self.in_progress = {}
129 def reset_cache(self):
136 def __getitem__(self, k):
137 if self.cache.has_key(k):
139 if self.in_progress.has_key(k):
140 raise MoeConfigEvalErr, "Definition of $%s is recursive" % k;
141 self.in_progress[k] = 1;
142 v = self.do_get(k, len(self.stk)-1)
143 del self.in_progress[k]
144 ## FIXME: This is disabled, because the immutability invariant is broken!
148 def do_get(self, k, pos):
151 if cfg.vars.has_key(k):
154 v = self.do_get(k, pos-1)
169 for k in cfg.vars.keys():
173 def dump(self, file=sys.stdout):
174 for k in sorted(self.keys()):
176 file.write("%s=%s\n" % (k,v))
178 def dump_defs(self, file=sys.stdout):
179 file.write("Configuration stack:\n")
183 file.write("(level %d)\n" % level)
185 file.write("(end)\n")
187 def apply_overrides(self, prefix):
192 for k in cfg.vars.keys():
193 if k.startswith(prefix):
194 over.vars[k[len(prefix):]] = cfg.vars[k]
198 for k in cfg.vars.keys():
199 if not k.startswith(prefix):
200 clean.vars[k] = cfg.vars[k]