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