##// END OF EJS Templates
merge with stable
Mads Kiilerich -
r13315:0d1dca7d merge default
parent child Browse files
Show More
@@ -1,1100 +1,1118 b''
1 ======
1 ======
2 hgrc
2 hgrc
3 ======
3 ======
4
4
5 ---------------------------------
5 ---------------------------------
6 configuration files for Mercurial
6 configuration files for Mercurial
7 ---------------------------------
7 ---------------------------------
8
8
9 :Author: Bryan O'Sullivan <bos@serpentine.com>
9 :Author: Bryan O'Sullivan <bos@serpentine.com>
10 :Organization: Mercurial
10 :Organization: Mercurial
11 :Manual section: 5
11 :Manual section: 5
12 :Manual group: Mercurial Manual
12 :Manual group: Mercurial Manual
13
13
14 .. contents::
14 .. contents::
15 :backlinks: top
15 :backlinks: top
16 :class: htmlonly
16 :class: htmlonly
17
17
18
18
19 Synopsis
19 Synopsis
20 --------
20 --------
21
21
22 The Mercurial system uses a set of configuration files to control
22 The Mercurial system uses a set of configuration files to control
23 aspects of its behavior.
23 aspects of its behavior.
24
24
25 Files
25 Files
26 -----
26 -----
27
27
28 Mercurial reads configuration data from several files, if they exist.
28 Mercurial reads configuration data from several files, if they exist.
29 The names of these files depend on the system on which Mercurial is
29 The names of these files depend on the system on which Mercurial is
30 installed. ``*.rc`` files from a single directory are read in
30 installed. ``*.rc`` files from a single directory are read in
31 alphabetical order, later ones overriding earlier ones. Where multiple
31 alphabetical order, later ones overriding earlier ones. Where multiple
32 paths are given below, settings from earlier paths override later
32 paths are given below, settings from earlier paths override later
33 ones.
33 ones.
34
34
35 | (Unix, Windows) ``<repo>/.hg/hgrc``
35 | (Unix, Windows) ``<repo>/.hg/hgrc``
36
36
37 Per-repository configuration options that only apply in a
37 Per-repository configuration options that only apply in a
38 particular repository. This file is not version-controlled, and
38 particular repository. This file is not version-controlled, and
39 will not get transferred during a "clone" operation. Options in
39 will not get transferred during a "clone" operation. Options in
40 this file override options in all other configuration files. On
40 this file override options in all other configuration files. On
41 Unix, most of this file will be ignored if it doesn't belong to a
41 Unix, most of this file will be ignored if it doesn't belong to a
42 trusted user or to a trusted group. See the documentation for the
42 trusted user or to a trusted group. See the documentation for the
43 trusted_ section below for more details.
43 trusted_ section below for more details.
44
44
45 | (Unix) ``$HOME/.hgrc``
45 | (Unix) ``$HOME/.hgrc``
46 | (Windows) ``%USERPROFILE%\.hgrc``
46 | (Windows) ``%USERPROFILE%\.hgrc``
47 | (Windows) ``%USERPROFILE%\Mercurial.ini``
47 | (Windows) ``%USERPROFILE%\Mercurial.ini``
48 | (Windows) ``%HOME%\.hgrc``
48 | (Windows) ``%HOME%\.hgrc``
49 | (Windows) ``%HOME%\Mercurial.ini``
49 | (Windows) ``%HOME%\Mercurial.ini``
50
50
51 Per-user configuration file(s), for the user running Mercurial. On
51 Per-user configuration file(s), for the user running Mercurial. On
52 Windows 9x, ``%HOME%`` is replaced by ``%APPDATA%``. Options in these
52 Windows 9x, ``%HOME%`` is replaced by ``%APPDATA%``. Options in these
53 files apply to all Mercurial commands executed by this user in any
53 files apply to all Mercurial commands executed by this user in any
54 directory. Options in these files override per-system and per-installation
54 directory. Options in these files override per-system and per-installation
55 options.
55 options.
56
56
57 | (Unix) ``/etc/mercurial/hgrc``
57 | (Unix) ``/etc/mercurial/hgrc``
58 | (Unix) ``/etc/mercurial/hgrc.d/*.rc``
58 | (Unix) ``/etc/mercurial/hgrc.d/*.rc``
59
59
60 Per-system configuration files, for the system on which Mercurial
60 Per-system configuration files, for the system on which Mercurial
61 is running. Options in these files apply to all Mercurial commands
61 is running. Options in these files apply to all Mercurial commands
62 executed by any user in any directory. Options in these files
62 executed by any user in any directory. Options in these files
63 override per-installation options.
63 override per-installation options.
64
64
65 | (Unix) ``<install-root>/etc/mercurial/hgrc``
65 | (Unix) ``<install-root>/etc/mercurial/hgrc``
66 | (Unix) ``<install-root>/etc/mercurial/hgrc.d/*.rc``
66 | (Unix) ``<install-root>/etc/mercurial/hgrc.d/*.rc``
67
67
68 Per-installation configuration files, searched for in the
68 Per-installation configuration files, searched for in the
69 directory where Mercurial is installed. ``<install-root>`` is the
69 directory where Mercurial is installed. ``<install-root>`` is the
70 parent directory of the **hg** executable (or symlink) being run. For
70 parent directory of the **hg** executable (or symlink) being run. For
71 example, if installed in ``/shared/tools/bin/hg``, Mercurial will look
71 example, if installed in ``/shared/tools/bin/hg``, Mercurial will look
72 in ``/shared/tools/etc/mercurial/hgrc``. Options in these files apply
72 in ``/shared/tools/etc/mercurial/hgrc``. Options in these files apply
73 to all Mercurial commands executed by any user in any directory.
73 to all Mercurial commands executed by any user in any directory.
74
74
75 | (Windows) ``<install-dir>\Mercurial.ini``
75 | (Windows) ``<install-dir>\Mercurial.ini``
76 | (Windows) ``<install-dir>\hgrc.d\*.rc``
76 | (Windows) ``<install-dir>\hgrc.d\*.rc``
77 | (Windows) ``HKEY_LOCAL_MACHINE\SOFTWARE\Mercurial``
77 | (Windows) ``HKEY_LOCAL_MACHINE\SOFTWARE\Mercurial``
78
78
79 Per-installation/system configuration files, for the system on
79 Per-installation/system configuration files, for the system on
80 which Mercurial is running. Options in these files apply to all
80 which Mercurial is running. Options in these files apply to all
81 Mercurial commands executed by any user in any directory. Registry
81 Mercurial commands executed by any user in any directory. Registry
82 keys contain PATH-like strings, every part of which must reference
82 keys contain PATH-like strings, every part of which must reference
83 a ``Mercurial.ini`` file or be a directory where ``*.rc`` files will
83 a ``Mercurial.ini`` file or be a directory where ``*.rc`` files will
84 be read. Mercurial checks each of these locations in the specified
84 be read. Mercurial checks each of these locations in the specified
85 order until one or more configuration files are detected. If the
85 order until one or more configuration files are detected. If the
86 pywin32 extensions are not installed, Mercurial will only look for
86 pywin32 extensions are not installed, Mercurial will only look for
87 site-wide configuration in ``C:\Mercurial\Mercurial.ini``.
87 site-wide configuration in ``C:\Mercurial\Mercurial.ini``.
88
88
89 Syntax
89 Syntax
90 ------
90 ------
91
91
92 A configuration file consists of sections, led by a ``[section]`` header
92 A configuration file consists of sections, led by a ``[section]`` header
93 and followed by ``name = value`` entries (sometimes called
93 and followed by ``name = value`` entries (sometimes called
94 ``configuration keys``)::
94 ``configuration keys``)::
95
95
96 [spam]
96 [spam]
97 eggs=ham
97 eggs=ham
98 green=
98 green=
99 eggs
99 eggs
100
100
101 Each line contains one entry. If the lines that follow are indented,
101 Each line contains one entry. If the lines that follow are indented,
102 they are treated as continuations of that entry. Leading whitespace is
102 they are treated as continuations of that entry. Leading whitespace is
103 removed from values. Empty lines are skipped. Lines beginning with
103 removed from values. Empty lines are skipped. Lines beginning with
104 ``#`` or ``;`` are ignored and may be used to provide comments.
104 ``#`` or ``;`` are ignored and may be used to provide comments.
105
105
106 Configuration keys can be set multiple times, in which case mercurial
106 Configuration keys can be set multiple times, in which case mercurial
107 will use the value that was configured last. As an example::
107 will use the value that was configured last. As an example::
108
108
109 [spam]
109 [spam]
110 eggs=large
110 eggs=large
111 ham=serrano
111 ham=serrano
112 eggs=small
112 eggs=small
113
113
114 This would set the configuration key named ``eggs`` to ``small``.
114 This would set the configuration key named ``eggs`` to ``small``.
115
115
116 It is also possible to define a section multiple times. A section can
116 It is also possible to define a section multiple times. A section can
117 be redefined on the same and/or on different hgrc files. For example::
117 be redefined on the same and/or on different hgrc files. For example::
118
118
119 [foo]
119 [foo]
120 eggs=large
120 eggs=large
121 ham=serrano
121 ham=serrano
122 eggs=small
122 eggs=small
123
123
124 [bar]
124 [bar]
125 eggs=ham
125 eggs=ham
126 green=
126 green=
127 eggs
127 eggs
128
128
129 [foo]
129 [foo]
130 ham=prosciutto
130 ham=prosciutto
131 eggs=medium
131 eggs=medium
132 bread=toasted
132 bread=toasted
133
133
134 This would set the ``eggs``, ``ham``, and ``bread`` configuration keys
134 This would set the ``eggs``, ``ham``, and ``bread`` configuration keys
135 of the ``foo`` section to ``medium``, ``prosciutto``, and ``toasted``,
135 of the ``foo`` section to ``medium``, ``prosciutto``, and ``toasted``,
136 respectively. As you can see there only thing that matters is the last
136 respectively. As you can see there only thing that matters is the last
137 value that was set for each of the configuration keys.
137 value that was set for each of the configuration keys.
138
138
139 If a configuration key is set multiple times in different
139 If a configuration key is set multiple times in different
140 configuration files the final value will depend on the order in which
140 configuration files the final value will depend on the order in which
141 the different configuration files are read, with settings from earlier
141 the different configuration files are read, with settings from earlier
142 paths overriding later ones as described on the ``Files`` section
142 paths overriding later ones as described on the ``Files`` section
143 above.
143 above.
144
144
145 A line of the form ``%include file`` will include ``file`` into the
145 A line of the form ``%include file`` will include ``file`` into the
146 current configuration file. The inclusion is recursive, which means
146 current configuration file. The inclusion is recursive, which means
147 that included files can include other files. Filenames are relative to
147 that included files can include other files. Filenames are relative to
148 the configuration file in which the ``%include`` directive is found.
148 the configuration file in which the ``%include`` directive is found.
149 Environment variables and ``~user`` constructs are expanded in
149 Environment variables and ``~user`` constructs are expanded in
150 ``file``. This lets you do something like::
150 ``file``. This lets you do something like::
151
151
152 %include ~/.hgrc.d/$HOST.rc
152 %include ~/.hgrc.d/$HOST.rc
153
153
154 to include a different configuration file on each computer you use.
154 to include a different configuration file on each computer you use.
155
155
156 A line with ``%unset name`` will remove ``name`` from the current
156 A line with ``%unset name`` will remove ``name`` from the current
157 section, if it has been set previously.
157 section, if it has been set previously.
158
158
159 The values are either free-form text strings, lists of text strings,
159 The values are either free-form text strings, lists of text strings,
160 or Boolean values. Boolean values can be set to true using any of "1",
160 or Boolean values. Boolean values can be set to true using any of "1",
161 "yes", "true", or "on" and to false using "0", "no", "false", or "off"
161 "yes", "true", or "on" and to false using "0", "no", "false", or "off"
162 (all case insensitive).
162 (all case insensitive).
163
163
164 List values are separated by whitespace or comma, except when values are
164 List values are separated by whitespace or comma, except when values are
165 placed in double quotation marks::
165 placed in double quotation marks::
166
166
167 allow_read = "John Doe, PhD", brian, betty
167 allow_read = "John Doe, PhD", brian, betty
168
168
169 Quotation marks can be escaped by prefixing them with a backslash. Only
169 Quotation marks can be escaped by prefixing them with a backslash. Only
170 quotation marks at the beginning of a word is counted as a quotation
170 quotation marks at the beginning of a word is counted as a quotation
171 (e.g., ``foo"bar baz`` is the list of ``foo"bar`` and ``baz``).
171 (e.g., ``foo"bar baz`` is the list of ``foo"bar`` and ``baz``).
172
172
173 Sections
173 Sections
174 --------
174 --------
175
175
176 This section describes the different sections that may appear in a
176 This section describes the different sections that may appear in a
177 Mercurial "hgrc" file, the purpose of each section, its possible keys,
177 Mercurial "hgrc" file, the purpose of each section, its possible keys,
178 and their possible values.
178 and their possible values.
179
179
180 ``alias``
180 ``alias``
181 """""""""
181 """""""""
182 Defines command aliases.
182 Defines command aliases.
183 Aliases allow you to define your own commands in terms of other
183 Aliases allow you to define your own commands in terms of other
184 commands (or aliases), optionally including arguments.
184 commands (or aliases), optionally including arguments.
185
185
186 Alias definitions consist of lines of the form::
186 Alias definitions consist of lines of the form::
187
187
188 <alias> = <command> [<argument]...
188 <alias> = <command> [<argument]...
189
189
190 For example, this definition::
190 For example, this definition::
191
191
192 latest = log --limit 5
192 latest = log --limit 5
193
193
194 creates a new command ``latest`` that shows only the five most recent
194 creates a new command ``latest`` that shows only the five most recent
195 changesets. You can define subsequent aliases using earlier ones::
195 changesets. You can define subsequent aliases using earlier ones::
196
196
197 stable5 = latest -b stable
197 stable5 = latest -b stable
198
198
199 .. note:: It is possible to create aliases with the same names as
199 .. note:: It is possible to create aliases with the same names as
200 existing commands, which will then override the original
200 existing commands, which will then override the original
201 definitions. This is almost always a bad idea!
201 definitions. This is almost always a bad idea!
202
202
203
203
204 ``auth``
204 ``auth``
205 """"""""
205 """"""""
206
206
207 Authentication credentials for HTTP authentication. This section
207 Authentication credentials for HTTP authentication. This section
208 allows you to store usernames and passwords for use when logging
208 allows you to store usernames and passwords for use when logging
209 *into* HTTP servers. See the web_ configuration section if you want to
209 *into* HTTP servers. See the web_ configuration section if you want to
210 configure *who* can login to your HTTP server.
210 configure *who* can login to your HTTP server.
211
211
212 Each line has the following format::
212 Each line has the following format::
213
213
214 <name>.<argument> = <value>
214 <name>.<argument> = <value>
215
215
216 where ``<name>`` is used to group arguments into authentication
216 where ``<name>`` is used to group arguments into authentication
217 entries. Example::
217 entries. Example::
218
218
219 foo.prefix = hg.intevation.org/mercurial
219 foo.prefix = hg.intevation.org/mercurial
220 foo.username = foo
220 foo.username = foo
221 foo.password = bar
221 foo.password = bar
222 foo.schemes = http https
222 foo.schemes = http https
223
223
224 bar.prefix = secure.example.org
224 bar.prefix = secure.example.org
225 bar.key = path/to/file.key
225 bar.key = path/to/file.key
226 bar.cert = path/to/file.cert
226 bar.cert = path/to/file.cert
227 bar.schemes = https
227 bar.schemes = https
228
228
229 Supported arguments:
229 Supported arguments:
230
230
231 ``prefix``
231 ``prefix``
232 Either ``*`` or a URI prefix with or without the scheme part.
232 Either ``*`` or a URI prefix with or without the scheme part.
233 The authentication entry with the longest matching prefix is used
233 The authentication entry with the longest matching prefix is used
234 (where ``*`` matches everything and counts as a match of length
234 (where ``*`` matches everything and counts as a match of length
235 1). If the prefix doesn't include a scheme, the match is performed
235 1). If the prefix doesn't include a scheme, the match is performed
236 against the URI with its scheme stripped as well, and the schemes
236 against the URI with its scheme stripped as well, and the schemes
237 argument, q.v., is then subsequently consulted.
237 argument, q.v., is then subsequently consulted.
238 ``username``
238 ``username``
239 Optional. Username to authenticate with. If not given, and the
239 Optional. Username to authenticate with. If not given, and the
240 remote site requires basic or digest authentication, the user will
240 remote site requires basic or digest authentication, the user will
241 be prompted for it. Environment variables are expanded in the
241 be prompted for it. Environment variables are expanded in the
242 username letting you do ``foo.username = $USER``.
242 username letting you do ``foo.username = $USER``.
243 ``password``
243 ``password``
244 Optional. Password to authenticate with. If not given, and the
244 Optional. Password to authenticate with. If not given, and the
245 remote site requires basic or digest authentication, the user
245 remote site requires basic or digest authentication, the user
246 will be prompted for it.
246 will be prompted for it.
247 ``key``
247 ``key``
248 Optional. PEM encoded client certificate key file. Environment
248 Optional. PEM encoded client certificate key file. Environment
249 variables are expanded in the filename.
249 variables are expanded in the filename.
250 ``cert``
250 ``cert``
251 Optional. PEM encoded client certificate chain file. Environment
251 Optional. PEM encoded client certificate chain file. Environment
252 variables are expanded in the filename.
252 variables are expanded in the filename.
253 ``schemes``
253 ``schemes``
254 Optional. Space separated list of URI schemes to use this
254 Optional. Space separated list of URI schemes to use this
255 authentication entry with. Only used if the prefix doesn't include
255 authentication entry with. Only used if the prefix doesn't include
256 a scheme. Supported schemes are http and https. They will match
256 a scheme. Supported schemes are http and https. They will match
257 static-http and static-https respectively, as well.
257 static-http and static-https respectively, as well.
258 Default: https.
258 Default: https.
259
259
260 If no suitable authentication entry is found, the user is prompted
260 If no suitable authentication entry is found, the user is prompted
261 for credentials as usual if required by the remote.
261 for credentials as usual if required by the remote.
262
262
263
263
264 ``decode/encode``
264 ``decode/encode``
265 """""""""""""""""
265 """""""""""""""""
266 Filters for transforming files on checkout/checkin. This would
266 Filters for transforming files on checkout/checkin. This would
267 typically be used for newline processing or other
267 typically be used for newline processing or other
268 localization/canonicalization of files.
268 localization/canonicalization of files.
269
269
270 Filters consist of a filter pattern followed by a filter command.
270 Filters consist of a filter pattern followed by a filter command.
271 Filter patterns are globs by default, rooted at the repository root.
271 Filter patterns are globs by default, rooted at the repository root.
272 For example, to match any file ending in ``.txt`` in the root
272 For example, to match any file ending in ``.txt`` in the root
273 directory only, use the pattern ``*.txt``. To match any file ending
273 directory only, use the pattern ``*.txt``. To match any file ending
274 in ``.c`` anywhere in the repository, use the pattern ``**.c``.
274 in ``.c`` anywhere in the repository, use the pattern ``**.c``.
275 For each file only the first matching filter applies.
275 For each file only the first matching filter applies.
276
276
277 The filter command can start with a specifier, either ``pipe:`` or
277 The filter command can start with a specifier, either ``pipe:`` or
278 ``tempfile:``. If no specifier is given, ``pipe:`` is used by default.
278 ``tempfile:``. If no specifier is given, ``pipe:`` is used by default.
279
279
280 A ``pipe:`` command must accept data on stdin and return the transformed
280 A ``pipe:`` command must accept data on stdin and return the transformed
281 data on stdout.
281 data on stdout.
282
282
283 Pipe example::
283 Pipe example::
284
284
285 [encode]
285 [encode]
286 # uncompress gzip files on checkin to improve delta compression
286 # uncompress gzip files on checkin to improve delta compression
287 # note: not necessarily a good idea, just an example
287 # note: not necessarily a good idea, just an example
288 *.gz = pipe: gunzip
288 *.gz = pipe: gunzip
289
289
290 [decode]
290 [decode]
291 # recompress gzip files when writing them to the working dir (we
291 # recompress gzip files when writing them to the working dir (we
292 # can safely omit "pipe:", because it's the default)
292 # can safely omit "pipe:", because it's the default)
293 *.gz = gzip
293 *.gz = gzip
294
294
295 A ``tempfile:`` command is a template. The string ``INFILE`` is replaced
295 A ``tempfile:`` command is a template. The string ``INFILE`` is replaced
296 with the name of a temporary file that contains the data to be
296 with the name of a temporary file that contains the data to be
297 filtered by the command. The string ``OUTFILE`` is replaced with the name
297 filtered by the command. The string ``OUTFILE`` is replaced with the name
298 of an empty temporary file, where the filtered data must be written by
298 of an empty temporary file, where the filtered data must be written by
299 the command.
299 the command.
300
300
301 .. note:: The tempfile mechanism is recommended for Windows systems,
301 .. note:: The tempfile mechanism is recommended for Windows systems,
302 where the standard shell I/O redirection operators often have
302 where the standard shell I/O redirection operators often have
303 strange effects and may corrupt the contents of your files.
303 strange effects and may corrupt the contents of your files.
304
304
305 This filter mechanism is used internally by the ``eol`` extension to
305 This filter mechanism is used internally by the ``eol`` extension to
306 translate line ending characters between Windows (CRLF) and Unix (LF)
306 translate line ending characters between Windows (CRLF) and Unix (LF)
307 format. We suggest you use the ``eol`` extension for convenience.
307 format. We suggest you use the ``eol`` extension for convenience.
308
308
309
309
310 ``defaults``
310 ``defaults``
311 """"""""""""
311 """"""""""""
312
312
313 (defaults are deprecated. Don't use them. Use aliases instead)
313 (defaults are deprecated. Don't use them. Use aliases instead)
314
314
315 Use the ``[defaults]`` section to define command defaults, i.e. the
315 Use the ``[defaults]`` section to define command defaults, i.e. the
316 default options/arguments to pass to the specified commands.
316 default options/arguments to pass to the specified commands.
317
317
318 The following example makes :hg:`log` run in verbose mode, and
318 The following example makes :hg:`log` run in verbose mode, and
319 :hg:`status` show only the modified files, by default::
319 :hg:`status` show only the modified files, by default::
320
320
321 [defaults]
321 [defaults]
322 log = -v
322 log = -v
323 status = -m
323 status = -m
324
324
325 The actual commands, instead of their aliases, must be used when
325 The actual commands, instead of their aliases, must be used when
326 defining command defaults. The command defaults will also be applied
326 defining command defaults. The command defaults will also be applied
327 to the aliases of the commands defined.
327 to the aliases of the commands defined.
328
328
329
329
330 ``diff``
330 ``diff``
331 """"""""
331 """"""""
332
332
333 Settings used when displaying diffs. They are all Boolean and
333 Settings used when displaying diffs. They are all Boolean and
334 defaults to False.
334 defaults to False.
335
335
336 ``git``
336 ``git``
337 Use git extended diff format.
337 Use git extended diff format.
338 ``nodates``
338 ``nodates``
339 Don't include dates in diff headers.
339 Don't include dates in diff headers.
340 ``showfunc``
340 ``showfunc``
341 Show which function each change is in.
341 Show which function each change is in.
342 ``ignorews``
342 ``ignorews``
343 Ignore white space when comparing lines.
343 Ignore white space when comparing lines.
344 ``ignorewsamount``
344 ``ignorewsamount``
345 Ignore changes in the amount of white space.
345 Ignore changes in the amount of white space.
346 ``ignoreblanklines``
346 ``ignoreblanklines``
347 Ignore changes whose lines are all blank.
347 Ignore changes whose lines are all blank.
348
348
349 ``email``
349 ``email``
350 """""""""
350 """""""""
351 Settings for extensions that send email messages.
351 Settings for extensions that send email messages.
352
352
353 ``from``
353 ``from``
354 Optional. Email address to use in "From" header and SMTP envelope
354 Optional. Email address to use in "From" header and SMTP envelope
355 of outgoing messages.
355 of outgoing messages.
356 ``to``
356 ``to``
357 Optional. Comma-separated list of recipients' email addresses.
357 Optional. Comma-separated list of recipients' email addresses.
358 ``cc``
358 ``cc``
359 Optional. Comma-separated list of carbon copy recipients'
359 Optional. Comma-separated list of carbon copy recipients'
360 email addresses.
360 email addresses.
361 ``bcc``
361 ``bcc``
362 Optional. Comma-separated list of blind carbon copy recipients'
362 Optional. Comma-separated list of blind carbon copy recipients'
363 email addresses.
363 email addresses.
364 ``method``
364 ``method``
365 Optional. Method to use to send email messages. If value is ``smtp``
365 Optional. Method to use to send email messages. If value is ``smtp``
366 (default), use SMTP (see the SMTP_ section for configuration).
366 (default), use SMTP (see the SMTP_ section for configuration).
367 Otherwise, use as name of program to run that acts like sendmail
367 Otherwise, use as name of program to run that acts like sendmail
368 (takes ``-f`` option for sender, list of recipients on command line,
368 (takes ``-f`` option for sender, list of recipients on command line,
369 message on stdin). Normally, setting this to ``sendmail`` or
369 message on stdin). Normally, setting this to ``sendmail`` or
370 ``/usr/sbin/sendmail`` is enough to use sendmail to send messages.
370 ``/usr/sbin/sendmail`` is enough to use sendmail to send messages.
371 ``charsets``
371 ``charsets``
372 Optional. Comma-separated list of character sets considered
372 Optional. Comma-separated list of character sets considered
373 convenient for recipients. Addresses, headers, and parts not
373 convenient for recipients. Addresses, headers, and parts not
374 containing patches of outgoing messages will be encoded in the
374 containing patches of outgoing messages will be encoded in the
375 first character set to which conversion from local encoding
375 first character set to which conversion from local encoding
376 (``$HGENCODING``, ``ui.fallbackencoding``) succeeds. If correct
376 (``$HGENCODING``, ``ui.fallbackencoding``) succeeds. If correct
377 conversion fails, the text in question is sent as is. Defaults to
377 conversion fails, the text in question is sent as is. Defaults to
378 empty (explicit) list.
378 empty (explicit) list.
379
379
380 Order of outgoing email character sets:
380 Order of outgoing email character sets:
381
381
382 1. ``us-ascii``: always first, regardless of settings
382 1. ``us-ascii``: always first, regardless of settings
383 2. ``email.charsets``: in order given by user
383 2. ``email.charsets``: in order given by user
384 3. ``ui.fallbackencoding``: if not in email.charsets
384 3. ``ui.fallbackencoding``: if not in email.charsets
385 4. ``$HGENCODING``: if not in email.charsets
385 4. ``$HGENCODING``: if not in email.charsets
386 5. ``utf-8``: always last, regardless of settings
386 5. ``utf-8``: always last, regardless of settings
387
387
388 Email example::
388 Email example::
389
389
390 [email]
390 [email]
391 from = Joseph User <joe.user@example.com>
391 from = Joseph User <joe.user@example.com>
392 method = /usr/sbin/sendmail
392 method = /usr/sbin/sendmail
393 # charsets for western Europeans
393 # charsets for western Europeans
394 # us-ascii, utf-8 omitted, as they are tried first and last
394 # us-ascii, utf-8 omitted, as they are tried first and last
395 charsets = iso-8859-1, iso-8859-15, windows-1252
395 charsets = iso-8859-1, iso-8859-15, windows-1252
396
396
397
397
398 ``extensions``
398 ``extensions``
399 """"""""""""""
399 """"""""""""""
400
400
401 Mercurial has an extension mechanism for adding new features. To
401 Mercurial has an extension mechanism for adding new features. To
402 enable an extension, create an entry for it in this section.
402 enable an extension, create an entry for it in this section.
403
403
404 If you know that the extension is already in Python's search path,
404 If you know that the extension is already in Python's search path,
405 you can give the name of the module, followed by ``=``, with nothing
405 you can give the name of the module, followed by ``=``, with nothing
406 after the ``=``.
406 after the ``=``.
407
407
408 Otherwise, give a name that you choose, followed by ``=``, followed by
408 Otherwise, give a name that you choose, followed by ``=``, followed by
409 the path to the ``.py`` file (including the file name extension) that
409 the path to the ``.py`` file (including the file name extension) that
410 defines the extension.
410 defines the extension.
411
411
412 To explicitly disable an extension that is enabled in an hgrc of
412 To explicitly disable an extension that is enabled in an hgrc of
413 broader scope, prepend its path with ``!``, as in
413 broader scope, prepend its path with ``!``, as in
414 ``hgext.foo = !/ext/path`` or ``hgext.foo = !`` when path is not
414 ``hgext.foo = !/ext/path`` or ``hgext.foo = !`` when path is not
415 supplied.
415 supplied.
416
416
417 Example for ``~/.hgrc``::
417 Example for ``~/.hgrc``::
418
418
419 [extensions]
419 [extensions]
420 # (the mq extension will get loaded from Mercurial's path)
420 # (the mq extension will get loaded from Mercurial's path)
421 hgext.mq =
421 hgext.mq =
422 # (this extension will get loaded from the file specified)
422 # (this extension will get loaded from the file specified)
423 myfeature = ~/.hgext/myfeature.py
423 myfeature = ~/.hgext/myfeature.py
424
424
425
425
426 ``hostfingerprints``
427 """"""""""""""""""""
428
429 Fingerprints of the certificates of known HTTPS servers.
430 A HTTPS connection to a server with a fingerprint configured here will
431 only succeed if the servers certificate matches the fingerprint.
432 This is very similar to how ssh known hosts works.
433 The fingerprint is the SHA-1 hash value of the DER encoded certificate.
434 The CA chain and web.cacerts is not used for servers with a fingerprint.
435
436 For example::
437
438 [hostfingerprints]
439 hg.intevation.org = 38:76:52:7c:87:26:9a:8f:4a:f8:d3:de:08:45:3b:ea:d6:4b:ee:cc
440
441 This feature is only supported when using Python 2.6 or later.
442
443
426 ``format``
444 ``format``
427 """"""""""
445 """"""""""
428
446
429 ``usestore``
447 ``usestore``
430 Enable or disable the "store" repository format which improves
448 Enable or disable the "store" repository format which improves
431 compatibility with systems that fold case or otherwise mangle
449 compatibility with systems that fold case or otherwise mangle
432 filenames. Enabled by default. Disabling this option will allow
450 filenames. Enabled by default. Disabling this option will allow
433 you to store longer filenames in some situations at the expense of
451 you to store longer filenames in some situations at the expense of
434 compatibility and ensures that the on-disk format of newly created
452 compatibility and ensures that the on-disk format of newly created
435 repositories will be compatible with Mercurial before version 0.9.4.
453 repositories will be compatible with Mercurial before version 0.9.4.
436
454
437 ``usefncache``
455 ``usefncache``
438 Enable or disable the "fncache" repository format which enhances
456 Enable or disable the "fncache" repository format which enhances
439 the "store" repository format (which has to be enabled to use
457 the "store" repository format (which has to be enabled to use
440 fncache) to allow longer filenames and avoids using Windows
458 fncache) to allow longer filenames and avoids using Windows
441 reserved names, e.g. "nul". Enabled by default. Disabling this
459 reserved names, e.g. "nul". Enabled by default. Disabling this
442 option ensures that the on-disk format of newly created
460 option ensures that the on-disk format of newly created
443 repositories will be compatible with Mercurial before version 1.1.
461 repositories will be compatible with Mercurial before version 1.1.
444
462
445 ``dotencode``
463 ``dotencode``
446 Enable or disable the "dotencode" repository format which enhances
464 Enable or disable the "dotencode" repository format which enhances
447 the "fncache" repository format (which has to be enabled to use
465 the "fncache" repository format (which has to be enabled to use
448 dotencode) to avoid issues with filenames starting with ._ on
466 dotencode) to avoid issues with filenames starting with ._ on
449 Mac OS X and spaces on Windows. Enabled by default. Disabling this
467 Mac OS X and spaces on Windows. Enabled by default. Disabling this
450 option ensures that the on-disk format of newly created
468 option ensures that the on-disk format of newly created
451 repositories will be compatible with Mercurial before version 1.7.
469 repositories will be compatible with Mercurial before version 1.7.
452
470
453 ``merge-patterns``
471 ``merge-patterns``
454 """"""""""""""""""
472 """"""""""""""""""
455
473
456 This section specifies merge tools to associate with particular file
474 This section specifies merge tools to associate with particular file
457 patterns. Tools matched here will take precedence over the default
475 patterns. Tools matched here will take precedence over the default
458 merge tool. Patterns are globs by default, rooted at the repository
476 merge tool. Patterns are globs by default, rooted at the repository
459 root.
477 root.
460
478
461 Example::
479 Example::
462
480
463 [merge-patterns]
481 [merge-patterns]
464 **.c = kdiff3
482 **.c = kdiff3
465 **.jpg = myimgmerge
483 **.jpg = myimgmerge
466
484
467 ``merge-tools``
485 ``merge-tools``
468 """""""""""""""
486 """""""""""""""
469
487
470 This section configures external merge tools to use for file-level
488 This section configures external merge tools to use for file-level
471 merges.
489 merges.
472
490
473 Example ``~/.hgrc``::
491 Example ``~/.hgrc``::
474
492
475 [merge-tools]
493 [merge-tools]
476 # Override stock tool location
494 # Override stock tool location
477 kdiff3.executable = ~/bin/kdiff3
495 kdiff3.executable = ~/bin/kdiff3
478 # Specify command line
496 # Specify command line
479 kdiff3.args = $base $local $other -o $output
497 kdiff3.args = $base $local $other -o $output
480 # Give higher priority
498 # Give higher priority
481 kdiff3.priority = 1
499 kdiff3.priority = 1
482
500
483 # Define new tool
501 # Define new tool
484 myHtmlTool.args = -m $local $other $base $output
502 myHtmlTool.args = -m $local $other $base $output
485 myHtmlTool.regkey = Software\FooSoftware\HtmlMerge
503 myHtmlTool.regkey = Software\FooSoftware\HtmlMerge
486 myHtmlTool.priority = 1
504 myHtmlTool.priority = 1
487
505
488 Supported arguments:
506 Supported arguments:
489
507
490 ``priority``
508 ``priority``
491 The priority in which to evaluate this tool.
509 The priority in which to evaluate this tool.
492 Default: 0.
510 Default: 0.
493 ``executable``
511 ``executable``
494 Either just the name of the executable or its pathname. On Windows,
512 Either just the name of the executable or its pathname. On Windows,
495 the path can use environment variables with ${ProgramFiles} syntax.
513 the path can use environment variables with ${ProgramFiles} syntax.
496 Default: the tool name.
514 Default: the tool name.
497 ``args``
515 ``args``
498 The arguments to pass to the tool executable. You can refer to the
516 The arguments to pass to the tool executable. You can refer to the
499 files being merged as well as the output file through these
517 files being merged as well as the output file through these
500 variables: ``$base``, ``$local``, ``$other``, ``$output``.
518 variables: ``$base``, ``$local``, ``$other``, ``$output``.
501 Default: ``$local $base $other``
519 Default: ``$local $base $other``
502 ``premerge``
520 ``premerge``
503 Attempt to run internal non-interactive 3-way merge tool before
521 Attempt to run internal non-interactive 3-way merge tool before
504 launching external tool. Options are ``true``, ``false``, or ``keep``
522 launching external tool. Options are ``true``, ``false``, or ``keep``
505 to leave markers in the file if the premerge fails.
523 to leave markers in the file if the premerge fails.
506 Default: True
524 Default: True
507 ``binary``
525 ``binary``
508 This tool can merge binary files. Defaults to False, unless tool
526 This tool can merge binary files. Defaults to False, unless tool
509 was selected by file pattern match.
527 was selected by file pattern match.
510 ``symlink``
528 ``symlink``
511 This tool can merge symlinks. Defaults to False, even if tool was
529 This tool can merge symlinks. Defaults to False, even if tool was
512 selected by file pattern match.
530 selected by file pattern match.
513 ``check``
531 ``check``
514 A list of merge success-checking options:
532 A list of merge success-checking options:
515
533
516 ``changed``
534 ``changed``
517 Ask whether merge was successful when the merged file shows no changes.
535 Ask whether merge was successful when the merged file shows no changes.
518 ``conflicts``
536 ``conflicts``
519 Check whether there are conflicts even though the tool reported success.
537 Check whether there are conflicts even though the tool reported success.
520 ``prompt``
538 ``prompt``
521 Always prompt for merge success, regardless of success reported by tool.
539 Always prompt for merge success, regardless of success reported by tool.
522
540
523 ``checkchanged``
541 ``checkchanged``
524 True is equivalent to ``check = changed``.
542 True is equivalent to ``check = changed``.
525 Default: False
543 Default: False
526 ``checkconflicts``
544 ``checkconflicts``
527 True is equivalent to ``check = conflicts``.
545 True is equivalent to ``check = conflicts``.
528 Default: False
546 Default: False
529 ``fixeol``
547 ``fixeol``
530 Attempt to fix up EOL changes caused by the merge tool.
548 Attempt to fix up EOL changes caused by the merge tool.
531 Default: False
549 Default: False
532 ``gui``
550 ``gui``
533 This tool requires a graphical interface to run. Default: False
551 This tool requires a graphical interface to run. Default: False
534 ``regkey``
552 ``regkey``
535 Windows registry key which describes install location of this
553 Windows registry key which describes install location of this
536 tool. Mercurial will search for this key first under
554 tool. Mercurial will search for this key first under
537 ``HKEY_CURRENT_USER`` and then under ``HKEY_LOCAL_MACHINE``.
555 ``HKEY_CURRENT_USER`` and then under ``HKEY_LOCAL_MACHINE``.
538 Default: None
556 Default: None
539 ``regname``
557 ``regname``
540 Name of value to read from specified registry key. Defaults to the
558 Name of value to read from specified registry key. Defaults to the
541 unnamed (default) value.
559 unnamed (default) value.
542 ``regappend``
560 ``regappend``
543 String to append to the value read from the registry, typically
561 String to append to the value read from the registry, typically
544 the executable name of the tool.
562 the executable name of the tool.
545 Default: None
563 Default: None
546
564
547
565
548 ``hooks``
566 ``hooks``
549 """""""""
567 """""""""
550 Commands or Python functions that get automatically executed by
568 Commands or Python functions that get automatically executed by
551 various actions such as starting or finishing a commit. Multiple
569 various actions such as starting or finishing a commit. Multiple
552 hooks can be run for the same action by appending a suffix to the
570 hooks can be run for the same action by appending a suffix to the
553 action. Overriding a site-wide hook can be done by changing its
571 action. Overriding a site-wide hook can be done by changing its
554 value or setting it to an empty string.
572 value or setting it to an empty string.
555
573
556 Example ``.hg/hgrc``::
574 Example ``.hg/hgrc``::
557
575
558 [hooks]
576 [hooks]
559 # update working directory after adding changesets
577 # update working directory after adding changesets
560 changegroup.update = hg update
578 changegroup.update = hg update
561 # do not use the site-wide hook
579 # do not use the site-wide hook
562 incoming =
580 incoming =
563 incoming.email = /my/email/hook
581 incoming.email = /my/email/hook
564 incoming.autobuild = /my/build/hook
582 incoming.autobuild = /my/build/hook
565
583
566 Most hooks are run with environment variables set that give useful
584 Most hooks are run with environment variables set that give useful
567 additional information. For each hook below, the environment
585 additional information. For each hook below, the environment
568 variables it is passed are listed with names of the form ``$HG_foo``.
586 variables it is passed are listed with names of the form ``$HG_foo``.
569
587
570 ``changegroup``
588 ``changegroup``
571 Run after a changegroup has been added via push, pull or unbundle.
589 Run after a changegroup has been added via push, pull or unbundle.
572 ID of the first new changeset is in ``$HG_NODE``. URL from which
590 ID of the first new changeset is in ``$HG_NODE``. URL from which
573 changes came is in ``$HG_URL``.
591 changes came is in ``$HG_URL``.
574 ``commit``
592 ``commit``
575 Run after a changeset has been created in the local repository. ID
593 Run after a changeset has been created in the local repository. ID
576 of the newly created changeset is in ``$HG_NODE``. Parent changeset
594 of the newly created changeset is in ``$HG_NODE``. Parent changeset
577 IDs are in ``$HG_PARENT1`` and ``$HG_PARENT2``.
595 IDs are in ``$HG_PARENT1`` and ``$HG_PARENT2``.
578 ``incoming``
596 ``incoming``
579 Run after a changeset has been pulled, pushed, or unbundled into
597 Run after a changeset has been pulled, pushed, or unbundled into
580 the local repository. The ID of the newly arrived changeset is in
598 the local repository. The ID of the newly arrived changeset is in
581 ``$HG_NODE``. URL that was source of changes came is in ``$HG_URL``.
599 ``$HG_NODE``. URL that was source of changes came is in ``$HG_URL``.
582 ``outgoing``
600 ``outgoing``
583 Run after sending changes from local repository to another. ID of
601 Run after sending changes from local repository to another. ID of
584 first changeset sent is in ``$HG_NODE``. Source of operation is in
602 first changeset sent is in ``$HG_NODE``. Source of operation is in
585 ``$HG_SOURCE``; see "preoutgoing" hook for description.
603 ``$HG_SOURCE``; see "preoutgoing" hook for description.
586 ``post-<command>``
604 ``post-<command>``
587 Run after successful invocations of the associated command. The
605 Run after successful invocations of the associated command. The
588 contents of the command line are passed as ``$HG_ARGS`` and the result
606 contents of the command line are passed as ``$HG_ARGS`` and the result
589 code in ``$HG_RESULT``. Parsed command line arguments are passed as
607 code in ``$HG_RESULT``. Parsed command line arguments are passed as
590 ``$HG_PATS`` and ``$HG_OPTS``. These contain string representations of
608 ``$HG_PATS`` and ``$HG_OPTS``. These contain string representations of
591 the python data internally passed to <command>. ``$HG_OPTS`` is a
609 the python data internally passed to <command>. ``$HG_OPTS`` is a
592 dictionary of options (with unspecified options set to their defaults).
610 dictionary of options (with unspecified options set to their defaults).
593 ``$HG_PATS`` is a list of arguments. Hook failure is ignored.
611 ``$HG_PATS`` is a list of arguments. Hook failure is ignored.
594 ``pre-<command>``
612 ``pre-<command>``
595 Run before executing the associated command. The contents of the
613 Run before executing the associated command. The contents of the
596 command line are passed as ``$HG_ARGS``. Parsed command line arguments
614 command line are passed as ``$HG_ARGS``. Parsed command line arguments
597 are passed as ``$HG_PATS`` and ``$HG_OPTS``. These contain string
615 are passed as ``$HG_PATS`` and ``$HG_OPTS``. These contain string
598 representations of the data internally passed to <command>. ``$HG_OPTS``
616 representations of the data internally passed to <command>. ``$HG_OPTS``
599 is a dictionary of options (with unspecified options set to their
617 is a dictionary of options (with unspecified options set to their
600 defaults). ``$HG_PATS`` is a list of arguments. If the hook returns
618 defaults). ``$HG_PATS`` is a list of arguments. If the hook returns
601 failure, the command doesn't execute and Mercurial returns the failure
619 failure, the command doesn't execute and Mercurial returns the failure
602 code.
620 code.
603 ``prechangegroup``
621 ``prechangegroup``
604 Run before a changegroup is added via push, pull or unbundle. Exit
622 Run before a changegroup is added via push, pull or unbundle. Exit
605 status 0 allows the changegroup to proceed. Non-zero status will
623 status 0 allows the changegroup to proceed. Non-zero status will
606 cause the push, pull or unbundle to fail. URL from which changes
624 cause the push, pull or unbundle to fail. URL from which changes
607 will come is in ``$HG_URL``.
625 will come is in ``$HG_URL``.
608 ``precommit``
626 ``precommit``
609 Run before starting a local commit. Exit status 0 allows the
627 Run before starting a local commit. Exit status 0 allows the
610 commit to proceed. Non-zero status will cause the commit to fail.
628 commit to proceed. Non-zero status will cause the commit to fail.
611 Parent changeset IDs are in ``$HG_PARENT1`` and ``$HG_PARENT2``.
629 Parent changeset IDs are in ``$HG_PARENT1`` and ``$HG_PARENT2``.
612 ``preoutgoing``
630 ``preoutgoing``
613 Run before collecting changes to send from the local repository to
631 Run before collecting changes to send from the local repository to
614 another. Non-zero status will cause failure. This lets you prevent
632 another. Non-zero status will cause failure. This lets you prevent
615 pull over HTTP or SSH. Also prevents against local pull, push
633 pull over HTTP or SSH. Also prevents against local pull, push
616 (outbound) or bundle commands, but not effective, since you can
634 (outbound) or bundle commands, but not effective, since you can
617 just copy files instead then. Source of operation is in
635 just copy files instead then. Source of operation is in
618 ``$HG_SOURCE``. If "serve", operation is happening on behalf of remote
636 ``$HG_SOURCE``. If "serve", operation is happening on behalf of remote
619 SSH or HTTP repository. If "push", "pull" or "bundle", operation
637 SSH or HTTP repository. If "push", "pull" or "bundle", operation
620 is happening on behalf of repository on same system.
638 is happening on behalf of repository on same system.
621 ``pretag``
639 ``pretag``
622 Run before creating a tag. Exit status 0 allows the tag to be
640 Run before creating a tag. Exit status 0 allows the tag to be
623 created. Non-zero status will cause the tag to fail. ID of
641 created. Non-zero status will cause the tag to fail. ID of
624 changeset to tag is in ``$HG_NODE``. Name of tag is in ``$HG_TAG``. Tag is
642 changeset to tag is in ``$HG_NODE``. Name of tag is in ``$HG_TAG``. Tag is
625 local if ``$HG_LOCAL=1``, in repository if ``$HG_LOCAL=0``.
643 local if ``$HG_LOCAL=1``, in repository if ``$HG_LOCAL=0``.
626 ``pretxnchangegroup``
644 ``pretxnchangegroup``
627 Run after a changegroup has been added via push, pull or unbundle,
645 Run after a changegroup has been added via push, pull or unbundle,
628 but before the transaction has been committed. Changegroup is
646 but before the transaction has been committed. Changegroup is
629 visible to hook program. This lets you validate incoming changes
647 visible to hook program. This lets you validate incoming changes
630 before accepting them. Passed the ID of the first new changeset in
648 before accepting them. Passed the ID of the first new changeset in
631 ``$HG_NODE``. Exit status 0 allows the transaction to commit. Non-zero
649 ``$HG_NODE``. Exit status 0 allows the transaction to commit. Non-zero
632 status will cause the transaction to be rolled back and the push,
650 status will cause the transaction to be rolled back and the push,
633 pull or unbundle will fail. URL that was source of changes is in
651 pull or unbundle will fail. URL that was source of changes is in
634 ``$HG_URL``.
652 ``$HG_URL``.
635 ``pretxncommit``
653 ``pretxncommit``
636 Run after a changeset has been created but the transaction not yet
654 Run after a changeset has been created but the transaction not yet
637 committed. Changeset is visible to hook program. This lets you
655 committed. Changeset is visible to hook program. This lets you
638 validate commit message and changes. Exit status 0 allows the
656 validate commit message and changes. Exit status 0 allows the
639 commit to proceed. Non-zero status will cause the transaction to
657 commit to proceed. Non-zero status will cause the transaction to
640 be rolled back. ID of changeset is in ``$HG_NODE``. Parent changeset
658 be rolled back. ID of changeset is in ``$HG_NODE``. Parent changeset
641 IDs are in ``$HG_PARENT1`` and ``$HG_PARENT2``.
659 IDs are in ``$HG_PARENT1`` and ``$HG_PARENT2``.
642 ``preupdate``
660 ``preupdate``
643 Run before updating the working directory. Exit status 0 allows
661 Run before updating the working directory. Exit status 0 allows
644 the update to proceed. Non-zero status will prevent the update.
662 the update to proceed. Non-zero status will prevent the update.
645 Changeset ID of first new parent is in ``$HG_PARENT1``. If merge, ID
663 Changeset ID of first new parent is in ``$HG_PARENT1``. If merge, ID
646 of second new parent is in ``$HG_PARENT2``.
664 of second new parent is in ``$HG_PARENT2``.
647 ``tag``
665 ``tag``
648 Run after a tag is created. ID of tagged changeset is in ``$HG_NODE``.
666 Run after a tag is created. ID of tagged changeset is in ``$HG_NODE``.
649 Name of tag is in ``$HG_TAG``. Tag is local if ``$HG_LOCAL=1``, in
667 Name of tag is in ``$HG_TAG``. Tag is local if ``$HG_LOCAL=1``, in
650 repository if ``$HG_LOCAL=0``.
668 repository if ``$HG_LOCAL=0``.
651 ``update``
669 ``update``
652 Run after updating the working directory. Changeset ID of first
670 Run after updating the working directory. Changeset ID of first
653 new parent is in ``$HG_PARENT1``. If merge, ID of second new parent is
671 new parent is in ``$HG_PARENT1``. If merge, ID of second new parent is
654 in ``$HG_PARENT2``. If the update succeeded, ``$HG_ERROR=0``. If the
672 in ``$HG_PARENT2``. If the update succeeded, ``$HG_ERROR=0``. If the
655 update failed (e.g. because conflicts not resolved), ``$HG_ERROR=1``.
673 update failed (e.g. because conflicts not resolved), ``$HG_ERROR=1``.
656
674
657 .. note:: It is generally better to use standard hooks rather than the
675 .. note:: It is generally better to use standard hooks rather than the
658 generic pre- and post- command hooks as they are guaranteed to be
676 generic pre- and post- command hooks as they are guaranteed to be
659 called in the appropriate contexts for influencing transactions.
677 called in the appropriate contexts for influencing transactions.
660 Also, hooks like "commit" will be called in all contexts that
678 Also, hooks like "commit" will be called in all contexts that
661 generate a commit (e.g. tag) and not just the commit command.
679 generate a commit (e.g. tag) and not just the commit command.
662
680
663 .. note:: Environment variables with empty values may not be passed to
681 .. note:: Environment variables with empty values may not be passed to
664 hooks on platforms such as Windows. As an example, ``$HG_PARENT2``
682 hooks on platforms such as Windows. As an example, ``$HG_PARENT2``
665 will have an empty value under Unix-like platforms for non-merge
683 will have an empty value under Unix-like platforms for non-merge
666 changesets, while it will not be available at all under Windows.
684 changesets, while it will not be available at all under Windows.
667
685
668 The syntax for Python hooks is as follows::
686 The syntax for Python hooks is as follows::
669
687
670 hookname = python:modulename.submodule.callable
688 hookname = python:modulename.submodule.callable
671 hookname = python:/path/to/python/module.py:callable
689 hookname = python:/path/to/python/module.py:callable
672
690
673 Python hooks are run within the Mercurial process. Each hook is
691 Python hooks are run within the Mercurial process. Each hook is
674 called with at least three keyword arguments: a ui object (keyword
692 called with at least three keyword arguments: a ui object (keyword
675 ``ui``), a repository object (keyword ``repo``), and a ``hooktype``
693 ``ui``), a repository object (keyword ``repo``), and a ``hooktype``
676 keyword that tells what kind of hook is used. Arguments listed as
694 keyword that tells what kind of hook is used. Arguments listed as
677 environment variables above are passed as keyword arguments, with no
695 environment variables above are passed as keyword arguments, with no
678 ``HG_`` prefix, and names in lower case.
696 ``HG_`` prefix, and names in lower case.
679
697
680 If a Python hook returns a "true" value or raises an exception, this
698 If a Python hook returns a "true" value or raises an exception, this
681 is treated as a failure.
699 is treated as a failure.
682
700
683
701
684 ``http_proxy``
702 ``http_proxy``
685 """"""""""""""
703 """"""""""""""
686 Used to access web-based Mercurial repositories through a HTTP
704 Used to access web-based Mercurial repositories through a HTTP
687 proxy.
705 proxy.
688
706
689 ``host``
707 ``host``
690 Host name and (optional) port of the proxy server, for example
708 Host name and (optional) port of the proxy server, for example
691 "myproxy:8000".
709 "myproxy:8000".
692 ``no``
710 ``no``
693 Optional. Comma-separated list of host names that should bypass
711 Optional. Comma-separated list of host names that should bypass
694 the proxy.
712 the proxy.
695 ``passwd``
713 ``passwd``
696 Optional. Password to authenticate with at the proxy server.
714 Optional. Password to authenticate with at the proxy server.
697 ``user``
715 ``user``
698 Optional. User name to authenticate with at the proxy server.
716 Optional. User name to authenticate with at the proxy server.
699 ``always``
717 ``always``
700 Optional. Always use the proxy, even for localhost and any entries
718 Optional. Always use the proxy, even for localhost and any entries
701 in ``http_proxy.no``. True or False. Default: False.
719 in ``http_proxy.no``. True or False. Default: False.
702
720
703 ``smtp``
721 ``smtp``
704 """"""""
722 """"""""
705 Configuration for extensions that need to send email messages.
723 Configuration for extensions that need to send email messages.
706
724
707 ``host``
725 ``host``
708 Host name of mail server, e.g. "mail.example.com".
726 Host name of mail server, e.g. "mail.example.com".
709 ``port``
727 ``port``
710 Optional. Port to connect to on mail server. Default: 25.
728 Optional. Port to connect to on mail server. Default: 25.
711 ``tls``
729 ``tls``
712 Optional. Method to enable TLS when connecting to mail server: starttls,
730 Optional. Method to enable TLS when connecting to mail server: starttls,
713 smtps or none. Default: none.
731 smtps or none. Default: none.
714 ``username``
732 ``username``
715 Optional. User name for authenticating with the SMTP server.
733 Optional. User name for authenticating with the SMTP server.
716 Default: none.
734 Default: none.
717 ``password``
735 ``password``
718 Optional. Password for authenticating with the SMTP server. If not
736 Optional. Password for authenticating with the SMTP server. If not
719 specified, interactive sessions will prompt the user for a
737 specified, interactive sessions will prompt the user for a
720 password; non-interactive sessions will fail. Default: none.
738 password; non-interactive sessions will fail. Default: none.
721 ``local_hostname``
739 ``local_hostname``
722 Optional. It's the hostname that the sender can use to identify
740 Optional. It's the hostname that the sender can use to identify
723 itself to the MTA.
741 itself to the MTA.
724
742
725
743
726 ``patch``
744 ``patch``
727 """""""""
745 """""""""
728 Settings used when applying patches, for instance through the 'import'
746 Settings used when applying patches, for instance through the 'import'
729 command or with Mercurial Queues extension.
747 command or with Mercurial Queues extension.
730
748
731 ``eol``
749 ``eol``
732 When set to 'strict' patch content and patched files end of lines
750 When set to 'strict' patch content and patched files end of lines
733 are preserved. When set to ``lf`` or ``crlf``, both files end of
751 are preserved. When set to ``lf`` or ``crlf``, both files end of
734 lines are ignored when patching and the result line endings are
752 lines are ignored when patching and the result line endings are
735 normalized to either LF (Unix) or CRLF (Windows). When set to
753 normalized to either LF (Unix) or CRLF (Windows). When set to
736 ``auto``, end of lines are again ignored while patching but line
754 ``auto``, end of lines are again ignored while patching but line
737 endings in patched files are normalized to their original setting
755 endings in patched files are normalized to their original setting
738 on a per-file basis. If target file does not exist or has no end
756 on a per-file basis. If target file does not exist or has no end
739 of line, patch line endings are preserved.
757 of line, patch line endings are preserved.
740 Default: strict.
758 Default: strict.
741
759
742
760
743 ``paths``
761 ``paths``
744 """""""""
762 """""""""
745 Assigns symbolic names to repositories. The left side is the
763 Assigns symbolic names to repositories. The left side is the
746 symbolic name, and the right gives the directory or URL that is the
764 symbolic name, and the right gives the directory or URL that is the
747 location of the repository. Default paths can be declared by setting
765 location of the repository. Default paths can be declared by setting
748 the following entries.
766 the following entries.
749
767
750 ``default``
768 ``default``
751 Directory or URL to use when pulling if no source is specified.
769 Directory or URL to use when pulling if no source is specified.
752 Default is set to repository from which the current repository was
770 Default is set to repository from which the current repository was
753 cloned.
771 cloned.
754 ``default-push``
772 ``default-push``
755 Optional. Directory or URL to use when pushing if no destination
773 Optional. Directory or URL to use when pushing if no destination
756 is specified.
774 is specified.
757
775
758
776
759 ``profiling``
777 ``profiling``
760 """""""""""""
778 """""""""""""
761 Specifies profiling format and file output. In this section
779 Specifies profiling format and file output. In this section
762 description, 'profiling data' stands for the raw data collected
780 description, 'profiling data' stands for the raw data collected
763 during profiling, while 'profiling report' stands for a statistical
781 during profiling, while 'profiling report' stands for a statistical
764 text report generated from the profiling data. The profiling is done
782 text report generated from the profiling data. The profiling is done
765 using lsprof.
783 using lsprof.
766
784
767 ``format``
785 ``format``
768 Profiling format.
786 Profiling format.
769 Default: text.
787 Default: text.
770
788
771 ``text``
789 ``text``
772 Generate a profiling report. When saving to a file, it should be
790 Generate a profiling report. When saving to a file, it should be
773 noted that only the report is saved, and the profiling data is
791 noted that only the report is saved, and the profiling data is
774 not kept.
792 not kept.
775 ``kcachegrind``
793 ``kcachegrind``
776 Format profiling data for kcachegrind use: when saving to a
794 Format profiling data for kcachegrind use: when saving to a
777 file, the generated file can directly be loaded into
795 file, the generated file can directly be loaded into
778 kcachegrind.
796 kcachegrind.
779 ``output``
797 ``output``
780 File path where profiling data or report should be saved. If the
798 File path where profiling data or report should be saved. If the
781 file exists, it is replaced. Default: None, data is printed on
799 file exists, it is replaced. Default: None, data is printed on
782 stderr
800 stderr
783
801
784 ``server``
802 ``server``
785 """"""""""
803 """"""""""
786 Controls generic server settings.
804 Controls generic server settings.
787
805
788 ``uncompressed``
806 ``uncompressed``
789 Whether to allow clients to clone a repository using the
807 Whether to allow clients to clone a repository using the
790 uncompressed streaming protocol. This transfers about 40% more
808 uncompressed streaming protocol. This transfers about 40% more
791 data than a regular clone, but uses less memory and CPU on both
809 data than a regular clone, but uses less memory and CPU on both
792 server and client. Over a LAN (100 Mbps or better) or a very fast
810 server and client. Over a LAN (100 Mbps or better) or a very fast
793 WAN, an uncompressed streaming clone is a lot faster (~10x) than a
811 WAN, an uncompressed streaming clone is a lot faster (~10x) than a
794 regular clone. Over most WAN connections (anything slower than
812 regular clone. Over most WAN connections (anything slower than
795 about 6 Mbps), uncompressed streaming is slower, because of the
813 about 6 Mbps), uncompressed streaming is slower, because of the
796 extra data transfer overhead. This mode will also temporarily hold
814 extra data transfer overhead. This mode will also temporarily hold
797 the write lock while determining what data to transfer.
815 the write lock while determining what data to transfer.
798 Default is True.
816 Default is True.
799
817
800 ``validate``
818 ``validate``
801 Whether to validate the completeness of pushed changesets by
819 Whether to validate the completeness of pushed changesets by
802 checking that all new file revisions specified in manifests are
820 checking that all new file revisions specified in manifests are
803 present. Default is False.
821 present. Default is False.
804
822
805 ``subpaths``
823 ``subpaths``
806 """"""""""""
824 """"""""""""
807 Defines subrepositories source locations rewriting rules of the form::
825 Defines subrepositories source locations rewriting rules of the form::
808
826
809 <pattern> = <replacement>
827 <pattern> = <replacement>
810
828
811 Where ``pattern`` is a regular expression matching the source and
829 Where ``pattern`` is a regular expression matching the source and
812 ``replacement`` is the replacement string used to rewrite it. Groups
830 ``replacement`` is the replacement string used to rewrite it. Groups
813 can be matched in ``pattern`` and referenced in ``replacements``. For
831 can be matched in ``pattern`` and referenced in ``replacements``. For
814 instance::
832 instance::
815
833
816 http://server/(.*)-hg/ = http://hg.server/\1/
834 http://server/(.*)-hg/ = http://hg.server/\1/
817
835
818 rewrites ``http://server/foo-hg/`` into ``http://hg.server/foo/``.
836 rewrites ``http://server/foo-hg/`` into ``http://hg.server/foo/``.
819
837
820 All patterns are applied in definition order.
838 All patterns are applied in definition order.
821
839
822 ``trusted``
840 ``trusted``
823 """""""""""
841 """""""""""
824
842
825 Mercurial will not use the settings in the
843 Mercurial will not use the settings in the
826 ``.hg/hgrc`` file from a repository if it doesn't belong to a trusted
844 ``.hg/hgrc`` file from a repository if it doesn't belong to a trusted
827 user or to a trusted group, as various hgrc features allow arbitrary
845 user or to a trusted group, as various hgrc features allow arbitrary
828 commands to be run. This issue is often encountered when configuring
846 commands to be run. This issue is often encountered when configuring
829 hooks or extensions for shared repositories or servers. However,
847 hooks or extensions for shared repositories or servers. However,
830 the web interface will use some safe settings from the ``[web]``
848 the web interface will use some safe settings from the ``[web]``
831 section.
849 section.
832
850
833 This section specifies what users and groups are trusted. The
851 This section specifies what users and groups are trusted. The
834 current user is always trusted. To trust everybody, list a user or a
852 current user is always trusted. To trust everybody, list a user or a
835 group with name ``*``. These settings must be placed in an
853 group with name ``*``. These settings must be placed in an
836 *already-trusted file* to take effect, such as ``$HOME/.hgrc`` of the
854 *already-trusted file* to take effect, such as ``$HOME/.hgrc`` of the
837 user or service running Mercurial.
855 user or service running Mercurial.
838
856
839 ``users``
857 ``users``
840 Comma-separated list of trusted users.
858 Comma-separated list of trusted users.
841 ``groups``
859 ``groups``
842 Comma-separated list of trusted groups.
860 Comma-separated list of trusted groups.
843
861
844
862
845 ``ui``
863 ``ui``
846 """"""
864 """"""
847
865
848 User interface controls.
866 User interface controls.
849
867
850 ``archivemeta``
868 ``archivemeta``
851 Whether to include the .hg_archival.txt file containing meta data
869 Whether to include the .hg_archival.txt file containing meta data
852 (hashes for the repository base and for tip) in archives created
870 (hashes for the repository base and for tip) in archives created
853 by the :hg:`archive` command or downloaded via hgweb.
871 by the :hg:`archive` command or downloaded via hgweb.
854 Default is True.
872 Default is True.
855 ``askusername``
873 ``askusername``
856 Whether to prompt for a username when committing. If True, and
874 Whether to prompt for a username when committing. If True, and
857 neither ``$HGUSER`` nor ``$EMAIL`` has been specified, then the user will
875 neither ``$HGUSER`` nor ``$EMAIL`` has been specified, then the user will
858 be prompted to enter a username. If no username is entered, the
876 be prompted to enter a username. If no username is entered, the
859 default ``USER@HOST`` is used instead.
877 default ``USER@HOST`` is used instead.
860 Default is False.
878 Default is False.
861 ``debug``
879 ``debug``
862 Print debugging information. True or False. Default is False.
880 Print debugging information. True or False. Default is False.
863 ``editor``
881 ``editor``
864 The editor to use during a commit. Default is ``$EDITOR`` or ``vi``.
882 The editor to use during a commit. Default is ``$EDITOR`` or ``vi``.
865 ``fallbackencoding``
883 ``fallbackencoding``
866 Encoding to try if it's not possible to decode the changelog using
884 Encoding to try if it's not possible to decode the changelog using
867 UTF-8. Default is ISO-8859-1.
885 UTF-8. Default is ISO-8859-1.
868 ``ignore``
886 ``ignore``
869 A file to read per-user ignore patterns from. This file should be
887 A file to read per-user ignore patterns from. This file should be
870 in the same format as a repository-wide .hgignore file. This
888 in the same format as a repository-wide .hgignore file. This
871 option supports hook syntax, so if you want to specify multiple
889 option supports hook syntax, so if you want to specify multiple
872 ignore files, you can do so by setting something like
890 ignore files, you can do so by setting something like
873 ``ignore.other = ~/.hgignore2``. For details of the ignore file
891 ``ignore.other = ~/.hgignore2``. For details of the ignore file
874 format, see the |hgignore(5)|_ man page.
892 format, see the |hgignore(5)|_ man page.
875 ``interactive``
893 ``interactive``
876 Allow to prompt the user. True or False. Default is True.
894 Allow to prompt the user. True or False. Default is True.
877 ``logtemplate``
895 ``logtemplate``
878 Template string for commands that print changesets.
896 Template string for commands that print changesets.
879 ``merge``
897 ``merge``
880 The conflict resolution program to use during a manual merge.
898 The conflict resolution program to use during a manual merge.
881 For more information on merge tools see :hg:`help merge-tools`.
899 For more information on merge tools see :hg:`help merge-tools`.
882 For configuring merge tools see the merge-tools_ section.
900 For configuring merge tools see the merge-tools_ section.
883 ``patch``
901 ``patch``
884 command to use to apply patches. Look for ``gpatch`` or ``patch`` in
902 command to use to apply patches. Look for ``gpatch`` or ``patch`` in
885 PATH if unset.
903 PATH if unset.
886 ``quiet``
904 ``quiet``
887 Reduce the amount of output printed. True or False. Default is False.
905 Reduce the amount of output printed. True or False. Default is False.
888 ``remotecmd``
906 ``remotecmd``
889 remote command to use for clone/push/pull operations. Default is ``hg``.
907 remote command to use for clone/push/pull operations. Default is ``hg``.
890 ``report_untrusted``
908 ``report_untrusted``
891 Warn if a ``.hg/hgrc`` file is ignored due to not being owned by a
909 Warn if a ``.hg/hgrc`` file is ignored due to not being owned by a
892 trusted user or group. True or False. Default is True.
910 trusted user or group. True or False. Default is True.
893 ``slash``
911 ``slash``
894 Display paths using a slash (``/``) as the path separator. This
912 Display paths using a slash (``/``) as the path separator. This
895 only makes a difference on systems where the default path
913 only makes a difference on systems where the default path
896 separator is not the slash character (e.g. Windows uses the
914 separator is not the slash character (e.g. Windows uses the
897 backslash character (``\``)).
915 backslash character (``\``)).
898 Default is False.
916 Default is False.
899 ``ssh``
917 ``ssh``
900 command to use for SSH connections. Default is ``ssh``.
918 command to use for SSH connections. Default is ``ssh``.
901 ``strict``
919 ``strict``
902 Require exact command names, instead of allowing unambiguous
920 Require exact command names, instead of allowing unambiguous
903 abbreviations. True or False. Default is False.
921 abbreviations. True or False. Default is False.
904 ``style``
922 ``style``
905 Name of style to use for command output.
923 Name of style to use for command output.
906 ``timeout``
924 ``timeout``
907 The timeout used when a lock is held (in seconds), a negative value
925 The timeout used when a lock is held (in seconds), a negative value
908 means no timeout. Default is 600.
926 means no timeout. Default is 600.
909 ``traceback``
927 ``traceback``
910 Mercurial always prints a traceback when an unknown exception
928 Mercurial always prints a traceback when an unknown exception
911 occurs. Setting this to True will make Mercurial print a traceback
929 occurs. Setting this to True will make Mercurial print a traceback
912 on all exceptions, even those recognized by Mercurial (such as
930 on all exceptions, even those recognized by Mercurial (such as
913 IOError or MemoryError). Default is False.
931 IOError or MemoryError). Default is False.
914 ``username``
932 ``username``
915 The committer of a changeset created when running "commit".
933 The committer of a changeset created when running "commit".
916 Typically a person's name and email address, e.g. ``Fred Widget
934 Typically a person's name and email address, e.g. ``Fred Widget
917 <fred@example.com>``. Default is ``$EMAIL`` or ``username@hostname``. If
935 <fred@example.com>``. Default is ``$EMAIL`` or ``username@hostname``. If
918 the username in hgrc is empty, it has to be specified manually or
936 the username in hgrc is empty, it has to be specified manually or
919 in a different hgrc file (e.g. ``$HOME/.hgrc``, if the admin set
937 in a different hgrc file (e.g. ``$HOME/.hgrc``, if the admin set
920 ``username =`` in the system hgrc). Environment variables in the
938 ``username =`` in the system hgrc). Environment variables in the
921 username are expanded.
939 username are expanded.
922 ``verbose``
940 ``verbose``
923 Increase the amount of output printed. True or False. Default is False.
941 Increase the amount of output printed. True or False. Default is False.
924
942
925
943
926 ``web``
944 ``web``
927 """""""
945 """""""
928
946
929 Web interface configuration. The settings in this section apply to
947 Web interface configuration. The settings in this section apply to
930 both the builtin webserver (started by :hg:`serve`) and the script you
948 both the builtin webserver (started by :hg:`serve`) and the script you
931 run through a webserver (``hgweb.cgi`` and the derivatives for FastCGI
949 run through a webserver (``hgweb.cgi`` and the derivatives for FastCGI
932 and WSGI).
950 and WSGI).
933
951
934 The Mercurial webserver does no authentication (it does not prompt for
952 The Mercurial webserver does no authentication (it does not prompt for
935 usernames and passwords to validate *who* users are), but it does do
953 usernames and passwords to validate *who* users are), but it does do
936 authorization (it grants or denies access for *authenticated users*
954 authorization (it grants or denies access for *authenticated users*
937 based on settings in this section). You must either configure your
955 based on settings in this section). You must either configure your
938 webserver to do authentication for you, or disable the authorization
956 webserver to do authentication for you, or disable the authorization
939 checks.
957 checks.
940
958
941 For a quick setup in a trusted environment, e.g., a private LAN, where
959 For a quick setup in a trusted environment, e.g., a private LAN, where
942 you want it to accept pushes from anybody, you can use the following
960 you want it to accept pushes from anybody, you can use the following
943 command line::
961 command line::
944
962
945 $ hg --config web.allow_push=* --config web.push_ssl=False serve
963 $ hg --config web.allow_push=* --config web.push_ssl=False serve
946
964
947 Note that this will allow anybody to push anything to the server and
965 Note that this will allow anybody to push anything to the server and
948 that this should not be used for public servers.
966 that this should not be used for public servers.
949
967
950 The full set of options is:
968 The full set of options is:
951
969
952 ``accesslog``
970 ``accesslog``
953 Where to output the access log. Default is stdout.
971 Where to output the access log. Default is stdout.
954 ``address``
972 ``address``
955 Interface address to bind to. Default is all.
973 Interface address to bind to. Default is all.
956 ``allow_archive``
974 ``allow_archive``
957 List of archive format (bz2, gz, zip) allowed for downloading.
975 List of archive format (bz2, gz, zip) allowed for downloading.
958 Default is empty.
976 Default is empty.
959 ``allowbz2``
977 ``allowbz2``
960 (DEPRECATED) Whether to allow .tar.bz2 downloading of repository
978 (DEPRECATED) Whether to allow .tar.bz2 downloading of repository
961 revisions.
979 revisions.
962 Default is False.
980 Default is False.
963 ``allowgz``
981 ``allowgz``
964 (DEPRECATED) Whether to allow .tar.gz downloading of repository
982 (DEPRECATED) Whether to allow .tar.gz downloading of repository
965 revisions.
983 revisions.
966 Default is False.
984 Default is False.
967 ``allowpull``
985 ``allowpull``
968 Whether to allow pulling from the repository. Default is True.
986 Whether to allow pulling from the repository. Default is True.
969 ``allow_push``
987 ``allow_push``
970 Whether to allow pushing to the repository. If empty or not set,
988 Whether to allow pushing to the repository. If empty or not set,
971 push is not allowed. If the special value ``*``, any remote user can
989 push is not allowed. If the special value ``*``, any remote user can
972 push, including unauthenticated users. Otherwise, the remote user
990 push, including unauthenticated users. Otherwise, the remote user
973 must have been authenticated, and the authenticated user name must
991 must have been authenticated, and the authenticated user name must
974 be present in this list. The contents of the allow_push list are
992 be present in this list. The contents of the allow_push list are
975 examined after the deny_push list.
993 examined after the deny_push list.
976 ``allow_read``
994 ``allow_read``
977 If the user has not already been denied repository access due to
995 If the user has not already been denied repository access due to
978 the contents of deny_read, this list determines whether to grant
996 the contents of deny_read, this list determines whether to grant
979 repository access to the user. If this list is not empty, and the
997 repository access to the user. If this list is not empty, and the
980 user is unauthenticated or not present in the list, then access is
998 user is unauthenticated or not present in the list, then access is
981 denied for the user. If the list is empty or not set, then access
999 denied for the user. If the list is empty or not set, then access
982 is permitted to all users by default. Setting allow_read to the
1000 is permitted to all users by default. Setting allow_read to the
983 special value ``*`` is equivalent to it not being set (i.e. access
1001 special value ``*`` is equivalent to it not being set (i.e. access
984 is permitted to all users). The contents of the allow_read list are
1002 is permitted to all users). The contents of the allow_read list are
985 examined after the deny_read list.
1003 examined after the deny_read list.
986 ``allowzip``
1004 ``allowzip``
987 (DEPRECATED) Whether to allow .zip downloading of repository
1005 (DEPRECATED) Whether to allow .zip downloading of repository
988 revisions. Default is False. This feature creates temporary files.
1006 revisions. Default is False. This feature creates temporary files.
989 ``baseurl``
1007 ``baseurl``
990 Base URL to use when publishing URLs in other locations, so
1008 Base URL to use when publishing URLs in other locations, so
991 third-party tools like email notification hooks can construct
1009 third-party tools like email notification hooks can construct
992 URLs. Example: ``http://hgserver/repos/``.
1010 URLs. Example: ``http://hgserver/repos/``.
993 ``cacerts``
1011 ``cacerts``
994 Path to file containing a list of PEM encoded certificate
1012 Path to file containing a list of PEM encoded certificate
995 authority certificates. Environment variables and ``~user``
1013 authority certificates. Environment variables and ``~user``
996 constructs are expanded in the filename. If specified on the
1014 constructs are expanded in the filename. If specified on the
997 client, then it will verify the identity of remote HTTPS servers
1015 client, then it will verify the identity of remote HTTPS servers
998 with these certificates. The form must be as follows::
1016 with these certificates. The form must be as follows::
999
1017
1000 -----BEGIN CERTIFICATE-----
1018 -----BEGIN CERTIFICATE-----
1001 ... (certificate in base64 PEM encoding) ...
1019 ... (certificate in base64 PEM encoding) ...
1002 -----END CERTIFICATE-----
1020 -----END CERTIFICATE-----
1003 -----BEGIN CERTIFICATE-----
1021 -----BEGIN CERTIFICATE-----
1004 ... (certificate in base64 PEM encoding) ...
1022 ... (certificate in base64 PEM encoding) ...
1005 -----END CERTIFICATE-----
1023 -----END CERTIFICATE-----
1006
1024
1007 This feature is only supported when using Python 2.6 or later. If you wish
1025 This feature is only supported when using Python 2.6 or later. If you wish
1008 to use it with earlier versions of Python, install the backported
1026 to use it with earlier versions of Python, install the backported
1009 version of the ssl library that is available from
1027 version of the ssl library that is available from
1010 ``http://pypi.python.org``.
1028 ``http://pypi.python.org``.
1011
1029
1012 You can use OpenSSL's CA certificate file if your platform has one.
1030 You can use OpenSSL's CA certificate file if your platform has one.
1013 On most Linux systems this will be ``/etc/ssl/certs/ca-certificates.crt``.
1031 On most Linux systems this will be ``/etc/ssl/certs/ca-certificates.crt``.
1014 Otherwise you will have to generate this file manually.
1032 Otherwise you will have to generate this file manually.
1015 ``contact``
1033 ``contact``
1016 Name or email address of the person in charge of the repository.
1034 Name or email address of the person in charge of the repository.
1017 Defaults to ui.username or ``$EMAIL`` or "unknown" if unset or empty.
1035 Defaults to ui.username or ``$EMAIL`` or "unknown" if unset or empty.
1018 ``deny_push``
1036 ``deny_push``
1019 Whether to deny pushing to the repository. If empty or not set,
1037 Whether to deny pushing to the repository. If empty or not set,
1020 push is not denied. If the special value ``*``, all remote users are
1038 push is not denied. If the special value ``*``, all remote users are
1021 denied push. Otherwise, unauthenticated users are all denied, and
1039 denied push. Otherwise, unauthenticated users are all denied, and
1022 any authenticated user name present in this list is also denied. The
1040 any authenticated user name present in this list is also denied. The
1023 contents of the deny_push list are examined before the allow_push list.
1041 contents of the deny_push list are examined before the allow_push list.
1024 ``deny_read``
1042 ``deny_read``
1025 Whether to deny reading/viewing of the repository. If this list is
1043 Whether to deny reading/viewing of the repository. If this list is
1026 not empty, unauthenticated users are all denied, and any
1044 not empty, unauthenticated users are all denied, and any
1027 authenticated user name present in this list is also denied access to
1045 authenticated user name present in this list is also denied access to
1028 the repository. If set to the special value ``*``, all remote users
1046 the repository. If set to the special value ``*``, all remote users
1029 are denied access (rarely needed ;). If deny_read is empty or not set,
1047 are denied access (rarely needed ;). If deny_read is empty or not set,
1030 the determination of repository access depends on the presence and
1048 the determination of repository access depends on the presence and
1031 content of the allow_read list (see description). If both
1049 content of the allow_read list (see description). If both
1032 deny_read and allow_read are empty or not set, then access is
1050 deny_read and allow_read are empty or not set, then access is
1033 permitted to all users by default. If the repository is being
1051 permitted to all users by default. If the repository is being
1034 served via hgwebdir, denied users will not be able to see it in
1052 served via hgwebdir, denied users will not be able to see it in
1035 the list of repositories. The contents of the deny_read list have
1053 the list of repositories. The contents of the deny_read list have
1036 priority over (are examined before) the contents of the allow_read
1054 priority over (are examined before) the contents of the allow_read
1037 list.
1055 list.
1038 ``descend``
1056 ``descend``
1039 hgwebdir indexes will not descend into subdirectories. Only repositories
1057 hgwebdir indexes will not descend into subdirectories. Only repositories
1040 directly in the current path will be shown (other repositories are still
1058 directly in the current path will be shown (other repositories are still
1041 available from the index corresponding to their containing path).
1059 available from the index corresponding to their containing path).
1042 ``description``
1060 ``description``
1043 Textual description of the repository's purpose or contents.
1061 Textual description of the repository's purpose or contents.
1044 Default is "unknown".
1062 Default is "unknown".
1045 ``encoding``
1063 ``encoding``
1046 Character encoding name. Default is the current locale charset.
1064 Character encoding name. Default is the current locale charset.
1047 Example: "UTF-8"
1065 Example: "UTF-8"
1048 ``errorlog``
1066 ``errorlog``
1049 Where to output the error log. Default is stderr.
1067 Where to output the error log. Default is stderr.
1050 ``hidden``
1068 ``hidden``
1051 Whether to hide the repository in the hgwebdir index.
1069 Whether to hide the repository in the hgwebdir index.
1052 Default is False.
1070 Default is False.
1053 ``ipv6``
1071 ``ipv6``
1054 Whether to use IPv6. Default is False.
1072 Whether to use IPv6. Default is False.
1055 ``name``
1073 ``name``
1056 Repository name to use in the web interface. Default is current
1074 Repository name to use in the web interface. Default is current
1057 working directory.
1075 working directory.
1058 ``maxchanges``
1076 ``maxchanges``
1059 Maximum number of changes to list on the changelog. Default is 10.
1077 Maximum number of changes to list on the changelog. Default is 10.
1060 ``maxfiles``
1078 ``maxfiles``
1061 Maximum number of files to list per changeset. Default is 10.
1079 Maximum number of files to list per changeset. Default is 10.
1062 ``port``
1080 ``port``
1063 Port to listen on. Default is 8000.
1081 Port to listen on. Default is 8000.
1064 ``prefix``
1082 ``prefix``
1065 Prefix path to serve from. Default is '' (server root).
1083 Prefix path to serve from. Default is '' (server root).
1066 ``push_ssl``
1084 ``push_ssl``
1067 Whether to require that inbound pushes be transported over SSL to
1085 Whether to require that inbound pushes be transported over SSL to
1068 prevent password sniffing. Default is True.
1086 prevent password sniffing. Default is True.
1069 ``staticurl``
1087 ``staticurl``
1070 Base URL to use for static files. If unset, static files (e.g. the
1088 Base URL to use for static files. If unset, static files (e.g. the
1071 hgicon.png favicon) will be served by the CGI script itself. Use
1089 hgicon.png favicon) will be served by the CGI script itself. Use
1072 this setting to serve them directly with the HTTP server.
1090 this setting to serve them directly with the HTTP server.
1073 Example: ``http://hgserver/static/``.
1091 Example: ``http://hgserver/static/``.
1074 ``stripes``
1092 ``stripes``
1075 How many lines a "zebra stripe" should span in multiline output.
1093 How many lines a "zebra stripe" should span in multiline output.
1076 Default is 1; set to 0 to disable.
1094 Default is 1; set to 0 to disable.
1077 ``style``
1095 ``style``
1078 Which template map style to use.
1096 Which template map style to use.
1079 ``templates``
1097 ``templates``
1080 Where to find the HTML templates. Default is install path.
1098 Where to find the HTML templates. Default is install path.
1081
1099
1082
1100
1083 Author
1101 Author
1084 ------
1102 ------
1085 Bryan O'Sullivan <bos@serpentine.com>.
1103 Bryan O'Sullivan <bos@serpentine.com>.
1086
1104
1087 Mercurial was written by Matt Mackall <mpm@selenic.com>.
1105 Mercurial was written by Matt Mackall <mpm@selenic.com>.
1088
1106
1089 See Also
1107 See Also
1090 --------
1108 --------
1091 |hg(1)|_, |hgignore(5)|_
1109 |hg(1)|_, |hgignore(5)|_
1092
1110
1093 Copying
1111 Copying
1094 -------
1112 -------
1095 This manual page is copyright 2005 Bryan O'Sullivan.
1113 This manual page is copyright 2005 Bryan O'Sullivan.
1096 Mercurial is copyright 2005-2010 Matt Mackall.
1114 Mercurial is copyright 2005-2010 Matt Mackall.
1097 Free use of this software is granted under the terms of the GNU General
1115 Free use of this software is granted under the terms of the GNU General
1098 Public License version 2 or any later version.
1116 Public License version 2 or any later version.
1099
1117
1100 .. include:: common.txt
1118 .. include:: common.txt
@@ -1,554 +1,554 b''
1 # hg.py - repository classes for mercurial
1 # hg.py - repository classes for mercurial
2 #
2 #
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
4 # Copyright 2006 Vadim Gelfer <vadim.gelfer@gmail.com>
4 # Copyright 2006 Vadim Gelfer <vadim.gelfer@gmail.com>
5 #
5 #
6 # This software may be used and distributed according to the terms of the
6 # This software may be used and distributed according to the terms of the
7 # GNU General Public License version 2 or any later version.
7 # GNU General Public License version 2 or any later version.
8
8
9 from i18n import _
9 from i18n import _
10 from lock import release
10 from lock import release
11 from node import hex, nullid, nullrev, short
11 from node import hex, nullid, nullrev, short
12 import localrepo, bundlerepo, httprepo, sshrepo, statichttprepo
12 import localrepo, bundlerepo, httprepo, sshrepo, statichttprepo
13 import lock, util, extensions, error, encoding, node
13 import lock, util, extensions, error, encoding, node
14 import cmdutil, discovery, url
14 import cmdutil, discovery, url
15 import merge as mergemod
15 import merge as mergemod
16 import verify as verifymod
16 import verify as verifymod
17 import errno, os, shutil
17 import errno, os, shutil
18
18
19 def _local(path):
19 def _local(path):
20 path = util.expandpath(util.drop_scheme('file', path))
20 path = util.expandpath(util.drop_scheme('file', path))
21 return (os.path.isfile(path) and bundlerepo or localrepo)
21 return (os.path.isfile(path) and bundlerepo or localrepo)
22
22
23 def addbranchrevs(lrepo, repo, branches, revs):
23 def addbranchrevs(lrepo, repo, branches, revs):
24 hashbranch, branches = branches
24 hashbranch, branches = branches
25 if not hashbranch and not branches:
25 if not hashbranch and not branches:
26 return revs or None, revs and revs[0] or None
26 return revs or None, revs and revs[0] or None
27 revs = revs and list(revs) or []
27 revs = revs and list(revs) or []
28 if not repo.capable('branchmap'):
28 if not repo.capable('branchmap'):
29 if branches:
29 if branches:
30 raise util.Abort(_("remote branch lookup not supported"))
30 raise util.Abort(_("remote branch lookup not supported"))
31 revs.append(hashbranch)
31 revs.append(hashbranch)
32 return revs, revs[0]
32 return revs, revs[0]
33 branchmap = repo.branchmap()
33 branchmap = repo.branchmap()
34
34
35 def primary(branch):
35 def primary(branch):
36 if branch == '.':
36 if branch == '.':
37 if not lrepo or not lrepo.local():
37 if not lrepo or not lrepo.local():
38 raise util.Abort(_("dirstate branch not accessible"))
38 raise util.Abort(_("dirstate branch not accessible"))
39 branch = lrepo.dirstate.branch()
39 branch = lrepo.dirstate.branch()
40 if branch in branchmap:
40 if branch in branchmap:
41 revs.extend(node.hex(r) for r in reversed(branchmap[branch]))
41 revs.extend(node.hex(r) for r in reversed(branchmap[branch]))
42 return True
42 return True
43 else:
43 else:
44 return False
44 return False
45
45
46 for branch in branches:
46 for branch in branches:
47 if not primary(branch):
47 if not primary(branch):
48 raise error.RepoLookupError(_("unknown branch '%s'") % branch)
48 raise error.RepoLookupError(_("unknown branch '%s'") % branch)
49 if hashbranch:
49 if hashbranch:
50 if not primary(hashbranch):
50 if not primary(hashbranch):
51 revs.append(hashbranch)
51 revs.append(hashbranch)
52 return revs, revs[0]
52 return revs, revs[0]
53
53
54 def parseurl(url, branches=None):
54 def parseurl(url, branches=None):
55 '''parse url#branch, returning (url, (branch, branches))'''
55 '''parse url#branch, returning (url, (branch, branches))'''
56
56
57 if '#' not in url:
57 if '#' not in url:
58 return url, (None, branches or [])
58 return url, (None, branches or [])
59 url, branch = url.split('#', 1)
59 url, branch = url.split('#', 1)
60 return url, (branch, branches or [])
60 return url, (branch, branches or [])
61
61
62 schemes = {
62 schemes = {
63 'bundle': bundlerepo,
63 'bundle': bundlerepo,
64 'file': _local,
64 'file': _local,
65 'http': httprepo,
65 'http': httprepo,
66 'https': httprepo,
66 'https': httprepo,
67 'ssh': sshrepo,
67 'ssh': sshrepo,
68 'static-http': statichttprepo,
68 'static-http': statichttprepo,
69 }
69 }
70
70
71 def _lookup(path):
71 def _lookup(path):
72 scheme = 'file'
72 scheme = 'file'
73 if path:
73 if path:
74 c = path.find(':')
74 c = path.find(':')
75 if c > 0:
75 if c > 0:
76 scheme = path[:c]
76 scheme = path[:c]
77 thing = schemes.get(scheme) or schemes['file']
77 thing = schemes.get(scheme) or schemes['file']
78 try:
78 try:
79 return thing(path)
79 return thing(path)
80 except TypeError:
80 except TypeError:
81 return thing
81 return thing
82
82
83 def islocal(repo):
83 def islocal(repo):
84 '''return true if repo or path is local'''
84 '''return true if repo or path is local'''
85 if isinstance(repo, str):
85 if isinstance(repo, str):
86 try:
86 try:
87 return _lookup(repo).islocal(repo)
87 return _lookup(repo).islocal(repo)
88 except AttributeError:
88 except AttributeError:
89 return False
89 return False
90 return repo.local()
90 return repo.local()
91
91
92 def repository(ui, path='', create=False):
92 def repository(ui, path='', create=False):
93 """return a repository object for the specified path"""
93 """return a repository object for the specified path"""
94 repo = _lookup(path).instance(ui, path, create)
94 repo = _lookup(path).instance(ui, path, create)
95 ui = getattr(repo, "ui", ui)
95 ui = getattr(repo, "ui", ui)
96 for name, module in extensions.extensions():
96 for name, module in extensions.extensions():
97 hook = getattr(module, 'reposetup', None)
97 hook = getattr(module, 'reposetup', None)
98 if hook:
98 if hook:
99 hook(ui, repo)
99 hook(ui, repo)
100 return repo
100 return repo
101
101
102 def defaultdest(source):
102 def defaultdest(source):
103 '''return default destination of clone if none is given'''
103 '''return default destination of clone if none is given'''
104 return os.path.basename(os.path.normpath(source))
104 return os.path.basename(os.path.normpath(source))
105
105
106 def localpath(path):
106 def localpath(path):
107 if path.startswith('file://localhost/'):
107 if path.startswith('file://localhost/'):
108 return path[16:]
108 return path[16:]
109 if path.startswith('file://'):
109 if path.startswith('file://'):
110 return path[7:]
110 return path[7:]
111 if path.startswith('file:'):
111 if path.startswith('file:'):
112 return path[5:]
112 return path[5:]
113 return path
113 return path
114
114
115 def share(ui, source, dest=None, update=True):
115 def share(ui, source, dest=None, update=True):
116 '''create a shared repository'''
116 '''create a shared repository'''
117
117
118 if not islocal(source):
118 if not islocal(source):
119 raise util.Abort(_('can only share local repositories'))
119 raise util.Abort(_('can only share local repositories'))
120
120
121 if not dest:
121 if not dest:
122 dest = defaultdest(source)
122 dest = defaultdest(source)
123 else:
123 else:
124 dest = ui.expandpath(dest)
124 dest = ui.expandpath(dest)
125
125
126 if isinstance(source, str):
126 if isinstance(source, str):
127 origsource = ui.expandpath(source)
127 origsource = ui.expandpath(source)
128 source, branches = parseurl(origsource)
128 source, branches = parseurl(origsource)
129 srcrepo = repository(ui, source)
129 srcrepo = repository(ui, source)
130 rev, checkout = addbranchrevs(srcrepo, srcrepo, branches, None)
130 rev, checkout = addbranchrevs(srcrepo, srcrepo, branches, None)
131 else:
131 else:
132 srcrepo = source
132 srcrepo = source
133 origsource = source = srcrepo.url()
133 origsource = source = srcrepo.url()
134 checkout = None
134 checkout = None
135
135
136 sharedpath = srcrepo.sharedpath # if our source is already sharing
136 sharedpath = srcrepo.sharedpath # if our source is already sharing
137
137
138 root = os.path.realpath(dest)
138 root = os.path.realpath(dest)
139 roothg = os.path.join(root, '.hg')
139 roothg = os.path.join(root, '.hg')
140
140
141 if os.path.exists(roothg):
141 if os.path.exists(roothg):
142 raise util.Abort(_('destination already exists'))
142 raise util.Abort(_('destination already exists'))
143
143
144 if not os.path.isdir(root):
144 if not os.path.isdir(root):
145 os.mkdir(root)
145 os.mkdir(root)
146 os.mkdir(roothg)
146 os.mkdir(roothg)
147
147
148 requirements = ''
148 requirements = ''
149 try:
149 try:
150 requirements = srcrepo.opener('requires').read()
150 requirements = srcrepo.opener('requires').read()
151 except IOError, inst:
151 except IOError, inst:
152 if inst.errno != errno.ENOENT:
152 if inst.errno != errno.ENOENT:
153 raise
153 raise
154
154
155 requirements += 'shared\n'
155 requirements += 'shared\n'
156 file(os.path.join(roothg, 'requires'), 'w').write(requirements)
156 file(os.path.join(roothg, 'requires'), 'w').write(requirements)
157 file(os.path.join(roothg, 'sharedpath'), 'w').write(sharedpath)
157 file(os.path.join(roothg, 'sharedpath'), 'w').write(sharedpath)
158
158
159 default = srcrepo.ui.config('paths', 'default')
159 default = srcrepo.ui.config('paths', 'default')
160 if default:
160 if default:
161 f = file(os.path.join(roothg, 'hgrc'), 'w')
161 f = file(os.path.join(roothg, 'hgrc'), 'w')
162 f.write('[paths]\ndefault = %s\n' % default)
162 f.write('[paths]\ndefault = %s\n' % default)
163 f.close()
163 f.close()
164
164
165 r = repository(ui, root)
165 r = repository(ui, root)
166
166
167 if update:
167 if update:
168 r.ui.status(_("updating working directory\n"))
168 r.ui.status(_("updating working directory\n"))
169 if update is not True:
169 if update is not True:
170 checkout = update
170 checkout = update
171 for test in (checkout, 'default', 'tip'):
171 for test in (checkout, 'default', 'tip'):
172 if test is None:
172 if test is None:
173 continue
173 continue
174 try:
174 try:
175 uprev = r.lookup(test)
175 uprev = r.lookup(test)
176 break
176 break
177 except error.RepoLookupError:
177 except error.RepoLookupError:
178 continue
178 continue
179 _update(r, uprev)
179 _update(r, uprev)
180
180
181 def clone(ui, source, dest=None, pull=False, rev=None, update=True,
181 def clone(ui, source, dest=None, pull=False, rev=None, update=True,
182 stream=False, branch=None):
182 stream=False, branch=None):
183 """Make a copy of an existing repository.
183 """Make a copy of an existing repository.
184
184
185 Create a copy of an existing repository in a new directory. The
185 Create a copy of an existing repository in a new directory. The
186 source and destination are URLs, as passed to the repository
186 source and destination are URLs, as passed to the repository
187 function. Returns a pair of repository objects, the source and
187 function. Returns a pair of repository objects, the source and
188 newly created destination.
188 newly created destination.
189
189
190 The location of the source is added to the new repository's
190 The location of the source is added to the new repository's
191 .hg/hgrc file, as the default to be used for future pulls and
191 .hg/hgrc file, as the default to be used for future pulls and
192 pushes.
192 pushes.
193
193
194 If an exception is raised, the partly cloned/updated destination
194 If an exception is raised, the partly cloned/updated destination
195 repository will be deleted.
195 repository will be deleted.
196
196
197 Arguments:
197 Arguments:
198
198
199 source: repository object or URL
199 source: repository object or URL
200
200
201 dest: URL of destination repository to create (defaults to base
201 dest: URL of destination repository to create (defaults to base
202 name of source repository)
202 name of source repository)
203
203
204 pull: always pull from source repository, even in local case
204 pull: always pull from source repository, even in local case
205
205
206 stream: stream raw data uncompressed from repository (fast over
206 stream: stream raw data uncompressed from repository (fast over
207 LAN, slow over WAN)
207 LAN, slow over WAN)
208
208
209 rev: revision to clone up to (implies pull=True)
209 rev: revision to clone up to (implies pull=True)
210
210
211 update: update working directory after clone completes, if
211 update: update working directory after clone completes, if
212 destination is local repository (True means update to default rev,
212 destination is local repository (True means update to default rev,
213 anything else is treated as a revision)
213 anything else is treated as a revision)
214
214
215 branch: branches to clone
215 branch: branches to clone
216 """
216 """
217
217
218 if isinstance(source, str):
218 if isinstance(source, str):
219 origsource = ui.expandpath(source)
219 origsource = ui.expandpath(source)
220 source, branch = parseurl(origsource, branch)
220 source, branch = parseurl(origsource, branch)
221 src_repo = repository(ui, source)
221 src_repo = repository(ui, source)
222 else:
222 else:
223 src_repo = source
223 src_repo = source
224 branch = (None, branch or [])
224 branch = (None, branch or [])
225 origsource = source = src_repo.url()
225 origsource = source = src_repo.url()
226 rev, checkout = addbranchrevs(src_repo, src_repo, branch, rev)
226 rev, checkout = addbranchrevs(src_repo, src_repo, branch, rev)
227
227
228 if dest is None:
228 if dest is None:
229 dest = defaultdest(source)
229 dest = defaultdest(source)
230 ui.status(_("destination directory: %s\n") % dest)
230 ui.status(_("destination directory: %s\n") % dest)
231 else:
231 else:
232 dest = ui.expandpath(dest)
232 dest = ui.expandpath(dest)
233
233
234 dest = localpath(dest)
234 dest = localpath(dest)
235 source = localpath(source)
235 source = localpath(source)
236
236
237 if os.path.exists(dest):
237 if os.path.exists(dest):
238 if not os.path.isdir(dest):
238 if not os.path.isdir(dest):
239 raise util.Abort(_("destination '%s' already exists") % dest)
239 raise util.Abort(_("destination '%s' already exists") % dest)
240 elif os.listdir(dest):
240 elif os.listdir(dest):
241 raise util.Abort(_("destination '%s' is not empty") % dest)
241 raise util.Abort(_("destination '%s' is not empty") % dest)
242
242
243 class DirCleanup(object):
243 class DirCleanup(object):
244 def __init__(self, dir_):
244 def __init__(self, dir_):
245 self.rmtree = shutil.rmtree
245 self.rmtree = shutil.rmtree
246 self.dir_ = dir_
246 self.dir_ = dir_
247 def close(self):
247 def close(self):
248 self.dir_ = None
248 self.dir_ = None
249 def cleanup(self):
249 def cleanup(self):
250 if self.dir_:
250 if self.dir_:
251 self.rmtree(self.dir_, True)
251 self.rmtree(self.dir_, True)
252
252
253 src_lock = dest_lock = dir_cleanup = None
253 src_lock = dest_lock = dir_cleanup = None
254 try:
254 try:
255 if islocal(dest):
255 if islocal(dest):
256 dir_cleanup = DirCleanup(dest)
256 dir_cleanup = DirCleanup(dest)
257
257
258 abspath = origsource
258 abspath = origsource
259 copy = False
259 copy = False
260 if src_repo.cancopy() and islocal(dest):
260 if src_repo.cancopy() and islocal(dest):
261 abspath = os.path.abspath(util.drop_scheme('file', origsource))
261 abspath = os.path.abspath(util.drop_scheme('file', origsource))
262 copy = not pull and not rev
262 copy = not pull and not rev
263
263
264 if copy:
264 if copy:
265 try:
265 try:
266 # we use a lock here because if we race with commit, we
266 # we use a lock here because if we race with commit, we
267 # can end up with extra data in the cloned revlogs that's
267 # can end up with extra data in the cloned revlogs that's
268 # not pointed to by changesets, thus causing verify to
268 # not pointed to by changesets, thus causing verify to
269 # fail
269 # fail
270 src_lock = src_repo.lock(wait=False)
270 src_lock = src_repo.lock(wait=False)
271 except error.LockError:
271 except error.LockError:
272 copy = False
272 copy = False
273
273
274 if copy:
274 if copy:
275 src_repo.hook('preoutgoing', throw=True, source='clone')
275 src_repo.hook('preoutgoing', throw=True, source='clone')
276 hgdir = os.path.realpath(os.path.join(dest, ".hg"))
276 hgdir = os.path.realpath(os.path.join(dest, ".hg"))
277 if not os.path.exists(dest):
277 if not os.path.exists(dest):
278 os.mkdir(dest)
278 os.mkdir(dest)
279 else:
279 else:
280 # only clean up directories we create ourselves
280 # only clean up directories we create ourselves
281 dir_cleanup.dir_ = hgdir
281 dir_cleanup.dir_ = hgdir
282 try:
282 try:
283 dest_path = hgdir
283 dest_path = hgdir
284 os.mkdir(dest_path)
284 os.mkdir(dest_path)
285 except OSError, inst:
285 except OSError, inst:
286 if inst.errno == errno.EEXIST:
286 if inst.errno == errno.EEXIST:
287 dir_cleanup.close()
287 dir_cleanup.close()
288 raise util.Abort(_("destination '%s' already exists")
288 raise util.Abort(_("destination '%s' already exists")
289 % dest)
289 % dest)
290 raise
290 raise
291
291
292 hardlink = None
292 hardlink = None
293 num = 0
293 num = 0
294 for f in src_repo.store.copylist():
294 for f in src_repo.store.copylist():
295 src = os.path.join(src_repo.sharedpath, f)
295 src = os.path.join(src_repo.sharedpath, f)
296 dst = os.path.join(dest_path, f)
296 dst = os.path.join(dest_path, f)
297 dstbase = os.path.dirname(dst)
297 dstbase = os.path.dirname(dst)
298 if dstbase and not os.path.exists(dstbase):
298 if dstbase and not os.path.exists(dstbase):
299 os.mkdir(dstbase)
299 os.mkdir(dstbase)
300 if os.path.exists(src):
300 if os.path.exists(src):
301 if dst.endswith('data'):
301 if dst.endswith('data'):
302 # lock to avoid premature writing to the target
302 # lock to avoid premature writing to the target
303 dest_lock = lock.lock(os.path.join(dstbase, "lock"))
303 dest_lock = lock.lock(os.path.join(dstbase, "lock"))
304 hardlink, n = util.copyfiles(src, dst, hardlink)
304 hardlink, n = util.copyfiles(src, dst, hardlink)
305 num += n
305 num += n
306 if hardlink:
306 if hardlink:
307 ui.debug("linked %d files\n" % num)
307 ui.debug("linked %d files\n" % num)
308 else:
308 else:
309 ui.debug("copied %d files\n" % num)
309 ui.debug("copied %d files\n" % num)
310
310
311 # we need to re-init the repo after manually copying the data
311 # we need to re-init the repo after manually copying the data
312 # into it
312 # into it
313 dest_repo = repository(ui, dest)
313 dest_repo = repository(ui, dest)
314 src_repo.hook('outgoing', source='clone',
314 src_repo.hook('outgoing', source='clone',
315 node=node.hex(node.nullid))
315 node=node.hex(node.nullid))
316 else:
316 else:
317 try:
317 try:
318 dest_repo = repository(ui, dest, create=True)
318 dest_repo = repository(ui, dest, create=True)
319 except OSError, inst:
319 except OSError, inst:
320 if inst.errno == errno.EEXIST:
320 if inst.errno == errno.EEXIST:
321 dir_cleanup.close()
321 dir_cleanup.close()
322 raise util.Abort(_("destination '%s' already exists")
322 raise util.Abort(_("destination '%s' already exists")
323 % dest)
323 % dest)
324 raise
324 raise
325
325
326 revs = None
326 revs = None
327 if rev:
327 if rev:
328 if 'lookup' not in src_repo.capabilities:
328 if 'lookup' not in src_repo.capabilities:
329 raise util.Abort(_("src repository does not support "
329 raise util.Abort(_("src repository does not support "
330 "revision lookup and so doesn't "
330 "revision lookup and so doesn't "
331 "support clone by revision"))
331 "support clone by revision"))
332 revs = [src_repo.lookup(r) for r in rev]
332 revs = [src_repo.lookup(r) for r in rev]
333 checkout = revs[0]
333 checkout = revs[0]
334 if dest_repo.local():
334 if dest_repo.local():
335 dest_repo.clone(src_repo, heads=revs, stream=stream)
335 dest_repo.clone(src_repo, heads=revs, stream=stream)
336 elif src_repo.local():
336 elif src_repo.local():
337 src_repo.push(dest_repo, revs=revs)
337 src_repo.push(dest_repo, revs=revs)
338 else:
338 else:
339 raise util.Abort(_("clone from remote to remote not supported"))
339 raise util.Abort(_("clone from remote to remote not supported"))
340
340
341 if dir_cleanup:
341 if dir_cleanup:
342 dir_cleanup.close()
342 dir_cleanup.close()
343
343
344 if dest_repo.local():
344 if dest_repo.local():
345 fp = dest_repo.opener("hgrc", "w", text=True)
345 fp = dest_repo.opener("hgrc", "w", text=True)
346 fp.write("[paths]\n")
346 fp.write("[paths]\n")
347 fp.write("default = %s\n" % abspath)
347 fp.write("default = %s\n" % abspath)
348 fp.close()
348 fp.close()
349
349
350 dest_repo.ui.setconfig('paths', 'default', abspath)
350 dest_repo.ui.setconfig('paths', 'default', abspath)
351
351
352 if update:
352 if update:
353 if update is not True:
353 if update is not True:
354 checkout = update
354 checkout = update
355 if src_repo.local():
355 if src_repo.local():
356 checkout = src_repo.lookup(update)
356 checkout = src_repo.lookup(update)
357 for test in (checkout, 'default', 'tip'):
357 for test in (checkout, 'default', 'tip'):
358 if test is None:
358 if test is None:
359 continue
359 continue
360 try:
360 try:
361 uprev = dest_repo.lookup(test)
361 uprev = dest_repo.lookup(test)
362 break
362 break
363 except error.RepoLookupError:
363 except error.RepoLookupError:
364 continue
364 continue
365 bn = dest_repo[uprev].branch()
365 bn = dest_repo[uprev].branch()
366 dest_repo.ui.status(_("updating to branch %s\n") % bn)
366 dest_repo.ui.status(_("updating to branch %s\n") % bn)
367 _update(dest_repo, uprev)
367 _update(dest_repo, uprev)
368
368
369 return src_repo, dest_repo
369 return src_repo, dest_repo
370 finally:
370 finally:
371 release(src_lock, dest_lock)
371 release(src_lock, dest_lock)
372 if dir_cleanup is not None:
372 if dir_cleanup is not None:
373 dir_cleanup.cleanup()
373 dir_cleanup.cleanup()
374
374
375 def _showstats(repo, stats):
375 def _showstats(repo, stats):
376 repo.ui.status(_("%d files updated, %d files merged, "
376 repo.ui.status(_("%d files updated, %d files merged, "
377 "%d files removed, %d files unresolved\n") % stats)
377 "%d files removed, %d files unresolved\n") % stats)
378
378
379 def update(repo, node):
379 def update(repo, node):
380 """update the working directory to node, merging linear changes"""
380 """update the working directory to node, merging linear changes"""
381 stats = mergemod.update(repo, node, False, False, None)
381 stats = mergemod.update(repo, node, False, False, None)
382 _showstats(repo, stats)
382 _showstats(repo, stats)
383 if stats[3]:
383 if stats[3]:
384 repo.ui.status(_("use 'hg resolve' to retry unresolved file merges\n"))
384 repo.ui.status(_("use 'hg resolve' to retry unresolved file merges\n"))
385 return stats[3] > 0
385 return stats[3] > 0
386
386
387 # naming conflict in clone()
387 # naming conflict in clone()
388 _update = update
388 _update = update
389
389
390 def clean(repo, node, show_stats=True):
390 def clean(repo, node, show_stats=True):
391 """forcibly switch the working directory to node, clobbering changes"""
391 """forcibly switch the working directory to node, clobbering changes"""
392 stats = mergemod.update(repo, node, False, True, None)
392 stats = mergemod.update(repo, node, False, True, None)
393 if show_stats:
393 if show_stats:
394 _showstats(repo, stats)
394 _showstats(repo, stats)
395 return stats[3] > 0
395 return stats[3] > 0
396
396
397 def merge(repo, node, force=None, remind=True):
397 def merge(repo, node, force=None, remind=True):
398 """Branch merge with node, resolving changes. Return true if any
398 """Branch merge with node, resolving changes. Return true if any
399 unresolved conflicts."""
399 unresolved conflicts."""
400 stats = mergemod.update(repo, node, True, force, False)
400 stats = mergemod.update(repo, node, True, force, False)
401 _showstats(repo, stats)
401 _showstats(repo, stats)
402 if stats[3]:
402 if stats[3]:
403 repo.ui.status(_("use 'hg resolve' to retry unresolved file merges "
403 repo.ui.status(_("use 'hg resolve' to retry unresolved file merges "
404 "or 'hg update -C .' to abandon\n"))
404 "or 'hg update -C .' to abandon\n"))
405 elif remind:
405 elif remind:
406 repo.ui.status(_("(branch merge, don't forget to commit)\n"))
406 repo.ui.status(_("(branch merge, don't forget to commit)\n"))
407 return stats[3] > 0
407 return stats[3] > 0
408
408
409 def _incoming(displaychlist, subreporecurse, ui, repo, source,
409 def _incoming(displaychlist, subreporecurse, ui, repo, source,
410 opts, buffered=False):
410 opts, buffered=False):
411 """
411 """
412 Helper for incoming / gincoming.
412 Helper for incoming / gincoming.
413 displaychlist gets called with
413 displaychlist gets called with
414 (remoterepo, incomingchangesetlist, displayer) parameters,
414 (remoterepo, incomingchangesetlist, displayer) parameters,
415 and is supposed to contain only code that can't be unified.
415 and is supposed to contain only code that can't be unified.
416 """
416 """
417 source, branches = parseurl(ui.expandpath(source), opts.get('branch'))
417 source, branches = parseurl(ui.expandpath(source), opts.get('branch'))
418 other = repository(remoteui(repo, opts), source)
418 other = repository(remoteui(repo, opts), source)
419 ui.status(_('comparing with %s\n') % url.hidepassword(source))
419 ui.status(_('comparing with %s\n') % url.hidepassword(source))
420 revs, checkout = addbranchrevs(repo, other, branches, opts.get('rev'))
420 revs, checkout = addbranchrevs(repo, other, branches, opts.get('rev'))
421
421
422 if revs:
422 if revs:
423 revs = [other.lookup(rev) for rev in revs]
423 revs = [other.lookup(rev) for rev in revs]
424 other, incoming, bundle = bundlerepo.getremotechanges(ui, repo, other, revs,
424 other, incoming, bundle = bundlerepo.getremotechanges(ui, repo, other, revs,
425 opts["bundle"], opts["force"])
425 opts["bundle"], opts["force"])
426 if incoming is None:
426 if incoming is None:
427 ui.status(_("no changes found\n"))
427 ui.status(_("no changes found\n"))
428 return subreporecurse()
428 return subreporecurse()
429
429
430 try:
430 try:
431 chlist = other.changelog.nodesbetween(incoming, revs)[0]
431 chlist = other.changelog.nodesbetween(incoming, revs)[0]
432 displayer = cmdutil.show_changeset(ui, other, opts, buffered)
432 displayer = cmdutil.show_changeset(ui, other, opts, buffered)
433
433
434 # XXX once graphlog extension makes it into core,
434 # XXX once graphlog extension makes it into core,
435 # should be replaced by a if graph/else
435 # should be replaced by a if graph/else
436 displaychlist(other, chlist, displayer)
436 displaychlist(other, chlist, displayer)
437
437
438 displayer.close()
438 displayer.close()
439 finally:
439 finally:
440 if hasattr(other, 'close'):
440 if hasattr(other, 'close'):
441 other.close()
441 other.close()
442 if bundle:
442 if bundle:
443 os.unlink(bundle)
443 os.unlink(bundle)
444 subreporecurse()
444 subreporecurse()
445 return 0 # exit code is zero since we found incoming changes
445 return 0 # exit code is zero since we found incoming changes
446
446
447 def incoming(ui, repo, source, opts):
447 def incoming(ui, repo, source, opts):
448 def subreporecurse():
448 def subreporecurse():
449 ret = 1
449 ret = 1
450 if opts.get('subrepos'):
450 if opts.get('subrepos'):
451 ctx = repo[None]
451 ctx = repo[None]
452 for subpath in sorted(ctx.substate):
452 for subpath in sorted(ctx.substate):
453 sub = ctx.sub(subpath)
453 sub = ctx.sub(subpath)
454 ret = min(ret, sub.incoming(ui, source, opts))
454 ret = min(ret, sub.incoming(ui, source, opts))
455 return ret
455 return ret
456
456
457 def display(other, chlist, displayer):
457 def display(other, chlist, displayer):
458 limit = cmdutil.loglimit(opts)
458 limit = cmdutil.loglimit(opts)
459 if opts.get('newest_first'):
459 if opts.get('newest_first'):
460 chlist.reverse()
460 chlist.reverse()
461 count = 0
461 count = 0
462 for n in chlist:
462 for n in chlist:
463 if limit is not None and count >= limit:
463 if limit is not None and count >= limit:
464 break
464 break
465 parents = [p for p in other.changelog.parents(n) if p != nullid]
465 parents = [p for p in other.changelog.parents(n) if p != nullid]
466 if opts.get('no_merges') and len(parents) == 2:
466 if opts.get('no_merges') and len(parents) == 2:
467 continue
467 continue
468 count += 1
468 count += 1
469 displayer.show(other[n])
469 displayer.show(other[n])
470 return _incoming(display, subreporecurse, ui, repo, source, opts)
470 return _incoming(display, subreporecurse, ui, repo, source, opts)
471
471
472 def _outgoing(ui, repo, dest, opts):
472 def _outgoing(ui, repo, dest, opts):
473 dest = ui.expandpath(dest or 'default-push', dest or 'default')
473 dest = ui.expandpath(dest or 'default-push', dest or 'default')
474 dest, branches = parseurl(dest, opts.get('branch'))
474 dest, branches = parseurl(dest, opts.get('branch'))
475 revs, checkout = addbranchrevs(repo, repo, branches, opts.get('rev'))
475 revs, checkout = addbranchrevs(repo, repo, branches, opts.get('rev'))
476 if revs:
476 if revs:
477 revs = [repo.lookup(rev) for rev in revs]
477 revs = [repo.lookup(rev) for rev in revs]
478
478
479 other = repository(remoteui(repo, opts), dest)
479 other = repository(remoteui(repo, opts), dest)
480 ui.status(_('comparing with %s\n') % url.hidepassword(dest))
480 ui.status(_('comparing with %s\n') % url.hidepassword(dest))
481 o = discovery.findoutgoing(repo, other, force=opts.get('force'))
481 o = discovery.findoutgoing(repo, other, force=opts.get('force'))
482 if not o:
482 if not o:
483 ui.status(_("no changes found\n"))
483 ui.status(_("no changes found\n"))
484 return None
484 return None
485
485
486 return repo.changelog.nodesbetween(o, revs)[0]
486 return repo.changelog.nodesbetween(o, revs)[0]
487
487
488 def outgoing(ui, repo, dest, opts):
488 def outgoing(ui, repo, dest, opts):
489 def recurse():
489 def recurse():
490 ret = 1
490 ret = 1
491 if opts.get('subrepos'):
491 if opts.get('subrepos'):
492 ctx = repo[None]
492 ctx = repo[None]
493 for subpath in sorted(ctx.substate):
493 for subpath in sorted(ctx.substate):
494 sub = ctx.sub(subpath)
494 sub = ctx.sub(subpath)
495 ret = min(ret, sub.outgoing(ui, dest, opts))
495 ret = min(ret, sub.outgoing(ui, dest, opts))
496 return ret
496 return ret
497
497
498 limit = cmdutil.loglimit(opts)
498 limit = cmdutil.loglimit(opts)
499 o = _outgoing(ui, repo, dest, opts)
499 o = _outgoing(ui, repo, dest, opts)
500 if o is None:
500 if o is None:
501 return recurse()
501 return recurse()
502
502
503 if opts.get('newest_first'):
503 if opts.get('newest_first'):
504 o.reverse()
504 o.reverse()
505 displayer = cmdutil.show_changeset(ui, repo, opts)
505 displayer = cmdutil.show_changeset(ui, repo, opts)
506 count = 0
506 count = 0
507 for n in o:
507 for n in o:
508 if limit is not None and count >= limit:
508 if limit is not None and count >= limit:
509 break
509 break
510 parents = [p for p in repo.changelog.parents(n) if p != nullid]
510 parents = [p for p in repo.changelog.parents(n) if p != nullid]
511 if opts.get('no_merges') and len(parents) == 2:
511 if opts.get('no_merges') and len(parents) == 2:
512 continue
512 continue
513 count += 1
513 count += 1
514 displayer.show(repo[n])
514 displayer.show(repo[n])
515 displayer.close()
515 displayer.close()
516 recurse()
516 recurse()
517 return 0 # exit code is zero since we found outgoing changes
517 return 0 # exit code is zero since we found outgoing changes
518
518
519 def revert(repo, node, choose):
519 def revert(repo, node, choose):
520 """revert changes to revision in node without updating dirstate"""
520 """revert changes to revision in node without updating dirstate"""
521 return mergemod.update(repo, node, False, True, choose)[3] > 0
521 return mergemod.update(repo, node, False, True, choose)[3] > 0
522
522
523 def verify(repo):
523 def verify(repo):
524 """verify the consistency of a repository"""
524 """verify the consistency of a repository"""
525 return verifymod.verify(repo)
525 return verifymod.verify(repo)
526
526
527 def remoteui(src, opts):
527 def remoteui(src, opts):
528 'build a remote ui from ui or repo and opts'
528 'build a remote ui from ui or repo and opts'
529 if hasattr(src, 'baseui'): # looks like a repository
529 if hasattr(src, 'baseui'): # looks like a repository
530 dst = src.baseui.copy() # drop repo-specific config
530 dst = src.baseui.copy() # drop repo-specific config
531 src = src.ui # copy target options from repo
531 src = src.ui # copy target options from repo
532 else: # assume it's a global ui object
532 else: # assume it's a global ui object
533 dst = src.copy() # keep all global options
533 dst = src.copy() # keep all global options
534
534
535 # copy ssh-specific options
535 # copy ssh-specific options
536 for o in 'ssh', 'remotecmd':
536 for o in 'ssh', 'remotecmd':
537 v = opts.get(o) or src.config('ui', o)
537 v = opts.get(o) or src.config('ui', o)
538 if v:
538 if v:
539 dst.setconfig("ui", o, v)
539 dst.setconfig("ui", o, v)
540
540
541 # copy bundle-specific options
541 # copy bundle-specific options
542 r = src.config('bundle', 'mainreporoot')
542 r = src.config('bundle', 'mainreporoot')
543 if r:
543 if r:
544 dst.setconfig('bundle', 'mainreporoot', r)
544 dst.setconfig('bundle', 'mainreporoot', r)
545
545
546 # copy selected local settings to the remote ui
546 # copy selected local settings to the remote ui
547 for sect in ('auth', 'http_proxy'):
547 for sect in ('auth', 'hostfingerprints', 'http_proxy'):
548 for key, val in src.configitems(sect):
548 for key, val in src.configitems(sect):
549 dst.setconfig(sect, key, val)
549 dst.setconfig(sect, key, val)
550 v = src.config('web', 'cacerts')
550 v = src.config('web', 'cacerts')
551 if v:
551 if v:
552 dst.setconfig('web', 'cacerts', util.expandpath(v))
552 dst.setconfig('web', 'cacerts', util.expandpath(v))
553
553
554 return dst
554 return dst
@@ -1,737 +1,761 b''
1 # url.py - HTTP handling for mercurial
1 # url.py - HTTP handling for mercurial
2 #
2 #
3 # Copyright 2005, 2006, 2007, 2008 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005, 2006, 2007, 2008 Matt Mackall <mpm@selenic.com>
4 # Copyright 2006, 2007 Alexis S. L. Carvalho <alexis@cecm.usp.br>
4 # Copyright 2006, 2007 Alexis S. L. Carvalho <alexis@cecm.usp.br>
5 # Copyright 2006 Vadim Gelfer <vadim.gelfer@gmail.com>
5 # Copyright 2006 Vadim Gelfer <vadim.gelfer@gmail.com>
6 #
6 #
7 # This software may be used and distributed according to the terms of the
7 # This software may be used and distributed according to the terms of the
8 # GNU General Public License version 2 or any later version.
8 # GNU General Public License version 2 or any later version.
9
9
10 import urllib, urllib2, urlparse, httplib, os, re, socket, cStringIO
10 import urllib, urllib2, urlparse, httplib, os, re, socket, cStringIO
11 import __builtin__
11 import __builtin__
12 from i18n import _
12 from i18n import _
13 import keepalive, util
13 import keepalive, util
14
14
15 def _urlunparse(scheme, netloc, path, params, query, fragment, url):
15 def _urlunparse(scheme, netloc, path, params, query, fragment, url):
16 '''Handle cases where urlunparse(urlparse(x://)) doesn't preserve the "//"'''
16 '''Handle cases where urlunparse(urlparse(x://)) doesn't preserve the "//"'''
17 result = urlparse.urlunparse((scheme, netloc, path, params, query, fragment))
17 result = urlparse.urlunparse((scheme, netloc, path, params, query, fragment))
18 if (scheme and
18 if (scheme and
19 result.startswith(scheme + ':') and
19 result.startswith(scheme + ':') and
20 not result.startswith(scheme + '://') and
20 not result.startswith(scheme + '://') and
21 url.startswith(scheme + '://')
21 url.startswith(scheme + '://')
22 ):
22 ):
23 result = scheme + '://' + result[len(scheme + ':'):]
23 result = scheme + '://' + result[len(scheme + ':'):]
24 return result
24 return result
25
25
26 def hidepassword(url):
26 def hidepassword(url):
27 '''hide user credential in a url string'''
27 '''hide user credential in a url string'''
28 scheme, netloc, path, params, query, fragment = urlparse.urlparse(url)
28 scheme, netloc, path, params, query, fragment = urlparse.urlparse(url)
29 netloc = re.sub('([^:]*):([^@]*)@(.*)', r'\1:***@\3', netloc)
29 netloc = re.sub('([^:]*):([^@]*)@(.*)', r'\1:***@\3', netloc)
30 return _urlunparse(scheme, netloc, path, params, query, fragment, url)
30 return _urlunparse(scheme, netloc, path, params, query, fragment, url)
31
31
32 def removeauth(url):
32 def removeauth(url):
33 '''remove all authentication information from a url string'''
33 '''remove all authentication information from a url string'''
34 scheme, netloc, path, params, query, fragment = urlparse.urlparse(url)
34 scheme, netloc, path, params, query, fragment = urlparse.urlparse(url)
35 netloc = netloc[netloc.find('@')+1:]
35 netloc = netloc[netloc.find('@')+1:]
36 return _urlunparse(scheme, netloc, path, params, query, fragment, url)
36 return _urlunparse(scheme, netloc, path, params, query, fragment, url)
37
37
38 def netlocsplit(netloc):
38 def netlocsplit(netloc):
39 '''split [user[:passwd]@]host[:port] into 4-tuple.'''
39 '''split [user[:passwd]@]host[:port] into 4-tuple.'''
40
40
41 a = netloc.find('@')
41 a = netloc.find('@')
42 if a == -1:
42 if a == -1:
43 user, passwd = None, None
43 user, passwd = None, None
44 else:
44 else:
45 userpass, netloc = netloc[:a], netloc[a + 1:]
45 userpass, netloc = netloc[:a], netloc[a + 1:]
46 c = userpass.find(':')
46 c = userpass.find(':')
47 if c == -1:
47 if c == -1:
48 user, passwd = urllib.unquote(userpass), None
48 user, passwd = urllib.unquote(userpass), None
49 else:
49 else:
50 user = urllib.unquote(userpass[:c])
50 user = urllib.unquote(userpass[:c])
51 passwd = urllib.unquote(userpass[c + 1:])
51 passwd = urllib.unquote(userpass[c + 1:])
52 c = netloc.find(':')
52 c = netloc.find(':')
53 if c == -1:
53 if c == -1:
54 host, port = netloc, None
54 host, port = netloc, None
55 else:
55 else:
56 host, port = netloc[:c], netloc[c + 1:]
56 host, port = netloc[:c], netloc[c + 1:]
57 return host, port, user, passwd
57 return host, port, user, passwd
58
58
59 def netlocunsplit(host, port, user=None, passwd=None):
59 def netlocunsplit(host, port, user=None, passwd=None):
60 '''turn host, port, user, passwd into [user[:passwd]@]host[:port].'''
60 '''turn host, port, user, passwd into [user[:passwd]@]host[:port].'''
61 if port:
61 if port:
62 hostport = host + ':' + port
62 hostport = host + ':' + port
63 else:
63 else:
64 hostport = host
64 hostport = host
65 if user:
65 if user:
66 quote = lambda s: urllib.quote(s, safe='')
66 quote = lambda s: urllib.quote(s, safe='')
67 if passwd:
67 if passwd:
68 userpass = quote(user) + ':' + quote(passwd)
68 userpass = quote(user) + ':' + quote(passwd)
69 else:
69 else:
70 userpass = quote(user)
70 userpass = quote(user)
71 return userpass + '@' + hostport
71 return userpass + '@' + hostport
72 return hostport
72 return hostport
73
73
74 _safe = ('abcdefghijklmnopqrstuvwxyz'
74 _safe = ('abcdefghijklmnopqrstuvwxyz'
75 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
75 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
76 '0123456789' '_.-/')
76 '0123456789' '_.-/')
77 _safeset = None
77 _safeset = None
78 _hex = None
78 _hex = None
79 def quotepath(path):
79 def quotepath(path):
80 '''quote the path part of a URL
80 '''quote the path part of a URL
81
81
82 This is similar to urllib.quote, but it also tries to avoid
82 This is similar to urllib.quote, but it also tries to avoid
83 quoting things twice (inspired by wget):
83 quoting things twice (inspired by wget):
84
84
85 >>> quotepath('abc def')
85 >>> quotepath('abc def')
86 'abc%20def'
86 'abc%20def'
87 >>> quotepath('abc%20def')
87 >>> quotepath('abc%20def')
88 'abc%20def'
88 'abc%20def'
89 >>> quotepath('abc%20 def')
89 >>> quotepath('abc%20 def')
90 'abc%20%20def'
90 'abc%20%20def'
91 >>> quotepath('abc def%20')
91 >>> quotepath('abc def%20')
92 'abc%20def%20'
92 'abc%20def%20'
93 >>> quotepath('abc def%2')
93 >>> quotepath('abc def%2')
94 'abc%20def%252'
94 'abc%20def%252'
95 >>> quotepath('abc def%')
95 >>> quotepath('abc def%')
96 'abc%20def%25'
96 'abc%20def%25'
97 '''
97 '''
98 global _safeset, _hex
98 global _safeset, _hex
99 if _safeset is None:
99 if _safeset is None:
100 _safeset = set(_safe)
100 _safeset = set(_safe)
101 _hex = set('abcdefABCDEF0123456789')
101 _hex = set('abcdefABCDEF0123456789')
102 l = list(path)
102 l = list(path)
103 for i in xrange(len(l)):
103 for i in xrange(len(l)):
104 c = l[i]
104 c = l[i]
105 if (c == '%' and i + 2 < len(l) and
105 if (c == '%' and i + 2 < len(l) and
106 l[i + 1] in _hex and l[i + 2] in _hex):
106 l[i + 1] in _hex and l[i + 2] in _hex):
107 pass
107 pass
108 elif c not in _safeset:
108 elif c not in _safeset:
109 l[i] = '%%%02X' % ord(c)
109 l[i] = '%%%02X' % ord(c)
110 return ''.join(l)
110 return ''.join(l)
111
111
112 class passwordmgr(urllib2.HTTPPasswordMgrWithDefaultRealm):
112 class passwordmgr(urllib2.HTTPPasswordMgrWithDefaultRealm):
113 def __init__(self, ui):
113 def __init__(self, ui):
114 urllib2.HTTPPasswordMgrWithDefaultRealm.__init__(self)
114 urllib2.HTTPPasswordMgrWithDefaultRealm.__init__(self)
115 self.ui = ui
115 self.ui = ui
116
116
117 def find_user_password(self, realm, authuri):
117 def find_user_password(self, realm, authuri):
118 authinfo = urllib2.HTTPPasswordMgrWithDefaultRealm.find_user_password(
118 authinfo = urllib2.HTTPPasswordMgrWithDefaultRealm.find_user_password(
119 self, realm, authuri)
119 self, realm, authuri)
120 user, passwd = authinfo
120 user, passwd = authinfo
121 if user and passwd:
121 if user and passwd:
122 self._writedebug(user, passwd)
122 self._writedebug(user, passwd)
123 return (user, passwd)
123 return (user, passwd)
124
124
125 if not user:
125 if not user:
126 auth = self.readauthtoken(authuri)
126 auth = self.readauthtoken(authuri)
127 if auth:
127 if auth:
128 user, passwd = auth.get('username'), auth.get('password')
128 user, passwd = auth.get('username'), auth.get('password')
129 if not user or not passwd:
129 if not user or not passwd:
130 if not self.ui.interactive():
130 if not self.ui.interactive():
131 raise util.Abort(_('http authorization required'))
131 raise util.Abort(_('http authorization required'))
132
132
133 self.ui.write(_("http authorization required\n"))
133 self.ui.write(_("http authorization required\n"))
134 self.ui.write(_("realm: %s\n") % realm)
134 self.ui.write(_("realm: %s\n") % realm)
135 if user:
135 if user:
136 self.ui.write(_("user: %s\n") % user)
136 self.ui.write(_("user: %s\n") % user)
137 else:
137 else:
138 user = self.ui.prompt(_("user:"), default=None)
138 user = self.ui.prompt(_("user:"), default=None)
139
139
140 if not passwd:
140 if not passwd:
141 passwd = self.ui.getpass()
141 passwd = self.ui.getpass()
142
142
143 self.add_password(realm, authuri, user, passwd)
143 self.add_password(realm, authuri, user, passwd)
144 self._writedebug(user, passwd)
144 self._writedebug(user, passwd)
145 return (user, passwd)
145 return (user, passwd)
146
146
147 def _writedebug(self, user, passwd):
147 def _writedebug(self, user, passwd):
148 msg = _('http auth: user %s, password %s\n')
148 msg = _('http auth: user %s, password %s\n')
149 self.ui.debug(msg % (user, passwd and '*' * len(passwd) or 'not set'))
149 self.ui.debug(msg % (user, passwd and '*' * len(passwd) or 'not set'))
150
150
151 def readauthtoken(self, uri):
151 def readauthtoken(self, uri):
152 # Read configuration
152 # Read configuration
153 config = dict()
153 config = dict()
154 for key, val in self.ui.configitems('auth'):
154 for key, val in self.ui.configitems('auth'):
155 if '.' not in key:
155 if '.' not in key:
156 self.ui.warn(_("ignoring invalid [auth] key '%s'\n") % key)
156 self.ui.warn(_("ignoring invalid [auth] key '%s'\n") % key)
157 continue
157 continue
158 group, setting = key.split('.', 1)
158 group, setting = key.split('.', 1)
159 gdict = config.setdefault(group, dict())
159 gdict = config.setdefault(group, dict())
160 if setting in ('username', 'cert', 'key'):
160 if setting in ('username', 'cert', 'key'):
161 val = util.expandpath(val)
161 val = util.expandpath(val)
162 gdict[setting] = val
162 gdict[setting] = val
163
163
164 # Find the best match
164 # Find the best match
165 scheme, hostpath = uri.split('://', 1)
165 scheme, hostpath = uri.split('://', 1)
166 bestlen = 0
166 bestlen = 0
167 bestauth = None
167 bestauth = None
168 for auth in config.itervalues():
168 for auth in config.itervalues():
169 prefix = auth.get('prefix')
169 prefix = auth.get('prefix')
170 if not prefix:
170 if not prefix:
171 continue
171 continue
172 p = prefix.split('://', 1)
172 p = prefix.split('://', 1)
173 if len(p) > 1:
173 if len(p) > 1:
174 schemes, prefix = [p[0]], p[1]
174 schemes, prefix = [p[0]], p[1]
175 else:
175 else:
176 schemes = (auth.get('schemes') or 'https').split()
176 schemes = (auth.get('schemes') or 'https').split()
177 if (prefix == '*' or hostpath.startswith(prefix)) and \
177 if (prefix == '*' or hostpath.startswith(prefix)) and \
178 len(prefix) > bestlen and scheme in schemes:
178 len(prefix) > bestlen and scheme in schemes:
179 bestlen = len(prefix)
179 bestlen = len(prefix)
180 bestauth = auth
180 bestauth = auth
181 return bestauth
181 return bestauth
182
182
183 class proxyhandler(urllib2.ProxyHandler):
183 class proxyhandler(urllib2.ProxyHandler):
184 def __init__(self, ui):
184 def __init__(self, ui):
185 proxyurl = ui.config("http_proxy", "host") or os.getenv('http_proxy')
185 proxyurl = ui.config("http_proxy", "host") or os.getenv('http_proxy')
186 # XXX proxyauthinfo = None
186 # XXX proxyauthinfo = None
187
187
188 if proxyurl:
188 if proxyurl:
189 # proxy can be proper url or host[:port]
189 # proxy can be proper url or host[:port]
190 if not (proxyurl.startswith('http:') or
190 if not (proxyurl.startswith('http:') or
191 proxyurl.startswith('https:')):
191 proxyurl.startswith('https:')):
192 proxyurl = 'http://' + proxyurl + '/'
192 proxyurl = 'http://' + proxyurl + '/'
193 snpqf = urlparse.urlsplit(proxyurl)
193 snpqf = urlparse.urlsplit(proxyurl)
194 proxyscheme, proxynetloc, proxypath, proxyquery, proxyfrag = snpqf
194 proxyscheme, proxynetloc, proxypath, proxyquery, proxyfrag = snpqf
195 hpup = netlocsplit(proxynetloc)
195 hpup = netlocsplit(proxynetloc)
196
196
197 proxyhost, proxyport, proxyuser, proxypasswd = hpup
197 proxyhost, proxyport, proxyuser, proxypasswd = hpup
198 if not proxyuser:
198 if not proxyuser:
199 proxyuser = ui.config("http_proxy", "user")
199 proxyuser = ui.config("http_proxy", "user")
200 proxypasswd = ui.config("http_proxy", "passwd")
200 proxypasswd = ui.config("http_proxy", "passwd")
201
201
202 # see if we should use a proxy for this url
202 # see if we should use a proxy for this url
203 no_list = ["localhost", "127.0.0.1"]
203 no_list = ["localhost", "127.0.0.1"]
204 no_list.extend([p.lower() for
204 no_list.extend([p.lower() for
205 p in ui.configlist("http_proxy", "no")])
205 p in ui.configlist("http_proxy", "no")])
206 no_list.extend([p.strip().lower() for
206 no_list.extend([p.strip().lower() for
207 p in os.getenv("no_proxy", '').split(',')
207 p in os.getenv("no_proxy", '').split(',')
208 if p.strip()])
208 if p.strip()])
209 # "http_proxy.always" config is for running tests on localhost
209 # "http_proxy.always" config is for running tests on localhost
210 if ui.configbool("http_proxy", "always"):
210 if ui.configbool("http_proxy", "always"):
211 self.no_list = []
211 self.no_list = []
212 else:
212 else:
213 self.no_list = no_list
213 self.no_list = no_list
214
214
215 proxyurl = urlparse.urlunsplit((
215 proxyurl = urlparse.urlunsplit((
216 proxyscheme, netlocunsplit(proxyhost, proxyport,
216 proxyscheme, netlocunsplit(proxyhost, proxyport,
217 proxyuser, proxypasswd or ''),
217 proxyuser, proxypasswd or ''),
218 proxypath, proxyquery, proxyfrag))
218 proxypath, proxyquery, proxyfrag))
219 proxies = {'http': proxyurl, 'https': proxyurl}
219 proxies = {'http': proxyurl, 'https': proxyurl}
220 ui.debug('proxying through http://%s:%s\n' %
220 ui.debug('proxying through http://%s:%s\n' %
221 (proxyhost, proxyport))
221 (proxyhost, proxyport))
222 else:
222 else:
223 proxies = {}
223 proxies = {}
224
224
225 # urllib2 takes proxy values from the environment and those
225 # urllib2 takes proxy values from the environment and those
226 # will take precedence if found, so drop them
226 # will take precedence if found, so drop them
227 for env in ["HTTP_PROXY", "http_proxy", "no_proxy"]:
227 for env in ["HTTP_PROXY", "http_proxy", "no_proxy"]:
228 try:
228 try:
229 if env in os.environ:
229 if env in os.environ:
230 del os.environ[env]
230 del os.environ[env]
231 except OSError:
231 except OSError:
232 pass
232 pass
233
233
234 urllib2.ProxyHandler.__init__(self, proxies)
234 urllib2.ProxyHandler.__init__(self, proxies)
235 self.ui = ui
235 self.ui = ui
236
236
237 def proxy_open(self, req, proxy, type_):
237 def proxy_open(self, req, proxy, type_):
238 host = req.get_host().split(':')[0]
238 host = req.get_host().split(':')[0]
239 if host in self.no_list:
239 if host in self.no_list:
240 return None
240 return None
241
241
242 # work around a bug in Python < 2.4.2
242 # work around a bug in Python < 2.4.2
243 # (it leaves a "\n" at the end of Proxy-authorization headers)
243 # (it leaves a "\n" at the end of Proxy-authorization headers)
244 baseclass = req.__class__
244 baseclass = req.__class__
245 class _request(baseclass):
245 class _request(baseclass):
246 def add_header(self, key, val):
246 def add_header(self, key, val):
247 if key.lower() == 'proxy-authorization':
247 if key.lower() == 'proxy-authorization':
248 val = val.strip()
248 val = val.strip()
249 return baseclass.add_header(self, key, val)
249 return baseclass.add_header(self, key, val)
250 req.__class__ = _request
250 req.__class__ = _request
251
251
252 return urllib2.ProxyHandler.proxy_open(self, req, proxy, type_)
252 return urllib2.ProxyHandler.proxy_open(self, req, proxy, type_)
253
253
254 class httpsendfile(object):
254 class httpsendfile(object):
255 """This is a wrapper around the objects returned by python's "open".
255 """This is a wrapper around the objects returned by python's "open".
256
256
257 Its purpose is to send file-like objects via HTTP and, to do so, it
257 Its purpose is to send file-like objects via HTTP and, to do so, it
258 defines a __len__ attribute to feed the Content-Length header.
258 defines a __len__ attribute to feed the Content-Length header.
259 """
259 """
260
260
261 def __init__(self, ui, *args, **kwargs):
261 def __init__(self, ui, *args, **kwargs):
262 # We can't just "self._data = open(*args, **kwargs)" here because there
262 # We can't just "self._data = open(*args, **kwargs)" here because there
263 # is an "open" function defined in this module that shadows the global
263 # is an "open" function defined in this module that shadows the global
264 # one
264 # one
265 self.ui = ui
265 self.ui = ui
266 self._data = __builtin__.open(*args, **kwargs)
266 self._data = __builtin__.open(*args, **kwargs)
267 self.seek = self._data.seek
267 self.seek = self._data.seek
268 self.close = self._data.close
268 self.close = self._data.close
269 self.write = self._data.write
269 self.write = self._data.write
270 self._len = os.fstat(self._data.fileno()).st_size
270 self._len = os.fstat(self._data.fileno()).st_size
271 self._pos = 0
271 self._pos = 0
272 self._total = len(self) / 1024 * 2
272 self._total = len(self) / 1024 * 2
273
273
274 def read(self, *args, **kwargs):
274 def read(self, *args, **kwargs):
275 try:
275 try:
276 ret = self._data.read(*args, **kwargs)
276 ret = self._data.read(*args, **kwargs)
277 except EOFError:
277 except EOFError:
278 self.ui.progress(_('sending'), None)
278 self.ui.progress(_('sending'), None)
279 self._pos += len(ret)
279 self._pos += len(ret)
280 # We pass double the max for total because we currently have
280 # We pass double the max for total because we currently have
281 # to send the bundle twice in the case of a server that
281 # to send the bundle twice in the case of a server that
282 # requires authentication. Since we can't know until we try
282 # requires authentication. Since we can't know until we try
283 # once whether authentication will be required, just lie to
283 # once whether authentication will be required, just lie to
284 # the user and maybe the push succeeds suddenly at 50%.
284 # the user and maybe the push succeeds suddenly at 50%.
285 self.ui.progress(_('sending'), self._pos / 1024,
285 self.ui.progress(_('sending'), self._pos / 1024,
286 unit=_('kb'), total=self._total)
286 unit=_('kb'), total=self._total)
287 return ret
287 return ret
288
288
289 def __len__(self):
289 def __len__(self):
290 return self._len
290 return self._len
291
291
292 def _gen_sendfile(connection):
292 def _gen_sendfile(connection):
293 def _sendfile(self, data):
293 def _sendfile(self, data):
294 # send a file
294 # send a file
295 if isinstance(data, httpsendfile):
295 if isinstance(data, httpsendfile):
296 # if auth required, some data sent twice, so rewind here
296 # if auth required, some data sent twice, so rewind here
297 data.seek(0)
297 data.seek(0)
298 for chunk in util.filechunkiter(data):
298 for chunk in util.filechunkiter(data):
299 connection.send(self, chunk)
299 connection.send(self, chunk)
300 else:
300 else:
301 connection.send(self, data)
301 connection.send(self, data)
302 return _sendfile
302 return _sendfile
303
303
304 has_https = hasattr(urllib2, 'HTTPSHandler')
304 has_https = hasattr(urllib2, 'HTTPSHandler')
305 if has_https:
305 if has_https:
306 try:
306 try:
307 # avoid using deprecated/broken FakeSocket in python 2.6
307 # avoid using deprecated/broken FakeSocket in python 2.6
308 import ssl
308 import ssl
309 _ssl_wrap_socket = ssl.wrap_socket
309 _ssl_wrap_socket = ssl.wrap_socket
310 CERT_REQUIRED = ssl.CERT_REQUIRED
310 CERT_REQUIRED = ssl.CERT_REQUIRED
311 except ImportError:
311 except ImportError:
312 CERT_REQUIRED = 2
312 CERT_REQUIRED = 2
313
313
314 def _ssl_wrap_socket(sock, key_file, cert_file,
314 def _ssl_wrap_socket(sock, key_file, cert_file,
315 cert_reqs=CERT_REQUIRED, ca_certs=None):
315 cert_reqs=CERT_REQUIRED, ca_certs=None):
316 if ca_certs:
316 if ca_certs:
317 raise util.Abort(_(
317 raise util.Abort(_(
318 'certificate checking requires Python 2.6'))
318 'certificate checking requires Python 2.6'))
319
319
320 ssl = socket.ssl(sock, key_file, cert_file)
320 ssl = socket.ssl(sock, key_file, cert_file)
321 return httplib.FakeSocket(sock, ssl)
321 return httplib.FakeSocket(sock, ssl)
322
322
323 try:
323 try:
324 _create_connection = socket.create_connection
324 _create_connection = socket.create_connection
325 except AttributeError:
325 except AttributeError:
326 _GLOBAL_DEFAULT_TIMEOUT = object()
326 _GLOBAL_DEFAULT_TIMEOUT = object()
327
327
328 def _create_connection(address, timeout=_GLOBAL_DEFAULT_TIMEOUT,
328 def _create_connection(address, timeout=_GLOBAL_DEFAULT_TIMEOUT,
329 source_address=None):
329 source_address=None):
330 # lifted from Python 2.6
330 # lifted from Python 2.6
331
331
332 msg = "getaddrinfo returns an empty list"
332 msg = "getaddrinfo returns an empty list"
333 host, port = address
333 host, port = address
334 for res in socket.getaddrinfo(host, port, 0, socket.SOCK_STREAM):
334 for res in socket.getaddrinfo(host, port, 0, socket.SOCK_STREAM):
335 af, socktype, proto, canonname, sa = res
335 af, socktype, proto, canonname, sa = res
336 sock = None
336 sock = None
337 try:
337 try:
338 sock = socket.socket(af, socktype, proto)
338 sock = socket.socket(af, socktype, proto)
339 if timeout is not _GLOBAL_DEFAULT_TIMEOUT:
339 if timeout is not _GLOBAL_DEFAULT_TIMEOUT:
340 sock.settimeout(timeout)
340 sock.settimeout(timeout)
341 if source_address:
341 if source_address:
342 sock.bind(source_address)
342 sock.bind(source_address)
343 sock.connect(sa)
343 sock.connect(sa)
344 return sock
344 return sock
345
345
346 except socket.error, msg:
346 except socket.error, msg:
347 if sock is not None:
347 if sock is not None:
348 sock.close()
348 sock.close()
349
349
350 raise socket.error, msg
350 raise socket.error, msg
351
351
352 class httpconnection(keepalive.HTTPConnection):
352 class httpconnection(keepalive.HTTPConnection):
353 # must be able to send big bundle as stream.
353 # must be able to send big bundle as stream.
354 send = _gen_sendfile(keepalive.HTTPConnection)
354 send = _gen_sendfile(keepalive.HTTPConnection)
355
355
356 def connect(self):
356 def connect(self):
357 if has_https and self.realhostport: # use CONNECT proxy
357 if has_https and self.realhostport: # use CONNECT proxy
358 self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
358 self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
359 self.sock.connect((self.host, self.port))
359 self.sock.connect((self.host, self.port))
360 if _generic_proxytunnel(self):
360 if _generic_proxytunnel(self):
361 # we do not support client x509 certificates
361 # we do not support client x509 certificates
362 self.sock = _ssl_wrap_socket(self.sock, None, None)
362 self.sock = _ssl_wrap_socket(self.sock, None, None)
363 else:
363 else:
364 keepalive.HTTPConnection.connect(self)
364 keepalive.HTTPConnection.connect(self)
365
365
366 def getresponse(self):
366 def getresponse(self):
367 proxyres = getattr(self, 'proxyres', None)
367 proxyres = getattr(self, 'proxyres', None)
368 if proxyres:
368 if proxyres:
369 if proxyres.will_close:
369 if proxyres.will_close:
370 self.close()
370 self.close()
371 self.proxyres = None
371 self.proxyres = None
372 return proxyres
372 return proxyres
373 return keepalive.HTTPConnection.getresponse(self)
373 return keepalive.HTTPConnection.getresponse(self)
374
374
375 # general transaction handler to support different ways to handle
375 # general transaction handler to support different ways to handle
376 # HTTPS proxying before and after Python 2.6.3.
376 # HTTPS proxying before and after Python 2.6.3.
377 def _generic_start_transaction(handler, h, req):
377 def _generic_start_transaction(handler, h, req):
378 if hasattr(req, '_tunnel_host') and req._tunnel_host:
378 if hasattr(req, '_tunnel_host') and req._tunnel_host:
379 tunnel_host = req._tunnel_host
379 tunnel_host = req._tunnel_host
380 if tunnel_host[:7] not in ['http://', 'https:/']:
380 if tunnel_host[:7] not in ['http://', 'https:/']:
381 tunnel_host = 'https://' + tunnel_host
381 tunnel_host = 'https://' + tunnel_host
382 new_tunnel = True
382 new_tunnel = True
383 else:
383 else:
384 tunnel_host = req.get_selector()
384 tunnel_host = req.get_selector()
385 new_tunnel = False
385 new_tunnel = False
386
386
387 if new_tunnel or tunnel_host == req.get_full_url(): # has proxy
387 if new_tunnel or tunnel_host == req.get_full_url(): # has proxy
388 urlparts = urlparse.urlparse(tunnel_host)
388 urlparts = urlparse.urlparse(tunnel_host)
389 if new_tunnel or urlparts[0] == 'https': # only use CONNECT for HTTPS
389 if new_tunnel or urlparts[0] == 'https': # only use CONNECT for HTTPS
390 realhostport = urlparts[1]
390 realhostport = urlparts[1]
391 if realhostport[-1] == ']' or ':' not in realhostport:
391 if realhostport[-1] == ']' or ':' not in realhostport:
392 realhostport += ':443'
392 realhostport += ':443'
393
393
394 h.realhostport = realhostport
394 h.realhostport = realhostport
395 h.headers = req.headers.copy()
395 h.headers = req.headers.copy()
396 h.headers.update(handler.parent.addheaders)
396 h.headers.update(handler.parent.addheaders)
397 return
397 return
398
398
399 h.realhostport = None
399 h.realhostport = None
400 h.headers = None
400 h.headers = None
401
401
402 def _generic_proxytunnel(self):
402 def _generic_proxytunnel(self):
403 proxyheaders = dict(
403 proxyheaders = dict(
404 [(x, self.headers[x]) for x in self.headers
404 [(x, self.headers[x]) for x in self.headers
405 if x.lower().startswith('proxy-')])
405 if x.lower().startswith('proxy-')])
406 self._set_hostport(self.host, self.port)
406 self._set_hostport(self.host, self.port)
407 self.send('CONNECT %s HTTP/1.0\r\n' % self.realhostport)
407 self.send('CONNECT %s HTTP/1.0\r\n' % self.realhostport)
408 for header in proxyheaders.iteritems():
408 for header in proxyheaders.iteritems():
409 self.send('%s: %s\r\n' % header)
409 self.send('%s: %s\r\n' % header)
410 self.send('\r\n')
410 self.send('\r\n')
411
411
412 # majority of the following code is duplicated from
412 # majority of the following code is duplicated from
413 # httplib.HTTPConnection as there are no adequate places to
413 # httplib.HTTPConnection as there are no adequate places to
414 # override functions to provide the needed functionality
414 # override functions to provide the needed functionality
415 res = self.response_class(self.sock,
415 res = self.response_class(self.sock,
416 strict=self.strict,
416 strict=self.strict,
417 method=self._method)
417 method=self._method)
418
418
419 while True:
419 while True:
420 version, status, reason = res._read_status()
420 version, status, reason = res._read_status()
421 if status != httplib.CONTINUE:
421 if status != httplib.CONTINUE:
422 break
422 break
423 while True:
423 while True:
424 skip = res.fp.readline().strip()
424 skip = res.fp.readline().strip()
425 if not skip:
425 if not skip:
426 break
426 break
427 res.status = status
427 res.status = status
428 res.reason = reason.strip()
428 res.reason = reason.strip()
429
429
430 if res.status == 200:
430 if res.status == 200:
431 while True:
431 while True:
432 line = res.fp.readline()
432 line = res.fp.readline()
433 if line == '\r\n':
433 if line == '\r\n':
434 break
434 break
435 return True
435 return True
436
436
437 if version == 'HTTP/1.0':
437 if version == 'HTTP/1.0':
438 res.version = 10
438 res.version = 10
439 elif version.startswith('HTTP/1.'):
439 elif version.startswith('HTTP/1.'):
440 res.version = 11
440 res.version = 11
441 elif version == 'HTTP/0.9':
441 elif version == 'HTTP/0.9':
442 res.version = 9
442 res.version = 9
443 else:
443 else:
444 raise httplib.UnknownProtocol(version)
444 raise httplib.UnknownProtocol(version)
445
445
446 if res.version == 9:
446 if res.version == 9:
447 res.length = None
447 res.length = None
448 res.chunked = 0
448 res.chunked = 0
449 res.will_close = 1
449 res.will_close = 1
450 res.msg = httplib.HTTPMessage(cStringIO.StringIO())
450 res.msg = httplib.HTTPMessage(cStringIO.StringIO())
451 return False
451 return False
452
452
453 res.msg = httplib.HTTPMessage(res.fp)
453 res.msg = httplib.HTTPMessage(res.fp)
454 res.msg.fp = None
454 res.msg.fp = None
455
455
456 # are we using the chunked-style of transfer encoding?
456 # are we using the chunked-style of transfer encoding?
457 trenc = res.msg.getheader('transfer-encoding')
457 trenc = res.msg.getheader('transfer-encoding')
458 if trenc and trenc.lower() == "chunked":
458 if trenc and trenc.lower() == "chunked":
459 res.chunked = 1
459 res.chunked = 1
460 res.chunk_left = None
460 res.chunk_left = None
461 else:
461 else:
462 res.chunked = 0
462 res.chunked = 0
463
463
464 # will the connection close at the end of the response?
464 # will the connection close at the end of the response?
465 res.will_close = res._check_close()
465 res.will_close = res._check_close()
466
466
467 # do we have a Content-Length?
467 # do we have a Content-Length?
468 # NOTE: RFC 2616, S4.4, #3 says we ignore this if tr_enc is "chunked"
468 # NOTE: RFC 2616, S4.4, #3 says we ignore this if tr_enc is "chunked"
469 length = res.msg.getheader('content-length')
469 length = res.msg.getheader('content-length')
470 if length and not res.chunked:
470 if length and not res.chunked:
471 try:
471 try:
472 res.length = int(length)
472 res.length = int(length)
473 except ValueError:
473 except ValueError:
474 res.length = None
474 res.length = None
475 else:
475 else:
476 if res.length < 0: # ignore nonsensical negative lengths
476 if res.length < 0: # ignore nonsensical negative lengths
477 res.length = None
477 res.length = None
478 else:
478 else:
479 res.length = None
479 res.length = None
480
480
481 # does the body have a fixed length? (of zero)
481 # does the body have a fixed length? (of zero)
482 if (status == httplib.NO_CONTENT or status == httplib.NOT_MODIFIED or
482 if (status == httplib.NO_CONTENT or status == httplib.NOT_MODIFIED or
483 100 <= status < 200 or # 1xx codes
483 100 <= status < 200 or # 1xx codes
484 res._method == 'HEAD'):
484 res._method == 'HEAD'):
485 res.length = 0
485 res.length = 0
486
486
487 # if the connection remains open, and we aren't using chunked, and
487 # if the connection remains open, and we aren't using chunked, and
488 # a content-length was not provided, then assume that the connection
488 # a content-length was not provided, then assume that the connection
489 # WILL close.
489 # WILL close.
490 if (not res.will_close and
490 if (not res.will_close and
491 not res.chunked and
491 not res.chunked and
492 res.length is None):
492 res.length is None):
493 res.will_close = 1
493 res.will_close = 1
494
494
495 self.proxyres = res
495 self.proxyres = res
496
496
497 return False
497 return False
498
498
499 class httphandler(keepalive.HTTPHandler):
499 class httphandler(keepalive.HTTPHandler):
500 def http_open(self, req):
500 def http_open(self, req):
501 return self.do_open(httpconnection, req)
501 return self.do_open(httpconnection, req)
502
502
503 def _start_transaction(self, h, req):
503 def _start_transaction(self, h, req):
504 _generic_start_transaction(self, h, req)
504 _generic_start_transaction(self, h, req)
505 return keepalive.HTTPHandler._start_transaction(self, h, req)
505 return keepalive.HTTPHandler._start_transaction(self, h, req)
506
506
507 def _verifycert(cert, hostname):
507 def _verifycert(cert, hostname):
508 '''Verify that cert (in socket.getpeercert() format) matches hostname.
508 '''Verify that cert (in socket.getpeercert() format) matches hostname.
509 CRLs is not handled.
509 CRLs is not handled.
510
510
511 Returns error message if any problems are found and None on success.
511 Returns error message if any problems are found and None on success.
512 '''
512 '''
513 if not cert:
513 if not cert:
514 return _('no certificate received')
514 return _('no certificate received')
515 dnsname = hostname.lower()
515 dnsname = hostname.lower()
516 def matchdnsname(certname):
516 def matchdnsname(certname):
517 return (certname == dnsname or
517 return (certname == dnsname or
518 '.' in dnsname and certname == '*.' + dnsname.split('.', 1)[1])
518 '.' in dnsname and certname == '*.' + dnsname.split('.', 1)[1])
519
519
520 san = cert.get('subjectAltName', [])
520 san = cert.get('subjectAltName', [])
521 if san:
521 if san:
522 certnames = [value.lower() for key, value in san if key == 'DNS']
522 certnames = [value.lower() for key, value in san if key == 'DNS']
523 for name in certnames:
523 for name in certnames:
524 if matchdnsname(name):
524 if matchdnsname(name):
525 return None
525 return None
526 return _('certificate is for %s') % ', '.join(certnames)
526 return _('certificate is for %s') % ', '.join(certnames)
527
527
528 # subject is only checked when subjectAltName is empty
528 # subject is only checked when subjectAltName is empty
529 for s in cert.get('subject', []):
529 for s in cert.get('subject', []):
530 key, value = s[0]
530 key, value = s[0]
531 if key == 'commonName':
531 if key == 'commonName':
532 try:
532 try:
533 # 'subject' entries are unicode
533 # 'subject' entries are unicode
534 certname = value.lower().encode('ascii')
534 certname = value.lower().encode('ascii')
535 except UnicodeEncodeError:
535 except UnicodeEncodeError:
536 return _('IDN in certificate not supported')
536 return _('IDN in certificate not supported')
537 if matchdnsname(certname):
537 if matchdnsname(certname):
538 return None
538 return None
539 return _('certificate is for %s') % certname
539 return _('certificate is for %s') % certname
540 return _('no commonName or subjectAltName found in certificate')
540 return _('no commonName or subjectAltName found in certificate')
541
541
542 if has_https:
542 if has_https:
543 class BetterHTTPS(httplib.HTTPSConnection):
543 class BetterHTTPS(httplib.HTTPSConnection):
544 send = keepalive.safesend
544 send = keepalive.safesend
545
545
546 def connect(self):
546 def connect(self):
547 if hasattr(self, 'ui'):
547 if hasattr(self, 'ui'):
548 cacerts = self.ui.config('web', 'cacerts')
548 cacerts = self.ui.config('web', 'cacerts')
549 if cacerts:
549 if cacerts:
550 cacerts = util.expandpath(cacerts)
550 cacerts = util.expandpath(cacerts)
551 else:
551 else:
552 cacerts = None
552 cacerts = None
553
553
554 if cacerts:
554 hostfingerprint = self.ui.config('hostfingerprints', self.host)
555 if cacerts and not hostfingerprint:
555 sock = _create_connection((self.host, self.port))
556 sock = _create_connection((self.host, self.port))
556 self.sock = _ssl_wrap_socket(sock, self.key_file,
557 self.sock = _ssl_wrap_socket(sock, self.key_file,
557 self.cert_file, cert_reqs=CERT_REQUIRED,
558 self.cert_file, cert_reqs=CERT_REQUIRED,
558 ca_certs=cacerts)
559 ca_certs=cacerts)
559 msg = _verifycert(self.sock.getpeercert(), self.host)
560 msg = _verifycert(self.sock.getpeercert(), self.host)
560 if msg:
561 if msg:
561 raise util.Abort(_('%s certificate error: %s') %
562 raise util.Abort(_('%s certificate error: %s') %
562 (self.host, msg))
563 (self.host, msg))
563 self.ui.debug('%s certificate successfully verified\n' %
564 self.ui.debug('%s certificate successfully verified\n' %
564 self.host)
565 self.host)
565 else:
566 else:
566 self.ui.warn(_("warning: %s certificate not verified "
567 "(check web.cacerts config setting)\n") %
568 self.host)
569 httplib.HTTPSConnection.connect(self)
567 httplib.HTTPSConnection.connect(self)
568 if hasattr(self.sock, 'getpeercert'):
569 peercert = self.sock.getpeercert(True)
570 peerfingerprint = util.sha1(peercert).hexdigest()
571 nicefingerprint = ":".join([peerfingerprint[x:x + 2]
572 for x in xrange(0, len(peerfingerprint), 2)])
573 if hostfingerprint:
574 if peerfingerprint.lower() != \
575 hostfingerprint.replace(':', '').lower():
576 raise util.Abort(_('invalid certificate for %s '
577 'with fingerprint %s') %
578 (self.host, nicefingerprint))
579 self.ui.debug('%s certificate matched fingerprint %s\n' %
580 (self.host, nicefingerprint))
581 else:
582 self.ui.warn(_('warning: %s certificate '
583 'with fingerprint %s not verified '
584 '(check hostfingerprints or web.cacerts '
585 'config setting)\n') %
586 (self.host, nicefingerprint))
587 else: # python 2.5 ?
588 if hostfingerprint:
589 raise util.Abort(_('no certificate for %s '
590 'with fingerprint') % self.host)
591 self.ui.warn(_('warning: %s certificate not verified '
592 '(check web.cacerts config setting)\n') %
593 self.host)
570
594
571 class httpsconnection(BetterHTTPS):
595 class httpsconnection(BetterHTTPS):
572 response_class = keepalive.HTTPResponse
596 response_class = keepalive.HTTPResponse
573 # must be able to send big bundle as stream.
597 # must be able to send big bundle as stream.
574 send = _gen_sendfile(BetterHTTPS)
598 send = _gen_sendfile(BetterHTTPS)
575 getresponse = keepalive.wrapgetresponse(httplib.HTTPSConnection)
599 getresponse = keepalive.wrapgetresponse(httplib.HTTPSConnection)
576
600
577 def connect(self):
601 def connect(self):
578 if self.realhostport: # use CONNECT proxy
602 if self.realhostport: # use CONNECT proxy
579 self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
603 self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
580 self.sock.connect((self.host, self.port))
604 self.sock.connect((self.host, self.port))
581 if _generic_proxytunnel(self):
605 if _generic_proxytunnel(self):
582 self.sock = _ssl_wrap_socket(self.sock, self.key_file,
606 self.sock = _ssl_wrap_socket(self.sock, self.key_file,
583 self.cert_file)
607 self.cert_file)
584 else:
608 else:
585 BetterHTTPS.connect(self)
609 BetterHTTPS.connect(self)
586
610
587 class httpshandler(keepalive.KeepAliveHandler, urllib2.HTTPSHandler):
611 class httpshandler(keepalive.KeepAliveHandler, urllib2.HTTPSHandler):
588 def __init__(self, ui):
612 def __init__(self, ui):
589 keepalive.KeepAliveHandler.__init__(self)
613 keepalive.KeepAliveHandler.__init__(self)
590 urllib2.HTTPSHandler.__init__(self)
614 urllib2.HTTPSHandler.__init__(self)
591 self.ui = ui
615 self.ui = ui
592 self.pwmgr = passwordmgr(self.ui)
616 self.pwmgr = passwordmgr(self.ui)
593
617
594 def _start_transaction(self, h, req):
618 def _start_transaction(self, h, req):
595 _generic_start_transaction(self, h, req)
619 _generic_start_transaction(self, h, req)
596 return keepalive.KeepAliveHandler._start_transaction(self, h, req)
620 return keepalive.KeepAliveHandler._start_transaction(self, h, req)
597
621
598 def https_open(self, req):
622 def https_open(self, req):
599 self.auth = self.pwmgr.readauthtoken(req.get_full_url())
623 self.auth = self.pwmgr.readauthtoken(req.get_full_url())
600 return self.do_open(self._makeconnection, req)
624 return self.do_open(self._makeconnection, req)
601
625
602 def _makeconnection(self, host, port=None, *args, **kwargs):
626 def _makeconnection(self, host, port=None, *args, **kwargs):
603 keyfile = None
627 keyfile = None
604 certfile = None
628 certfile = None
605
629
606 if len(args) >= 1: # key_file
630 if len(args) >= 1: # key_file
607 keyfile = args[0]
631 keyfile = args[0]
608 if len(args) >= 2: # cert_file
632 if len(args) >= 2: # cert_file
609 certfile = args[1]
633 certfile = args[1]
610 args = args[2:]
634 args = args[2:]
611
635
612 # if the user has specified different key/cert files in
636 # if the user has specified different key/cert files in
613 # hgrc, we prefer these
637 # hgrc, we prefer these
614 if self.auth and 'key' in self.auth and 'cert' in self.auth:
638 if self.auth and 'key' in self.auth and 'cert' in self.auth:
615 keyfile = self.auth['key']
639 keyfile = self.auth['key']
616 certfile = self.auth['cert']
640 certfile = self.auth['cert']
617
641
618 conn = httpsconnection(host, port, keyfile, certfile, *args, **kwargs)
642 conn = httpsconnection(host, port, keyfile, certfile, *args, **kwargs)
619 conn.ui = self.ui
643 conn.ui = self.ui
620 return conn
644 return conn
621
645
622 class httpdigestauthhandler(urllib2.HTTPDigestAuthHandler):
646 class httpdigestauthhandler(urllib2.HTTPDigestAuthHandler):
623 def __init__(self, *args, **kwargs):
647 def __init__(self, *args, **kwargs):
624 urllib2.HTTPDigestAuthHandler.__init__(self, *args, **kwargs)
648 urllib2.HTTPDigestAuthHandler.__init__(self, *args, **kwargs)
625 self.retried_req = None
649 self.retried_req = None
626
650
627 def reset_retry_count(self):
651 def reset_retry_count(self):
628 # Python 2.6.5 will call this on 401 or 407 errors and thus loop
652 # Python 2.6.5 will call this on 401 or 407 errors and thus loop
629 # forever. We disable reset_retry_count completely and reset in
653 # forever. We disable reset_retry_count completely and reset in
630 # http_error_auth_reqed instead.
654 # http_error_auth_reqed instead.
631 pass
655 pass
632
656
633 def http_error_auth_reqed(self, auth_header, host, req, headers):
657 def http_error_auth_reqed(self, auth_header, host, req, headers):
634 # Reset the retry counter once for each request.
658 # Reset the retry counter once for each request.
635 if req is not self.retried_req:
659 if req is not self.retried_req:
636 self.retried_req = req
660 self.retried_req = req
637 self.retried = 0
661 self.retried = 0
638 # In python < 2.5 AbstractDigestAuthHandler raises a ValueError if
662 # In python < 2.5 AbstractDigestAuthHandler raises a ValueError if
639 # it doesn't know about the auth type requested. This can happen if
663 # it doesn't know about the auth type requested. This can happen if
640 # somebody is using BasicAuth and types a bad password.
664 # somebody is using BasicAuth and types a bad password.
641 try:
665 try:
642 return urllib2.HTTPDigestAuthHandler.http_error_auth_reqed(
666 return urllib2.HTTPDigestAuthHandler.http_error_auth_reqed(
643 self, auth_header, host, req, headers)
667 self, auth_header, host, req, headers)
644 except ValueError, inst:
668 except ValueError, inst:
645 arg = inst.args[0]
669 arg = inst.args[0]
646 if arg.startswith("AbstractDigestAuthHandler doesn't know "):
670 if arg.startswith("AbstractDigestAuthHandler doesn't know "):
647 return
671 return
648 raise
672 raise
649
673
650 class httpbasicauthhandler(urllib2.HTTPBasicAuthHandler):
674 class httpbasicauthhandler(urllib2.HTTPBasicAuthHandler):
651 def __init__(self, *args, **kwargs):
675 def __init__(self, *args, **kwargs):
652 urllib2.HTTPBasicAuthHandler.__init__(self, *args, **kwargs)
676 urllib2.HTTPBasicAuthHandler.__init__(self, *args, **kwargs)
653 self.retried_req = None
677 self.retried_req = None
654
678
655 def reset_retry_count(self):
679 def reset_retry_count(self):
656 # Python 2.6.5 will call this on 401 or 407 errors and thus loop
680 # Python 2.6.5 will call this on 401 or 407 errors and thus loop
657 # forever. We disable reset_retry_count completely and reset in
681 # forever. We disable reset_retry_count completely and reset in
658 # http_error_auth_reqed instead.
682 # http_error_auth_reqed instead.
659 pass
683 pass
660
684
661 def http_error_auth_reqed(self, auth_header, host, req, headers):
685 def http_error_auth_reqed(self, auth_header, host, req, headers):
662 # Reset the retry counter once for each request.
686 # Reset the retry counter once for each request.
663 if req is not self.retried_req:
687 if req is not self.retried_req:
664 self.retried_req = req
688 self.retried_req = req
665 self.retried = 0
689 self.retried = 0
666 return urllib2.HTTPBasicAuthHandler.http_error_auth_reqed(
690 return urllib2.HTTPBasicAuthHandler.http_error_auth_reqed(
667 self, auth_header, host, req, headers)
691 self, auth_header, host, req, headers)
668
692
669 def getauthinfo(path):
693 def getauthinfo(path):
670 scheme, netloc, urlpath, query, frag = urlparse.urlsplit(path)
694 scheme, netloc, urlpath, query, frag = urlparse.urlsplit(path)
671 if not urlpath:
695 if not urlpath:
672 urlpath = '/'
696 urlpath = '/'
673 if scheme != 'file':
697 if scheme != 'file':
674 # XXX: why are we quoting the path again with some smart
698 # XXX: why are we quoting the path again with some smart
675 # heuristic here? Anyway, it cannot be done with file://
699 # heuristic here? Anyway, it cannot be done with file://
676 # urls since path encoding is os/fs dependent (see
700 # urls since path encoding is os/fs dependent (see
677 # urllib.pathname2url() for details).
701 # urllib.pathname2url() for details).
678 urlpath = quotepath(urlpath)
702 urlpath = quotepath(urlpath)
679 host, port, user, passwd = netlocsplit(netloc)
703 host, port, user, passwd = netlocsplit(netloc)
680
704
681 # urllib cannot handle URLs with embedded user or passwd
705 # urllib cannot handle URLs with embedded user or passwd
682 url = urlparse.urlunsplit((scheme, netlocunsplit(host, port),
706 url = urlparse.urlunsplit((scheme, netlocunsplit(host, port),
683 urlpath, query, frag))
707 urlpath, query, frag))
684 if user:
708 if user:
685 netloc = host
709 netloc = host
686 if port:
710 if port:
687 netloc += ':' + port
711 netloc += ':' + port
688 # Python < 2.4.3 uses only the netloc to search for a password
712 # Python < 2.4.3 uses only the netloc to search for a password
689 authinfo = (None, (url, netloc), user, passwd or '')
713 authinfo = (None, (url, netloc), user, passwd or '')
690 else:
714 else:
691 authinfo = None
715 authinfo = None
692 return url, authinfo
716 return url, authinfo
693
717
694 handlerfuncs = []
718 handlerfuncs = []
695
719
696 def opener(ui, authinfo=None):
720 def opener(ui, authinfo=None):
697 '''
721 '''
698 construct an opener suitable for urllib2
722 construct an opener suitable for urllib2
699 authinfo will be added to the password manager
723 authinfo will be added to the password manager
700 '''
724 '''
701 handlers = [httphandler()]
725 handlers = [httphandler()]
702 if has_https:
726 if has_https:
703 handlers.append(httpshandler(ui))
727 handlers.append(httpshandler(ui))
704
728
705 handlers.append(proxyhandler(ui))
729 handlers.append(proxyhandler(ui))
706
730
707 passmgr = passwordmgr(ui)
731 passmgr = passwordmgr(ui)
708 if authinfo is not None:
732 if authinfo is not None:
709 passmgr.add_password(*authinfo)
733 passmgr.add_password(*authinfo)
710 user, passwd = authinfo[2:4]
734 user, passwd = authinfo[2:4]
711 ui.debug('http auth: user %s, password %s\n' %
735 ui.debug('http auth: user %s, password %s\n' %
712 (user, passwd and '*' * len(passwd) or 'not set'))
736 (user, passwd and '*' * len(passwd) or 'not set'))
713
737
714 handlers.extend((httpbasicauthhandler(passmgr),
738 handlers.extend((httpbasicauthhandler(passmgr),
715 httpdigestauthhandler(passmgr)))
739 httpdigestauthhandler(passmgr)))
716 handlers.extend([h(ui, passmgr) for h in handlerfuncs])
740 handlers.extend([h(ui, passmgr) for h in handlerfuncs])
717 opener = urllib2.build_opener(*handlers)
741 opener = urllib2.build_opener(*handlers)
718
742
719 # 1.0 here is the _protocol_ version
743 # 1.0 here is the _protocol_ version
720 opener.addheaders = [('User-agent', 'mercurial/proto-1.0')]
744 opener.addheaders = [('User-agent', 'mercurial/proto-1.0')]
721 opener.addheaders.append(('Accept', 'application/mercurial-0.1'))
745 opener.addheaders.append(('Accept', 'application/mercurial-0.1'))
722 return opener
746 return opener
723
747
724 scheme_re = re.compile(r'^([a-zA-Z0-9+-.]+)://')
748 scheme_re = re.compile(r'^([a-zA-Z0-9+-.]+)://')
725
749
726 def open(ui, url, data=None):
750 def open(ui, url, data=None):
727 scheme = None
751 scheme = None
728 m = scheme_re.search(url)
752 m = scheme_re.search(url)
729 if m:
753 if m:
730 scheme = m.group(1).lower()
754 scheme = m.group(1).lower()
731 if not scheme:
755 if not scheme:
732 path = util.normpath(os.path.abspath(url))
756 path = util.normpath(os.path.abspath(url))
733 url = 'file://' + urllib.pathname2url(path)
757 url = 'file://' + urllib.pathname2url(path)
734 authinfo = None
758 authinfo = None
735 else:
759 else:
736 url, authinfo = getauthinfo(url)
760 url, authinfo = getauthinfo(url)
737 return opener(ui, authinfo).open(url, data)
761 return opener(ui, authinfo).open(url, data)
@@ -1,190 +1,209 b''
1 Proper https client requires the built-in ssl from Python 2.6.
1 Proper https client requires the built-in ssl from Python 2.6.
2
2
3 $ "$TESTDIR/hghave" ssl || exit 80
3 $ "$TESTDIR/hghave" ssl || exit 80
4
4
5 Certificates created with:
5 Certificates created with:
6 printf '.\n.\n.\n.\n.\nlocalhost\nhg@localhost\n' | \
6 printf '.\n.\n.\n.\n.\nlocalhost\nhg@localhost\n' | \
7 openssl req -newkey rsa:512 -keyout priv.pem -nodes -x509 -days 9000 -out pub.pem
7 openssl req -newkey rsa:512 -keyout priv.pem -nodes -x509 -days 9000 -out pub.pem
8 Can be dumped with:
8 Can be dumped with:
9 openssl x509 -in pub.pem -text
9 openssl x509 -in pub.pem -text
10
10
11 $ cat << EOT > priv.pem
11 $ cat << EOT > priv.pem
12 > -----BEGIN PRIVATE KEY-----
12 > -----BEGIN PRIVATE KEY-----
13 > MIIBVAIBADANBgkqhkiG9w0BAQEFAASCAT4wggE6AgEAAkEApjCWeYGrIa/Vo7LH
13 > MIIBVAIBADANBgkqhkiG9w0BAQEFAASCAT4wggE6AgEAAkEApjCWeYGrIa/Vo7LH
14 > aRF8ou0tbgHKE33Use/whCnKEUm34rDaXQd4lxxX6aDWg06n9tiVStAKTgQAHJY8
14 > aRF8ou0tbgHKE33Use/whCnKEUm34rDaXQd4lxxX6aDWg06n9tiVStAKTgQAHJY8
15 > j/xgSwIDAQABAkBxHC6+Qlf0VJXGlb6NL16yEVVTQxqDS6hA9zqu6TZjrr0YMfzc
15 > j/xgSwIDAQABAkBxHC6+Qlf0VJXGlb6NL16yEVVTQxqDS6hA9zqu6TZjrr0YMfzc
16 > EGNIiZGt7HCBL0zO+cPDg/LeCZc6HQhf0KrhAiEAzlJq4hWWzvguWFIJWSoBeBUG
16 > EGNIiZGt7HCBL0zO+cPDg/LeCZc6HQhf0KrhAiEAzlJq4hWWzvguWFIJWSoBeBUG
17 > MF1ACazQO7PYE8M0qfECIQDONHHP0SKZzz/ZwBZcAveC5K61f/v9hONFwbeYulzR
17 > MF1ACazQO7PYE8M0qfECIQDONHHP0SKZzz/ZwBZcAveC5K61f/v9hONFwbeYulzR
18 > +wIgc9SvbtgB/5Yzpp//4ZAEnR7oh5SClCvyB+KSx52K3nECICbhQphhoXmI10wy
18 > +wIgc9SvbtgB/5Yzpp//4ZAEnR7oh5SClCvyB+KSx52K3nECICbhQphhoXmI10wy
19 > aMTellaq0bpNMHFDziqH9RsqAHhjAiEAgYGxfzkftt5IUUn/iFK89aaIpyrpuaAh
19 > aMTellaq0bpNMHFDziqH9RsqAHhjAiEAgYGxfzkftt5IUUn/iFK89aaIpyrpuaAh
20 > HY8gUVkVRVs=
20 > HY8gUVkVRVs=
21 > -----END PRIVATE KEY-----
21 > -----END PRIVATE KEY-----
22 > EOT
22 > EOT
23
23
24 $ cat << EOT > pub.pem
24 $ cat << EOT > pub.pem
25 > -----BEGIN CERTIFICATE-----
25 > -----BEGIN CERTIFICATE-----
26 > MIIBqzCCAVWgAwIBAgIJANAXFFyWjGnRMA0GCSqGSIb3DQEBBQUAMDExEjAQBgNV
26 > MIIBqzCCAVWgAwIBAgIJANAXFFyWjGnRMA0GCSqGSIb3DQEBBQUAMDExEjAQBgNV
27 > BAMMCWxvY2FsaG9zdDEbMBkGCSqGSIb3DQEJARYMaGdAbG9jYWxob3N0MB4XDTEw
27 > BAMMCWxvY2FsaG9zdDEbMBkGCSqGSIb3DQEJARYMaGdAbG9jYWxob3N0MB4XDTEw
28 > MTAxNDIwMzAxNFoXDTM1MDYwNTIwMzAxNFowMTESMBAGA1UEAwwJbG9jYWxob3N0
28 > MTAxNDIwMzAxNFoXDTM1MDYwNTIwMzAxNFowMTESMBAGA1UEAwwJbG9jYWxob3N0
29 > MRswGQYJKoZIhvcNAQkBFgxoZ0Bsb2NhbGhvc3QwXDANBgkqhkiG9w0BAQEFAANL
29 > MRswGQYJKoZIhvcNAQkBFgxoZ0Bsb2NhbGhvc3QwXDANBgkqhkiG9w0BAQEFAANL
30 > ADBIAkEApjCWeYGrIa/Vo7LHaRF8ou0tbgHKE33Use/whCnKEUm34rDaXQd4lxxX
30 > ADBIAkEApjCWeYGrIa/Vo7LHaRF8ou0tbgHKE33Use/whCnKEUm34rDaXQd4lxxX
31 > 6aDWg06n9tiVStAKTgQAHJY8j/xgSwIDAQABo1AwTjAdBgNVHQ4EFgQUE6sA+amm
31 > 6aDWg06n9tiVStAKTgQAHJY8j/xgSwIDAQABo1AwTjAdBgNVHQ4EFgQUE6sA+amm
32 > r24dGX0kpjxOgO45hzQwHwYDVR0jBBgwFoAUE6sA+ammr24dGX0kpjxOgO45hzQw
32 > r24dGX0kpjxOgO45hzQwHwYDVR0jBBgwFoAUE6sA+ammr24dGX0kpjxOgO45hzQw
33 > DAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQUFAANBAFArvQFiAZJgQczRsbYlG1xl
33 > DAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQUFAANBAFArvQFiAZJgQczRsbYlG1xl
34 > t+truk37w5B3m3Ick1ntRcQrqs+hf0CO1q6Squ144geYaQ8CDirSR92fICELI1c=
34 > t+truk37w5B3m3Ick1ntRcQrqs+hf0CO1q6Squ144geYaQ8CDirSR92fICELI1c=
35 > -----END CERTIFICATE-----
35 > -----END CERTIFICATE-----
36 > EOT
36 > EOT
37 $ cat priv.pem pub.pem >> server.pem
37 $ cat priv.pem pub.pem >> server.pem
38 $ PRIV=`pwd`/server.pem
38 $ PRIV=`pwd`/server.pem
39
39
40 $ cat << EOT > pub-other.pem
40 $ cat << EOT > pub-other.pem
41 > -----BEGIN CERTIFICATE-----
41 > -----BEGIN CERTIFICATE-----
42 > MIIBqzCCAVWgAwIBAgIJALwZS731c/ORMA0GCSqGSIb3DQEBBQUAMDExEjAQBgNV
42 > MIIBqzCCAVWgAwIBAgIJALwZS731c/ORMA0GCSqGSIb3DQEBBQUAMDExEjAQBgNV
43 > BAMMCWxvY2FsaG9zdDEbMBkGCSqGSIb3DQEJARYMaGdAbG9jYWxob3N0MB4XDTEw
43 > BAMMCWxvY2FsaG9zdDEbMBkGCSqGSIb3DQEJARYMaGdAbG9jYWxob3N0MB4XDTEw
44 > MTAxNDIwNDUxNloXDTM1MDYwNTIwNDUxNlowMTESMBAGA1UEAwwJbG9jYWxob3N0
44 > MTAxNDIwNDUxNloXDTM1MDYwNTIwNDUxNlowMTESMBAGA1UEAwwJbG9jYWxob3N0
45 > MRswGQYJKoZIhvcNAQkBFgxoZ0Bsb2NhbGhvc3QwXDANBgkqhkiG9w0BAQEFAANL
45 > MRswGQYJKoZIhvcNAQkBFgxoZ0Bsb2NhbGhvc3QwXDANBgkqhkiG9w0BAQEFAANL
46 > ADBIAkEAsxsapLbHrqqUKuQBxdpK4G3m2LjtyrTSdpzzzFlecxd5yhNP6AyWrufo
46 > ADBIAkEAsxsapLbHrqqUKuQBxdpK4G3m2LjtyrTSdpzzzFlecxd5yhNP6AyWrufo
47 > K4VMGo2xlu9xOo88nDSUNSKPuD09MwIDAQABo1AwTjAdBgNVHQ4EFgQUoIB1iMhN
47 > K4VMGo2xlu9xOo88nDSUNSKPuD09MwIDAQABo1AwTjAdBgNVHQ4EFgQUoIB1iMhN
48 > y868rpQ2qk9dHnU6ebswHwYDVR0jBBgwFoAUoIB1iMhNy868rpQ2qk9dHnU6ebsw
48 > y868rpQ2qk9dHnU6ebswHwYDVR0jBBgwFoAUoIB1iMhNy868rpQ2qk9dHnU6ebsw
49 > DAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQUFAANBAJ544f125CsE7J2t55PdFaF6
49 > DAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQUFAANBAJ544f125CsE7J2t55PdFaF6
50 > bBlNBb91FCywBgSjhBjf+GG3TNPwrPdc3yqeq+hzJiuInqbOBv9abmMyq8Wsoig=
50 > bBlNBb91FCywBgSjhBjf+GG3TNPwrPdc3yqeq+hzJiuInqbOBv9abmMyq8Wsoig=
51 > -----END CERTIFICATE-----
51 > -----END CERTIFICATE-----
52 > EOT
52 > EOT
53
53
54 pub.pem patched with other notBefore / notAfter:
54 pub.pem patched with other notBefore / notAfter:
55
55
56 $ cat << EOT > pub-not-yet.pem
56 $ cat << EOT > pub-not-yet.pem
57 > -----BEGIN CERTIFICATE-----
57 > -----BEGIN CERTIFICATE-----
58 > MIIBqzCCAVWgAwIBAgIJANAXFFyWjGnRMA0GCSqGSIb3DQEBBQUAMDExEjAQBgNVBAMMCWxvY2Fs
58 > MIIBqzCCAVWgAwIBAgIJANAXFFyWjGnRMA0GCSqGSIb3DQEBBQUAMDExEjAQBgNVBAMMCWxvY2Fs
59 > aG9zdDEbMBkGCSqGSIb3DQEJARYMaGdAbG9jYWxob3N0MB4XDTM1MDYwNTIwMzAxNFoXDTM1MDYw
59 > aG9zdDEbMBkGCSqGSIb3DQEJARYMaGdAbG9jYWxob3N0MB4XDTM1MDYwNTIwMzAxNFoXDTM1MDYw
60 > NTIwMzAxNFowMTESMBAGA1UEAwwJbG9jYWxob3N0MRswGQYJKoZIhvcNAQkBFgxoZ0Bsb2NhbGhv
60 > NTIwMzAxNFowMTESMBAGA1UEAwwJbG9jYWxob3N0MRswGQYJKoZIhvcNAQkBFgxoZ0Bsb2NhbGhv
61 > c3QwXDANBgkqhkiG9w0BAQEFAANLADBIAkEApjCWeYGrIa/Vo7LHaRF8ou0tbgHKE33Use/whCnK
61 > c3QwXDANBgkqhkiG9w0BAQEFAANLADBIAkEApjCWeYGrIa/Vo7LHaRF8ou0tbgHKE33Use/whCnK
62 > EUm34rDaXQd4lxxX6aDWg06n9tiVStAKTgQAHJY8j/xgSwIDAQABo1AwTjAdBgNVHQ4EFgQUE6sA
62 > EUm34rDaXQd4lxxX6aDWg06n9tiVStAKTgQAHJY8j/xgSwIDAQABo1AwTjAdBgNVHQ4EFgQUE6sA
63 > +ammr24dGX0kpjxOgO45hzQwHwYDVR0jBBgwFoAUE6sA+ammr24dGX0kpjxOgO45hzQwDAYDVR0T
63 > +ammr24dGX0kpjxOgO45hzQwHwYDVR0jBBgwFoAUE6sA+ammr24dGX0kpjxOgO45hzQwDAYDVR0T
64 > BAUwAwEB/zANBgkqhkiG9w0BAQUFAANBAJXV41gWnkgC7jcpPpFRSUSZaxyzrXmD1CIqQf0WgVDb
64 > BAUwAwEB/zANBgkqhkiG9w0BAQUFAANBAJXV41gWnkgC7jcpPpFRSUSZaxyzrXmD1CIqQf0WgVDb
65 > /12E0vR2DuZitgzUYtBaofM81aTtc0a2/YsrmqePGm0=
65 > /12E0vR2DuZitgzUYtBaofM81aTtc0a2/YsrmqePGm0=
66 > -----END CERTIFICATE-----
66 > -----END CERTIFICATE-----
67 > EOT
67 > EOT
68 $ cat priv.pem pub-not-yet.pem > server-not-yet.pem
68 $ cat priv.pem pub-not-yet.pem > server-not-yet.pem
69
69
70 $ cat << EOT > pub-expired.pem
70 $ cat << EOT > pub-expired.pem
71 > -----BEGIN CERTIFICATE-----
71 > -----BEGIN CERTIFICATE-----
72 > MIIBqzCCAVWgAwIBAgIJANAXFFyWjGnRMA0GCSqGSIb3DQEBBQUAMDExEjAQBgNVBAMMCWxvY2Fs
72 > MIIBqzCCAVWgAwIBAgIJANAXFFyWjGnRMA0GCSqGSIb3DQEBBQUAMDExEjAQBgNVBAMMCWxvY2Fs
73 > aG9zdDEbMBkGCSqGSIb3DQEJARYMaGdAbG9jYWxob3N0MB4XDTEwMTAxNDIwMzAxNFoXDTEwMTAx
73 > aG9zdDEbMBkGCSqGSIb3DQEJARYMaGdAbG9jYWxob3N0MB4XDTEwMTAxNDIwMzAxNFoXDTEwMTAx
74 > NDIwMzAxNFowMTESMBAGA1UEAwwJbG9jYWxob3N0MRswGQYJKoZIhvcNAQkBFgxoZ0Bsb2NhbGhv
74 > NDIwMzAxNFowMTESMBAGA1UEAwwJbG9jYWxob3N0MRswGQYJKoZIhvcNAQkBFgxoZ0Bsb2NhbGhv
75 > c3QwXDANBgkqhkiG9w0BAQEFAANLADBIAkEApjCWeYGrIa/Vo7LHaRF8ou0tbgHKE33Use/whCnK
75 > c3QwXDANBgkqhkiG9w0BAQEFAANLADBIAkEApjCWeYGrIa/Vo7LHaRF8ou0tbgHKE33Use/whCnK
76 > EUm34rDaXQd4lxxX6aDWg06n9tiVStAKTgQAHJY8j/xgSwIDAQABo1AwTjAdBgNVHQ4EFgQUE6sA
76 > EUm34rDaXQd4lxxX6aDWg06n9tiVStAKTgQAHJY8j/xgSwIDAQABo1AwTjAdBgNVHQ4EFgQUE6sA
77 > +ammr24dGX0kpjxOgO45hzQwHwYDVR0jBBgwFoAUE6sA+ammr24dGX0kpjxOgO45hzQwDAYDVR0T
77 > +ammr24dGX0kpjxOgO45hzQwHwYDVR0jBBgwFoAUE6sA+ammr24dGX0kpjxOgO45hzQwDAYDVR0T
78 > BAUwAwEB/zANBgkqhkiG9w0BAQUFAANBAJfk57DTRf2nUbYaMSlVAARxMNbFGOjQhAUtY400GhKt
78 > BAUwAwEB/zANBgkqhkiG9w0BAQUFAANBAJfk57DTRf2nUbYaMSlVAARxMNbFGOjQhAUtY400GhKt
79 > 2uiKCNGKXVXD3AHWe13yHc5KttzbHQStE5Nm/DlWBWQ=
79 > 2uiKCNGKXVXD3AHWe13yHc5KttzbHQStE5Nm/DlWBWQ=
80 > -----END CERTIFICATE-----
80 > -----END CERTIFICATE-----
81 > EOT
81 > EOT
82 $ cat priv.pem pub-expired.pem > server-expired.pem
82 $ cat priv.pem pub-expired.pem > server-expired.pem
83
83
84 $ hg init test
84 $ hg init test
85 $ cd test
85 $ cd test
86 $ echo foo>foo
86 $ echo foo>foo
87 $ mkdir foo.d foo.d/bAr.hg.d foo.d/baR.d.hg
87 $ mkdir foo.d foo.d/bAr.hg.d foo.d/baR.d.hg
88 $ echo foo>foo.d/foo
88 $ echo foo>foo.d/foo
89 $ echo bar>foo.d/bAr.hg.d/BaR
89 $ echo bar>foo.d/bAr.hg.d/BaR
90 $ echo bar>foo.d/baR.d.hg/bAR
90 $ echo bar>foo.d/baR.d.hg/bAR
91 $ hg commit -A -m 1
91 $ hg commit -A -m 1
92 adding foo
92 adding foo
93 adding foo.d/bAr.hg.d/BaR
93 adding foo.d/bAr.hg.d/BaR
94 adding foo.d/baR.d.hg/bAR
94 adding foo.d/baR.d.hg/bAR
95 adding foo.d/foo
95 adding foo.d/foo
96 $ hg serve -p $HGPORT -d --pid-file=../hg0.pid --certificate=$PRIV
96 $ hg serve -p $HGPORT -d --pid-file=../hg0.pid --certificate=$PRIV
97 $ cat ../hg0.pid >> $DAEMON_PIDS
97 $ cat ../hg0.pid >> $DAEMON_PIDS
98
98
99 Test server address cannot be reused
99 Test server address cannot be reused
100
100
101 $ hg serve -p $HGPORT --certificate=$PRIV 2>&1
101 $ hg serve -p $HGPORT --certificate=$PRIV 2>&1
102 abort: cannot start server at ':$HGPORT': Address already in use
102 abort: cannot start server at ':$HGPORT': Address already in use
103 [255]
103 [255]
104 $ cd ..
104 $ cd ..
105
105
106 clone via pull
106 clone via pull
107
107
108 $ hg clone https://localhost:$HGPORT/ copy-pull
108 $ hg clone https://localhost:$HGPORT/ copy-pull
109 warning: localhost certificate not verified (check web.cacerts config setting)
109 warning: localhost certificate with fingerprint 91:4f:1a:ff:87:24:9c:09:b6:85:9b:88:b1:90:6d:30:75:64:91:ca not verified (check hostfingerprints or web.cacerts config setting)
110 requesting all changes
110 requesting all changes
111 adding changesets
111 adding changesets
112 adding manifests
112 adding manifests
113 adding file changes
113 adding file changes
114 added 1 changesets with 4 changes to 4 files
114 added 1 changesets with 4 changes to 4 files
115 updating to branch default
115 updating to branch default
116 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
116 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
117 $ hg verify -R copy-pull
117 $ hg verify -R copy-pull
118 checking changesets
118 checking changesets
119 checking manifests
119 checking manifests
120 crosschecking files in changesets and manifests
120 crosschecking files in changesets and manifests
121 checking files
121 checking files
122 4 files, 1 changesets, 4 total revisions
122 4 files, 1 changesets, 4 total revisions
123 $ cd test
123 $ cd test
124 $ echo bar > bar
124 $ echo bar > bar
125 $ hg commit -A -d '1 0' -m 2
125 $ hg commit -A -d '1 0' -m 2
126 adding bar
126 adding bar
127 $ cd ..
127 $ cd ..
128
128
129 pull without cacert
129 pull without cacert
130
130
131 $ cd copy-pull
131 $ cd copy-pull
132 $ echo '[hooks]' >> .hg/hgrc
132 $ echo '[hooks]' >> .hg/hgrc
133 $ echo "changegroup = python '$TESTDIR'/printenv.py changegroup" >> .hg/hgrc
133 $ echo "changegroup = python '$TESTDIR'/printenv.py changegroup" >> .hg/hgrc
134 $ hg pull
134 $ hg pull
135 warning: localhost certificate not verified (check web.cacerts config setting)
135 warning: localhost certificate with fingerprint 91:4f:1a:ff:87:24:9c:09:b6:85:9b:88:b1:90:6d:30:75:64:91:ca not verified (check hostfingerprints or web.cacerts config setting)
136 changegroup hook: HG_NODE=5fed3813f7f5e1824344fdc9cf8f63bb662c292d HG_SOURCE=pull HG_URL=https://localhost:$HGPORT/
136 changegroup hook: HG_NODE=5fed3813f7f5e1824344fdc9cf8f63bb662c292d HG_SOURCE=pull HG_URL=https://localhost:$HGPORT/
137 pulling from https://localhost:$HGPORT/
137 pulling from https://localhost:$HGPORT/
138 searching for changes
138 searching for changes
139 adding changesets
139 adding changesets
140 adding manifests
140 adding manifests
141 adding file changes
141 adding file changes
142 added 1 changesets with 1 changes to 1 files
142 added 1 changesets with 1 changes to 1 files
143 (run 'hg update' to get a working copy)
143 (run 'hg update' to get a working copy)
144 $ cd ..
144 $ cd ..
145
145
146 cacert configured in local repo
146 cacert configured in local repo
147
147
148 $ cp copy-pull/.hg/hgrc copy-pull/.hg/hgrc.bu
148 $ cp copy-pull/.hg/hgrc copy-pull/.hg/hgrc.bu
149 $ echo "[web]" >> copy-pull/.hg/hgrc
149 $ echo "[web]" >> copy-pull/.hg/hgrc
150 $ echo "cacerts=`pwd`/pub.pem" >> copy-pull/.hg/hgrc
150 $ echo "cacerts=`pwd`/pub.pem" >> copy-pull/.hg/hgrc
151 $ hg -R copy-pull pull --traceback
151 $ hg -R copy-pull pull --traceback
152 pulling from https://localhost:$HGPORT/
152 pulling from https://localhost:$HGPORT/
153 searching for changes
153 searching for changes
154 no changes found
154 no changes found
155 $ mv copy-pull/.hg/hgrc.bu copy-pull/.hg/hgrc
155 $ mv copy-pull/.hg/hgrc.bu copy-pull/.hg/hgrc
156
156
157 cacert configured globally, also testing expansion of environment
157 cacert configured globally, also testing expansion of environment
158 variables in the filename
158 variables in the filename
159
159
160 $ echo "[web]" >> $HGRCPATH
160 $ echo "[web]" >> $HGRCPATH
161 $ echo 'cacerts=$P/pub.pem' >> $HGRCPATH
161 $ echo 'cacerts=$P/pub.pem' >> $HGRCPATH
162 $ P=`pwd` hg -R copy-pull pull
162 $ P=`pwd` hg -R copy-pull pull
163 pulling from https://localhost:$HGPORT/
163 pulling from https://localhost:$HGPORT/
164 searching for changes
164 searching for changes
165 no changes found
165 no changes found
166
166
167 cacert mismatch
167 cacert mismatch
168
168
169 $ hg -R copy-pull pull --config web.cacerts=pub.pem https://127.0.0.1:$HGPORT/
169 $ hg -R copy-pull pull --config web.cacerts=pub.pem https://127.0.0.1:$HGPORT/
170 abort: 127.0.0.1 certificate error: certificate is for localhost
170 abort: 127.0.0.1 certificate error: certificate is for localhost
171 [255]
171 [255]
172 $ hg -R copy-pull pull --config web.cacerts=pub-other.pem
172 $ hg -R copy-pull pull --config web.cacerts=pub-other.pem
173 abort: error: *:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed (glob)
173 abort: error: *:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed (glob)
174 [255]
174 [255]
175
175
176 Test server cert which isn't valid yet
176 Test server cert which isn't valid yet
177
177
178 $ hg -R test serve -p $HGPORT1 -d --pid-file=hg1.pid --certificate=server-not-yet.pem
178 $ hg -R test serve -p $HGPORT1 -d --pid-file=hg1.pid --certificate=server-not-yet.pem
179 $ cat hg1.pid >> $DAEMON_PIDS
179 $ cat hg1.pid >> $DAEMON_PIDS
180 $ hg -R copy-pull pull --config web.cacerts=pub-not-yet.pem https://localhost:$HGPORT1/
180 $ hg -R copy-pull pull --config web.cacerts=pub-not-yet.pem https://localhost:$HGPORT1/
181 abort: error: *:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed (glob)
181 abort: error: *:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed (glob)
182 [255]
182 [255]
183
183
184 Test server cert which no longer is valid
184 Test server cert which no longer is valid
185
185
186 $ hg -R test serve -p $HGPORT2 -d --pid-file=hg2.pid --certificate=server-expired.pem
186 $ hg -R test serve -p $HGPORT2 -d --pid-file=hg2.pid --certificate=server-expired.pem
187 $ cat hg2.pid >> $DAEMON_PIDS
187 $ cat hg2.pid >> $DAEMON_PIDS
188 $ hg -R copy-pull pull --config web.cacerts=pub-expired.pem https://localhost:$HGPORT2/
188 $ hg -R copy-pull pull --config web.cacerts=pub-expired.pem https://localhost:$HGPORT2/
189 abort: error: *:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed (glob)
189 abort: error: *:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed (glob)
190 [255]
190 [255]
191
192 Fingerprints
193
194 $ echo "[hostfingerprints]" >> copy-pull/.hg/hgrc
195 $ echo "localhost = 91:4f:1a:ff:87:24:9c:09:b6:85:9b:88:b1:90:6d:30:75:64:91:ca" >> copy-pull/.hg/hgrc
196 $ echo "127.0.0.1 = 914f1aff87249c09b6859b88b1906d30756491ca" >> copy-pull/.hg/hgrc
197
198 - works without cacerts
199 $ hg -R copy-pull id https://localhost:$HGPORT/ --config web.cacerts=
200 5fed3813f7f5
201
202 - fails when cert doesn't match hostname (port is ignored)
203 $ hg -R copy-pull id https://localhost:$HGPORT1/
204 abort: invalid certificate for localhost with fingerprint 28:ff:71:bf:65:31:14:23:ad:62:92:b4:0e:31:99:18:fc:83:e3:9b
205 [255]
206
207 - ignores that certificate doesn't match hostname
208 $ hg -R copy-pull id https://127.0.0.1:$HGPORT/
209 5fed3813f7f5
General Comments 0
You need to be logged in to leave comments. Login now