##// END OF EJS Templates
config: allow including other config files
Matt Mackall -
r8183:2858ab75 default
parent child Browse files
Show More
@@ -1,97 +1,106 b''
1 from i18n import _
1 from i18n import _
2 import re, error
2 import re, error, os
3
3
4 class sortdict(dict):
4 class sortdict(dict):
5 'a simple append-only sorted dictionary'
5 'a simple append-only sorted dictionary'
6 def __init__(self, data=None):
6 def __init__(self, data=None):
7 self._list = []
7 self._list = []
8 if data:
8 if data:
9 if hasattr(data, '_list'):
9 if hasattr(data, '_list'):
10 self._list = list(data._list)
10 self._list = list(data._list)
11 self.update(data)
11 self.update(data)
12 def copy(self):
12 def copy(self):
13 return sortdict(self)
13 return sortdict(self)
14 def __setitem__(self, key, val):
14 def __setitem__(self, key, val):
15 if key in self:
15 if key in self:
16 self._list.remove(key)
16 self._list.remove(key)
17 self._list.append(key)
17 self._list.append(key)
18 dict.__setitem__(self, key, val)
18 dict.__setitem__(self, key, val)
19 def __iter__(self):
19 def __iter__(self):
20 return self._list.__iter__()
20 return self._list.__iter__()
21 def update(self, src):
21 def update(self, src):
22 for k in src:
22 for k in src:
23 self[k] = src[k]
23 self[k] = src[k]
24 def items(self):
24 def items(self):
25 return [(k,self[k]) for k in self._list]
25 return [(k,self[k]) for k in self._list]
26
26
27 class config:
27 class config:
28 def __init__(self, data=None):
28 def __init__(self, data=None):
29 self._data = {}
29 self._data = {}
30 if data:
30 if data:
31 for k in data._data:
31 for k in data._data:
32 self._data[k] = data[k].copy()
32 self._data[k] = data[k].copy()
33 def copy(self):
33 def copy(self):
34 return config(self)
34 return config(self)
35 def __contains__(self, section):
35 def __contains__(self, section):
36 return section in self._data
36 return section in self._data
37 def update(self, src, sections=None):
37 def update(self, src, sections=None):
38 if not sections:
38 if not sections:
39 sections = src.sections()
39 sections = src.sections()
40 for s in sections:
40 for s in sections:
41 if s not in src:
41 if s not in src:
42 continue
42 continue
43 if s not in self:
43 if s not in self:
44 self._data[s] = sortdict()
44 self._data[s] = sortdict()
45 for k in src._data[s]:
45 for k in src._data[s]:
46 self._data[s][k] = src._data[s][k]
46 self._data[s][k] = src._data[s][k]
47 def get(self, section, item, default=None):
47 def get(self, section, item, default=None):
48 return self._data.get(section, {}).get(item, (default, ""))[0]
48 return self._data.get(section, {}).get(item, (default, ""))[0]
49 def getsource(self, section, item):
49 def getsource(self, section, item):
50 return self._data.get(section, {}).get(item, (None, ""))[1]
50 return self._data.get(section, {}).get(item, (None, ""))[1]
51 def sections(self):
51 def sections(self):
52 return sorted(self._data.keys())
52 return sorted(self._data.keys())
53 def items(self, section):
53 def items(self, section):
54 return [(k, v[0]) for k,v in self._data.get(section, {}).items()]
54 return [(k, v[0]) for k,v in self._data.get(section, {}).items()]
55 def set(self, section, item, value, source=""):
55 def set(self, section, item, value, source=""):
56 if section not in self:
56 if section not in self:
57 self._data[section] = sortdict()
57 self._data[section] = sortdict()
58 self._data[section][item] = (value, source)
58 self._data[section][item] = (value, source)
59
59
60 def read(self, path, fp=None):
60 def read(self, path, fp=None):
61 sectionre = re.compile(r'\[([^\[]+)\]')
61 sectionre = re.compile(r'\[([^\[]+)\]')
62 itemre = re.compile(r'([^=\s]+)\s*=\s*(.*)')
62 itemre = re.compile(r'([^=\s]+)\s*=\s*(.*)')
63 contre = re.compile(r'\s+(\S.*)')
63 contre = re.compile(r'\s+(\S.*)')
64 emptyre = re.compile(r'(;|#|\s*$)')
64 emptyre = re.compile(r'(;|#|\s*$)')
65 includere = re.compile(r'%include\s+(\S.*)')
65 section = ""
66 section = ""
66 item = None
67 item = None
67 line = 0
68 line = 0
68 cont = 0
69 cont = 0
69
70
70 if not fp:
71 if not fp:
71 fp = open(path)
72 fp = open(path)
72
73
73 for l in fp:
74 for l in fp:
74 line += 1
75 line += 1
75 if cont:
76 if cont:
76 m = contre.match(l)
77 m = contre.match(l)
77 if m:
78 if m:
78 v = self.get(section, item) + "\n" + m.group(1)
79 v = self.get(section, item) + "\n" + m.group(1)
79 self.set(section, item, v, "%s:%d" % (path, line))
80 self.set(section, item, v, "%s:%d" % (path, line))
80 continue
81 continue
81 item = None
82 item = None
83 m = includere.match(l)
84 if m:
85 inc = m.group(1)
86 base = os.path.dirname(path)
87 inc = os.path.normpath(os.path.join(base, inc))
88 incfp = open(inc)
89 self.read(inc, incfp)
90 continue
82 if emptyre.match(l):
91 if emptyre.match(l):
83 continue
92 continue
84 m = sectionre.match(l)
93 m = sectionre.match(l)
85 if m:
94 if m:
86 section = m.group(1)
95 section = m.group(1)
87 if section not in self:
96 if section not in self:
88 self._data[section] = sortdict()
97 self._data[section] = sortdict()
89 continue
98 continue
90 m = itemre.match(l)
99 m = itemre.match(l)
91 if m:
100 if m:
92 item = m.group(1)
101 item = m.group(1)
93 self.set(section, item, m.group(2), "%s:%d" % (path, line))
102 self.set(section, item, m.group(2), "%s:%d" % (path, line))
94 cont = 1
103 cont = 1
95 continue
104 continue
96 raise error.ConfigError(_('config error at %s:%d: \'%s\'')
105 raise error.ConfigError(_('config error at %s:%d: \'%s\'')
97 % (path, line, l.rstrip()))
106 % (path, line, l.rstrip()))
General Comments 0
You need to be logged in to leave comments. Login now