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:
24 self.load(open(name, 'r'))
26 def parse_line(self, x):
27 x = x.rstrip("\n").lstrip(" \t")
28 if x=='' or x.startswith('#'):
37 if not self.vars.has_key(k):
38 self.vars[k] = [('a','')];
41 if not key_pattern.match(k):
42 raise MoeConfigInvalid, "Malformed name of configuration variable"
45 if not v.endswith("'"):
46 raise MoeConfigInvalid, "Misquoted string"
47 self.vars[k].append(('s', v[:-1]))
48 elif v.startswith('"'):
50 if not v.endswith('"'):
51 raise MoeConfigInvalid, "Misquoted string"
52 self.parse_interpolated(self.vars[k], v[:-1])
54 self.parse_interpolated(self.vars[k], v)
56 raise MoeConfigInvalid, "Parse error"
60 for x in file.readlines():
64 except MoeConfigInvalid, x:
65 msg = x.message + ' at line ' + str(lino)
66 if hasattr(self, 'name'):
67 msg += ' of ' + self.name
68 raise MoeConfigInvalid, msg
70 def parse_interpolated(self, list, s):
77 raise MoeConfigInvalid, "Unbalanced braces"
78 k, s = s[1:p], s[p+1:]
79 if not key_pattern.match(k):
80 raise MoeConfigInvalid, "Invalid variable name"
82 m = ref_pattern.match(s)
84 k, s = s[:m.end()], s[m.end():]
86 raise MoeConfigInvalid, "Invalid variable reference"
92 list.append(('s', s[:p]))
95 def dump(self, file=sys.stdout):
96 for k,v in self.vars.items():
98 if len(v) > 0 and v[0][0] == 'a':
104 file.write("'" + w + "'")
106 file.write('"$' + w + '"')
109 class MoeConfigStack:
110 """Stack of configuration files."""
112 def __init__(self, base=None):
113 ## FIXME: Do we need to duplicate the config files themselves?
115 self.stk = base.stk[:]
118 self.in_progress = {}
121 def reset_cache(self):
128 def __getitem__(self, k):
129 if self.cache.has_key(k):
131 if self.in_progress.has_key(k):
132 raise MoeConfigEvalErr, "Definition of $%s is recursive" % k;
133 self.in_progress[k] = 1;
134 v = self.do_get(k, len(self.stk)-1)
135 del self.in_progress[k]
139 def do_get(self, k, pos):
142 if cfg.vars.has_key(k):
145 v = self.do_get(k, pos-1)
160 for k in cfg.vars.keys():
164 def dump(self, file=sys.stdout):
165 for k in self.keys():
167 file.write("%s=%s\n" % (k,v))
169 def dump_defs(self, file=sys.stdout):
170 file.write("Configuration stack:\n")
174 file.write("(level %d)\n" % level)
176 file.write("(end)\n")
178 def apply_overrides(self, prefix):
183 for k in cfg.vars.keys():
184 if k.startswith(prefix):
185 over.vars[k[len(prefix):]] = cfg.vars[k]
189 for k in cfg.vars.keys():
190 if not k.startswith(prefix):
191 clean.vars[k] = cfg.vars[k]