Show More
@@ -1,554 +1,554 b'' | |||||
1 | # ui.py - user interface bits for mercurial |
|
1 | # ui.py - user interface bits for mercurial | |
2 | # |
|
2 | # | |
3 | # Copyright 2005-2007 Matt Mackall <mpm@selenic.com> |
|
3 | # Copyright 2005-2007 Matt Mackall <mpm@selenic.com> | |
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 errno, getpass, os, socket, sys, tempfile, traceback |
|
9 | import errno, getpass, os, socket, sys, tempfile, traceback | |
10 | import config, util, error |
|
10 | import config, util, error | |
11 |
|
11 | |||
12 | _booleans = {'1': True, 'yes': True, 'true': True, 'on': True, |
|
12 | _booleans = {'1': True, 'yes': True, 'true': True, 'on': True, | |
13 | '0': False, 'no': False, 'false': False, 'off': False} |
|
13 | '0': False, 'no': False, 'false': False, 'off': False} | |
14 |
|
14 | |||
15 | class ui(object): |
|
15 | class ui(object): | |
16 | def __init__(self, src=None): |
|
16 | def __init__(self, src=None): | |
17 | self._buffers = [] |
|
17 | self._buffers = [] | |
18 | self.quiet = self.verbose = self.debugflag = self.tracebackflag = False |
|
18 | self.quiet = self.verbose = self.debugflag = self.tracebackflag = False | |
19 | self._reportuntrusted = True |
|
19 | self._reportuntrusted = True | |
20 | self._ocfg = config.config() # overlay |
|
20 | self._ocfg = config.config() # overlay | |
21 | self._tcfg = config.config() # trusted |
|
21 | self._tcfg = config.config() # trusted | |
22 | self._ucfg = config.config() # untrusted |
|
22 | self._ucfg = config.config() # untrusted | |
23 | self._trustusers = set() |
|
23 | self._trustusers = set() | |
24 | self._trustgroups = set() |
|
24 | self._trustgroups = set() | |
25 |
|
25 | |||
26 | if src: |
|
26 | if src: | |
27 | self._tcfg = src._tcfg.copy() |
|
27 | self._tcfg = src._tcfg.copy() | |
28 | self._ucfg = src._ucfg.copy() |
|
28 | self._ucfg = src._ucfg.copy() | |
29 | self._ocfg = src._ocfg.copy() |
|
29 | self._ocfg = src._ocfg.copy() | |
30 | self._trustusers = src._trustusers.copy() |
|
30 | self._trustusers = src._trustusers.copy() | |
31 | self._trustgroups = src._trustgroups.copy() |
|
31 | self._trustgroups = src._trustgroups.copy() | |
32 | self.environ = src.environ |
|
32 | self.environ = src.environ | |
33 | self.fixconfig() |
|
33 | self.fixconfig() | |
34 | else: |
|
34 | else: | |
35 | # shared read-only environment |
|
35 | # shared read-only environment | |
36 | self.environ = os.environ |
|
36 | self.environ = os.environ | |
37 | # we always trust global config files |
|
37 | # we always trust global config files | |
38 | for f in util.rcpath(): |
|
38 | for f in util.rcpath(): | |
39 | self.readconfig(f, trust=True) |
|
39 | self.readconfig(f, trust=True) | |
40 |
|
40 | |||
41 | def copy(self): |
|
41 | def copy(self): | |
42 | return self.__class__(self) |
|
42 | return self.__class__(self) | |
43 |
|
43 | |||
44 | def _is_trusted(self, fp, f): |
|
44 | def _is_trusted(self, fp, f): | |
45 | st = util.fstat(fp) |
|
45 | st = util.fstat(fp) | |
46 | if util.isowner(st): |
|
46 | if util.isowner(st): | |
47 | return True |
|
47 | return True | |
48 |
|
48 | |||
49 | tusers, tgroups = self._trustusers, self._trustgroups |
|
49 | tusers, tgroups = self._trustusers, self._trustgroups | |
50 | if '*' in tusers or '*' in tgroups: |
|
50 | if '*' in tusers or '*' in tgroups: | |
51 | return True |
|
51 | return True | |
52 |
|
52 | |||
53 | user = util.username(st.st_uid) |
|
53 | user = util.username(st.st_uid) | |
54 | group = util.groupname(st.st_gid) |
|
54 | group = util.groupname(st.st_gid) | |
55 | if user in tusers or group in tgroups or user == util.username(): |
|
55 | if user in tusers or group in tgroups or user == util.username(): | |
56 | return True |
|
56 | return True | |
57 |
|
57 | |||
58 | if self._reportuntrusted: |
|
58 | if self._reportuntrusted: | |
59 | self.warn(_('Not trusting file %s from untrusted ' |
|
59 | self.warn(_('Not trusting file %s from untrusted ' | |
60 | 'user %s, group %s\n') % (f, user, group)) |
|
60 | 'user %s, group %s\n') % (f, user, group)) | |
61 | return False |
|
61 | return False | |
62 |
|
62 | |||
63 | def readconfig(self, filename, root=None, trust=False, |
|
63 | def readconfig(self, filename, root=None, trust=False, | |
64 | sections=None, remap=None): |
|
64 | sections=None, remap=None): | |
65 | try: |
|
65 | try: | |
66 | fp = open(filename) |
|
66 | fp = open(filename) | |
67 | except IOError: |
|
67 | except IOError: | |
68 | if not sections: # ignore unless we were looking for something |
|
68 | if not sections: # ignore unless we were looking for something | |
69 | return |
|
69 | return | |
70 | raise |
|
70 | raise | |
71 |
|
71 | |||
72 | cfg = config.config() |
|
72 | cfg = config.config() | |
73 | trusted = sections or trust or self._is_trusted(fp, filename) |
|
73 | trusted = sections or trust or self._is_trusted(fp, filename) | |
74 |
|
74 | |||
75 | try: |
|
75 | try: | |
76 | cfg.read(filename, fp, sections=sections, remap=remap) |
|
76 | cfg.read(filename, fp, sections=sections, remap=remap) | |
77 | except error.ConfigError, inst: |
|
77 | except error.ConfigError, inst: | |
78 | if trusted: |
|
78 | if trusted: | |
79 | raise |
|
79 | raise | |
80 | self.warn(_("Ignored: %s\n") % str(inst)) |
|
80 | self.warn(_("Ignored: %s\n") % str(inst)) | |
81 |
|
81 | |||
82 | if self.plain(): |
|
82 | if self.plain(): | |
83 | for k in ('debug', 'fallbackencoding', 'quiet', 'slash', |
|
83 | for k in ('debug', 'fallbackencoding', 'quiet', 'slash', | |
84 | 'logtemplate', 'style', |
|
84 | 'logtemplate', 'style', | |
85 | 'traceback', 'verbose'): |
|
85 | 'traceback', 'verbose'): | |
86 | if k in cfg['ui']: |
|
86 | if k in cfg['ui']: | |
87 | del cfg['ui'][k] |
|
87 | del cfg['ui'][k] | |
88 | for k, v in cfg.items('alias'): |
|
88 | for k, v in cfg.items('alias'): | |
89 | del cfg['alias'][k] |
|
89 | del cfg['alias'][k] | |
90 | for k, v in cfg.items('defaults'): |
|
90 | for k, v in cfg.items('defaults'): | |
91 | del cfg['defaults'][k] |
|
91 | del cfg['defaults'][k] | |
92 |
|
92 | |||
93 | if trusted: |
|
93 | if trusted: | |
94 | self._tcfg.update(cfg) |
|
94 | self._tcfg.update(cfg) | |
95 | self._tcfg.update(self._ocfg) |
|
95 | self._tcfg.update(self._ocfg) | |
96 | self._ucfg.update(cfg) |
|
96 | self._ucfg.update(cfg) | |
97 | self._ucfg.update(self._ocfg) |
|
97 | self._ucfg.update(self._ocfg) | |
98 |
|
98 | |||
99 | if root is None: |
|
99 | if root is None: | |
100 | root = os.path.expanduser('~') |
|
100 | root = os.path.expanduser('~') | |
101 | self.fixconfig(root=root) |
|
101 | self.fixconfig(root=root) | |
102 |
|
102 | |||
103 | def fixconfig(self, root=None): |
|
103 | def fixconfig(self, root=None): | |
104 | # translate paths relative to root (or home) into absolute paths |
|
104 | # translate paths relative to root (or home) into absolute paths | |
105 | root = root or os.getcwd() |
|
105 | root = root or os.getcwd() | |
106 | for c in self._tcfg, self._ucfg, self._ocfg: |
|
106 | for c in self._tcfg, self._ucfg, self._ocfg: | |
107 | for n, p in c.items('paths'): |
|
107 | for n, p in c.items('paths'): | |
108 | if p and "://" not in p and not os.path.isabs(p): |
|
108 | if p and "://" not in p and not os.path.isabs(p): | |
109 | c.set("paths", n, os.path.normpath(os.path.join(root, p))) |
|
109 | c.set("paths", n, os.path.normpath(os.path.join(root, p))) | |
110 |
|
110 | |||
111 | # update ui options |
|
111 | # update ui options | |
112 | self.debugflag = self.configbool('ui', 'debug') |
|
112 | self.debugflag = self.configbool('ui', 'debug') | |
113 | self.verbose = self.debugflag or self.configbool('ui', 'verbose') |
|
113 | self.verbose = self.debugflag or self.configbool('ui', 'verbose') | |
114 | self.quiet = not self.debugflag and self.configbool('ui', 'quiet') |
|
114 | self.quiet = not self.debugflag and self.configbool('ui', 'quiet') | |
115 | if self.verbose and self.quiet: |
|
115 | if self.verbose and self.quiet: | |
116 | self.quiet = self.verbose = False |
|
116 | self.quiet = self.verbose = False | |
117 | self._reportuntrusted = self.configbool("ui", "report_untrusted", True) |
|
117 | self._reportuntrusted = self.configbool("ui", "report_untrusted", True) | |
118 | self.tracebackflag = self.configbool('ui', 'traceback', False) |
|
118 | self.tracebackflag = self.configbool('ui', 'traceback', False) | |
119 |
|
119 | |||
120 | # update trust information |
|
120 | # update trust information | |
121 | self._trustusers.update(self.configlist('trusted', 'users')) |
|
121 | self._trustusers.update(self.configlist('trusted', 'users')) | |
122 | self._trustgroups.update(self.configlist('trusted', 'groups')) |
|
122 | self._trustgroups.update(self.configlist('trusted', 'groups')) | |
123 |
|
123 | |||
124 | def setconfig(self, section, name, value): |
|
124 | def setconfig(self, section, name, value): | |
125 | for cfg in (self._ocfg, self._tcfg, self._ucfg): |
|
125 | for cfg in (self._ocfg, self._tcfg, self._ucfg): | |
126 | cfg.set(section, name, value) |
|
126 | cfg.set(section, name, value) | |
127 | self.fixconfig() |
|
127 | self.fixconfig() | |
128 |
|
128 | |||
129 | def _data(self, untrusted): |
|
129 | def _data(self, untrusted): | |
130 | return untrusted and self._ucfg or self._tcfg |
|
130 | return untrusted and self._ucfg or self._tcfg | |
131 |
|
131 | |||
132 | def configsource(self, section, name, untrusted=False): |
|
132 | def configsource(self, section, name, untrusted=False): | |
133 | return self._data(untrusted).source(section, name) or 'none' |
|
133 | return self._data(untrusted).source(section, name) or 'none' | |
134 |
|
134 | |||
135 | def config(self, section, name, default=None, untrusted=False): |
|
135 | def config(self, section, name, default=None, untrusted=False): | |
136 | value = self._data(untrusted).get(section, name, default) |
|
136 | value = self._data(untrusted).get(section, name, default) | |
137 | if self.debugflag and not untrusted and self._reportuntrusted: |
|
137 | if self.debugflag and not untrusted and self._reportuntrusted: | |
138 | uvalue = self._ucfg.get(section, name) |
|
138 | uvalue = self._ucfg.get(section, name) | |
139 | if uvalue is not None and uvalue != value: |
|
139 | if uvalue is not None and uvalue != value: | |
140 | self.debug(_("ignoring untrusted configuration option " |
|
140 | self.debug(_("ignoring untrusted configuration option " | |
141 | "%s.%s = %s\n") % (section, name, uvalue)) |
|
141 | "%s.%s = %s\n") % (section, name, uvalue)) | |
142 | return value |
|
142 | return value | |
143 |
|
143 | |||
144 | def configbool(self, section, name, default=False, untrusted=False): |
|
144 | def configbool(self, section, name, default=False, untrusted=False): | |
145 | v = self.config(section, name, None, untrusted) |
|
145 | v = self.config(section, name, None, untrusted) | |
146 | if v is None: |
|
146 | if v is None: | |
147 | return default |
|
147 | return default | |
148 | if isinstance(v, bool): |
|
148 | if isinstance(v, bool): | |
149 | return v |
|
149 | return v | |
150 | if v.lower() not in _booleans: |
|
150 | if v.lower() not in _booleans: | |
151 | raise error.ConfigError(_("%s.%s not a boolean ('%s')") |
|
151 | raise error.ConfigError(_("%s.%s not a boolean ('%s')") | |
152 | % (section, name, v)) |
|
152 | % (section, name, v)) | |
153 | return _booleans[v.lower()] |
|
153 | return _booleans[v.lower()] | |
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 |
|
157 | |||
158 | def _parse_plain(parts, s, offset): |
|
158 | def _parse_plain(parts, s, offset): | |
159 | whitespace = False |
|
159 | whitespace = False | |
160 | while offset < len(s) and (s[offset].isspace() or s[offset] == ','): |
|
160 | while offset < len(s) and (s[offset].isspace() or s[offset] == ','): | |
161 | whitespace = True |
|
161 | whitespace = True | |
162 | offset += 1 |
|
162 | offset += 1 | |
163 | if offset >= len(s): |
|
163 | if offset >= len(s): | |
164 | return None, parts, offset |
|
164 | return None, parts, offset | |
165 | if whitespace: |
|
165 | if whitespace: | |
166 | parts.append('') |
|
166 | parts.append('') | |
167 | if s[offset] == '"' and not parts[-1]: |
|
167 | if s[offset] == '"' and not parts[-1]: | |
168 | return _parse_quote, parts, offset + 1 |
|
168 | return _parse_quote, parts, offset + 1 | |
169 | elif s[offset] == '"' and parts[-1][-1] == '\\': |
|
169 | elif s[offset] == '"' and parts[-1][-1] == '\\': | |
170 | parts[-1] = parts[-1][:-1] + s[offset] |
|
170 | parts[-1] = parts[-1][:-1] + s[offset] | |
171 | return _parse_plain, parts, offset + 1 |
|
171 | return _parse_plain, parts, offset + 1 | |
172 | parts[-1] += s[offset] |
|
172 | parts[-1] += s[offset] | |
173 | return _parse_plain, parts, offset + 1 |
|
173 | return _parse_plain, parts, offset + 1 | |
174 |
|
174 | |||
175 | def _parse_quote(parts, s, offset): |
|
175 | def _parse_quote(parts, s, offset): | |
176 | if offset < len(s) and s[offset] == '"': # "" |
|
176 | if offset < len(s) and s[offset] == '"': # "" | |
177 | parts.append('') |
|
177 | parts.append('') | |
178 | offset += 1 |
|
178 | offset += 1 | |
179 | while offset < len(s) and (s[offset].isspace() or |
|
179 | while offset < len(s) and (s[offset].isspace() or | |
180 | s[offset] == ','): |
|
180 | s[offset] == ','): | |
181 | offset += 1 |
|
181 | offset += 1 | |
182 | return _parse_plain, parts, offset |
|
182 | return _parse_plain, parts, offset | |
183 |
|
183 | |||
184 | while offset < len(s) and s[offset] != '"': |
|
184 | while offset < len(s) and s[offset] != '"': | |
185 | if (s[offset] == '\\' and offset + 1 < len(s) |
|
185 | if (s[offset] == '\\' and offset + 1 < len(s) | |
186 | and s[offset + 1] == '"'): |
|
186 | and s[offset + 1] == '"'): | |
187 | offset += 1 |
|
187 | offset += 1 | |
188 | parts[-1] += '"' |
|
188 | parts[-1] += '"' | |
189 | else: |
|
189 | else: | |
190 | parts[-1] += s[offset] |
|
190 | parts[-1] += s[offset] | |
191 | offset += 1 |
|
191 | offset += 1 | |
192 |
|
192 | |||
193 | if offset >= len(s): |
|
193 | if offset >= len(s): | |
194 | real_parts = _configlist(parts[-1]) |
|
194 | real_parts = _configlist(parts[-1]) | |
195 | if not real_parts: |
|
195 | if not real_parts: | |
196 | parts[-1] = '"' |
|
196 | parts[-1] = '"' | |
197 | else: |
|
197 | else: | |
198 | real_parts[0] = '"' + real_parts[0] |
|
198 | real_parts[0] = '"' + real_parts[0] | |
199 | parts = parts[:-1] |
|
199 | parts = parts[:-1] | |
200 | parts.extend(real_parts) |
|
200 | parts.extend(real_parts) | |
201 | return None, parts, offset |
|
201 | return None, parts, offset | |
202 |
|
202 | |||
203 | offset += 1 |
|
203 | offset += 1 | |
204 | while offset < len(s) and s[offset] in [' ', ',']: |
|
204 | while offset < len(s) and s[offset] in [' ', ',']: | |
205 | offset += 1 |
|
205 | offset += 1 | |
206 |
|
206 | |||
207 | if offset < len(s): |
|
207 | if offset < len(s): | |
208 | if offset + 1 == len(s) and s[offset] == '"': |
|
208 | if offset + 1 == len(s) and s[offset] == '"': | |
209 | parts[-1] += '"' |
|
209 | parts[-1] += '"' | |
210 | offset += 1 |
|
210 | offset += 1 | |
211 | else: |
|
211 | else: | |
212 | parts.append('') |
|
212 | parts.append('') | |
213 | else: |
|
213 | else: | |
214 | return None, parts, offset |
|
214 | return None, parts, offset | |
215 |
|
215 | |||
216 | return _parse_plain, parts, offset |
|
216 | return _parse_plain, parts, offset | |
217 |
|
217 | |||
218 | def _configlist(s): |
|
218 | def _configlist(s): | |
219 | s = s.rstrip(' ,') |
|
219 | s = s.rstrip(' ,') | |
220 | if not s: |
|
220 | if not s: | |
221 | return None |
|
221 | return None | |
222 | parser, parts, offset = _parse_plain, [''], 0 |
|
222 | parser, parts, offset = _parse_plain, [''], 0 | |
223 | while parser: |
|
223 | while parser: | |
224 | parser, parts, offset = parser(parts, s, offset) |
|
224 | parser, parts, offset = parser(parts, s, offset) | |
225 | return parts |
|
225 | return parts | |
226 |
|
226 | |||
227 | result = self.config(section, name, untrusted=untrusted) |
|
227 | result = self.config(section, name, untrusted=untrusted) | |
228 | if result is None: |
|
228 | if result is None: | |
229 | result = default or [] |
|
229 | result = default or [] | |
230 | if isinstance(result, basestring): |
|
230 | if isinstance(result, basestring): | |
231 | result = _configlist(result) |
|
231 | result = _configlist(result.lstrip(' ,\n')) | |
232 | if result is None: |
|
232 | if result is None: | |
233 | result = default or [] |
|
233 | result = default or [] | |
234 | return result |
|
234 | return result | |
235 |
|
235 | |||
236 | def has_section(self, section, untrusted=False): |
|
236 | def has_section(self, section, untrusted=False): | |
237 | '''tell whether section exists in config.''' |
|
237 | '''tell whether section exists in config.''' | |
238 | return section in self._data(untrusted) |
|
238 | return section in self._data(untrusted) | |
239 |
|
239 | |||
240 | def configitems(self, section, untrusted=False): |
|
240 | def configitems(self, section, untrusted=False): | |
241 | items = self._data(untrusted).items(section) |
|
241 | items = self._data(untrusted).items(section) | |
242 | if self.debugflag and not untrusted and self._reportuntrusted: |
|
242 | if self.debugflag and not untrusted and self._reportuntrusted: | |
243 | for k, v in self._ucfg.items(section): |
|
243 | for k, v in self._ucfg.items(section): | |
244 | if self._tcfg.get(section, k) != v: |
|
244 | if self._tcfg.get(section, k) != v: | |
245 | self.debug(_("ignoring untrusted configuration option " |
|
245 | self.debug(_("ignoring untrusted configuration option " | |
246 | "%s.%s = %s\n") % (section, k, v)) |
|
246 | "%s.%s = %s\n") % (section, k, v)) | |
247 | return items |
|
247 | return items | |
248 |
|
248 | |||
249 | def walkconfig(self, untrusted=False): |
|
249 | def walkconfig(self, untrusted=False): | |
250 | cfg = self._data(untrusted) |
|
250 | cfg = self._data(untrusted) | |
251 | for section in cfg.sections(): |
|
251 | for section in cfg.sections(): | |
252 | for name, value in self.configitems(section, untrusted): |
|
252 | for name, value in self.configitems(section, untrusted): | |
253 | yield section, name, str(value).replace('\n', '\\n') |
|
253 | yield section, name, str(value).replace('\n', '\\n') | |
254 |
|
254 | |||
255 | def plain(self): |
|
255 | def plain(self): | |
256 | return 'HGPLAIN' in os.environ |
|
256 | return 'HGPLAIN' in os.environ | |
257 |
|
257 | |||
258 | def username(self): |
|
258 | def username(self): | |
259 | """Return default username to be used in commits. |
|
259 | """Return default username to be used in commits. | |
260 |
|
260 | |||
261 | Searched in this order: $HGUSER, [ui] section of hgrcs, $EMAIL |
|
261 | Searched in this order: $HGUSER, [ui] section of hgrcs, $EMAIL | |
262 | and stop searching if one of these is set. |
|
262 | and stop searching if one of these is set. | |
263 | If not found and ui.askusername is True, ask the user, else use |
|
263 | If not found and ui.askusername is True, ask the user, else use | |
264 | ($LOGNAME or $USER or $LNAME or $USERNAME) + "@full.hostname". |
|
264 | ($LOGNAME or $USER or $LNAME or $USERNAME) + "@full.hostname". | |
265 | """ |
|
265 | """ | |
266 | user = os.environ.get("HGUSER") |
|
266 | user = os.environ.get("HGUSER") | |
267 | if user is None: |
|
267 | if user is None: | |
268 | user = self.config("ui", "username") |
|
268 | user = self.config("ui", "username") | |
269 | if user is not None: |
|
269 | if user is not None: | |
270 | user = os.path.expandvars(user) |
|
270 | user = os.path.expandvars(user) | |
271 | if user is None: |
|
271 | if user is None: | |
272 | user = os.environ.get("EMAIL") |
|
272 | user = os.environ.get("EMAIL") | |
273 | if user is None and self.configbool("ui", "askusername"): |
|
273 | if user is None and self.configbool("ui", "askusername"): | |
274 | user = self.prompt(_("enter a commit username:"), default=None) |
|
274 | user = self.prompt(_("enter a commit username:"), default=None) | |
275 | if user is None and not self.interactive(): |
|
275 | if user is None and not self.interactive(): | |
276 | try: |
|
276 | try: | |
277 | user = '%s@%s' % (util.getuser(), socket.getfqdn()) |
|
277 | user = '%s@%s' % (util.getuser(), socket.getfqdn()) | |
278 | self.warn(_("No username found, using '%s' instead\n") % user) |
|
278 | self.warn(_("No username found, using '%s' instead\n") % user) | |
279 | except KeyError: |
|
279 | except KeyError: | |
280 | pass |
|
280 | pass | |
281 | if not user: |
|
281 | if not user: | |
282 | raise util.Abort(_('no username supplied (see "hg help config")')) |
|
282 | raise util.Abort(_('no username supplied (see "hg help config")')) | |
283 | if "\n" in user: |
|
283 | if "\n" in user: | |
284 | raise util.Abort(_("username %s contains a newline\n") % repr(user)) |
|
284 | raise util.Abort(_("username %s contains a newline\n") % repr(user)) | |
285 | return user |
|
285 | return user | |
286 |
|
286 | |||
287 | def shortuser(self, user): |
|
287 | def shortuser(self, user): | |
288 | """Return a short representation of a user name or email address.""" |
|
288 | """Return a short representation of a user name or email address.""" | |
289 | if not self.verbose: |
|
289 | if not self.verbose: | |
290 | user = util.shortuser(user) |
|
290 | user = util.shortuser(user) | |
291 | return user |
|
291 | return user | |
292 |
|
292 | |||
293 | def _path(self, loc): |
|
293 | def _path(self, loc): | |
294 | p = self.config('paths', loc) |
|
294 | p = self.config('paths', loc) | |
295 | if p: |
|
295 | if p: | |
296 | if '%%' in p: |
|
296 | if '%%' in p: | |
297 | self.warn("(deprecated '%%' in path %s=%s from %s)\n" % |
|
297 | self.warn("(deprecated '%%' in path %s=%s from %s)\n" % | |
298 | (loc, p, self.configsource('paths', loc))) |
|
298 | (loc, p, self.configsource('paths', loc))) | |
299 | p = p.replace('%%', '%') |
|
299 | p = p.replace('%%', '%') | |
300 | p = util.expandpath(p) |
|
300 | p = util.expandpath(p) | |
301 | return p |
|
301 | return p | |
302 |
|
302 | |||
303 | def expandpath(self, loc, default=None): |
|
303 | def expandpath(self, loc, default=None): | |
304 | """Return repository location relative to cwd or from [paths]""" |
|
304 | """Return repository location relative to cwd or from [paths]""" | |
305 | if "://" in loc or os.path.isdir(os.path.join(loc, '.hg')): |
|
305 | if "://" in loc or os.path.isdir(os.path.join(loc, '.hg')): | |
306 | return loc |
|
306 | return loc | |
307 |
|
307 | |||
308 | path = self._path(loc) |
|
308 | path = self._path(loc) | |
309 | if not path and default is not None: |
|
309 | if not path and default is not None: | |
310 | path = self._path(default) |
|
310 | path = self._path(default) | |
311 | return path or loc |
|
311 | return path or loc | |
312 |
|
312 | |||
313 | def pushbuffer(self): |
|
313 | def pushbuffer(self): | |
314 | self._buffers.append([]) |
|
314 | self._buffers.append([]) | |
315 |
|
315 | |||
316 | def popbuffer(self, labeled=False): |
|
316 | def popbuffer(self, labeled=False): | |
317 | '''pop the last buffer and return the buffered output |
|
317 | '''pop the last buffer and return the buffered output | |
318 |
|
318 | |||
319 | If labeled is True, any labels associated with buffered |
|
319 | If labeled is True, any labels associated with buffered | |
320 | output will be handled. By default, this has no effect |
|
320 | output will be handled. By default, this has no effect | |
321 | on the output returned, but extensions and GUI tools may |
|
321 | on the output returned, but extensions and GUI tools may | |
322 | handle this argument and returned styled output. If output |
|
322 | handle this argument and returned styled output. If output | |
323 | is being buffered so it can be captured and parsed or |
|
323 | is being buffered so it can be captured and parsed or | |
324 | processed, labeled should not be set to True. |
|
324 | processed, labeled should not be set to True. | |
325 | ''' |
|
325 | ''' | |
326 | return "".join(self._buffers.pop()) |
|
326 | return "".join(self._buffers.pop()) | |
327 |
|
327 | |||
328 | def write(self, *args, **opts): |
|
328 | def write(self, *args, **opts): | |
329 | '''write args to output |
|
329 | '''write args to output | |
330 |
|
330 | |||
331 | By default, this method simply writes to the buffer or stdout, |
|
331 | By default, this method simply writes to the buffer or stdout, | |
332 | but extensions or GUI tools may override this method, |
|
332 | but extensions or GUI tools may override this method, | |
333 | write_err(), popbuffer(), and label() to style output from |
|
333 | write_err(), popbuffer(), and label() to style output from | |
334 | various parts of hg. |
|
334 | various parts of hg. | |
335 |
|
335 | |||
336 | An optional keyword argument, "label", can be passed in. |
|
336 | An optional keyword argument, "label", can be passed in. | |
337 | This should be a string containing label names separated by |
|
337 | This should be a string containing label names separated by | |
338 | space. Label names take the form of "topic.type". For example, |
|
338 | space. Label names take the form of "topic.type". For example, | |
339 | ui.debug() issues a label of "ui.debug". |
|
339 | ui.debug() issues a label of "ui.debug". | |
340 |
|
340 | |||
341 | When labeling output for a specific command, a label of |
|
341 | When labeling output for a specific command, a label of | |
342 | "cmdname.type" is recommended. For example, status issues |
|
342 | "cmdname.type" is recommended. For example, status issues | |
343 | a label of "status.modified" for modified files. |
|
343 | a label of "status.modified" for modified files. | |
344 | ''' |
|
344 | ''' | |
345 | if self._buffers: |
|
345 | if self._buffers: | |
346 | self._buffers[-1].extend([str(a) for a in args]) |
|
346 | self._buffers[-1].extend([str(a) for a in args]) | |
347 | else: |
|
347 | else: | |
348 | for a in args: |
|
348 | for a in args: | |
349 | sys.stdout.write(str(a)) |
|
349 | sys.stdout.write(str(a)) | |
350 |
|
350 | |||
351 | def write_err(self, *args, **opts): |
|
351 | def write_err(self, *args, **opts): | |
352 | try: |
|
352 | try: | |
353 | if not getattr(sys.stdout, 'closed', False): |
|
353 | if not getattr(sys.stdout, 'closed', False): | |
354 | sys.stdout.flush() |
|
354 | sys.stdout.flush() | |
355 | for a in args: |
|
355 | for a in args: | |
356 | sys.stderr.write(str(a)) |
|
356 | sys.stderr.write(str(a)) | |
357 | # stderr may be buffered under win32 when redirected to files, |
|
357 | # stderr may be buffered under win32 when redirected to files, | |
358 | # including stdout. |
|
358 | # including stdout. | |
359 | if not getattr(sys.stderr, 'closed', False): |
|
359 | if not getattr(sys.stderr, 'closed', False): | |
360 | sys.stderr.flush() |
|
360 | sys.stderr.flush() | |
361 | except IOError, inst: |
|
361 | except IOError, inst: | |
362 | if inst.errno != errno.EPIPE: |
|
362 | if inst.errno != errno.EPIPE: | |
363 | raise |
|
363 | raise | |
364 |
|
364 | |||
365 | def flush(self): |
|
365 | def flush(self): | |
366 | try: sys.stdout.flush() |
|
366 | try: sys.stdout.flush() | |
367 | except: pass |
|
367 | except: pass | |
368 | try: sys.stderr.flush() |
|
368 | try: sys.stderr.flush() | |
369 | except: pass |
|
369 | except: pass | |
370 |
|
370 | |||
371 | def interactive(self): |
|
371 | def interactive(self): | |
372 | i = self.configbool("ui", "interactive", None) |
|
372 | i = self.configbool("ui", "interactive", None) | |
373 | if i is None: |
|
373 | if i is None: | |
374 | try: |
|
374 | try: | |
375 | return sys.stdin.isatty() |
|
375 | return sys.stdin.isatty() | |
376 | except AttributeError: |
|
376 | except AttributeError: | |
377 | # some environments replace stdin without implementing isatty |
|
377 | # some environments replace stdin without implementing isatty | |
378 | # usually those are non-interactive |
|
378 | # usually those are non-interactive | |
379 | return False |
|
379 | return False | |
380 |
|
380 | |||
381 | return i |
|
381 | return i | |
382 |
|
382 | |||
383 | def _readline(self, prompt=''): |
|
383 | def _readline(self, prompt=''): | |
384 | if sys.stdin.isatty(): |
|
384 | if sys.stdin.isatty(): | |
385 | try: |
|
385 | try: | |
386 | # magically add command line editing support, where |
|
386 | # magically add command line editing support, where | |
387 | # available |
|
387 | # available | |
388 | import readline |
|
388 | import readline | |
389 | # force demandimport to really load the module |
|
389 | # force demandimport to really load the module | |
390 | readline.read_history_file |
|
390 | readline.read_history_file | |
391 | # windows sometimes raises something other than ImportError |
|
391 | # windows sometimes raises something other than ImportError | |
392 | except Exception: |
|
392 | except Exception: | |
393 | pass |
|
393 | pass | |
394 | line = raw_input(prompt) |
|
394 | line = raw_input(prompt) | |
395 | # When stdin is in binary mode on Windows, it can cause |
|
395 | # When stdin is in binary mode on Windows, it can cause | |
396 | # raw_input() to emit an extra trailing carriage return |
|
396 | # raw_input() to emit an extra trailing carriage return | |
397 | if os.linesep == '\r\n' and line and line[-1] == '\r': |
|
397 | if os.linesep == '\r\n' and line and line[-1] == '\r': | |
398 | line = line[:-1] |
|
398 | line = line[:-1] | |
399 | return line |
|
399 | return line | |
400 |
|
400 | |||
401 | def prompt(self, msg, default="y"): |
|
401 | def prompt(self, msg, default="y"): | |
402 | """Prompt user with msg, read response. |
|
402 | """Prompt user with msg, read response. | |
403 | If ui is not interactive, the default is returned. |
|
403 | If ui is not interactive, the default is returned. | |
404 | """ |
|
404 | """ | |
405 | if not self.interactive(): |
|
405 | if not self.interactive(): | |
406 | self.write(msg, ' ', default, "\n") |
|
406 | self.write(msg, ' ', default, "\n") | |
407 | return default |
|
407 | return default | |
408 | try: |
|
408 | try: | |
409 | r = self._readline(msg + ' ') |
|
409 | r = self._readline(msg + ' ') | |
410 | if not r: |
|
410 | if not r: | |
411 | return default |
|
411 | return default | |
412 | return r |
|
412 | return r | |
413 | except EOFError: |
|
413 | except EOFError: | |
414 | raise util.Abort(_('response expected')) |
|
414 | raise util.Abort(_('response expected')) | |
415 |
|
415 | |||
416 | def promptchoice(self, msg, choices, default=0): |
|
416 | def promptchoice(self, msg, choices, default=0): | |
417 | """Prompt user with msg, read response, and ensure it matches |
|
417 | """Prompt user with msg, read response, and ensure it matches | |
418 | one of the provided choices. The index of the choice is returned. |
|
418 | one of the provided choices. The index of the choice is returned. | |
419 | choices is a sequence of acceptable responses with the format: |
|
419 | choices is a sequence of acceptable responses with the format: | |
420 | ('&None', 'E&xec', 'Sym&link') Responses are case insensitive. |
|
420 | ('&None', 'E&xec', 'Sym&link') Responses are case insensitive. | |
421 | If ui is not interactive, the default is returned. |
|
421 | If ui is not interactive, the default is returned. | |
422 | """ |
|
422 | """ | |
423 | resps = [s[s.index('&')+1].lower() for s in choices] |
|
423 | resps = [s[s.index('&')+1].lower() for s in choices] | |
424 | while True: |
|
424 | while True: | |
425 | r = self.prompt(msg, resps[default]) |
|
425 | r = self.prompt(msg, resps[default]) | |
426 | if r.lower() in resps: |
|
426 | if r.lower() in resps: | |
427 | return resps.index(r.lower()) |
|
427 | return resps.index(r.lower()) | |
428 | self.write(_("unrecognized response\n")) |
|
428 | self.write(_("unrecognized response\n")) | |
429 |
|
429 | |||
430 | def getpass(self, prompt=None, default=None): |
|
430 | def getpass(self, prompt=None, default=None): | |
431 | if not self.interactive(): |
|
431 | if not self.interactive(): | |
432 | return default |
|
432 | return default | |
433 | try: |
|
433 | try: | |
434 | return getpass.getpass(prompt or _('password: ')) |
|
434 | return getpass.getpass(prompt or _('password: ')) | |
435 | except EOFError: |
|
435 | except EOFError: | |
436 | raise util.Abort(_('response expected')) |
|
436 | raise util.Abort(_('response expected')) | |
437 | def status(self, *msg, **opts): |
|
437 | def status(self, *msg, **opts): | |
438 | '''write status message to output (if ui.quiet is False) |
|
438 | '''write status message to output (if ui.quiet is False) | |
439 |
|
439 | |||
440 | This adds an output label of "ui.status". |
|
440 | This adds an output label of "ui.status". | |
441 | ''' |
|
441 | ''' | |
442 | if not self.quiet: |
|
442 | if not self.quiet: | |
443 | opts['label'] = opts.get('label', '') + ' ui.status' |
|
443 | opts['label'] = opts.get('label', '') + ' ui.status' | |
444 | self.write(*msg, **opts) |
|
444 | self.write(*msg, **opts) | |
445 | def warn(self, *msg, **opts): |
|
445 | def warn(self, *msg, **opts): | |
446 | '''write warning message to output (stderr) |
|
446 | '''write warning message to output (stderr) | |
447 |
|
447 | |||
448 | This adds an output label of "ui.warning". |
|
448 | This adds an output label of "ui.warning". | |
449 | ''' |
|
449 | ''' | |
450 | opts['label'] = opts.get('label', '') + ' ui.warning' |
|
450 | opts['label'] = opts.get('label', '') + ' ui.warning' | |
451 | self.write_err(*msg, **opts) |
|
451 | self.write_err(*msg, **opts) | |
452 | def note(self, *msg, **opts): |
|
452 | def note(self, *msg, **opts): | |
453 | '''write note to output (if ui.verbose is True) |
|
453 | '''write note to output (if ui.verbose is True) | |
454 |
|
454 | |||
455 | This adds an output label of "ui.note". |
|
455 | This adds an output label of "ui.note". | |
456 | ''' |
|
456 | ''' | |
457 | if self.verbose: |
|
457 | if self.verbose: | |
458 | opts['label'] = opts.get('label', '') + ' ui.note' |
|
458 | opts['label'] = opts.get('label', '') + ' ui.note' | |
459 | self.write(*msg, **opts) |
|
459 | self.write(*msg, **opts) | |
460 | def debug(self, *msg, **opts): |
|
460 | def debug(self, *msg, **opts): | |
461 | '''write debug message to output (if ui.debugflag is True) |
|
461 | '''write debug message to output (if ui.debugflag is True) | |
462 |
|
462 | |||
463 | This adds an output label of "ui.debug". |
|
463 | This adds an output label of "ui.debug". | |
464 | ''' |
|
464 | ''' | |
465 | if self.debugflag: |
|
465 | if self.debugflag: | |
466 | opts['label'] = opts.get('label', '') + ' ui.debug' |
|
466 | opts['label'] = opts.get('label', '') + ' ui.debug' | |
467 | self.write(*msg, **opts) |
|
467 | self.write(*msg, **opts) | |
468 | def edit(self, text, user): |
|
468 | def edit(self, text, user): | |
469 | (fd, name) = tempfile.mkstemp(prefix="hg-editor-", suffix=".txt", |
|
469 | (fd, name) = tempfile.mkstemp(prefix="hg-editor-", suffix=".txt", | |
470 | text=True) |
|
470 | text=True) | |
471 | try: |
|
471 | try: | |
472 | f = os.fdopen(fd, "w") |
|
472 | f = os.fdopen(fd, "w") | |
473 | f.write(text) |
|
473 | f.write(text) | |
474 | f.close() |
|
474 | f.close() | |
475 |
|
475 | |||
476 | editor = self.geteditor() |
|
476 | editor = self.geteditor() | |
477 |
|
477 | |||
478 | util.system("%s \"%s\"" % (editor, name), |
|
478 | util.system("%s \"%s\"" % (editor, name), | |
479 | environ={'HGUSER': user}, |
|
479 | environ={'HGUSER': user}, | |
480 | onerr=util.Abort, errprefix=_("edit failed")) |
|
480 | onerr=util.Abort, errprefix=_("edit failed")) | |
481 |
|
481 | |||
482 | f = open(name) |
|
482 | f = open(name) | |
483 | t = f.read() |
|
483 | t = f.read() | |
484 | f.close() |
|
484 | f.close() | |
485 | finally: |
|
485 | finally: | |
486 | os.unlink(name) |
|
486 | os.unlink(name) | |
487 |
|
487 | |||
488 | return t |
|
488 | return t | |
489 |
|
489 | |||
490 | def traceback(self, exc=None): |
|
490 | def traceback(self, exc=None): | |
491 | '''print exception traceback if traceback printing enabled. |
|
491 | '''print exception traceback if traceback printing enabled. | |
492 | only to call in exception handler. returns true if traceback |
|
492 | only to call in exception handler. returns true if traceback | |
493 | printed.''' |
|
493 | printed.''' | |
494 | if self.tracebackflag: |
|
494 | if self.tracebackflag: | |
495 | if exc: |
|
495 | if exc: | |
496 | traceback.print_exception(exc[0], exc[1], exc[2]) |
|
496 | traceback.print_exception(exc[0], exc[1], exc[2]) | |
497 | else: |
|
497 | else: | |
498 | traceback.print_exc() |
|
498 | traceback.print_exc() | |
499 | return self.tracebackflag |
|
499 | return self.tracebackflag | |
500 |
|
500 | |||
501 | def geteditor(self): |
|
501 | def geteditor(self): | |
502 | '''return editor to use''' |
|
502 | '''return editor to use''' | |
503 | return (os.environ.get("HGEDITOR") or |
|
503 | return (os.environ.get("HGEDITOR") or | |
504 | self.config("ui", "editor") or |
|
504 | self.config("ui", "editor") or | |
505 | os.environ.get("VISUAL") or |
|
505 | os.environ.get("VISUAL") or | |
506 | os.environ.get("EDITOR", "vi")) |
|
506 | os.environ.get("EDITOR", "vi")) | |
507 |
|
507 | |||
508 | def progress(self, topic, pos, item="", unit="", total=None): |
|
508 | def progress(self, topic, pos, item="", unit="", total=None): | |
509 | '''show a progress message |
|
509 | '''show a progress message | |
510 |
|
510 | |||
511 | With stock hg, this is simply a debug message that is hidden |
|
511 | With stock hg, this is simply a debug message that is hidden | |
512 | by default, but with extensions or GUI tools it may be |
|
512 | by default, but with extensions or GUI tools it may be | |
513 | visible. 'topic' is the current operation, 'item' is a |
|
513 | visible. 'topic' is the current operation, 'item' is a | |
514 | non-numeric marker of the current position (ie the currently |
|
514 | non-numeric marker of the current position (ie the currently | |
515 | in-process file), 'pos' is the current numeric position (ie |
|
515 | in-process file), 'pos' is the current numeric position (ie | |
516 | revision, bytes, etc.), unit is a corresponding unit label, |
|
516 | revision, bytes, etc.), unit is a corresponding unit label, | |
517 | and total is the highest expected pos. |
|
517 | and total is the highest expected pos. | |
518 |
|
518 | |||
519 | Multiple nested topics may be active at a time. |
|
519 | Multiple nested topics may be active at a time. | |
520 |
|
520 | |||
521 | All topics should be marked closed by setting pos to None at |
|
521 | All topics should be marked closed by setting pos to None at | |
522 | termination. |
|
522 | termination. | |
523 | ''' |
|
523 | ''' | |
524 |
|
524 | |||
525 | if pos == None or not self.debugflag: |
|
525 | if pos == None or not self.debugflag: | |
526 | return |
|
526 | return | |
527 |
|
527 | |||
528 | if unit: |
|
528 | if unit: | |
529 | unit = ' ' + unit |
|
529 | unit = ' ' + unit | |
530 | if item: |
|
530 | if item: | |
531 | item = ' ' + item |
|
531 | item = ' ' + item | |
532 |
|
532 | |||
533 | if total: |
|
533 | if total: | |
534 | pct = 100.0 * pos / total |
|
534 | pct = 100.0 * pos / total | |
535 | self.debug('%s:%s %s/%s%s (%4.2f%%)\n' |
|
535 | self.debug('%s:%s %s/%s%s (%4.2f%%)\n' | |
536 | % (topic, item, pos, total, unit, pct)) |
|
536 | % (topic, item, pos, total, unit, pct)) | |
537 | else: |
|
537 | else: | |
538 | self.debug('%s:%s %s%s\n' % (topic, item, pos, unit)) |
|
538 | self.debug('%s:%s %s%s\n' % (topic, item, pos, unit)) | |
539 |
|
539 | |||
540 | def label(self, msg, label): |
|
540 | def label(self, msg, label): | |
541 | '''style msg based on supplied label |
|
541 | '''style msg based on supplied label | |
542 |
|
542 | |||
543 | Like ui.write(), this just returns msg unchanged, but extensions |
|
543 | Like ui.write(), this just returns msg unchanged, but extensions | |
544 | and GUI tools can override it to allow styling output without |
|
544 | and GUI tools can override it to allow styling output without | |
545 | writing it. |
|
545 | writing it. | |
546 |
|
546 | |||
547 | ui.write(s, 'label') is equivalent to |
|
547 | ui.write(s, 'label') is equivalent to | |
548 | ui.write(ui.label(s, 'label')). |
|
548 | ui.write(ui.label(s, 'label')). | |
549 |
|
549 | |||
550 | Callers of ui.label() should pass labeled text back to |
|
550 | Callers of ui.label() should pass labeled text back to | |
551 | ui.write() with a label of 'ui.labeled' so implementations know |
|
551 | ui.write() with a label of 'ui.labeled' so implementations know | |
552 | that the text has already been escaped and marked up. |
|
552 | that the text has already been escaped and marked up. | |
553 | ''' |
|
553 | ''' | |
554 | return msg |
|
554 | return msg |
@@ -1,81 +1,83 b'' | |||||
1 | #!/usr/bin/env python |
|
1 | #!/usr/bin/env python | |
2 |
|
2 | |||
3 | from mercurial import ui, dispatch, error |
|
3 | from mercurial import ui, dispatch, error | |
4 |
|
4 | |||
5 | testui = ui.ui() |
|
5 | testui = ui.ui() | |
6 | parsed = dispatch._parseconfig(testui, [ |
|
6 | parsed = dispatch._parseconfig(testui, [ | |
7 | 'values.string=string value', |
|
7 | 'values.string=string value', | |
8 | 'values.bool1=true', |
|
8 | 'values.bool1=true', | |
9 | 'values.bool2=false', |
|
9 | 'values.bool2=false', | |
10 | 'lists.list1=foo', |
|
10 | 'lists.list1=foo', | |
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"', |
|
14 | 'lists.list5=abc d"ef"g "hij def"', | |
15 | 'lists.list6="hello world", "how are you?"', |
|
15 | 'lists.list6="hello world", "how are you?"', | |
16 | 'lists.list7=Do"Not"Separate', |
|
16 | 'lists.list7=Do"Not"Separate', | |
17 | 'lists.list8="Do"Separate', |
|
17 | 'lists.list8="Do"Separate', | |
18 | 'lists.list9="Do\\"NotSeparate"', |
|
18 | 'lists.list9="Do\\"NotSeparate"', | |
19 | 'lists.list10=string "with extraneous" quotation mark"', |
|
19 | 'lists.list10=string "with extraneous" quotation mark"', | |
20 | 'lists.list11=x, y', |
|
20 | 'lists.list11=x, y', | |
21 | 'lists.list12="x", "y"', |
|
21 | 'lists.list12="x", "y"', | |
22 | 'lists.list13=""" key = "x", "y" """', |
|
22 | 'lists.list13=""" key = "x", "y" """', | |
23 | 'lists.list14=,,,, ', |
|
23 | 'lists.list14=,,,, ', | |
24 | 'lists.list15=" just with starting quotation', |
|
24 | 'lists.list15=" just with starting quotation', | |
25 | 'lists.list16="longer quotation" with "no ending quotation', |
|
25 | 'lists.list16="longer quotation" with "no ending quotation', | |
26 | 'lists.list17=this is \\" "not a quotation mark"', |
|
26 | 'lists.list17=this is \\" "not a quotation mark"', | |
|
27 | 'lists.list18=\n \n\nding\ndong', | |||
27 | ]) |
|
28 | ]) | |
28 |
|
29 | |||
29 | print repr(testui.configitems('values')) |
|
30 | print repr(testui.configitems('values')) | |
30 | print repr(testui.configitems('lists')) |
|
31 | print repr(testui.configitems('lists')) | |
31 | print "---" |
|
32 | print "---" | |
32 | print repr(testui.config('values', 'string')) |
|
33 | print repr(testui.config('values', 'string')) | |
33 | print repr(testui.config('values', 'bool1')) |
|
34 | print repr(testui.config('values', 'bool1')) | |
34 | print repr(testui.config('values', 'bool2')) |
|
35 | print repr(testui.config('values', 'bool2')) | |
35 | print repr(testui.config('values', 'unknown')) |
|
36 | print repr(testui.config('values', 'unknown')) | |
36 | print "---" |
|
37 | print "---" | |
37 | try: |
|
38 | try: | |
38 | print repr(testui.configbool('values', 'string')) |
|
39 | print repr(testui.configbool('values', 'string')) | |
39 | except error.ConfigError, inst: |
|
40 | except error.ConfigError, inst: | |
40 | print inst |
|
41 | print inst | |
41 | print repr(testui.configbool('values', 'bool1')) |
|
42 | print repr(testui.configbool('values', 'bool1')) | |
42 | print repr(testui.configbool('values', 'bool2')) |
|
43 | print repr(testui.configbool('values', 'bool2')) | |
43 | print repr(testui.configbool('values', 'bool2', True)) |
|
44 | print repr(testui.configbool('values', 'bool2', True)) | |
44 | print repr(testui.configbool('values', 'unknown')) |
|
45 | print repr(testui.configbool('values', 'unknown')) | |
45 | print repr(testui.configbool('values', 'unknown', True)) |
|
46 | print repr(testui.configbool('values', 'unknown', True)) | |
46 | print "---" |
|
47 | print "---" | |
47 | print repr(testui.configlist('lists', 'list1')) |
|
48 | print repr(testui.configlist('lists', 'list1')) | |
48 | print repr(testui.configlist('lists', 'list2')) |
|
49 | print repr(testui.configlist('lists', 'list2')) | |
49 | print repr(testui.configlist('lists', 'list3')) |
|
50 | print repr(testui.configlist('lists', 'list3')) | |
50 | print repr(testui.configlist('lists', 'list4')) |
|
51 | print repr(testui.configlist('lists', 'list4')) | |
51 | print repr(testui.configlist('lists', 'list4', ['foo'])) |
|
52 | print repr(testui.configlist('lists', 'list4', ['foo'])) | |
52 | print repr(testui.configlist('lists', 'list5')) |
|
53 | print repr(testui.configlist('lists', 'list5')) | |
53 | print repr(testui.configlist('lists', 'list6')) |
|
54 | print repr(testui.configlist('lists', 'list6')) | |
54 | print repr(testui.configlist('lists', 'list7')) |
|
55 | print repr(testui.configlist('lists', 'list7')) | |
55 | print repr(testui.configlist('lists', 'list8')) |
|
56 | print repr(testui.configlist('lists', 'list8')) | |
56 | print repr(testui.configlist('lists', 'list9')) |
|
57 | print repr(testui.configlist('lists', 'list9')) | |
57 | print repr(testui.configlist('lists', 'list10')) |
|
58 | print repr(testui.configlist('lists', 'list10')) | |
58 | print repr(testui.configlist('lists', 'list11')) |
|
59 | print repr(testui.configlist('lists', 'list11')) | |
59 | print repr(testui.configlist('lists', 'list12')) |
|
60 | print repr(testui.configlist('lists', 'list12')) | |
60 | print repr(testui.configlist('lists', 'list13')) |
|
61 | print repr(testui.configlist('lists', 'list13')) | |
61 | print repr(testui.configlist('lists', 'list14')) |
|
62 | print repr(testui.configlist('lists', 'list14')) | |
62 | print repr(testui.configlist('lists', 'list15')) |
|
63 | print repr(testui.configlist('lists', 'list15')) | |
63 | print repr(testui.configlist('lists', 'list16')) |
|
64 | print repr(testui.configlist('lists', 'list16')) | |
64 | print repr(testui.configlist('lists', 'list17')) |
|
65 | print repr(testui.configlist('lists', 'list17')) | |
|
66 | print repr(testui.configlist('lists', 'list18')) | |||
65 | print repr(testui.configlist('lists', 'unknown')) |
|
67 | print repr(testui.configlist('lists', 'unknown')) | |
66 | print repr(testui.configlist('lists', 'unknown', '')) |
|
68 | print repr(testui.configlist('lists', 'unknown', '')) | |
67 | print repr(testui.configlist('lists', 'unknown', 'foo')) |
|
69 | print repr(testui.configlist('lists', 'unknown', 'foo')) | |
68 | print repr(testui.configlist('lists', 'unknown', ['foo'])) |
|
70 | print repr(testui.configlist('lists', 'unknown', ['foo'])) | |
69 | print repr(testui.configlist('lists', 'unknown', 'foo bar')) |
|
71 | print repr(testui.configlist('lists', 'unknown', 'foo bar')) | |
70 | print repr(testui.configlist('lists', 'unknown', 'foo, bar')) |
|
72 | print repr(testui.configlist('lists', 'unknown', 'foo, bar')) | |
71 | print repr(testui.configlist('lists', 'unknown', ['foo bar'])) |
|
73 | print repr(testui.configlist('lists', 'unknown', ['foo bar'])) | |
72 | print repr(testui.configlist('lists', 'unknown', ['foo', 'bar'])) |
|
74 | print repr(testui.configlist('lists', 'unknown', ['foo', 'bar'])) | |
73 |
|
75 | |||
74 | print repr(testui.config('values', 'String')) |
|
76 | print repr(testui.config('values', 'String')) | |
75 |
|
77 | |||
76 | def function(): |
|
78 | def function(): | |
77 | pass |
|
79 | pass | |
78 |
|
80 | |||
79 | # values that aren't strings should work |
|
81 | # values that aren't strings should work | |
80 | testui.setconfig('hook', 'commit', function) |
|
82 | testui.setconfig('hook', 'commit', function) | |
81 | print function == testui.config('hook', 'commit') |
|
83 | print function == testui.config('hook', 'commit') |
@@ -1,43 +1,44 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'), ('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"')] |
|
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"'), ('list18', '\n \n\nding\ndong')] | |
3 | --- |
|
3 | --- | |
4 | 'string value' |
|
4 | 'string value' | |
5 | 'true' |
|
5 | 'true' | |
6 | 'false' |
|
6 | 'false' | |
7 | None |
|
7 | None | |
8 | --- |
|
8 | --- | |
9 | values.string not a boolean ('string value') |
|
9 | values.string not a boolean ('string value') | |
10 | True |
|
10 | True | |
11 | False |
|
11 | False | |
12 | False |
|
12 | False | |
13 | False |
|
13 | False | |
14 | True |
|
14 | True | |
15 | --- |
|
15 | --- | |
16 | ['foo'] |
|
16 | ['foo'] | |
17 | ['foo', 'bar', 'baz'] |
|
17 | ['foo', 'bar', 'baz'] | |
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'] |
|
21 | ['abc', 'd"ef"g', 'hij def'] | |
22 | ['hello world', 'how are you?'] |
|
22 | ['hello world', 'how are you?'] | |
23 | ['Do"Not"Separate'] |
|
23 | ['Do"Not"Separate'] | |
24 | ['Do', 'Separate'] |
|
24 | ['Do', 'Separate'] | |
25 | ['Do"NotSeparate'] |
|
25 | ['Do"NotSeparate'] | |
26 | ['string', 'with extraneous', 'quotation', 'mark"'] |
|
26 | ['string', 'with extraneous', 'quotation', 'mark"'] | |
27 | ['x', 'y'] |
|
27 | ['x', 'y'] | |
28 | ['x', 'y'] |
|
28 | ['x', 'y'] | |
29 | ['', ' key = ', 'x"', 'y', '', '"'] |
|
29 | ['', ' key = ', 'x"', 'y', '', '"'] | |
30 | [] |
|
30 | [] | |
31 | ['"', 'just', 'with', 'starting', 'quotation'] |
|
31 | ['"', 'just', 'with', 'starting', 'quotation'] | |
32 | ['longer quotation', 'with', '"no', 'ending', 'quotation'] |
|
32 | ['longer quotation', 'with', '"no', 'ending', 'quotation'] | |
33 | ['this', 'is', '"', 'not a quotation mark'] |
|
33 | ['this', 'is', '"', 'not a quotation mark'] | |
|
34 | ['ding', 'dong'] | |||
34 | [] |
|
35 | [] | |
35 | [] |
|
36 | [] | |
36 | ['foo'] |
|
37 | ['foo'] | |
37 | ['foo'] |
|
38 | ['foo'] | |
38 | ['foo', 'bar'] |
|
39 | ['foo', 'bar'] | |
39 | ['foo', 'bar'] |
|
40 | ['foo', 'bar'] | |
40 | ['foo bar'] |
|
41 | ['foo bar'] | |
41 | ['foo', 'bar'] |
|
42 | ['foo', 'bar'] | |
42 | None |
|
43 | None | |
43 | True |
|
44 | True |
General Comments 0
You need to be logged in to leave comments.
Login now