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