7 key_pattern = re.compile("^[A-Za-z0-9_-]+$")
8 ref_pattern = re.compile("^[A-Za-z0-9_-]+")
10 class MoeConfigInvalid(moe.MoeError):
13 class MoeConfigEvalError(moe.MoeError):
17 """Moe configuration file. Should be immutable once a part of a stack."""
19 def __init__(self, file=None, name=None, type="<unnamed>"):
24 elif name is not None:
27 file = open(name, "r")
29 raise MoeConfigInvalid, "Cannot open configuration file %s: %s" % (name, err.strerror)
34 self.vars[k] = [("s", v)]
36 def parse_line(self, x):
37 x = x.rstrip("\n").lstrip(" \t")
38 if x=="" or x.startswith("#"):
47 if not self.vars.has_key(k):
48 self.vars[k] = [("a","")];
50 self.vars[k] += [("s"," ")]
53 if not key_pattern.match(k):
54 raise MoeConfigInvalid, "Malformed name of configuration variable"
57 if not v.endswith("'"):
58 raise MoeConfigInvalid, "Misquoted string"
59 self.vars[k].append(("s", v[:-1]))
60 elif v.startswith('"'):
62 if not v.endswith('"'):
63 raise MoeConfigInvalid, "Misquoted string"
64 self.parse_interpolated(self.vars[k], v[:-1])
66 self.parse_interpolated(self.vars[k], v)
68 raise MoeConfigInvalid, "Parse error"
72 for x in file.readlines():
76 except MoeConfigInvalid, x:
77 msg = x.message + " at line " + str(lino)
78 if hasattr(self, "name"):
79 msg += " of " + self.name
80 raise MoeConfigInvalid, msg
82 def parse_interpolated(self, list, s):
89 raise MoeConfigInvalid, "Unbalanced braces"
90 k, s = s[1:p], s[p+1:]
91 if not key_pattern.match(k):
92 raise MoeConfigInvalid, "Invalid variable name"
94 m = ref_pattern.match(s)
96 k, s = s[:m.end()], s[m.end():]
98 raise MoeConfigInvalid, "Invalid variable reference"
104 list.append(("s", s[:p]))
107 def dump(self, file=sys.stdout, prefix=""):
108 for k,v in self.vars.items():
111 if len(v) > 0 and v[0][0] == "a":
117 file.write("'" + w + "'")
119 file.write('"$' + w + '"')
122 class MoeConfigStack:
123 """Stack of configuration files."""
125 def __init__(self, base=None):
127 self.stk = base.stk[:]
130 self.in_progress = {}
135 def __getitem__(self, k):
136 if self.in_progress.has_key(k):
137 raise MoeConfigEvalError, "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]
143 def do_get(self, k, pos):
146 if cfg.vars.has_key(k):
148 if len(new) > 0 and new[0][0] == "a":
149 v = self.do_get(k, pos-1)
150 if v != "" and not v.endswith(" "):
166 for k in cfg.vars.keys():
170 def dump(self, file=sys.stdout, prefix=""):
171 for k in sorted(self.keys()):
173 file.write("%s%s=%s\n" % (prefix,k,v))
175 def dump_defs(self, file=sys.stdout, prefix=""):
179 file.write("%s(level %d: %s)\n" % (prefix,level,cfg.type))
180 cfg.dump(file, prefix + "\t")
181 file.write("%s(end)\n" % prefix)
183 def apply_overrides(self, prefix):
186 over = MoeConfig(type = cfg.type + '-overrides')
188 for k in cfg.vars.keys():
189 if k.startswith(prefix):
190 over.vars[k[len(prefix):]] = cfg.vars[k]
193 clean = MoeConfig(type = cfg.type)
194 for k in cfg.vars.keys():
195 if not k.startswith(prefix):
196 clean.vars[k] = cfg.vars[k]
203 def parse_overrides(argv):
206 while len(argv) > 0 and argv[0].find("=") >= 0:
208 cfg = MoeConfig(type='cmdline')
209 cfg.parse_line(argv.pop(0))
210 argv.insert(0, argv0)