##// END OF EJS Templates
Merge with stable
Martin Geisler -
r10044:dc5462d9 merge default
parent child Browse files
Show More
@@ -1,138 +1,144
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 error
9 import error
10 import re, os
10 import re, os
11
11
12 class sortdict(dict):
12 class sortdict(dict):
13 'a simple sorted dictionary'
13 'a simple sorted dictionary'
14 def __init__(self, data=None):
14 def __init__(self, data=None):
15 self._list = []
15 self._list = []
16 if data:
16 if data:
17 self.update(data)
17 self.update(data)
18 def copy(self):
18 def copy(self):
19 return sortdict(self)
19 return sortdict(self)
20 def __setitem__(self, key, val):
20 def __setitem__(self, key, val):
21 if key in self:
21 if key in self:
22 self._list.remove(key)
22 self._list.remove(key)
23 self._list.append(key)
23 self._list.append(key)
24 dict.__setitem__(self, key, val)
24 dict.__setitem__(self, key, val)
25 def __iter__(self):
25 def __iter__(self):
26 return self._list.__iter__()
26 return self._list.__iter__()
27 def update(self, src):
27 def update(self, src):
28 for k in src:
28 for k in src:
29 self[k] = src[k]
29 self[k] = src[k]
30 def items(self):
30 def items(self):
31 return [(k, self[k]) for k in self._list]
31 return [(k, self[k]) for k in self._list]
32 def __delitem__(self, key):
32 def __delitem__(self, key):
33 dict.__delitem__(self, key)
33 dict.__delitem__(self, key)
34 self._list.remove(key)
34 self._list.remove(key)
35
35
36 class config(object):
36 class config(object):
37 def __init__(self, data=None):
37 def __init__(self, data=None):
38 self._data = {}
38 self._data = {}
39 self._source = {}
39 self._source = {}
40 if data:
40 if data:
41 for k in data._data:
41 for k in data._data:
42 self._data[k] = data[k].copy()
42 self._data[k] = data[k].copy()
43 self._source = data._source.copy()
43 self._source = data._source.copy()
44 def copy(self):
44 def copy(self):
45 return config(self)
45 return config(self)
46 def __contains__(self, section):
46 def __contains__(self, section):
47 return section in self._data
47 return section in self._data
48 def __getitem__(self, section):
48 def __getitem__(self, section):
49 return self._data.get(section, {})
49 return self._data.get(section, {})
50 def __iter__(self):
50 def __iter__(self):
51 for d in self.sections():
51 for d in self.sections():
52 yield d
52 yield d
53 def update(self, src):
53 def update(self, src):
54 for s in src:
54 for s in src:
55 if s not in self:
55 if s not in self:
56 self._data[s] = sortdict()
56 self._data[s] = sortdict()
57 self._data[s].update(src._data[s])
57 self._data[s].update(src._data[s])
58 self._source.update(src._source)
58 self._source.update(src._source)
59 def get(self, section, item, default=None):
59 def get(self, section, item, default=None):
60 return self._data.get(section, {}).get(item, default)
60 return self._data.get(section, {}).get(item, default)
61 def source(self, section, item):
61 def source(self, section, item):
62 return self._source.get((section, item), "")
62 return self._source.get((section, item), "")
63 def sections(self):
63 def sections(self):
64 return sorted(self._data.keys())
64 return sorted(self._data.keys())
65 def items(self, section):
65 def items(self, section):
66 return self._data.get(section, {}).items()
66 return self._data.get(section, {}).items()
67 def set(self, section, item, value, source=""):
67 def set(self, section, item, value, source=""):
68 if section not in self:
68 if section not in self:
69 self._data[section] = sortdict()
69 self._data[section] = sortdict()
70 self._data[section][item] = value
70 self._data[section][item] = value
71 self._source[(section, item)] = source
71 self._source[(section, item)] = source
72
72
73 def parse(self, src, data, sections=None, remap=None, include=None):
73 def parse(self, src, data, sections=None, remap=None, include=None):
74 sectionre = re.compile(r'\[([^\[]+)\]')
74 sectionre = re.compile(r'\[([^\[]+)\]')
75 itemre = re.compile(r'([^=\s][^=]*?)\s*=\s*(.*\S|)')
75 itemre = re.compile(r'([^=\s][^=]*?)\s*=\s*(.*\S|)')
76 contre = re.compile(r'\s+(\S.*\S)')
76 contre = re.compile(r'\s+(\S.*\S)')
77 emptyre = re.compile(r'(;|#|\s*$)')
77 emptyre = re.compile(r'(;|#|\s*$)')
78 unsetre = re.compile(r'%unset\s+(\S+)')
78 unsetre = re.compile(r'%unset\s+(\S+)')
79 includere = re.compile(r'%include\s+(\S.*\S)')
79 includere = re.compile(r'%include\s+(\S.*\S)')
80 section = ""
80 section = ""
81 item = None
81 item = None
82 line = 0
82 line = 0
83 cont = False
83 cont = False
84
84
85 for l in data.splitlines(True):
85 for l in data.splitlines(True):
86 line += 1
86 line += 1
87 if cont:
87 if cont:
88 m = contre.match(l)
88 m = contre.match(l)
89 if m:
89 if m:
90 if sections and section not in sections:
90 if sections and section not in sections:
91 continue
91 continue
92 v = self.get(section, item) + "\n" + m.group(1)
92 v = self.get(section, item) + "\n" + m.group(1)
93 self.set(section, item, v, "%s:%d" % (src, line))
93 self.set(section, item, v, "%s:%d" % (src, line))
94 continue
94 continue
95 item = None
95 item = None
96 cont = False
96 cont = False
97 m = includere.match(l)
97 m = includere.match(l)
98 if m:
98 if m:
99 inc = m.group(1)
99 inc = m.group(1)
100 base = os.path.dirname(src)
100 base = os.path.dirname(src)
101 inc = os.path.normpath(os.path.join(base, inc))
101 inc = os.path.normpath(os.path.join(base, inc))
102 if include:
102 if include:
103 try:
103 include(inc, remap=remap, sections=sections)
104 include(inc, remap=remap, sections=sections)
105 except IOError, inst:
106 msg = _("config error at %s:%d: "
107 "cannot include %s (%s)") \
108 % (src, line, inc, inst.strerror)
109 raise error.ConfigError(msg)
104 continue
110 continue
105 if emptyre.match(l):
111 if emptyre.match(l):
106 continue
112 continue
107 m = sectionre.match(l)
113 m = sectionre.match(l)
108 if m:
114 if m:
109 section = m.group(1)
115 section = m.group(1)
110 if remap:
116 if remap:
111 section = remap.get(section, section)
117 section = remap.get(section, section)
112 if section not in self:
118 if section not in self:
113 self._data[section] = sortdict()
119 self._data[section] = sortdict()
114 continue
120 continue
115 m = itemre.match(l)
121 m = itemre.match(l)
116 if m:
122 if m:
117 item = m.group(1)
123 item = m.group(1)
118 cont = True
124 cont = True
119 if sections and section not in sections:
125 if sections and section not in sections:
120 continue
126 continue
121 self.set(section, item, m.group(2), "%s:%d" % (src, line))
127 self.set(section, item, m.group(2), "%s:%d" % (src, line))
122 continue
128 continue
123 m = unsetre.match(l)
129 m = unsetre.match(l)
124 if m:
130 if m:
125 name = m.group(1)
131 name = m.group(1)
126 if sections and section not in sections:
132 if sections and section not in sections:
127 continue
133 continue
128 if self.get(section, name) != None:
134 if self.get(section, name) != None:
129 del self._data[section][name]
135 del self._data[section][name]
130 continue
136 continue
131
137
132 raise error.ConfigError(_("config error at %s:%d: '%s'")
138 raise error.ConfigError(_("config error at %s:%d: '%s'")
133 % (src, line, l.rstrip()))
139 % (src, line, l.rstrip()))
134
140
135 def read(self, path, fp=None, sections=None, remap=None):
141 def read(self, path, fp=None, sections=None, remap=None):
136 if not fp:
142 if not fp:
137 fp = open(path)
143 fp = open(path)
138 self.parse(path, fp.read(), sections, remap, self.read)
144 self.parse(path, fp.read(), sections, remap, self.read)
@@ -1,20 +1,23
1 #!/bin/sh
1 #!/bin/sh
2
2
3 echo "invalid" > $HGRCPATH
3 echo "invalid" > $HGRCPATH
4 hg version 2>&1 | sed -e "s|$HGRCPATH|\$HGRCPATH|"
4 hg version 2>&1 | sed -e "s|$HGRCPATH|\$HGRCPATH|"
5 echo "" > $HGRCPATH
5 echo "" > $HGRCPATH
6
6
7 # issue1199: escaping
7 # issue1199: escaping
8 hg init "foo%bar"
8 hg init "foo%bar"
9 hg clone "foo%bar" foobar
9 hg clone "foo%bar" foobar
10 p=`pwd`
10 p=`pwd`
11 cd foobar
11 cd foobar
12 cat .hg/hgrc | sed -e "s:$p:...:"
12 cat .hg/hgrc | sed -e "s:$p:...:"
13 hg paths | sed -e "s:$p:...:"
13 hg paths | sed -e "s:$p:...:"
14 hg showconfig | sed -e "s:$p:...:"
14 hg showconfig | sed -e "s:$p:...:"
15 cd ..
15 cd ..
16
16
17 # issue1829: wrong indentation
17 # issue1829: wrong indentation
18 echo '[foo]' > $HGRCPATH
18 echo '[foo]' > $HGRCPATH
19 echo ' x = y' >> $HGRCPATH
19 echo ' x = y' >> $HGRCPATH
20 hg version 2>&1 | sed -e "s|$HGRCPATH|\$HGRCPATH|"
20 hg version 2>&1 | sed -e "s|$HGRCPATH|\$HGRCPATH|"
21
22 echo '%include /no-such-file' > $HGRCPATH
23 hg version 2>&1 | sed -e "s|$HGRCPATH|\$HGRCPATH|"
@@ -1,9 +1,10
1 hg: config error at $HGRCPATH:1: 'invalid'
1 hg: config error at $HGRCPATH:1: 'invalid'
2 updating to branch default
2 updating to branch default
3 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
3 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
4 [paths]
4 [paths]
5 default = .../foo%bar
5 default = .../foo%bar
6 default = .../foo%bar
6 default = .../foo%bar
7 bundle.mainreporoot=.../foobar
7 bundle.mainreporoot=.../foobar
8 paths.default=.../foo%bar
8 paths.default=.../foo%bar
9 hg: config error at $HGRCPATH:2: ' x = y'
9 hg: config error at $HGRCPATH:2: ' x = y'
10 hg: config error at $HGRCPATH:1: cannot include /no-such-file (No such file or directory)
General Comments 0
You need to be logged in to leave comments. Login now