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","")];
51 if not key_pattern.match(k):
52 raise MoeConfigInvalid, "Malformed name of configuration variable"
55 if not v.endswith("'"):
56 raise MoeConfigInvalid, "Misquoted string"
57 self.vars[k].append(("s", v[:-1]))
58 elif v.startswith('"'):
60 if not v.endswith('"'):
61 raise MoeConfigInvalid, "Misquoted string"
62 self.parse_interpolated(self.vars[k], v[:-1])
64 self.parse_interpolated(self.vars[k], v)
66 raise MoeConfigInvalid, "Parse error"
70 for x in file.readlines():
74 except MoeConfigInvalid, x:
75 msg = x.message + " at line " + str(lino)
76 if hasattr(self, "name"):
77 msg += " of " + self.name
78 raise MoeConfigInvalid, msg
80 def parse_interpolated(self, list, s):
87 raise MoeConfigInvalid, "Unbalanced braces"
88 k, s = s[1:p], s[p+1:]
89 if not key_pattern.match(k):
90 raise MoeConfigInvalid, "Invalid variable name"
92 m = ref_pattern.match(s)
94 k, s = s[:m.end()], s[m.end():]
96 raise MoeConfigInvalid, "Invalid variable reference"
102 list.append(("s", s[:p]))
105 def dump(self, file=sys.stdout, prefix=""):
106 for k,v in self.vars.items():
109 if len(v) > 0 and v[0][0] == "a":
115 file.write("'" + w + "'")
117 file.write('"$' + w + '"')
120 class MoeConfigStack:
121 """Stack of configuration files."""
123 def __init__(self, base=None):
125 self.stk = base.stk[:]
128 self.in_progress = {}
133 def __getitem__(self, k):
134 if self.in_progress.has_key(k):
135 raise MoeConfigEvalError, "Definition of $%s is recursive" % k;
136 self.in_progress[k] = 1;
137 v = self.do_get(k, len(self.stk)-1)
138 del self.in_progress[k]
141 def do_get(self, k, pos):
144 if cfg.vars.has_key(k):
146 if len(new) > 0 and new[0][0] == "a":
147 v = self.do_get(k, pos-1)
162 for k in cfg.vars.keys():
166 def dump(self, file=sys.stdout, prefix=""):
167 for k in sorted(self.keys()):
169 file.write("%s%s=%s\n" % (prefix,k,v))
171 def dump_defs(self, file=sys.stdout, prefix=""):
175 file.write("%s(level %d: %s)\n" % (prefix,level,cfg.type))
176 cfg.dump(file, prefix + "\t")
177 file.write("%s(end)\n" % prefix)
179 def apply_overrides(self, prefix):
182 over = MoeConfig(type = cfg.type + '-overrides')
184 for k in cfg.vars.keys():
185 if k.startswith(prefix):
186 over.vars[k[len(prefix):]] = cfg.vars[k]
189 clean = MoeConfig(type = cfg.type)
190 for k in cfg.vars.keys():
191 if not k.startswith(prefix):
192 clean.vars[k] = cfg.vars[k]
199 def parse_overrides(argv):
202 while len(argv) > 0 and argv[0].find("=") >= 0:
204 cfg = MoeConfig(type='cmdline')
205 cfg.parse_line(argv.pop(0))
206 argv.insert(0, argv0)