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)
31 def parse_line(self, x):
32 x = x.rstrip("\n").lstrip(" \t")
33 if x=="" or x.startswith("#"):
42 if not self.vars.has_key(k):
43 self.vars[k] = [("a","")];
46 if not key_pattern.match(k):
47 raise MoeConfigInvalid, "Malformed name of configuration variable"
50 if not v.endswith("'"):
51 raise MoeConfigInvalid, "Misquoted string"
52 self.vars[k].append(("s", v[:-1]))
53 elif v.startswith('"'):
55 if not v.endswith('"'):
56 raise MoeConfigInvalid, "Misquoted string"
57 self.parse_interpolated(self.vars[k], v[:-1])
59 self.parse_interpolated(self.vars[k], v)
61 raise MoeConfigInvalid, "Parse error"
65 for x in file.readlines():
69 except MoeConfigInvalid, x:
70 msg = x.message + " at line " + str(lino)
71 if hasattr(self, "name"):
72 msg += " of " + self.name
73 raise MoeConfigInvalid, msg
75 def parse_interpolated(self, list, s):
82 raise MoeConfigInvalid, "Unbalanced braces"
83 k, s = s[1:p], s[p+1:]
84 if not key_pattern.match(k):
85 raise MoeConfigInvalid, "Invalid variable name"
87 m = ref_pattern.match(s)
89 k, s = s[:m.end()], s[m.end():]
91 raise MoeConfigInvalid, "Invalid variable reference"
97 list.append(("s", s[:p]))
100 def dump(self, file=sys.stdout):
101 for k,v in self.vars.items():
103 if len(v) > 0 and v[0][0] == "a":
109 file.write("'" + w + "'")
111 file.write('"$' + w + '"')
114 class MoeConfigStack:
115 """Stack of configuration files."""
117 def __init__(self, base=None):
118 ## FIXME: Do we need to duplicate the config files themselves?
120 self.stk = base.stk[:]
123 self.in_progress = {}
126 def reset_cache(self):
133 def __getitem__(self, k):
134 if self.cache.has_key(k):
136 if self.in_progress.has_key(k):
137 raise MoeConfigEvalErr, "Definition of $%s is recursive" % k;
138 self.in_progress[k] = 1;
139 v = self.do_get(k, len(self.stk)-1)
140 del self.in_progress[k]
144 def do_get(self, k, pos):
147 if cfg.vars.has_key(k):
150 v = self.do_get(k, pos-1)
165 for k in cfg.vars.keys():
169 def dump(self, file=sys.stdout):
170 for k in self.keys():
172 file.write("%s=%s\n" % (k,v))
174 def dump_defs(self, file=sys.stdout):
175 file.write("Configuration stack:\n")
179 file.write("(level %d)\n" % level)
181 file.write("(end)\n")
183 def apply_overrides(self, prefix):
188 for k in cfg.vars.keys():
189 if k.startswith(prefix):
190 over.vars[k[len(prefix):]] = cfg.vars[k]
194 for k in cfg.vars.keys():
195 if not k.startswith(prefix):
196 clean.vars[k] = cfg.vars[k]