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