##// END OF EJS Templates
save settings from untrusted config files in a separate configparser...
Alexis S. L. Carvalho -
r3552:9b52239d default
parent child Browse files
Show More
@@ -1,508 +1,514 b''
1 1 HGRC(5)
2 2 =======
3 3 Bryan O'Sullivan <bos@serpentine.com>
4 4
5 5 NAME
6 6 ----
7 7 hgrc - configuration files for Mercurial
8 8
9 9 SYNOPSIS
10 10 --------
11 11
12 12 The Mercurial system uses a set of configuration files to control
13 13 aspects of its behaviour.
14 14
15 15 FILES
16 16 -----
17 17
18 18 Mercurial reads configuration data from several files, if they exist.
19 19 The names of these files depend on the system on which Mercurial is
20 20 installed.
21 21
22 22 (Unix) <install-root>/etc/mercurial/hgrc.d/*.rc::
23 23 (Unix) <install-root>/etc/mercurial/hgrc::
24 24 Per-installation configuration files, searched for in the
25 25 directory where Mercurial is installed. For example, if installed
26 26 in /shared/tools, Mercurial will look in
27 27 /shared/tools/etc/mercurial/hgrc. Options in these files apply to
28 28 all Mercurial commands executed by any user in any directory.
29 29
30 30 (Unix) /etc/mercurial/hgrc.d/*.rc::
31 31 (Unix) /etc/mercurial/hgrc::
32 32 (Windows) C:\Mercurial\Mercurial.ini::
33 33 Per-system configuration files, for the system on which Mercurial
34 34 is running. Options in these files apply to all Mercurial
35 35 commands executed by any user in any directory. Options in these
36 36 files override per-installation options.
37 37
38 38 (Unix) $HOME/.hgrc::
39 39 (Windows) C:\Documents and Settings\USERNAME\Mercurial.ini::
40 40 (Windows) $HOME\Mercurial.ini::
41 41 Per-user configuration file, for the user running Mercurial.
42 42 Options in this file apply to all Mercurial commands executed by
43 43 any user in any directory. Options in this file override
44 44 per-installation and per-system options.
45 45 On Windows system, one of these is chosen exclusively according
46 46 to definition of HOME environment variable.
47 47
48 48 (Unix, Windows) <repo>/.hg/hgrc::
49 49 Per-repository configuration options that only apply in a
50 50 particular repository. This file is not version-controlled, and
51 51 will not get transferred during a "clone" operation. Options in
52 52 this file override options in all other configuration files.
53 On Unix, this file is only read if it belongs to a trusted user
54 or to a trusted group.
53 On Unix, most of this file will be ignored if it doesn't belong
54 to a trusted user or to a trusted group. See the documentation
55 for the trusted section below for more details.
55 56
56 57 SYNTAX
57 58 ------
58 59
59 60 A configuration file consists of sections, led by a "[section]" header
60 61 and followed by "name: value" entries; "name=value" is also accepted.
61 62
62 63 [spam]
63 64 eggs=ham
64 65 green=
65 66 eggs
66 67
67 68 Each line contains one entry. If the lines that follow are indented,
68 69 they are treated as continuations of that entry.
69 70
70 71 Leading whitespace is removed from values. Empty lines are skipped.
71 72
72 73 The optional values can contain format strings which refer to other
73 74 values in the same section, or values in a special DEFAULT section.
74 75
75 76 Lines beginning with "#" or ";" are ignored and may be used to provide
76 77 comments.
77 78
78 79 SECTIONS
79 80 --------
80 81
81 82 This section describes the different sections that may appear in a
82 83 Mercurial "hgrc" file, the purpose of each section, its possible
83 84 keys, and their possible values.
84 85
85 86 decode/encode::
86 87 Filters for transforming files on checkout/checkin. This would
87 88 typically be used for newline processing or other
88 89 localization/canonicalization of files.
89 90
90 91 Filters consist of a filter pattern followed by a filter command.
91 92 Filter patterns are globs by default, rooted at the repository
92 93 root. For example, to match any file ending in ".txt" in the root
93 94 directory only, use the pattern "*.txt". To match any file ending
94 95 in ".c" anywhere in the repository, use the pattern "**.c".
95 96
96 97 The filter command can start with a specifier, either "pipe:" or
97 98 "tempfile:". If no specifier is given, "pipe:" is used by default.
98 99
99 100 A "pipe:" command must accept data on stdin and return the
100 101 transformed data on stdout.
101 102
102 103 Pipe example:
103 104
104 105 [encode]
105 106 # uncompress gzip files on checkin to improve delta compression
106 107 # note: not necessarily a good idea, just an example
107 108 *.gz = pipe: gunzip
108 109
109 110 [decode]
110 111 # recompress gzip files when writing them to the working dir (we
111 112 # can safely omit "pipe:", because it's the default)
112 113 *.gz = gzip
113 114
114 115 A "tempfile:" command is a template. The string INFILE is replaced
115 116 with the name of a temporary file that contains the data to be
116 117 filtered by the command. The string OUTFILE is replaced with the
117 118 name of an empty temporary file, where the filtered data must be
118 119 written by the command.
119 120
120 121 NOTE: the tempfile mechanism is recommended for Windows systems,
121 122 where the standard shell I/O redirection operators often have
122 123 strange effects. In particular, if you are doing line ending
123 124 conversion on Windows using the popular dos2unix and unix2dos
124 125 programs, you *must* use the tempfile mechanism, as using pipes will
125 126 corrupt the contents of your files.
126 127
127 128 Tempfile example:
128 129
129 130 [encode]
130 131 # convert files to unix line ending conventions on checkin
131 132 **.txt = tempfile: dos2unix -n INFILE OUTFILE
132 133
133 134 [decode]
134 135 # convert files to windows line ending conventions when writing
135 136 # them to the working dir
136 137 **.txt = tempfile: unix2dos -n INFILE OUTFILE
137 138
138 139 defaults::
139 140 Use the [defaults] section to define command defaults, i.e. the
140 141 default options/arguments to pass to the specified commands.
141 142
142 143 The following example makes 'hg log' run in verbose mode, and
143 144 'hg status' show only the modified files, by default.
144 145
145 146 [defaults]
146 147 log = -v
147 148 status = -m
148 149
149 150 The actual commands, instead of their aliases, must be used when
150 151 defining command defaults. The command defaults will also be
151 152 applied to the aliases of the commands defined.
152 153
153 154 email::
154 155 Settings for extensions that send email messages.
155 156 from;;
156 157 Optional. Email address to use in "From" header and SMTP envelope
157 158 of outgoing messages.
158 159 to;;
159 160 Optional. Comma-separated list of recipients' email addresses.
160 161 cc;;
161 162 Optional. Comma-separated list of carbon copy recipients'
162 163 email addresses.
163 164 bcc;;
164 165 Optional. Comma-separated list of blind carbon copy
165 166 recipients' email addresses. Cannot be set interactively.
166 167 method;;
167 168 Optional. Method to use to send email messages. If value is
168 169 "smtp" (default), use SMTP (see section "[smtp]" for
169 170 configuration). Otherwise, use as name of program to run that
170 171 acts like sendmail (takes "-f" option for sender, list of
171 172 recipients on command line, message on stdin). Normally, setting
172 173 this to "sendmail" or "/usr/sbin/sendmail" is enough to use
173 174 sendmail to send messages.
174 175
175 176 Email example:
176 177
177 178 [email]
178 179 from = Joseph User <joe.user@example.com>
179 180 method = /usr/sbin/sendmail
180 181
181 182 extensions::
182 183 Mercurial has an extension mechanism for adding new features. To
183 184 enable an extension, create an entry for it in this section.
184 185
185 186 If you know that the extension is already in Python's search path,
186 187 you can give the name of the module, followed by "=", with nothing
187 188 after the "=".
188 189
189 190 Otherwise, give a name that you choose, followed by "=", followed by
190 191 the path to the ".py" file (including the file name extension) that
191 192 defines the extension.
192 193
193 194 Example for ~/.hgrc:
194 195
195 196 [extensions]
196 197 # (the mq extension will get loaded from mercurial's path)
197 198 hgext.mq =
198 199 # (this extension will get loaded from the file specified)
199 200 myfeature = ~/.hgext/myfeature.py
200 201
201 202 hooks::
202 203 Commands or Python functions that get automatically executed by
203 204 various actions such as starting or finishing a commit. Multiple
204 205 hooks can be run for the same action by appending a suffix to the
205 206 action. Overriding a site-wide hook can be done by changing its
206 207 value or setting it to an empty string.
207 208
208 209 Example .hg/hgrc:
209 210
210 211 [hooks]
211 212 # do not use the site-wide hook
212 213 incoming =
213 214 incoming.email = /my/email/hook
214 215 incoming.autobuild = /my/build/hook
215 216
216 217 Most hooks are run with environment variables set that give added
217 218 useful information. For each hook below, the environment variables
218 219 it is passed are listed with names of the form "$HG_foo".
219 220
220 221 changegroup;;
221 222 Run after a changegroup has been added via push, pull or
222 223 unbundle. ID of the first new changeset is in $HG_NODE. URL from
223 224 which changes came is in $HG_URL.
224 225 commit;;
225 226 Run after a changeset has been created in the local repository.
226 227 ID of the newly created changeset is in $HG_NODE. Parent
227 228 changeset IDs are in $HG_PARENT1 and $HG_PARENT2.
228 229 incoming;;
229 230 Run after a changeset has been pulled, pushed, or unbundled into
230 231 the local repository. The ID of the newly arrived changeset is in
231 232 $HG_NODE. URL that was source of changes came is in $HG_URL.
232 233 outgoing;;
233 234 Run after sending changes from local repository to another. ID of
234 235 first changeset sent is in $HG_NODE. Source of operation is in
235 236 $HG_SOURCE; see "preoutgoing" hook for description.
236 237 prechangegroup;;
237 238 Run before a changegroup is added via push, pull or unbundle.
238 239 Exit status 0 allows the changegroup to proceed. Non-zero status
239 240 will cause the push, pull or unbundle to fail. URL from which
240 241 changes will come is in $HG_URL.
241 242 precommit;;
242 243 Run before starting a local commit. Exit status 0 allows the
243 244 commit to proceed. Non-zero status will cause the commit to fail.
244 245 Parent changeset IDs are in $HG_PARENT1 and $HG_PARENT2.
245 246 preoutgoing;;
246 247 Run before computing changes to send from the local repository to
247 248 another. Non-zero status will cause failure. This lets you
248 249 prevent pull over http or ssh. Also prevents against local pull,
249 250 push (outbound) or bundle commands, but not effective, since you
250 251 can just copy files instead then. Source of operation is in
251 252 $HG_SOURCE. If "serve", operation is happening on behalf of
252 253 remote ssh or http repository. If "push", "pull" or "bundle",
253 254 operation is happening on behalf of repository on same system.
254 255 pretag;;
255 256 Run before creating a tag. Exit status 0 allows the tag to be
256 257 created. Non-zero status will cause the tag to fail. ID of
257 258 changeset to tag is in $HG_NODE. Name of tag is in $HG_TAG. Tag
258 259 is local if $HG_LOCAL=1, in repo if $HG_LOCAL=0.
259 260 pretxnchangegroup;;
260 261 Run after a changegroup has been added via push, pull or unbundle,
261 262 but before the transaction has been committed. Changegroup is
262 263 visible to hook program. This lets you validate incoming changes
263 264 before accepting them. Passed the ID of the first new changeset
264 265 in $HG_NODE. Exit status 0 allows the transaction to commit.
265 266 Non-zero status will cause the transaction to be rolled back and
266 267 the push, pull or unbundle will fail. URL that was source of
267 268 changes is in $HG_URL.
268 269 pretxncommit;;
269 270 Run after a changeset has been created but the transaction not yet
270 271 committed. Changeset is visible to hook program. This lets you
271 272 validate commit message and changes. Exit status 0 allows the
272 273 commit to proceed. Non-zero status will cause the transaction to
273 274 be rolled back. ID of changeset is in $HG_NODE. Parent changeset
274 275 IDs are in $HG_PARENT1 and $HG_PARENT2.
275 276 preupdate;;
276 277 Run before updating the working directory. Exit status 0 allows
277 278 the update to proceed. Non-zero status will prevent the update.
278 279 Changeset ID of first new parent is in $HG_PARENT1. If merge, ID
279 280 of second new parent is in $HG_PARENT2.
280 281 tag;;
281 282 Run after a tag is created. ID of tagged changeset is in
282 283 $HG_NODE. Name of tag is in $HG_TAG. Tag is local if
283 284 $HG_LOCAL=1, in repo if $HG_LOCAL=0.
284 285 update;;
285 286 Run after updating the working directory. Changeset ID of first
286 287 new parent is in $HG_PARENT1. If merge, ID of second new parent
287 288 is in $HG_PARENT2. If update succeeded, $HG_ERROR=0. If update
288 289 failed (e.g. because conflicts not resolved), $HG_ERROR=1.
289 290
290 291 Note: In earlier releases, the names of hook environment variables
291 292 did not have a "HG_" prefix. The old unprefixed names are no longer
292 293 provided in the environment.
293 294
294 295 The syntax for Python hooks is as follows:
295 296
296 297 hookname = python:modulename.submodule.callable
297 298
298 299 Python hooks are run within the Mercurial process. Each hook is
299 300 called with at least three keyword arguments: a ui object (keyword
300 301 "ui"), a repository object (keyword "repo"), and a "hooktype"
301 302 keyword that tells what kind of hook is used. Arguments listed as
302 303 environment variables above are passed as keyword arguments, with no
303 304 "HG_" prefix, and names in lower case.
304 305
305 306 A Python hook must return a "true" value to succeed. Returning a
306 307 "false" value or raising an exception is treated as failure of the
307 308 hook.
308 309
309 310 http_proxy::
310 311 Used to access web-based Mercurial repositories through a HTTP
311 312 proxy.
312 313 host;;
313 314 Host name and (optional) port of the proxy server, for example
314 315 "myproxy:8000".
315 316 no;;
316 317 Optional. Comma-separated list of host names that should bypass
317 318 the proxy.
318 319 passwd;;
319 320 Optional. Password to authenticate with at the proxy server.
320 321 user;;
321 322 Optional. User name to authenticate with at the proxy server.
322 323
323 324 smtp::
324 325 Configuration for extensions that need to send email messages.
325 326 host;;
326 327 Host name of mail server, e.g. "mail.example.com".
327 328 port;;
328 329 Optional. Port to connect to on mail server. Default: 25.
329 330 tls;;
330 331 Optional. Whether to connect to mail server using TLS. True or
331 332 False. Default: False.
332 333 username;;
333 334 Optional. User name to authenticate to SMTP server with.
334 335 If username is specified, password must also be specified.
335 336 Default: none.
336 337 password;;
337 338 Optional. Password to authenticate to SMTP server with.
338 339 If username is specified, password must also be specified.
339 340 Default: none.
340 341 local_hostname;;
341 342 Optional. It's the hostname that the sender can use to identify itself
342 343 to the MTA.
343 344
344 345 paths::
345 346 Assigns symbolic names to repositories. The left side is the
346 347 symbolic name, and the right gives the directory or URL that is the
347 348 location of the repository. Default paths can be declared by
348 349 setting the following entries.
349 350 default;;
350 351 Directory or URL to use when pulling if no source is specified.
351 352 Default is set to repository from which the current repository
352 353 was cloned.
353 354 default-push;;
354 355 Optional. Directory or URL to use when pushing if no destination
355 356 is specified.
356 357
357 358 server::
358 359 Controls generic server settings.
359 360 uncompressed;;
360 361 Whether to allow clients to clone a repo using the uncompressed
361 362 streaming protocol. This transfers about 40% more data than a
362 363 regular clone, but uses less memory and CPU on both server and
363 364 client. Over a LAN (100Mbps or better) or a very fast WAN, an
364 365 uncompressed streaming clone is a lot faster (~10x) than a regular
365 366 clone. Over most WAN connections (anything slower than about
366 367 6Mbps), uncompressed streaming is slower, because of the extra
367 368 data transfer overhead. Default is False.
368 369
369 370 trusted::
370 Mercurial will only read the .hg/hgrc file from a repository if
371 it belongs to a trusted user or to a trusted group. This section
372 specifies what users and groups are trusted. The current user is
373 always trusted. To trust everybody, list a user or a group with
374 name "*".
371 For security reasons, Mercurial will not use the settings in
372 the .hg/hgrc file from a repository if it doesn't belong to a
373 trusted user or to a trusted group. The main exception is the
374 web interface, which automatically uses some safe settings, since
375 it's common to serve repositories from different users.
376
377 This section specifies what users and groups are trusted. The
378 current user is always trusted. To trust everybody, list a user
379 or a group with name "*".
380
375 381 users;;
376 382 Comma-separated list of trusted users.
377 383 groups;;
378 384 Comma-separated list of trusted groups.
379 385
380 386 ui::
381 387 User interface controls.
382 388 debug;;
383 389 Print debugging information. True or False. Default is False.
384 390 editor;;
385 391 The editor to use during a commit. Default is $EDITOR or "vi".
386 392 ignore;;
387 393 A file to read per-user ignore patterns from. This file should be in
388 394 the same format as a repository-wide .hgignore file. This option
389 395 supports hook syntax, so if you want to specify multiple ignore
390 396 files, you can do so by setting something like
391 397 "ignore.other = ~/.hgignore2". For details of the ignore file
392 398 format, see the hgignore(5) man page.
393 399 interactive;;
394 400 Allow to prompt the user. True or False. Default is True.
395 401 logtemplate;;
396 402 Template string for commands that print changesets.
397 403 style;;
398 404 Name of style to use for command output.
399 405 merge;;
400 406 The conflict resolution program to use during a manual merge.
401 407 Default is "hgmerge".
402 408 quiet;;
403 409 Reduce the amount of output printed. True or False. Default is False.
404 410 remotecmd;;
405 411 remote command to use for clone/push/pull operations. Default is 'hg'.
406 412 ssh;;
407 413 command to use for SSH connections. Default is 'ssh'.
408 414 strict;;
409 415 Require exact command names, instead of allowing unambiguous
410 416 abbreviations. True or False. Default is False.
411 417 timeout;;
412 418 The timeout used when a lock is held (in seconds), a negative value
413 419 means no timeout. Default is 600.
414 420 username;;
415 421 The committer of a changeset created when running "commit".
416 422 Typically a person's name and email address, e.g. "Fred Widget
417 423 <fred@example.com>". Default is $EMAIL. If no default is found, or the
418 424 configured username is empty, it has to be specified manually.
419 425 verbose;;
420 426 Increase the amount of output printed. True or False. Default is False.
421 427
422 428
423 429 web::
424 430 Web interface configuration.
425 431 accesslog;;
426 432 Where to output the access log. Default is stdout.
427 433 address;;
428 434 Interface address to bind to. Default is all.
429 435 allow_archive;;
430 436 List of archive format (bz2, gz, zip) allowed for downloading.
431 437 Default is empty.
432 438 allowbz2;;
433 439 (DEPRECATED) Whether to allow .tar.bz2 downloading of repo revisions.
434 440 Default is false.
435 441 allowgz;;
436 442 (DEPRECATED) Whether to allow .tar.gz downloading of repo revisions.
437 443 Default is false.
438 444 allowpull;;
439 445 Whether to allow pulling from the repository. Default is true.
440 446 allow_push;;
441 447 Whether to allow pushing to the repository. If empty or not set,
442 448 push is not allowed. If the special value "*", any remote user
443 449 can push, including unauthenticated users. Otherwise, the remote
444 450 user must have been authenticated, and the authenticated user name
445 451 must be present in this list (separated by whitespace or ",").
446 452 The contents of the allow_push list are examined after the
447 453 deny_push list.
448 454 allowzip;;
449 455 (DEPRECATED) Whether to allow .zip downloading of repo revisions.
450 456 Default is false. This feature creates temporary files.
451 457 baseurl;;
452 458 Base URL to use when publishing URLs in other locations, so
453 459 third-party tools like email notification hooks can construct URLs.
454 460 Example: "http://hgserver/repos/"
455 461 contact;;
456 462 Name or email address of the person in charge of the repository.
457 463 Default is "unknown".
458 464 deny_push;;
459 465 Whether to deny pushing to the repository. If empty or not set,
460 466 push is not denied. If the special value "*", all remote users
461 467 are denied push. Otherwise, unauthenticated users are all denied,
462 468 and any authenticated user name present in this list (separated by
463 469 whitespace or ",") is also denied. The contents of the deny_push
464 470 list are examined before the allow_push list.
465 471 description;;
466 472 Textual description of the repository's purpose or contents.
467 473 Default is "unknown".
468 474 errorlog;;
469 475 Where to output the error log. Default is stderr.
470 476 ipv6;;
471 477 Whether to use IPv6. Default is false.
472 478 name;;
473 479 Repository name to use in the web interface. Default is current
474 480 working directory.
475 481 maxchanges;;
476 482 Maximum number of changes to list on the changelog. Default is 10.
477 483 maxfiles;;
478 484 Maximum number of files to list per changeset. Default is 10.
479 485 port;;
480 486 Port to listen on. Default is 8000.
481 487 push_ssl;;
482 488 Whether to require that inbound pushes be transported over SSL to
483 489 prevent password sniffing. Default is true.
484 490 stripes;;
485 491 How many lines a "zebra stripe" should span in multiline output.
486 492 Default is 1; set to 0 to disable.
487 493 style;;
488 494 Which template map style to use.
489 495 templates;;
490 496 Where to find the HTML templates. Default is install path.
491 497
492 498
493 499 AUTHOR
494 500 ------
495 501 Bryan O'Sullivan <bos@serpentine.com>.
496 502
497 503 Mercurial was written by Matt Mackall <mpm@selenic.com>.
498 504
499 505 SEE ALSO
500 506 --------
501 507 hg(1), hgignore(5)
502 508
503 509 COPYING
504 510 -------
505 511 This manual page is copyright 2005 Bryan O'Sullivan.
506 512 Mercurial is copyright 2005, 2006 Matt Mackall.
507 513 Free use of this software is granted under the terms of the GNU General
508 514 Public License (GPL).
@@ -1,377 +1,443 b''
1 1 # ui.py - user interface bits for mercurial
2 2 #
3 3 # Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
4 4 #
5 5 # This software may be used and distributed according to the terms
6 6 # of the GNU General Public License, incorporated herein by reference.
7 7
8 8 from i18n import gettext as _
9 9 from demandload import *
10 10 demandload(globals(), "errno getpass os re socket sys tempfile")
11 11 demandload(globals(), "ConfigParser traceback util")
12 12
13 13 def dupconfig(orig):
14 14 new = util.configparser(orig.defaults())
15 15 updateconfig(orig, new)
16 16 return new
17 17
18 18 def updateconfig(source, dest, sections=None):
19 19 if not sections:
20 20 sections = source.sections()
21 21 for section in sections:
22 22 if not dest.has_section(section):
23 23 dest.add_section(section)
24 24 for name, value in source.items(section, raw=True):
25 25 dest.set(section, name, value)
26 26
27 27 class ui(object):
28 28 def __init__(self, verbose=False, debug=False, quiet=False,
29 29 interactive=True, traceback=False, parentui=None):
30 30 self.overlay = None
31 31 self.header = []
32 32 self.prev_header = []
33 33 if parentui is None:
34 34 # this is the parent of all ui children
35 35 self.parentui = None
36 36 self.readhooks = []
37 37 self.quiet = quiet
38 38 self.verbose = verbose
39 39 self.debugflag = debug
40 40 self.interactive = interactive
41 41 self.traceback = traceback
42 42 self.trusted_users = {}
43 43 self.trusted_groups = {}
44 # if ucdata is not None, its keys must be a superset of cdata's
44 45 self.cdata = util.configparser()
46 self.ucdata = None
45 47 self.readconfig(util.rcpath())
46 48 self.updateopts(verbose, debug, quiet, interactive)
47 49 else:
48 50 # parentui may point to an ui object which is already a child
49 51 self.parentui = parentui.parentui or parentui
50 52 self.readhooks = self.parentui.readhooks[:]
51 53 self.trusted_users = parentui.trusted_users.copy()
52 54 self.trusted_groups = parentui.trusted_groups.copy()
53 55 self.cdata = dupconfig(self.parentui.cdata)
56 if self.parentui.ucdata:
57 self.ucdata = dupconfig(self.parentui.ucdata)
54 58 if self.parentui.overlay:
55 59 self.overlay = dupconfig(self.parentui.overlay)
56 60
57 61 def __getattr__(self, key):
58 62 return getattr(self.parentui, key)
59 63
60 64 def updateopts(self, verbose=False, debug=False, quiet=False,
61 65 interactive=True, traceback=False, config=[]):
62 66 for section, name, value in config:
63 67 self.setconfig(section, name, value)
64 68
65 69 if quiet or verbose or debug:
66 70 self.setconfig('ui', 'quiet', str(bool(quiet)))
67 71 self.setconfig('ui', 'verbose', str(bool(verbose)))
68 72 self.setconfig('ui', 'debug', str(bool(debug)))
69 73
70 74 self.verbosity_constraints()
71 75
72 76 if not interactive:
73 77 self.setconfig('ui', 'interactive', 'False')
74 78 self.interactive = False
75 79
76 80 self.traceback = self.traceback or traceback
77 81
78 82 def verbosity_constraints(self):
79 83 self.quiet = self.configbool('ui', 'quiet')
80 84 self.verbose = self.configbool('ui', 'verbose')
81 85 self.debugflag = self.configbool('ui', 'debug')
82 86
83 87 if self.debugflag:
84 88 self.verbose = True
85 89 self.quiet = False
86 90 elif self.verbose and self.quiet:
87 91 self.quiet = self.verbose = False
88 92
89 93 def _is_trusted(self, fp, f, warn=True):
90 94 tusers = self.trusted_users
91 95 tgroups = self.trusted_groups
92 96 if (tusers or tgroups) and '*' not in tusers and '*' not in tgroups:
93 97 st = util.fstat(fp)
94 98 user = util.username(st.st_uid)
95 99 group = util.groupname(st.st_gid)
96 100 if user not in tusers and group not in tgroups:
97 101 if warn:
98 self.warn(_('Not reading file %s from untrusted '
102 self.warn(_('Not trusting file %s from untrusted '
99 103 'user %s, group %s\n') % (f, user, group))
100 104 return False
101 105 return True
102 106
103 107 def readconfig(self, fn, root=None):
104 108 if isinstance(fn, basestring):
105 109 fn = [fn]
106 110 for f in fn:
107 111 try:
108 112 fp = open(f)
109 113 except IOError:
110 114 continue
111 if not self._is_trusted(fp, f):
112 continue
115 cdata = self.cdata
116 trusted = self._is_trusted(fp, f)
117 if not trusted:
118 if self.ucdata is None:
119 self.ucdata = dupconfig(self.cdata)
120 cdata = self.ucdata
121 elif self.ucdata is not None:
122 # use a separate configparser, so that we don't accidentally
123 # override ucdata settings later on.
124 cdata = util.configparser()
125
113 126 try:
114 self.cdata.readfp(fp, f)
127 cdata.readfp(fp, f)
115 128 except ConfigParser.ParsingError, inst:
116 raise util.Abort(_("Failed to parse %s\n%s") % (f, inst))
129 msg = _("Failed to parse %s\n%s") % (f, inst)
130 if trusted:
131 raise util.Abort(msg)
132 self.warn(_("Ignored: %s\n") % msg)
133
134 if trusted:
135 if cdata != self.cdata:
136 updateconfig(cdata, self.cdata)
137 if self.ucdata is not None:
138 updateconfig(cdata, self.ucdata)
117 139 # override data from config files with data set with ui.setconfig
118 140 if self.overlay:
119 141 updateconfig(self.overlay, self.cdata)
120 142 if root is None:
121 143 root = os.path.expanduser('~')
122 144 self.fixconfig(root=root)
123 145 for hook in self.readhooks:
124 146 hook(self)
125 147
126 148 def addreadhook(self, hook):
127 149 self.readhooks.append(hook)
128 150
129 151 def readsections(self, filename, *sections):
130 "read filename and add only the specified sections to the config data"
152 """Read filename and add only the specified sections to the config data
153
154 The settings are added to the trusted config data.
155 """
131 156 if not sections:
132 157 return
133 158
134 159 cdata = util.configparser()
135 160 try:
136 161 cdata.read(filename)
137 162 except ConfigParser.ParsingError, inst:
138 163 raise util.Abort(_("failed to parse %s\n%s") % (filename,
139 164 inst))
140 165
141 166 for section in sections:
142 167 if not cdata.has_section(section):
143 168 cdata.add_section(section)
144 169
145 170 updateconfig(cdata, self.cdata, sections)
171 if self.ucdata:
172 updateconfig(cdata, self.ucdata, sections)
146 173
147 174 def fixconfig(self, section=None, name=None, value=None, root=None):
148 175 # translate paths relative to root (or home) into absolute paths
149 176 if section is None or section == 'paths':
150 177 if root is None:
151 178 root = os.getcwd()
152 179 items = section and [(name, value)] or []
153 for cdata in self.cdata, self.overlay:
180 for cdata in self.cdata, self.ucdata, self.overlay:
154 181 if not cdata: continue
155 182 if not items and cdata.has_section('paths'):
156 183 pathsitems = cdata.items('paths')
157 184 else:
158 185 pathsitems = items
159 186 for n, path in pathsitems:
160 187 if path and "://" not in path and not os.path.isabs(path):
161 188 cdata.set("paths", n, os.path.join(root, path))
162 189
163 190 # update quiet/verbose/debug and interactive status
164 191 if section is None or section == 'ui':
165 192 if name is None or name in ('quiet', 'verbose', 'debug'):
166 193 self.verbosity_constraints()
167 194
168 195 if name is None or name == 'interactive':
169 196 self.interactive = self.configbool("ui", "interactive", True)
170 197
171 198 # update trust information
172 199 if section is None or section == 'trusted':
173 200 user = util.username()
174 201 if user is not None:
175 202 self.trusted_users[user] = 1
176 203 for user in self.configlist('trusted', 'users'):
177 204 self.trusted_users[user] = 1
178 205 for group in self.configlist('trusted', 'groups'):
179 206 self.trusted_groups[group] = 1
180 207
181 208 def setconfig(self, section, name, value):
182 209 if not self.overlay:
183 210 self.overlay = util.configparser()
184 for cdata in (self.overlay, self.cdata):
211 for cdata in (self.overlay, self.cdata, self.ucdata):
212 if not cdata: continue
185 213 if not cdata.has_section(section):
186 214 cdata.add_section(section)
187 215 cdata.set(section, name, value)
188 216 self.fixconfig(section, name, value)
189 217
190 def _config(self, section, name, default, funcname):
191 if self.cdata.has_option(section, name):
218 def _get_cdata(self, untrusted):
219 if untrusted and self.ucdata:
220 return self.ucdata
221 return self.cdata
222
223 def _config(self, section, name, default, funcname, untrusted, abort):
224 cdata = self._get_cdata(untrusted)
225 if cdata.has_option(section, name):
192 226 try:
193 func = getattr(self.cdata, funcname)
227 func = getattr(cdata, funcname)
194 228 return func(section, name)
195 229 except ConfigParser.InterpolationError, inst:
196 raise util.Abort(_("Error in configuration section [%s] "
197 "parameter '%s':\n%s")
198 % (section, name, inst))
230 msg = _("Error in configuration section [%s] "
231 "parameter '%s':\n%s") % (section, name, inst)
232 if abort:
233 raise util.Abort(msg)
234 self.warn(_("Ignored: %s\n") % msg)
199 235 return default
200 236
201 def config(self, section, name, default=None):
202 return self._config(section, name, default, 'get')
237 def _configcommon(self, section, name, default, funcname, untrusted):
238 value = self._config(section, name, default, funcname,
239 untrusted, abort=True)
240 if self.debugflag and not untrusted and self.ucdata:
241 uvalue = self._config(section, name, None, funcname,
242 untrusted=True, abort=False)
243 if uvalue is not None and uvalue != value:
244 self.warn(_("Ignoring untrusted configuration option "
245 "%s.%s = %s\n") % (section, name, uvalue))
246 return value
203 247
204 def configbool(self, section, name, default=False):
205 return self._config(section, name, default, 'getboolean')
248 def config(self, section, name, default=None, untrusted=False):
249 return self._configcommon(section, name, default, 'get', untrusted)
206 250
207 def configlist(self, section, name, default=None):
251 def configbool(self, section, name, default=False, untrusted=False):
252 return self._configcommon(section, name, default, 'getboolean',
253 untrusted)
254
255 def configlist(self, section, name, default=None, untrusted=False):
208 256 """Return a list of comma/space separated strings"""
209 result = self.config(section, name)
257 result = self.config(section, name, untrusted=untrusted)
210 258 if result is None:
211 259 result = default or []
212 260 if isinstance(result, basestring):
213 261 result = result.replace(",", " ").split()
214 262 return result
215 263
216 def has_config(self, section):
264 def has_config(self, section, untrusted=False):
217 265 '''tell whether section exists in config.'''
218 return self.cdata.has_section(section)
266 cdata = self._get_cdata(untrusted)
267 return cdata.has_section(section)
219 268
220 def configitems(self, section):
269 def _configitems(self, section, untrusted, abort):
221 270 items = {}
222 if self.cdata.has_section(section):
271 cdata = self._get_cdata(untrusted)
272 if cdata.has_section(section):
223 273 try:
224 items.update(dict(self.cdata.items(section)))
274 items.update(dict(cdata.items(section)))
225 275 except ConfigParser.InterpolationError, inst:
226 raise util.Abort(_("Error in configuration section [%s]:\n%s")
227 % (section, inst))
276 msg = _("Error in configuration section [%s]:\n"
277 "%s") % (section, inst)
278 if abort:
279 raise util.Abort(msg)
280 self.warn(_("Ignored: %s\n") % msg)
281 return items
282
283 def configitems(self, section, untrusted=False):
284 items = self._configitems(section, untrusted=untrusted, abort=True)
285 if self.debugflag and not untrusted and self.ucdata:
286 uitems = self._configitems(section, untrusted=True, abort=False)
287 keys = uitems.keys()
288 keys.sort()
289 for k in keys:
290 if uitems[k] != items.get(k):
291 self.warn(_("Ignoring untrusted configuration option "
292 "%s.%s = %s\n") % (section, k, uitems[k]))
228 293 x = items.items()
229 294 x.sort()
230 295 return x
231 296
232 def walkconfig(self):
233 sections = self.cdata.sections()
297 def walkconfig(self, untrusted=False):
298 cdata = self._get_cdata(untrusted)
299 sections = cdata.sections()
234 300 sections.sort()
235 301 for section in sections:
236 for name, value in self.configitems(section):
302 for name, value in self.configitems(section, untrusted):
237 303 yield section, name, value.replace('\n', '\\n')
238 304
239 305 def extensions(self):
240 306 result = self.configitems("extensions")
241 307 for i, (key, value) in enumerate(result):
242 308 if value:
243 309 result[i] = (key, os.path.expanduser(value))
244 310 return result
245 311
246 312 def hgignorefiles(self):
247 313 result = []
248 314 for key, value in self.configitems("ui"):
249 315 if key == 'ignore' or key.startswith('ignore.'):
250 316 result.append(os.path.expanduser(value))
251 317 return result
252 318
253 319 def configrevlog(self):
254 320 result = {}
255 321 for key, value in self.configitems("revlog"):
256 322 result[key.lower()] = value
257 323 return result
258 324
259 325 def username(self):
260 326 """Return default username to be used in commits.
261 327
262 328 Searched in this order: $HGUSER, [ui] section of hgrcs, $EMAIL
263 329 and stop searching if one of these is set.
264 330 Abort if no username is found, to force specifying the commit user
265 331 with line option or repo hgrc.
266 332 """
267 333 user = os.environ.get("HGUSER")
268 334 if user is None:
269 335 user = self.config("ui", "username")
270 336 if user is None:
271 337 user = os.environ.get("EMAIL")
272 338 if not user:
273 339 self.status(_("Please choose a commit username to be recorded "
274 340 "in the changelog via\ncommand line option "
275 341 '(-u "First Last <email@example.com>"), in the\n'
276 342 "configuration files (hgrc), or by setting the "
277 343 "EMAIL environment variable.\n\n"))
278 344 raise util.Abort(_("No commit username specified!"))
279 345 return user
280 346
281 347 def shortuser(self, user):
282 348 """Return a short representation of a user name or email address."""
283 349 if not self.verbose: user = util.shortuser(user)
284 350 return user
285 351
286 352 def expandpath(self, loc, default=None):
287 353 """Return repository location relative to cwd or from [paths]"""
288 354 if "://" in loc or os.path.isdir(loc):
289 355 return loc
290 356
291 357 path = self.config("paths", loc)
292 358 if not path and default is not None:
293 359 path = self.config("paths", default)
294 360 return path or loc
295 361
296 362 def write(self, *args):
297 363 if self.header:
298 364 if self.header != self.prev_header:
299 365 self.prev_header = self.header
300 366 self.write(*self.header)
301 367 self.header = []
302 368 for a in args:
303 369 sys.stdout.write(str(a))
304 370
305 371 def write_header(self, *args):
306 372 for a in args:
307 373 self.header.append(str(a))
308 374
309 375 def write_err(self, *args):
310 376 try:
311 377 if not sys.stdout.closed: sys.stdout.flush()
312 378 for a in args:
313 379 sys.stderr.write(str(a))
314 380 except IOError, inst:
315 381 if inst.errno != errno.EPIPE:
316 382 raise
317 383
318 384 def flush(self):
319 385 try: sys.stdout.flush()
320 386 except: pass
321 387 try: sys.stderr.flush()
322 388 except: pass
323 389
324 390 def readline(self):
325 391 return sys.stdin.readline()[:-1]
326 392 def prompt(self, msg, pat=None, default="y"):
327 393 if not self.interactive: return default
328 394 while 1:
329 395 self.write(msg, " ")
330 396 r = self.readline()
331 397 if not pat or re.match(pat, r):
332 398 return r
333 399 else:
334 400 self.write(_("unrecognized response\n"))
335 401 def getpass(self, prompt=None, default=None):
336 402 if not self.interactive: return default
337 403 return getpass.getpass(prompt or _('password: '))
338 404 def status(self, *msg):
339 405 if not self.quiet: self.write(*msg)
340 406 def warn(self, *msg):
341 407 self.write_err(*msg)
342 408 def note(self, *msg):
343 409 if self.verbose: self.write(*msg)
344 410 def debug(self, *msg):
345 411 if self.debugflag: self.write(*msg)
346 412 def edit(self, text, user):
347 413 (fd, name) = tempfile.mkstemp(prefix="hg-editor-", suffix=".txt",
348 414 text=True)
349 415 try:
350 416 f = os.fdopen(fd, "w")
351 417 f.write(text)
352 418 f.close()
353 419
354 420 editor = (os.environ.get("HGEDITOR") or
355 421 self.config("ui", "editor") or
356 422 os.environ.get("EDITOR", "vi"))
357 423
358 424 util.system("%s \"%s\"" % (editor, name),
359 425 environ={'HGUSER': user},
360 426 onerr=util.Abort, errprefix=_("edit failed"))
361 427
362 428 f = open(name)
363 429 t = f.read()
364 430 f.close()
365 431 t = re.sub("(?m)^HG:.*\n", "", t)
366 432 finally:
367 433 os.unlink(name)
368 434
369 435 return t
370 436
371 437 def print_exc(self):
372 438 '''print exception traceback if traceback printing enabled.
373 439 only to call in exception handler. returns true if traceback
374 440 printed.'''
375 441 if self.traceback:
376 442 traceback.print_exc()
377 443 return self.traceback
@@ -1,113 +1,204 b''
1 1 #!/usr/bin/env python
2 2 # Since it's not easy to write a test that portably deals
3 3 # with files from different users/groups, we cheat a bit by
4 4 # monkey-patching some functions in the util module
5 5
6 6 import os
7 7 from mercurial import ui, util
8 8
9 9 hgrc = os.environ['HGRCPATH']
10 10
11 11 def testui(user='foo', group='bar', tusers=(), tgroups=(),
12 cuser='foo', cgroup='bar', debug=False):
12 cuser='foo', cgroup='bar', debug=False, silent=False):
13 13 # user, group => owners of the file
14 14 # tusers, tgroups => trusted users/groups
15 15 # cuser, cgroup => user/group of the current process
16 16
17 17 # write a global hgrc with the list of trusted users/groups and
18 18 # some setting so that we can be sure it was read
19 19 f = open(hgrc, 'w')
20 20 f.write('[paths]\n')
21 21 f.write('global = /some/path\n\n')
22 22
23 23 if tusers or tgroups:
24 24 f.write('[trusted]\n')
25 25 if tusers:
26 26 f.write('users = %s\n' % ', '.join(tusers))
27 27 if tgroups:
28 28 f.write('groups = %s\n' % ', '.join(tgroups))
29 29 f.close()
30 30
31 31 # override the functions that give names to uids and gids
32 32 def username(uid=None):
33 33 if uid is None:
34 34 return cuser
35 35 return user
36 36 util.username = username
37 37
38 38 def groupname(gid=None):
39 39 if gid is None:
40 40 return 'bar'
41 41 return group
42 42 util.groupname = groupname
43 43
44 44 # try to read everything
45 45 #print '# File belongs to user %s, group %s' % (user, group)
46 46 #print '# trusted users = %s; trusted groups = %s' % (tusers, tgroups)
47 47 kind = ('different', 'same')
48 48 who = ('', 'user', 'group', 'user and the group')
49 49 trusted = who[(user in tusers) + 2*(group in tgroups)]
50 50 if trusted:
51 51 trusted = ', but we trust the ' + trusted
52 52 print '# %s user, %s group%s' % (kind[user == cuser], kind[group == cgroup],
53 53 trusted)
54 54
55 55 parentui = ui.ui()
56 56 parentui.updateopts(debug=debug)
57 57 u = ui.ui(parentui=parentui)
58 58 u.readconfig('.hg/hgrc')
59 if silent:
60 return u
61 print 'trusted'
59 62 for name, path in u.configitems('paths'):
60 63 print ' ', name, '=', path
64 print 'untrusted'
65 for name, path in u.configitems('paths', untrusted=True):
66 print '.',
67 u.config('paths', name) # warning with debug=True
68 print '.',
69 u.config('paths', name, untrusted=True) # no warnings
70 print name, '=', path
61 71 print
62 72
63 73 return u
64 74
65 75 os.mkdir('repo')
66 76 os.chdir('repo')
67 77 os.mkdir('.hg')
68 78 f = open('.hg/hgrc', 'w')
69 79 f.write('[paths]\n')
70 80 f.write('local = /another/path\n\n')
81 f.write('interpolated = %(global)s%(local)s\n\n')
71 82 f.close()
72 83
73 84 #print '# Everything is run by user foo, group bar\n'
74 85
75 86 # same user, same group
76 87 testui()
77 88 # same user, different group
78 89 testui(group='def')
79 90 # different user, same group
80 91 testui(user='abc')
81 92 # ... but we trust the group
82 93 testui(user='abc', tgroups=['bar'])
83 94 # different user, different group
84 95 testui(user='abc', group='def')
85 96 # ... but we trust the user
86 97 testui(user='abc', group='def', tusers=['abc'])
87 98 # ... but we trust the group
88 99 testui(user='abc', group='def', tgroups=['def'])
89 100 # ... but we trust the user and the group
90 101 testui(user='abc', group='def', tusers=['abc'], tgroups=['def'])
91 102 # ... but we trust all users
92 103 print '# we trust all users'
93 104 testui(user='abc', group='def', tusers=['*'])
94 105 # ... but we trust all groups
95 106 print '# we trust all groups'
96 107 testui(user='abc', group='def', tgroups=['*'])
97 108 # ... but we trust the whole universe
98 109 print '# we trust all users and groups'
99 110 testui(user='abc', group='def', tusers=['*'], tgroups=['*'])
100 111 # ... check that users and groups are in different namespaces
101 112 print "# we don't get confused by users and groups with the same name"
102 113 testui(user='abc', group='def', tusers=['def'], tgroups=['abc'])
103 114 # ... lists of user names work
104 115 print "# list of user names"
105 116 testui(user='abc', group='def', tusers=['foo', 'xyz', 'abc', 'bleh'],
106 117 tgroups=['bar', 'baz', 'qux'])
107 118 # ... lists of group names work
108 119 print "# list of group names"
109 120 testui(user='abc', group='def', tusers=['foo', 'xyz', 'bleh'],
110 121 tgroups=['bar', 'def', 'baz', 'qux'])
111 122
112 123 print "# Can't figure out the name of the user running this process"
113 124 testui(user='abc', group='def', cuser=None)
125
126 print "# prints debug warnings"
127 u = testui(user='abc', group='def', cuser='foo', debug=True)
128
129 print "# ui.readsections"
130 filename = 'foobar'
131 f = open(filename, 'w')
132 f.write('[foobar]\n')
133 f.write('baz = quux\n')
134 f.close()
135 u.readsections(filename, 'foobar')
136 print u.config('foobar', 'baz')
137
138 print
139 print "# read trusted, untrusted, new ui, trusted"
140 u = ui.ui()
141 u.updateopts(debug=True)
142 u.readconfig(filename)
143 u2 = ui.ui(parentui=u)
144 def username(uid=None):
145 return 'foo'
146 util.username = username
147 u2.readconfig('.hg/hgrc')
148 print 'trusted:'
149 print u2.config('foobar', 'baz')
150 print u2.config('paths', 'interpolated')
151 print 'untrusted:'
152 print u2.config('foobar', 'baz', untrusted=True)
153 print u2.config('paths', 'interpolated', untrusted=True)
154
155 print
156 print "# error handling"
157
158 def assertraises(f, exc=util.Abort):
159 try:
160 f()
161 except exc, inst:
162 print 'raised', inst.__class__.__name__
163 else:
164 print 'no exception?!'
165
166 print "# file doesn't exist"
167 os.unlink('.hg/hgrc')
168 assert not os.path.exists('.hg/hgrc')
169 testui(debug=True, silent=True)
170 testui(user='abc', group='def', debug=True, silent=True)
171
172 print
173 print "# parse error"
174 f = open('.hg/hgrc', 'w')
175 f.write('foo = bar')
176 f.close()
177 testui(user='abc', group='def', silent=True)
178 assertraises(lambda: testui(debug=True, silent=True))
179
180 print
181 print "# interpolation error"
182 f = open('.hg/hgrc', 'w')
183 f.write('[foo]\n')
184 f.write('bar = %(')
185 f.close()
186 u = testui(debug=True, silent=True)
187 print '# regular config:'
188 print ' trusted',
189 assertraises(lambda: u.config('foo', 'bar'))
190 print 'untrusted',
191 assertraises(lambda: u.config('foo', 'bar', untrusted=True))
192
193 u = testui(user='abc', group='def', debug=True, silent=True)
194 print ' trusted ',
195 print u.config('foo', 'bar')
196 print 'untrusted',
197 assertraises(lambda: u.config('foo', 'bar', untrusted=True))
198
199 print '# configitems:'
200 print ' trusted ',
201 print u.configitems('foo')
202 print 'untrusted',
203 assertraises(lambda: u.configitems('foo', untrusted=True))
204
@@ -1,67 +1,212 b''
1 1 # same user, same group
2 trusted
2 3 global = /some/path
4 interpolated = /some/path/another/path
3 5 local = /another/path
6 untrusted
7 . . global = /some/path
8 . . interpolated = /some/path/another/path
9 . . local = /another/path
4 10
5 11 # same user, different group
12 trusted
6 13 global = /some/path
14 interpolated = /some/path/another/path
7 15 local = /another/path
16 untrusted
17 . . global = /some/path
18 . . interpolated = /some/path/another/path
19 . . local = /another/path
8 20
9 21 # different user, same group
10 Not reading file .hg/hgrc from untrusted user abc, group bar
22 Not trusting file .hg/hgrc from untrusted user abc, group bar
23 trusted
11 24 global = /some/path
25 untrusted
26 . . global = /some/path
27 . . interpolated = /some/path/another/path
28 . . local = /another/path
12 29
13 30 # different user, same group, but we trust the group
31 trusted
14 32 global = /some/path
33 interpolated = /some/path/another/path
15 34 local = /another/path
35 untrusted
36 . . global = /some/path
37 . . interpolated = /some/path/another/path
38 . . local = /another/path
16 39
17 40 # different user, different group
18 Not reading file .hg/hgrc from untrusted user abc, group def
41 Not trusting file .hg/hgrc from untrusted user abc, group def
42 trusted
19 43 global = /some/path
44 untrusted
45 . . global = /some/path
46 . . interpolated = /some/path/another/path
47 . . local = /another/path
20 48
21 49 # different user, different group, but we trust the user
50 trusted
22 51 global = /some/path
52 interpolated = /some/path/another/path
23 53 local = /another/path
54 untrusted
55 . . global = /some/path
56 . . interpolated = /some/path/another/path
57 . . local = /another/path
24 58
25 59 # different user, different group, but we trust the group
60 trusted
26 61 global = /some/path
62 interpolated = /some/path/another/path
27 63 local = /another/path
64 untrusted
65 . . global = /some/path
66 . . interpolated = /some/path/another/path
67 . . local = /another/path
28 68
29 69 # different user, different group, but we trust the user and the group
70 trusted
30 71 global = /some/path
72 interpolated = /some/path/another/path
31 73 local = /another/path
74 untrusted
75 . . global = /some/path
76 . . interpolated = /some/path/another/path
77 . . local = /another/path
32 78
33 79 # we trust all users
34 80 # different user, different group
81 trusted
35 82 global = /some/path
83 interpolated = /some/path/another/path
36 84 local = /another/path
85 untrusted
86 . . global = /some/path
87 . . interpolated = /some/path/another/path
88 . . local = /another/path
37 89
38 90 # we trust all groups
39 91 # different user, different group
92 trusted
40 93 global = /some/path
94 interpolated = /some/path/another/path
41 95 local = /another/path
96 untrusted
97 . . global = /some/path
98 . . interpolated = /some/path/another/path
99 . . local = /another/path
42 100
43 101 # we trust all users and groups
44 102 # different user, different group
103 trusted
45 104 global = /some/path
105 interpolated = /some/path/another/path
46 106 local = /another/path
107 untrusted
108 . . global = /some/path
109 . . interpolated = /some/path/another/path
110 . . local = /another/path
47 111
48 112 # we don't get confused by users and groups with the same name
49 113 # different user, different group
50 Not reading file .hg/hgrc from untrusted user abc, group def
114 Not trusting file .hg/hgrc from untrusted user abc, group def
115 trusted
51 116 global = /some/path
117 untrusted
118 . . global = /some/path
119 . . interpolated = /some/path/another/path
120 . . local = /another/path
52 121
53 122 # list of user names
54 123 # different user, different group, but we trust the user
124 trusted
55 125 global = /some/path
126 interpolated = /some/path/another/path
56 127 local = /another/path
128 untrusted
129 . . global = /some/path
130 . . interpolated = /some/path/another/path
131 . . local = /another/path
57 132
58 133 # list of group names
59 134 # different user, different group, but we trust the group
135 trusted
60 136 global = /some/path
137 interpolated = /some/path/another/path
61 138 local = /another/path
139 untrusted
140 . . global = /some/path
141 . . interpolated = /some/path/another/path
142 . . local = /another/path
62 143
63 144 # Can't figure out the name of the user running this process
64 145 # different user, different group
146 trusted
65 147 global = /some/path
148 interpolated = /some/path/another/path
66 149 local = /another/path
150 untrusted
151 . . global = /some/path
152 . . interpolated = /some/path/another/path
153 . . local = /another/path
67 154
155 # prints debug warnings
156 # different user, different group
157 Not trusting file .hg/hgrc from untrusted user abc, group def
158 trusted
159 Ignoring untrusted configuration option paths.interpolated = /some/path/another/path
160 Ignoring untrusted configuration option paths.local = /another/path
161 global = /some/path
162 untrusted
163 . . global = /some/path
164 .Ignoring untrusted configuration option paths.interpolated = /some/path/another/path
165 . interpolated = /some/path/another/path
166 .Ignoring untrusted configuration option paths.local = /another/path
167 . local = /another/path
168
169 # ui.readsections
170 quux
171
172 # read trusted, untrusted, new ui, trusted
173 Not trusting file foobar from untrusted user abc, group def
174 trusted:
175 Ignoring untrusted configuration option foobar.baz = quux
176 None
177 /some/path/another/path
178 untrusted:
179 quux
180 /some/path/another/path
181
182 # error handling
183 # file doesn't exist
184 # same user, same group
185 # different user, different group
186
187 # parse error
188 # different user, different group
189 Not trusting file .hg/hgrc from untrusted user abc, group def
190 Ignored: Failed to parse .hg/hgrc
191 File contains no section headers.
192 file: .hg/hgrc, line: 1
193 'foo = bar'
194 # same user, same group
195 raised Abort
196
197 # interpolation error
198 # same user, same group
199 # regular config:
200 trusted raised Abort
201 untrusted raised Abort
202 # different user, different group
203 Not trusting file .hg/hgrc from untrusted user abc, group def
204 trusted Ignored: Error in configuration section [foo] parameter 'bar':
205 bad interpolation variable reference '%('
206 None
207 untrusted raised Abort
208 # configitems:
209 trusted Ignored: Error in configuration section [foo]:
210 bad interpolation variable reference '%('
211 []
212 untrusted raised Abort
General Comments 0
You need to be logged in to leave comments. Login now