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