##// END OF EJS Templates
config: add parse interface
Matt Mackall -
r8265:52c5be55 default
parent child Browse files
Show More
@@ -1,132 +1,134 b''
1 # config.py - configuration parsing for Mercurial
1 # config.py - configuration parsing for Mercurial
2 #
2 #
3 # Copyright 2009 Matt Mackall <mpm@selenic.com> and others
3 # Copyright 2009 Matt Mackall <mpm@selenic.com> and others
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2, incorporated herein by reference.
6 # GNU General Public License version 2, incorporated herein by reference.
7
7
8 from i18n import _
8 from i18n import _
9 import re, error, os
9 import re, error, os
10
10
11 class sortdict(dict):
11 class sortdict(dict):
12 'a simple sorted dictionary'
12 'a simple sorted dictionary'
13 def __init__(self, data=None):
13 def __init__(self, data=None):
14 self._list = []
14 self._list = []
15 if data:
15 if data:
16 self.update(data)
16 self.update(data)
17 def copy(self):
17 def copy(self):
18 return sortdict(self)
18 return sortdict(self)
19 def __setitem__(self, key, val):
19 def __setitem__(self, key, val):
20 if key in self:
20 if key in self:
21 self._list.remove(key)
21 self._list.remove(key)
22 self._list.append(key)
22 self._list.append(key)
23 dict.__setitem__(self, key, val)
23 dict.__setitem__(self, key, val)
24 def __iter__(self):
24 def __iter__(self):
25 return self._list.__iter__()
25 return self._list.__iter__()
26 def update(self, src):
26 def update(self, src):
27 for k in src:
27 for k in src:
28 self[k] = src[k]
28 self[k] = src[k]
29 def items(self):
29 def items(self):
30 return [(k, self[k]) for k in self._list]
30 return [(k, self[k]) for k in self._list]
31 def __delitem__(self, key):
31 def __delitem__(self, key):
32 dict.__delitem__(self, key)
32 dict.__delitem__(self, key)
33 self._list.remove(key)
33 self._list.remove(key)
34
34
35 class config(object):
35 class config(object):
36 def __init__(self, data=None):
36 def __init__(self, data=None):
37 self._data = {}
37 self._data = {}
38 self._source = {}
38 self._source = {}
39 if data:
39 if data:
40 for k in data._data:
40 for k in data._data:
41 self._data[k] = data[k].copy()
41 self._data[k] = data[k].copy()
42 self._source = data._source.copy()
42 self._source = data._source.copy()
43 def copy(self):
43 def copy(self):
44 return config(self)
44 return config(self)
45 def __contains__(self, section):
45 def __contains__(self, section):
46 return section in self._data
46 return section in self._data
47 def __getitem__(self, section):
47 def __getitem__(self, section):
48 return self._data.get(section, {})
48 return self._data.get(section, {})
49 def __iter__(self):
49 def __iter__(self):
50 for d in self.sections():
50 for d in self.sections():
51 yield d
51 yield d
52 def update(self, src):
52 def update(self, src):
53 for s in src:
53 for s in src:
54 if s not in self:
54 if s not in self:
55 self._data[s] = sortdict()
55 self._data[s] = sortdict()
56 self._data[s].update(src._data[s])
56 self._data[s].update(src._data[s])
57 self._source.update(src._source)
57 self._source.update(src._source)
58 def get(self, section, item, default=None):
58 def get(self, section, item, default=None):
59 return self._data.get(section, {}).get(item, default)
59 return self._data.get(section, {}).get(item, default)
60 def source(self, section, item):
60 def source(self, section, item):
61 return self._source.get((section, item), "")
61 return self._source.get((section, item), "")
62 def sections(self):
62 def sections(self):
63 return sorted(self._data.keys())
63 return sorted(self._data.keys())
64 def items(self, section):
64 def items(self, section):
65 return self._data.get(section, {}).items()
65 return self._data.get(section, {}).items()
66 def set(self, section, item, value, source=""):
66 def set(self, section, item, value, source=""):
67 if section not in self:
67 if section not in self:
68 self._data[section] = sortdict()
68 self._data[section] = sortdict()
69 self._data[section][item] = value
69 self._data[section][item] = value
70 self._source[(section, item)] = source
70 self._source[(section, item)] = source
71
71
72 def read(self, path, fp=None, sections=None):
72 def parse(self, src, data, sections=None, remap=None, include=None):
73 sectionre = re.compile(r'\[([^\[]+)\]')
73 sectionre = re.compile(r'\[([^\[]+)\]')
74 itemre = re.compile(r'([^=\s][^=]*?)\s*=\s*(.*\S|)')
74 itemre = re.compile(r'([^=\s][^=]*?)\s*=\s*(.*\S|)')
75 contre = re.compile(r'\s+(\S.*\S)')
75 contre = re.compile(r'\s+(\S.*\S)')
76 emptyre = re.compile(r'(;|#|\s*$)')
76 emptyre = re.compile(r'(;|#|\s*$)')
77 unsetre = re.compile(r'%unset\s+(\S+)')
77 unsetre = re.compile(r'%unset\s+(\S+)')
78 includere = re.compile(r'%include\s+(\S.*\S)')
78 includere = re.compile(r'%include\s+(\S.*\S)')
79 section = ""
79 section = ""
80 item = None
80 item = None
81 line = 0
81 line = 0
82 cont = 0
82 cont = 0
83
83
84 if not fp:
84 for l in data.splitlines(1):
85 fp = open(path)
86
87 for l in fp:
88 line += 1
85 line += 1
89 if cont:
86 if cont:
90 m = contre.match(l)
87 m = contre.match(l)
91 if m:
88 if m:
92 if sections and section not in sections:
89 if sections and section not in sections:
93 continue
90 continue
94 v = self.get(section, item) + "\n" + m.group(1)
91 v = self.get(section, item) + "\n" + m.group(1)
95 self.set(section, item, v, "%s:%d" % (path, line))
92 self.set(section, item, v, "%s:%d" % (src, line))
96 continue
93 continue
97 item = None
94 item = None
98 m = includere.match(l)
95 m = includere.match(l)
99 if m:
96 if m:
100 inc = m.group(1)
97 inc = m.group(1)
101 base = os.path.dirname(path)
98 base = os.path.dirname(src)
102 inc = os.path.normpath(os.path.join(base, inc))
99 inc = os.path.normpath(os.path.join(base, inc))
103 incfp = open(inc)
100 if include:
104 self.read(inc, incfp)
101 include(inc, remap=remap, sections=sections)
105 continue
102 continue
106 if emptyre.match(l):
103 if emptyre.match(l):
107 continue
104 continue
108 m = sectionre.match(l)
105 m = sectionre.match(l)
109 if m:
106 if m:
110 section = m.group(1)
107 section = m.group(1)
111 if section not in self:
108 if section not in self:
112 self._data[section] = sortdict()
109 self._data[section] = sortdict()
113 continue
110 continue
114 m = itemre.match(l)
111 m = itemre.match(l)
115 if m:
112 if m:
116 item = m.group(1)
113 item = m.group(1)
117 cont = 1
114 cont = 1
118 if sections and section not in sections:
115 if sections and section not in sections:
119 continue
116 continue
120 self.set(section, item, m.group(2), "%s:%d" % (path, line))
117 self.set(section, item, m.group(2), "%s:%d" % (src, line))
121 continue
118 continue
122 m = unsetre.match(l)
119 m = unsetre.match(l)
123 if m:
120 if m:
124 name = m.group(1)
121 name = m.group(1)
125 if sections and section not in sections:
122 if sections and section not in sections:
126 continue
123 continue
127 if self.get(section, name) != None:
124 if self.get(section, name) != None:
128 del self._data[section][name]
125 del self._data[section][name]
129 continue
126 continue
130
127
131 raise error.ConfigError(_('config error at %s:%d: \'%s\'')
128 raise error.ConfigError(_('config error at %s:%d: \'%s\'')
132 % (path, line, l.rstrip()))
129 % (src, line, l.rstrip()))
130
131 def read(self, path, fp=None, sections=None, remap=None):
132 if not fp:
133 fp = open(path)
134 self.parse(path, fp.read(), sections, remap, self.read)
General Comments 0
You need to be logged in to leave comments. Login now