##// END OF EJS Templates
ui: support quotes in configlist (issue2147)...
Henrik Stuart -
r10982:0a548640 default
parent child Browse files
Show More
@@ -111,10 +111,18 b' A line with ``%unset name`` will remove '
111 section, if it has been set previously.
111 section, if it has been set previously.
112
112
113 The values are either free-form text strings, lists of text strings,
113 The values are either free-form text strings, lists of text strings,
114 or Boolean values. Lists are split on whitespace and commas. Boolean
114 or Boolean values. Boolean values can be set to true using any of "1",
115 values can be set to true using any of "1", "yes", "true", or "on" and
115 "yes", "true", or "on" and to false using "0", "no", "false", or "off"
116 to false using "0", "no", "false", or "off" (all case insensitive).
116 (all case insensitive).
117
117
118 List values are separated by whitespace or comma, except when values are
119 placed in double quotation marks::
120
121 allow_read = "John Doe, PhD", brian, betty
122
123 Quotation marks can be escaped by prefixing them with a backslash. Only
124 quotation marks at the beginning of a word is counted as a quotation
125 (e.g., ``foo"bar baz`` is the list of ``foo"bar`` and ``baz``).
118
126
119 Sections
127 Sections
120 --------
128 --------
@@ -867,20 +875,18 b' Web interface configuration.'
867 push is not allowed. If the special value ``*``, any remote user can
875 push is not allowed. If the special value ``*``, any remote user can
868 push, including unauthenticated users. Otherwise, the remote user
876 push, including unauthenticated users. Otherwise, the remote user
869 must have been authenticated, and the authenticated user name must
877 must have been authenticated, and the authenticated user name must
870 be present in this list (separated by whitespace or ``,``). The
878 be present in this list. The contents of the allow_push list are
871 contents of the allow_push list are examined after the deny_push
879 examined after the deny_push list.
872 list.
873 ``allow_read``
880 ``allow_read``
874 If the user has not already been denied repository access due to
881 If the user has not already been denied repository access due to
875 the contents of deny_read, this list determines whether to grant
882 the contents of deny_read, this list determines whether to grant
876 repository access to the user. If this list is not empty, and the
883 repository access to the user. If this list is not empty, and the
877 user is unauthenticated or not present in the list (separated by
884 user is unauthenticated or not present in the list, then access is
878 whitespace or ``,``), then access is denied for the user. If the
885 denied for the user. If the list is empty or not set, then access
879 list is empty or not set, then access is permitted to all users by
886 is permitted to all users by default. Setting allow_read to the
880 default. Setting allow_read to the special value ``*`` is equivalent
887 special value ``*`` is equivalent to it not being set (i.e. access
881 to it not being set (i.e. access is permitted to all users). The
888 is permitted to all users). The contents of the allow_read list are
882 contents of the allow_read list are examined after the deny_read
889 examined after the deny_read list.
883 list.
884 ``allowzip``
890 ``allowzip``
885 (DEPRECATED) Whether to allow .zip downloading of repository
891 (DEPRECATED) Whether to allow .zip downloading of repository
886 revisions. Default is False. This feature creates temporary files.
892 revisions. Default is False. This feature creates temporary files.
@@ -915,17 +921,15 b' Web interface configuration.'
915 Whether to deny pushing to the repository. If empty or not set,
921 Whether to deny pushing to the repository. If empty or not set,
916 push is not denied. If the special value ``*``, all remote users are
922 push is not denied. If the special value ``*``, all remote users are
917 denied push. Otherwise, unauthenticated users are all denied, and
923 denied push. Otherwise, unauthenticated users are all denied, and
918 any authenticated user name present in this list (separated by
924 any authenticated user name present in this list is also denied. The
919 whitespace or ``,``) is also denied. The contents of the deny_push
925 contents of the deny_push list are examined before the allow_push list.
920 list are examined before the allow_push list.
921 ``deny_read``
926 ``deny_read``
922 Whether to deny reading/viewing of the repository. If this list is
927 Whether to deny reading/viewing of the repository. If this list is
923 not empty, unauthenticated users are all denied, and any
928 not empty, unauthenticated users are all denied, and any
924 authenticated user name present in this list (separated by
929 authenticated user name present in this list is also denied access to
925 whitespace or ``,``) is also denied access to the repository. If set
930 the repository. If set to the special value ``*``, all remote users
926 to the special value ``*``, all remote users are denied access
931 are denied access (rarely needed ;). If deny_read is empty or not set,
927 (rarely needed ;). If deny_read is empty or not set, the
932 the determination of repository access depends on the presence and
928 determination of repository access depends on the presence and
929 content of the allow_read list (see description). If both
933 content of the allow_read list (see description). If both
930 deny_read and allow_read are empty or not set, then access is
934 deny_read and allow_read are empty or not set, then access is
931 permitted to all users by default. If the repository is being
935 permitted to all users by default. If the repository is being
@@ -154,11 +154,82 b' class ui(object):'
154
154
155 def configlist(self, section, name, default=None, untrusted=False):
155 def configlist(self, section, name, default=None, untrusted=False):
156 """Return a list of comma/space separated strings"""
156 """Return a list of comma/space separated strings"""
157
158 def _parse_plain(parts, s, offset):
159 whitespace = False
160 while offset < len(s) and (s[offset].isspace() or s[offset] == ','):
161 whitespace = True
162 offset += 1
163 if offset >= len(s):
164 return None, parts, offset
165 if whitespace:
166 parts.append('')
167 if s[offset] == '"' and not parts[-1]:
168 return _parse_quote, parts, offset + 1
169 elif s[offset] == '"' and parts[-1][-1] == '\\':
170 parts[-1] = parts[-1][:-1] + s[offset]
171 return _parse_plain, parts, offset + 1
172 parts[-1] += s[offset]
173 return _parse_plain, parts, offset + 1
174
175 def _parse_quote(parts, s, offset):
176 if offset < len(s) and s[offset] == '"': # ""
177 parts.append('')
178 offset += 1
179 while offset < len(s) and (s[offset].isspace() or
180 s[offset] == ','):
181 offset += 1
182 return _parse_plain, parts, offset
183
184 while offset < len(s) and s[offset] != '"':
185 if s[offset] == '\\' and offset + 1 < len(s) and s[offset + 1] == '"':
186 offset += 1
187 parts[-1] += '"'
188 else:
189 parts[-1] += s[offset]
190 offset += 1
191
192 if offset >= len(s):
193 real_parts = _configlist(parts[-1])
194 if not real_parts:
195 parts[-1] = '"'
196 else:
197 real_parts[0] = '"' + real_parts[0]
198 parts = parts[:-1]
199 parts.extend(real_parts)
200 return None, parts, offset
201
202 offset += 1
203 while offset < len(s) and s[offset] in [' ', ',']:
204 offset += 1
205
206 if offset < len(s):
207 if offset + 1 == len(s) and s[offset] == '"':
208 parts[-1] += '"'
209 offset += 1
210 else:
211 parts.append('')
212 else:
213 return None, parts, offset
214
215 return _parse_plain, parts, offset
216
217 def _configlist(s):
218 s = s.rstrip(' ,')
219 if not s:
220 return None
221 parser, parts, offset = _parse_plain, [''], 0
222 while parser:
223 parser, parts, offset = parser(parts, s, offset)
224 return parts
225
157 result = self.config(section, name, untrusted=untrusted)
226 result = self.config(section, name, untrusted=untrusted)
158 if result is None:
227 if result is None:
159 result = default or []
228 result = default or []
160 if isinstance(result, basestring):
229 if isinstance(result, basestring):
161 result = result.replace(",", " ").split()
230 result = _configlist(result)
231 if result is None:
232 result = default or []
162 return result
233 return result
163
234
164 def has_section(self, section, untrusted=False):
235 def has_section(self, section, untrusted=False):
@@ -11,6 +11,19 b' parsed = dispatch._parseconfig(testui, ['
11 'lists.list2=foo bar baz',
11 'lists.list2=foo bar baz',
12 'lists.list3=alice, bob',
12 'lists.list3=alice, bob',
13 'lists.list4=foo bar baz alice, bob',
13 'lists.list4=foo bar baz alice, bob',
14 'lists.list5=abc d"ef"g "hij def"',
15 'lists.list6="hello world", "how are you?"',
16 'lists.list7=Do"Not"Separate',
17 'lists.list8="Do"Separate',
18 'lists.list9="Do\\"NotSeparate"',
19 'lists.list10=string "with extraneous" quotation mark"',
20 'lists.list11=x, y',
21 'lists.list12="x", "y"',
22 'lists.list13=""" key = "x", "y" """',
23 'lists.list14=,,,, ',
24 'lists.list15=" just with starting quotation',
25 'lists.list16="longer quotation" with "no ending quotation',
26 'lists.list17=this is \\" "not a quotation mark"',
14 ])
27 ])
15
28
16 print repr(testui.configitems('values'))
29 print repr(testui.configitems('values'))
@@ -36,6 +49,19 b" print repr(testui.configlist('lists', 'l"
36 print repr(testui.configlist('lists', 'list3'))
49 print repr(testui.configlist('lists', 'list3'))
37 print repr(testui.configlist('lists', 'list4'))
50 print repr(testui.configlist('lists', 'list4'))
38 print repr(testui.configlist('lists', 'list4', ['foo']))
51 print repr(testui.configlist('lists', 'list4', ['foo']))
52 print repr(testui.configlist('lists', 'list5'))
53 print repr(testui.configlist('lists', 'list6'))
54 print repr(testui.configlist('lists', 'list7'))
55 print repr(testui.configlist('lists', 'list8'))
56 print repr(testui.configlist('lists', 'list9'))
57 print repr(testui.configlist('lists', 'list10'))
58 print repr(testui.configlist('lists', 'list11'))
59 print repr(testui.configlist('lists', 'list12'))
60 print repr(testui.configlist('lists', 'list13'))
61 print repr(testui.configlist('lists', 'list14'))
62 print repr(testui.configlist('lists', 'list15'))
63 print repr(testui.configlist('lists', 'list16'))
64 print repr(testui.configlist('lists', 'list17'))
39 print repr(testui.configlist('lists', 'unknown'))
65 print repr(testui.configlist('lists', 'unknown'))
40 print repr(testui.configlist('lists', 'unknown', ''))
66 print repr(testui.configlist('lists', 'unknown', ''))
41 print repr(testui.configlist('lists', 'unknown', 'foo'))
67 print repr(testui.configlist('lists', 'unknown', 'foo'))
@@ -1,5 +1,5 b''
1 [('string', 'string value'), ('bool1', 'true'), ('bool2', 'false')]
1 [('string', 'string value'), ('bool1', 'true'), ('bool2', 'false')]
2 [('list1', 'foo'), ('list2', 'foo bar baz'), ('list3', 'alice, bob'), ('list4', 'foo bar baz alice, bob')]
2 [('list1', 'foo'), ('list2', 'foo bar baz'), ('list3', 'alice, bob'), ('list4', 'foo bar baz alice, bob'), ('list5', 'abc d"ef"g "hij def"'), ('list6', '"hello world", "how are you?"'), ('list7', 'Do"Not"Separate'), ('list8', '"Do"Separate'), ('list9', '"Do\\"NotSeparate"'), ('list10', 'string "with extraneous" quotation mark"'), ('list11', 'x, y'), ('list12', '"x", "y"'), ('list13', '""" key = "x", "y" """'), ('list14', ',,,, '), ('list15', '" just with starting quotation'), ('list16', '"longer quotation" with "no ending quotation'), ('list17', 'this is \\" "not a quotation mark"')]
3 ---
3 ---
4 'string value'
4 'string value'
5 'true'
5 'true'
@@ -18,6 +18,19 b' True'
18 ['alice', 'bob']
18 ['alice', 'bob']
19 ['foo', 'bar', 'baz', 'alice', 'bob']
19 ['foo', 'bar', 'baz', 'alice', 'bob']
20 ['foo', 'bar', 'baz', 'alice', 'bob']
20 ['foo', 'bar', 'baz', 'alice', 'bob']
21 ['abc', 'd"ef"g', 'hij def']
22 ['hello world', 'how are you?']
23 ['Do"Not"Separate']
24 ['Do', 'Separate']
25 ['Do"NotSeparate']
26 ['string', 'with extraneous', 'quotation', 'mark"']
27 ['x', 'y']
28 ['x', 'y']
29 ['', ' key = ', 'x"', 'y', '', '"']
30 []
31 ['"', 'just', 'with', 'starting', 'quotation']
32 ['longer quotation', 'with', '"no', 'ending', 'quotation']
33 ['this', 'is', '"', 'not a quotation mark']
21 []
34 []
22 []
35 []
23 ['foo']
36 ['foo']
General Comments 0
You need to be logged in to leave comments. Login now