##// END OF EJS Templates
config: load included config files in binary mode...
Augie Fackler -
r31154:fd3f4bf9 default
parent child Browse files
Show More
@@ -1,173 +1,173 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 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 from __future__ import absolute_import
8 from __future__ import absolute_import
9
9
10 import errno
10 import errno
11 import os
11 import os
12
12
13 from .i18n import _
13 from .i18n import _
14 from . import (
14 from . import (
15 error,
15 error,
16 util,
16 util,
17 )
17 )
18
18
19 class config(object):
19 class config(object):
20 def __init__(self, data=None, includepaths=[]):
20 def __init__(self, data=None, includepaths=[]):
21 self._data = {}
21 self._data = {}
22 self._source = {}
22 self._source = {}
23 self._unset = []
23 self._unset = []
24 self._includepaths = includepaths
24 self._includepaths = includepaths
25 if data:
25 if data:
26 for k in data._data:
26 for k in data._data:
27 self._data[k] = data[k].copy()
27 self._data[k] = data[k].copy()
28 self._source = data._source.copy()
28 self._source = data._source.copy()
29 def copy(self):
29 def copy(self):
30 return config(self)
30 return config(self)
31 def __contains__(self, section):
31 def __contains__(self, section):
32 return section in self._data
32 return section in self._data
33 def hasitem(self, section, item):
33 def hasitem(self, section, item):
34 return item in self._data.get(section, {})
34 return item in self._data.get(section, {})
35 def __getitem__(self, section):
35 def __getitem__(self, section):
36 return self._data.get(section, {})
36 return self._data.get(section, {})
37 def __iter__(self):
37 def __iter__(self):
38 for d in self.sections():
38 for d in self.sections():
39 yield d
39 yield d
40 def update(self, src):
40 def update(self, src):
41 for s, n in src._unset:
41 for s, n in src._unset:
42 if s in self and n in self._data[s]:
42 if s in self and n in self._data[s]:
43 del self._data[s][n]
43 del self._data[s][n]
44 del self._source[(s, n)]
44 del self._source[(s, n)]
45 for s in src:
45 for s in src:
46 if s not in self:
46 if s not in self:
47 self._data[s] = util.sortdict()
47 self._data[s] = util.sortdict()
48 self._data[s].update(src._data[s])
48 self._data[s].update(src._data[s])
49 self._source.update(src._source)
49 self._source.update(src._source)
50 def get(self, section, item, default=None):
50 def get(self, section, item, default=None):
51 return self._data.get(section, {}).get(item, default)
51 return self._data.get(section, {}).get(item, default)
52
52
53 def backup(self, section, item):
53 def backup(self, section, item):
54 """return a tuple allowing restore to reinstall a previous value
54 """return a tuple allowing restore to reinstall a previous value
55
55
56 The main reason we need it is because it handles the "no data" case.
56 The main reason we need it is because it handles the "no data" case.
57 """
57 """
58 try:
58 try:
59 value = self._data[section][item]
59 value = self._data[section][item]
60 source = self.source(section, item)
60 source = self.source(section, item)
61 return (section, item, value, source)
61 return (section, item, value, source)
62 except KeyError:
62 except KeyError:
63 return (section, item)
63 return (section, item)
64
64
65 def source(self, section, item):
65 def source(self, section, item):
66 return self._source.get((section, item), "")
66 return self._source.get((section, item), "")
67 def sections(self):
67 def sections(self):
68 return sorted(self._data.keys())
68 return sorted(self._data.keys())
69 def items(self, section):
69 def items(self, section):
70 return self._data.get(section, {}).items()
70 return self._data.get(section, {}).items()
71 def set(self, section, item, value, source=""):
71 def set(self, section, item, value, source=""):
72 if section not in self:
72 if section not in self:
73 self._data[section] = util.sortdict()
73 self._data[section] = util.sortdict()
74 self._data[section][item] = value
74 self._data[section][item] = value
75 if source:
75 if source:
76 self._source[(section, item)] = source
76 self._source[(section, item)] = source
77
77
78 def restore(self, data):
78 def restore(self, data):
79 """restore data returned by self.backup"""
79 """restore data returned by self.backup"""
80 if len(data) == 4:
80 if len(data) == 4:
81 # restore old data
81 # restore old data
82 section, item, value, source = data
82 section, item, value, source = data
83 self._data[section][item] = value
83 self._data[section][item] = value
84 self._source[(section, item)] = source
84 self._source[(section, item)] = source
85 else:
85 else:
86 # no data before, remove everything
86 # no data before, remove everything
87 section, item = data
87 section, item = data
88 if section in self._data:
88 if section in self._data:
89 self._data[section].pop(item, None)
89 self._data[section].pop(item, None)
90 self._source.pop((section, item), None)
90 self._source.pop((section, item), None)
91
91
92 def parse(self, src, data, sections=None, remap=None, include=None):
92 def parse(self, src, data, sections=None, remap=None, include=None):
93 sectionre = util.re.compile(br'\[([^\[]+)\]')
93 sectionre = util.re.compile(br'\[([^\[]+)\]')
94 itemre = util.re.compile(br'([^=\s][^=]*?)\s*=\s*(.*\S|)')
94 itemre = util.re.compile(br'([^=\s][^=]*?)\s*=\s*(.*\S|)')
95 contre = util.re.compile(br'\s+(\S|\S.*\S)\s*$')
95 contre = util.re.compile(br'\s+(\S|\S.*\S)\s*$')
96 emptyre = util.re.compile(br'(;|#|\s*$)')
96 emptyre = util.re.compile(br'(;|#|\s*$)')
97 commentre = util.re.compile(br'(;|#)')
97 commentre = util.re.compile(br'(;|#)')
98 unsetre = util.re.compile(br'%unset\s+(\S+)')
98 unsetre = util.re.compile(br'%unset\s+(\S+)')
99 includere = util.re.compile(br'%include\s+(\S|\S.*\S)\s*$')
99 includere = util.re.compile(br'%include\s+(\S|\S.*\S)\s*$')
100 section = ""
100 section = ""
101 item = None
101 item = None
102 line = 0
102 line = 0
103 cont = False
103 cont = False
104
104
105 for l in data.splitlines(True):
105 for l in data.splitlines(True):
106 line += 1
106 line += 1
107 if line == 1 and l.startswith('\xef\xbb\xbf'):
107 if line == 1 and l.startswith('\xef\xbb\xbf'):
108 # Someone set us up the BOM
108 # Someone set us up the BOM
109 l = l[3:]
109 l = l[3:]
110 if cont:
110 if cont:
111 if commentre.match(l):
111 if commentre.match(l):
112 continue
112 continue
113 m = contre.match(l)
113 m = contre.match(l)
114 if m:
114 if m:
115 if sections and section not in sections:
115 if sections and section not in sections:
116 continue
116 continue
117 v = self.get(section, item) + "\n" + m.group(1)
117 v = self.get(section, item) + "\n" + m.group(1)
118 self.set(section, item, v, "%s:%d" % (src, line))
118 self.set(section, item, v, "%s:%d" % (src, line))
119 continue
119 continue
120 item = None
120 item = None
121 cont = False
121 cont = False
122 m = includere.match(l)
122 m = includere.match(l)
123
123
124 if m and include:
124 if m and include:
125 expanded = util.expandpath(m.group(1))
125 expanded = util.expandpath(m.group(1))
126 includepaths = [os.path.dirname(src)] + self._includepaths
126 includepaths = [os.path.dirname(src)] + self._includepaths
127
127
128 for base in includepaths:
128 for base in includepaths:
129 inc = os.path.normpath(os.path.join(base, expanded))
129 inc = os.path.normpath(os.path.join(base, expanded))
130
130
131 try:
131 try:
132 include(inc, remap=remap, sections=sections)
132 include(inc, remap=remap, sections=sections)
133 break
133 break
134 except IOError as inst:
134 except IOError as inst:
135 if inst.errno != errno.ENOENT:
135 if inst.errno != errno.ENOENT:
136 raise error.ParseError(_("cannot include %s (%s)")
136 raise error.ParseError(_("cannot include %s (%s)")
137 % (inc, inst.strerror),
137 % (inc, inst.strerror),
138 "%s:%s" % (src, line))
138 "%s:%s" % (src, line))
139 continue
139 continue
140 if emptyre.match(l):
140 if emptyre.match(l):
141 continue
141 continue
142 m = sectionre.match(l)
142 m = sectionre.match(l)
143 if m:
143 if m:
144 section = m.group(1)
144 section = m.group(1)
145 if remap:
145 if remap:
146 section = remap.get(section, section)
146 section = remap.get(section, section)
147 if section not in self:
147 if section not in self:
148 self._data[section] = util.sortdict()
148 self._data[section] = util.sortdict()
149 continue
149 continue
150 m = itemre.match(l)
150 m = itemre.match(l)
151 if m:
151 if m:
152 item = m.group(1)
152 item = m.group(1)
153 cont = True
153 cont = True
154 if sections and section not in sections:
154 if sections and section not in sections:
155 continue
155 continue
156 self.set(section, item, m.group(2), "%s:%d" % (src, line))
156 self.set(section, item, m.group(2), "%s:%d" % (src, line))
157 continue
157 continue
158 m = unsetre.match(l)
158 m = unsetre.match(l)
159 if m:
159 if m:
160 name = m.group(1)
160 name = m.group(1)
161 if sections and section not in sections:
161 if sections and section not in sections:
162 continue
162 continue
163 if self.get(section, name) is not None:
163 if self.get(section, name) is not None:
164 del self._data[section][name]
164 del self._data[section][name]
165 self._unset.append((section, name))
165 self._unset.append((section, name))
166 continue
166 continue
167
167
168 raise error.ParseError(l.rstrip(), ("%s:%s" % (src, line)))
168 raise error.ParseError(l.rstrip(), ("%s:%s" % (src, line)))
169
169
170 def read(self, path, fp=None, sections=None, remap=None):
170 def read(self, path, fp=None, sections=None, remap=None):
171 if not fp:
171 if not fp:
172 fp = util.posixfile(path)
172 fp = util.posixfile(path, 'rb')
173 self.parse(path, fp.read(), sections, remap, self.read)
173 self.parse(path, fp.read(), sections, remap, self.read)
General Comments 0
You need to be logged in to leave comments. Login now