##// END OF EJS Templates
url: 'ssh known host'-like checking of fingerprints of HTTPS certificates...
Mads Kiilerich -
r13314:8dc488df stable
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. Whether to connect to mail server using TLS. True or
730 Optional. Whether to connect to mail server using TLS. True or
713 False. Default: False.
731 False. Default: False.
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,556 +1,556 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(butf8):
35 def primary(butf8):
36 if butf8 == '.':
36 if butf8 == '.':
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 butf8 = lrepo.dirstate.branch()
39 butf8 = lrepo.dirstate.branch()
40 if butf8 in branchmap:
40 if butf8 in branchmap:
41 revs.extend(node.hex(r) for r in reversed(branchmap[butf8]))
41 revs.extend(node.hex(r) for r in reversed(branchmap[butf8]))
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 butf8 = encoding.fromlocal(branch)
47 butf8 = encoding.fromlocal(branch)
48 if not primary(butf8):
48 if not primary(butf8):
49 raise error.RepoLookupError(_("unknown branch '%s'") % branch)
49 raise error.RepoLookupError(_("unknown branch '%s'") % branch)
50 if hashbranch:
50 if hashbranch:
51 butf8 = encoding.fromlocal(hashbranch)
51 butf8 = encoding.fromlocal(hashbranch)
52 if not primary(butf8):
52 if not primary(butf8):
53 revs.append(hashbranch)
53 revs.append(hashbranch)
54 return revs, revs[0]
54 return revs, revs[0]
55
55
56 def parseurl(url, branches=None):
56 def parseurl(url, branches=None):
57 '''parse url#branch, returning (url, (branch, branches))'''
57 '''parse url#branch, returning (url, (branch, branches))'''
58
58
59 if '#' not in url:
59 if '#' not in url:
60 return url, (None, branches or [])
60 return url, (None, branches or [])
61 url, branch = url.split('#', 1)
61 url, branch = url.split('#', 1)
62 return url, (branch, branches or [])
62 return url, (branch, branches or [])
63
63
64 schemes = {
64 schemes = {
65 'bundle': bundlerepo,
65 'bundle': bundlerepo,
66 'file': _local,
66 'file': _local,
67 'http': httprepo,
67 'http': httprepo,
68 'https': httprepo,
68 'https': httprepo,
69 'ssh': sshrepo,
69 'ssh': sshrepo,
70 'static-http': statichttprepo,
70 'static-http': statichttprepo,
71 }
71 }
72
72
73 def _lookup(path):
73 def _lookup(path):
74 scheme = 'file'
74 scheme = 'file'
75 if path:
75 if path:
76 c = path.find(':')
76 c = path.find(':')
77 if c > 0:
77 if c > 0:
78 scheme = path[:c]
78 scheme = path[:c]
79 thing = schemes.get(scheme) or schemes['file']
79 thing = schemes.get(scheme) or schemes['file']
80 try:
80 try:
81 return thing(path)
81 return thing(path)
82 except TypeError:
82 except TypeError:
83 return thing
83 return thing
84
84
85 def islocal(repo):
85 def islocal(repo):
86 '''return true if repo or path is local'''
86 '''return true if repo or path is local'''
87 if isinstance(repo, str):
87 if isinstance(repo, str):
88 try:
88 try:
89 return _lookup(repo).islocal(repo)
89 return _lookup(repo).islocal(repo)
90 except AttributeError:
90 except AttributeError:
91 return False
91 return False
92 return repo.local()
92 return repo.local()
93
93
94 def repository(ui, path='', create=False):
94 def repository(ui, path='', create=False):
95 """return a repository object for the specified path"""
95 """return a repository object for the specified path"""
96 repo = _lookup(path).instance(ui, path, create)
96 repo = _lookup(path).instance(ui, path, create)
97 ui = getattr(repo, "ui", ui)
97 ui = getattr(repo, "ui", ui)
98 for name, module in extensions.extensions():
98 for name, module in extensions.extensions():
99 hook = getattr(module, 'reposetup', None)
99 hook = getattr(module, 'reposetup', None)
100 if hook:
100 if hook:
101 hook(ui, repo)
101 hook(ui, repo)
102 return repo
102 return repo
103
103
104 def defaultdest(source):
104 def defaultdest(source):
105 '''return default destination of clone if none is given'''
105 '''return default destination of clone if none is given'''
106 return os.path.basename(os.path.normpath(source))
106 return os.path.basename(os.path.normpath(source))
107
107
108 def localpath(path):
108 def localpath(path):
109 if path.startswith('file://localhost/'):
109 if path.startswith('file://localhost/'):
110 return path[16:]
110 return path[16:]
111 if path.startswith('file://'):
111 if path.startswith('file://'):
112 return path[7:]
112 return path[7:]
113 if path.startswith('file:'):
113 if path.startswith('file:'):
114 return path[5:]
114 return path[5:]
115 return path
115 return path
116
116
117 def share(ui, source, dest=None, update=True):
117 def share(ui, source, dest=None, update=True):
118 '''create a shared repository'''
118 '''create a shared repository'''
119
119
120 if not islocal(source):
120 if not islocal(source):
121 raise util.Abort(_('can only share local repositories'))
121 raise util.Abort(_('can only share local repositories'))
122
122
123 if not dest:
123 if not dest:
124 dest = defaultdest(source)
124 dest = defaultdest(source)
125 else:
125 else:
126 dest = ui.expandpath(dest)
126 dest = ui.expandpath(dest)
127
127
128 if isinstance(source, str):
128 if isinstance(source, str):
129 origsource = ui.expandpath(source)
129 origsource = ui.expandpath(source)
130 source, branches = parseurl(origsource)
130 source, branches = parseurl(origsource)
131 srcrepo = repository(ui, source)
131 srcrepo = repository(ui, source)
132 rev, checkout = addbranchrevs(srcrepo, srcrepo, branches, None)
132 rev, checkout = addbranchrevs(srcrepo, srcrepo, branches, None)
133 else:
133 else:
134 srcrepo = source
134 srcrepo = source
135 origsource = source = srcrepo.url()
135 origsource = source = srcrepo.url()
136 checkout = None
136 checkout = None
137
137
138 sharedpath = srcrepo.sharedpath # if our source is already sharing
138 sharedpath = srcrepo.sharedpath # if our source is already sharing
139
139
140 root = os.path.realpath(dest)
140 root = os.path.realpath(dest)
141 roothg = os.path.join(root, '.hg')
141 roothg = os.path.join(root, '.hg')
142
142
143 if os.path.exists(roothg):
143 if os.path.exists(roothg):
144 raise util.Abort(_('destination already exists'))
144 raise util.Abort(_('destination already exists'))
145
145
146 if not os.path.isdir(root):
146 if not os.path.isdir(root):
147 os.mkdir(root)
147 os.mkdir(root)
148 os.mkdir(roothg)
148 os.mkdir(roothg)
149
149
150 requirements = ''
150 requirements = ''
151 try:
151 try:
152 requirements = srcrepo.opener('requires').read()
152 requirements = srcrepo.opener('requires').read()
153 except IOError, inst:
153 except IOError, inst:
154 if inst.errno != errno.ENOENT:
154 if inst.errno != errno.ENOENT:
155 raise
155 raise
156
156
157 requirements += 'shared\n'
157 requirements += 'shared\n'
158 file(os.path.join(roothg, 'requires'), 'w').write(requirements)
158 file(os.path.join(roothg, 'requires'), 'w').write(requirements)
159 file(os.path.join(roothg, 'sharedpath'), 'w').write(sharedpath)
159 file(os.path.join(roothg, 'sharedpath'), 'w').write(sharedpath)
160
160
161 default = srcrepo.ui.config('paths', 'default')
161 default = srcrepo.ui.config('paths', 'default')
162 if default:
162 if default:
163 f = file(os.path.join(roothg, 'hgrc'), 'w')
163 f = file(os.path.join(roothg, 'hgrc'), 'w')
164 f.write('[paths]\ndefault = %s\n' % default)
164 f.write('[paths]\ndefault = %s\n' % default)
165 f.close()
165 f.close()
166
166
167 r = repository(ui, root)
167 r = repository(ui, root)
168
168
169 if update:
169 if update:
170 r.ui.status(_("updating working directory\n"))
170 r.ui.status(_("updating working directory\n"))
171 if update is not True:
171 if update is not True:
172 checkout = update
172 checkout = update
173 for test in (checkout, 'default', 'tip'):
173 for test in (checkout, 'default', 'tip'):
174 if test is None:
174 if test is None:
175 continue
175 continue
176 try:
176 try:
177 uprev = r.lookup(test)
177 uprev = r.lookup(test)
178 break
178 break
179 except error.RepoLookupError:
179 except error.RepoLookupError:
180 continue
180 continue
181 _update(r, uprev)
181 _update(r, uprev)
182
182
183 def clone(ui, source, dest=None, pull=False, rev=None, update=True,
183 def clone(ui, source, dest=None, pull=False, rev=None, update=True,
184 stream=False, branch=None):
184 stream=False, branch=None):
185 """Make a copy of an existing repository.
185 """Make a copy of an existing repository.
186
186
187 Create a copy of an existing repository in a new directory. The
187 Create a copy of an existing repository in a new directory. The
188 source and destination are URLs, as passed to the repository
188 source and destination are URLs, as passed to the repository
189 function. Returns a pair of repository objects, the source and
189 function. Returns a pair of repository objects, the source and
190 newly created destination.
190 newly created destination.
191
191
192 The location of the source is added to the new repository's
192 The location of the source is added to the new repository's
193 .hg/hgrc file, as the default to be used for future pulls and
193 .hg/hgrc file, as the default to be used for future pulls and
194 pushes.
194 pushes.
195
195
196 If an exception is raised, the partly cloned/updated destination
196 If an exception is raised, the partly cloned/updated destination
197 repository will be deleted.
197 repository will be deleted.
198
198
199 Arguments:
199 Arguments:
200
200
201 source: repository object or URL
201 source: repository object or URL
202
202
203 dest: URL of destination repository to create (defaults to base
203 dest: URL of destination repository to create (defaults to base
204 name of source repository)
204 name of source repository)
205
205
206 pull: always pull from source repository, even in local case
206 pull: always pull from source repository, even in local case
207
207
208 stream: stream raw data uncompressed from repository (fast over
208 stream: stream raw data uncompressed from repository (fast over
209 LAN, slow over WAN)
209 LAN, slow over WAN)
210
210
211 rev: revision to clone up to (implies pull=True)
211 rev: revision to clone up to (implies pull=True)
212
212
213 update: update working directory after clone completes, if
213 update: update working directory after clone completes, if
214 destination is local repository (True means update to default rev,
214 destination is local repository (True means update to default rev,
215 anything else is treated as a revision)
215 anything else is treated as a revision)
216
216
217 branch: branches to clone
217 branch: branches to clone
218 """
218 """
219
219
220 if isinstance(source, str):
220 if isinstance(source, str):
221 origsource = ui.expandpath(source)
221 origsource = ui.expandpath(source)
222 source, branch = parseurl(origsource, branch)
222 source, branch = parseurl(origsource, branch)
223 src_repo = repository(ui, source)
223 src_repo = repository(ui, source)
224 else:
224 else:
225 src_repo = source
225 src_repo = source
226 branch = (None, branch or [])
226 branch = (None, branch or [])
227 origsource = source = src_repo.url()
227 origsource = source = src_repo.url()
228 rev, checkout = addbranchrevs(src_repo, src_repo, branch, rev)
228 rev, checkout = addbranchrevs(src_repo, src_repo, branch, rev)
229
229
230 if dest is None:
230 if dest is None:
231 dest = defaultdest(source)
231 dest = defaultdest(source)
232 ui.status(_("destination directory: %s\n") % dest)
232 ui.status(_("destination directory: %s\n") % dest)
233 else:
233 else:
234 dest = ui.expandpath(dest)
234 dest = ui.expandpath(dest)
235
235
236 dest = localpath(dest)
236 dest = localpath(dest)
237 source = localpath(source)
237 source = localpath(source)
238
238
239 if os.path.exists(dest):
239 if os.path.exists(dest):
240 if not os.path.isdir(dest):
240 if not os.path.isdir(dest):
241 raise util.Abort(_("destination '%s' already exists") % dest)
241 raise util.Abort(_("destination '%s' already exists") % dest)
242 elif os.listdir(dest):
242 elif os.listdir(dest):
243 raise util.Abort(_("destination '%s' is not empty") % dest)
243 raise util.Abort(_("destination '%s' is not empty") % dest)
244
244
245 class DirCleanup(object):
245 class DirCleanup(object):
246 def __init__(self, dir_):
246 def __init__(self, dir_):
247 self.rmtree = shutil.rmtree
247 self.rmtree = shutil.rmtree
248 self.dir_ = dir_
248 self.dir_ = dir_
249 def close(self):
249 def close(self):
250 self.dir_ = None
250 self.dir_ = None
251 def cleanup(self):
251 def cleanup(self):
252 if self.dir_:
252 if self.dir_:
253 self.rmtree(self.dir_, True)
253 self.rmtree(self.dir_, True)
254
254
255 src_lock = dest_lock = dir_cleanup = None
255 src_lock = dest_lock = dir_cleanup = None
256 try:
256 try:
257 if islocal(dest):
257 if islocal(dest):
258 dir_cleanup = DirCleanup(dest)
258 dir_cleanup = DirCleanup(dest)
259
259
260 abspath = origsource
260 abspath = origsource
261 copy = False
261 copy = False
262 if src_repo.cancopy() and islocal(dest):
262 if src_repo.cancopy() and islocal(dest):
263 abspath = os.path.abspath(util.drop_scheme('file', origsource))
263 abspath = os.path.abspath(util.drop_scheme('file', origsource))
264 copy = not pull and not rev
264 copy = not pull and not rev
265
265
266 if copy:
266 if copy:
267 try:
267 try:
268 # we use a lock here because if we race with commit, we
268 # we use a lock here because if we race with commit, we
269 # can end up with extra data in the cloned revlogs that's
269 # can end up with extra data in the cloned revlogs that's
270 # not pointed to by changesets, thus causing verify to
270 # not pointed to by changesets, thus causing verify to
271 # fail
271 # fail
272 src_lock = src_repo.lock(wait=False)
272 src_lock = src_repo.lock(wait=False)
273 except error.LockError:
273 except error.LockError:
274 copy = False
274 copy = False
275
275
276 if copy:
276 if copy:
277 src_repo.hook('preoutgoing', throw=True, source='clone')
277 src_repo.hook('preoutgoing', throw=True, source='clone')
278 hgdir = os.path.realpath(os.path.join(dest, ".hg"))
278 hgdir = os.path.realpath(os.path.join(dest, ".hg"))
279 if not os.path.exists(dest):
279 if not os.path.exists(dest):
280 os.mkdir(dest)
280 os.mkdir(dest)
281 else:
281 else:
282 # only clean up directories we create ourselves
282 # only clean up directories we create ourselves
283 dir_cleanup.dir_ = hgdir
283 dir_cleanup.dir_ = hgdir
284 try:
284 try:
285 dest_path = hgdir
285 dest_path = hgdir
286 os.mkdir(dest_path)
286 os.mkdir(dest_path)
287 except OSError, inst:
287 except OSError, inst:
288 if inst.errno == errno.EEXIST:
288 if inst.errno == errno.EEXIST:
289 dir_cleanup.close()
289 dir_cleanup.close()
290 raise util.Abort(_("destination '%s' already exists")
290 raise util.Abort(_("destination '%s' already exists")
291 % dest)
291 % dest)
292 raise
292 raise
293
293
294 hardlink = None
294 hardlink = None
295 num = 0
295 num = 0
296 for f in src_repo.store.copylist():
296 for f in src_repo.store.copylist():
297 src = os.path.join(src_repo.sharedpath, f)
297 src = os.path.join(src_repo.sharedpath, f)
298 dst = os.path.join(dest_path, f)
298 dst = os.path.join(dest_path, f)
299 dstbase = os.path.dirname(dst)
299 dstbase = os.path.dirname(dst)
300 if dstbase and not os.path.exists(dstbase):
300 if dstbase and not os.path.exists(dstbase):
301 os.mkdir(dstbase)
301 os.mkdir(dstbase)
302 if os.path.exists(src):
302 if os.path.exists(src):
303 if dst.endswith('data'):
303 if dst.endswith('data'):
304 # lock to avoid premature writing to the target
304 # lock to avoid premature writing to the target
305 dest_lock = lock.lock(os.path.join(dstbase, "lock"))
305 dest_lock = lock.lock(os.path.join(dstbase, "lock"))
306 hardlink, n = util.copyfiles(src, dst, hardlink)
306 hardlink, n = util.copyfiles(src, dst, hardlink)
307 num += n
307 num += n
308 if hardlink:
308 if hardlink:
309 ui.debug("linked %d files\n" % num)
309 ui.debug("linked %d files\n" % num)
310 else:
310 else:
311 ui.debug("copied %d files\n" % num)
311 ui.debug("copied %d files\n" % num)
312
312
313 # we need to re-init the repo after manually copying the data
313 # we need to re-init the repo after manually copying the data
314 # into it
314 # into it
315 dest_repo = repository(ui, dest)
315 dest_repo = repository(ui, dest)
316 src_repo.hook('outgoing', source='clone',
316 src_repo.hook('outgoing', source='clone',
317 node=node.hex(node.nullid))
317 node=node.hex(node.nullid))
318 else:
318 else:
319 try:
319 try:
320 dest_repo = repository(ui, dest, create=True)
320 dest_repo = repository(ui, dest, create=True)
321 except OSError, inst:
321 except OSError, inst:
322 if inst.errno == errno.EEXIST:
322 if inst.errno == errno.EEXIST:
323 dir_cleanup.close()
323 dir_cleanup.close()
324 raise util.Abort(_("destination '%s' already exists")
324 raise util.Abort(_("destination '%s' already exists")
325 % dest)
325 % dest)
326 raise
326 raise
327
327
328 revs = None
328 revs = None
329 if rev:
329 if rev:
330 if 'lookup' not in src_repo.capabilities:
330 if 'lookup' not in src_repo.capabilities:
331 raise util.Abort(_("src repository does not support "
331 raise util.Abort(_("src repository does not support "
332 "revision lookup and so doesn't "
332 "revision lookup and so doesn't "
333 "support clone by revision"))
333 "support clone by revision"))
334 revs = [src_repo.lookup(r) for r in rev]
334 revs = [src_repo.lookup(r) for r in rev]
335 checkout = revs[0]
335 checkout = revs[0]
336 if dest_repo.local():
336 if dest_repo.local():
337 dest_repo.clone(src_repo, heads=revs, stream=stream)
337 dest_repo.clone(src_repo, heads=revs, stream=stream)
338 elif src_repo.local():
338 elif src_repo.local():
339 src_repo.push(dest_repo, revs=revs)
339 src_repo.push(dest_repo, revs=revs)
340 else:
340 else:
341 raise util.Abort(_("clone from remote to remote not supported"))
341 raise util.Abort(_("clone from remote to remote not supported"))
342
342
343 if dir_cleanup:
343 if dir_cleanup:
344 dir_cleanup.close()
344 dir_cleanup.close()
345
345
346 if dest_repo.local():
346 if dest_repo.local():
347 fp = dest_repo.opener("hgrc", "w", text=True)
347 fp = dest_repo.opener("hgrc", "w", text=True)
348 fp.write("[paths]\n")
348 fp.write("[paths]\n")
349 fp.write("default = %s\n" % abspath)
349 fp.write("default = %s\n" % abspath)
350 fp.close()
350 fp.close()
351
351
352 dest_repo.ui.setconfig('paths', 'default', abspath)
352 dest_repo.ui.setconfig('paths', 'default', abspath)
353
353
354 if update:
354 if update:
355 if update is not True:
355 if update is not True:
356 checkout = update
356 checkout = update
357 if src_repo.local():
357 if src_repo.local():
358 checkout = src_repo.lookup(update)
358 checkout = src_repo.lookup(update)
359 for test in (checkout, 'default', 'tip'):
359 for test in (checkout, 'default', 'tip'):
360 if test is None:
360 if test is None:
361 continue
361 continue
362 try:
362 try:
363 uprev = dest_repo.lookup(test)
363 uprev = dest_repo.lookup(test)
364 break
364 break
365 except error.RepoLookupError:
365 except error.RepoLookupError:
366 continue
366 continue
367 bn = dest_repo[uprev].branch()
367 bn = dest_repo[uprev].branch()
368 dest_repo.ui.status(_("updating to branch %s\n")
368 dest_repo.ui.status(_("updating to branch %s\n")
369 % encoding.tolocal(bn))
369 % encoding.tolocal(bn))
370 _update(dest_repo, uprev)
370 _update(dest_repo, uprev)
371
371
372 return src_repo, dest_repo
372 return src_repo, dest_repo
373 finally:
373 finally:
374 release(src_lock, dest_lock)
374 release(src_lock, dest_lock)
375 if dir_cleanup is not None:
375 if dir_cleanup is not None:
376 dir_cleanup.cleanup()
376 dir_cleanup.cleanup()
377
377
378 def _showstats(repo, stats):
378 def _showstats(repo, stats):
379 repo.ui.status(_("%d files updated, %d files merged, "
379 repo.ui.status(_("%d files updated, %d files merged, "
380 "%d files removed, %d files unresolved\n") % stats)
380 "%d files removed, %d files unresolved\n") % stats)
381
381
382 def update(repo, node):
382 def update(repo, node):
383 """update the working directory to node, merging linear changes"""
383 """update the working directory to node, merging linear changes"""
384 stats = mergemod.update(repo, node, False, False, None)
384 stats = mergemod.update(repo, node, False, False, None)
385 _showstats(repo, stats)
385 _showstats(repo, stats)
386 if stats[3]:
386 if stats[3]:
387 repo.ui.status(_("use 'hg resolve' to retry unresolved file merges\n"))
387 repo.ui.status(_("use 'hg resolve' to retry unresolved file merges\n"))
388 return stats[3] > 0
388 return stats[3] > 0
389
389
390 # naming conflict in clone()
390 # naming conflict in clone()
391 _update = update
391 _update = update
392
392
393 def clean(repo, node, show_stats=True):
393 def clean(repo, node, show_stats=True):
394 """forcibly switch the working directory to node, clobbering changes"""
394 """forcibly switch the working directory to node, clobbering changes"""
395 stats = mergemod.update(repo, node, False, True, None)
395 stats = mergemod.update(repo, node, False, True, None)
396 if show_stats:
396 if show_stats:
397 _showstats(repo, stats)
397 _showstats(repo, stats)
398 return stats[3] > 0
398 return stats[3] > 0
399
399
400 def merge(repo, node, force=None, remind=True):
400 def merge(repo, node, force=None, remind=True):
401 """branch merge with node, resolving changes"""
401 """branch merge with node, resolving changes"""
402 stats = mergemod.update(repo, node, True, force, False)
402 stats = mergemod.update(repo, node, True, force, False)
403 _showstats(repo, stats)
403 _showstats(repo, stats)
404 if stats[3]:
404 if stats[3]:
405 repo.ui.status(_("use 'hg resolve' to retry unresolved file merges "
405 repo.ui.status(_("use 'hg resolve' to retry unresolved file merges "
406 "or 'hg update -C .' to abandon\n"))
406 "or 'hg update -C .' to abandon\n"))
407 elif remind:
407 elif remind:
408 repo.ui.status(_("(branch merge, don't forget to commit)\n"))
408 repo.ui.status(_("(branch merge, don't forget to commit)\n"))
409 return stats[3] > 0
409 return stats[3] > 0
410
410
411 def _incoming(displaychlist, subreporecurse, ui, repo, source,
411 def _incoming(displaychlist, subreporecurse, ui, repo, source,
412 opts, buffered=False):
412 opts, buffered=False):
413 """
413 """
414 Helper for incoming / gincoming.
414 Helper for incoming / gincoming.
415 displaychlist gets called with
415 displaychlist gets called with
416 (remoterepo, incomingchangesetlist, displayer) parameters,
416 (remoterepo, incomingchangesetlist, displayer) parameters,
417 and is supposed to contain only code that can't be unified.
417 and is supposed to contain only code that can't be unified.
418 """
418 """
419 source, branches = parseurl(ui.expandpath(source), opts.get('branch'))
419 source, branches = parseurl(ui.expandpath(source), opts.get('branch'))
420 other = repository(remoteui(repo, opts), source)
420 other = repository(remoteui(repo, opts), source)
421 ui.status(_('comparing with %s\n') % url.hidepassword(source))
421 ui.status(_('comparing with %s\n') % url.hidepassword(source))
422 revs, checkout = addbranchrevs(repo, other, branches, opts.get('rev'))
422 revs, checkout = addbranchrevs(repo, other, branches, opts.get('rev'))
423
423
424 if revs:
424 if revs:
425 revs = [other.lookup(rev) for rev in revs]
425 revs = [other.lookup(rev) for rev in revs]
426 other, incoming, bundle = bundlerepo.getremotechanges(ui, repo, other, revs,
426 other, incoming, bundle = bundlerepo.getremotechanges(ui, repo, other, revs,
427 opts["bundle"], opts["force"])
427 opts["bundle"], opts["force"])
428 if incoming is None:
428 if incoming is None:
429 ui.status(_("no changes found\n"))
429 ui.status(_("no changes found\n"))
430 return subreporecurse()
430 return subreporecurse()
431
431
432 try:
432 try:
433 chlist = other.changelog.nodesbetween(incoming, revs)[0]
433 chlist = other.changelog.nodesbetween(incoming, revs)[0]
434 displayer = cmdutil.show_changeset(ui, other, opts, buffered)
434 displayer = cmdutil.show_changeset(ui, other, opts, buffered)
435
435
436 # XXX once graphlog extension makes it into core,
436 # XXX once graphlog extension makes it into core,
437 # should be replaced by a if graph/else
437 # should be replaced by a if graph/else
438 displaychlist(other, chlist, displayer)
438 displaychlist(other, chlist, displayer)
439
439
440 displayer.close()
440 displayer.close()
441 finally:
441 finally:
442 if hasattr(other, 'close'):
442 if hasattr(other, 'close'):
443 other.close()
443 other.close()
444 if bundle:
444 if bundle:
445 os.unlink(bundle)
445 os.unlink(bundle)
446 subreporecurse()
446 subreporecurse()
447 return 0 # exit code is zero since we found incoming changes
447 return 0 # exit code is zero since we found incoming changes
448
448
449 def incoming(ui, repo, source, opts):
449 def incoming(ui, repo, source, opts):
450 def subreporecurse():
450 def subreporecurse():
451 ret = 1
451 ret = 1
452 if opts.get('subrepos'):
452 if opts.get('subrepos'):
453 ctx = repo[None]
453 ctx = repo[None]
454 for subpath in sorted(ctx.substate):
454 for subpath in sorted(ctx.substate):
455 sub = ctx.sub(subpath)
455 sub = ctx.sub(subpath)
456 ret = min(ret, sub.incoming(ui, source, opts))
456 ret = min(ret, sub.incoming(ui, source, opts))
457 return ret
457 return ret
458
458
459 def display(other, chlist, displayer):
459 def display(other, chlist, displayer):
460 limit = cmdutil.loglimit(opts)
460 limit = cmdutil.loglimit(opts)
461 if opts.get('newest_first'):
461 if opts.get('newest_first'):
462 chlist.reverse()
462 chlist.reverse()
463 count = 0
463 count = 0
464 for n in chlist:
464 for n in chlist:
465 if limit is not None and count >= limit:
465 if limit is not None and count >= limit:
466 break
466 break
467 parents = [p for p in other.changelog.parents(n) if p != nullid]
467 parents = [p for p in other.changelog.parents(n) if p != nullid]
468 if opts.get('no_merges') and len(parents) == 2:
468 if opts.get('no_merges') and len(parents) == 2:
469 continue
469 continue
470 count += 1
470 count += 1
471 displayer.show(other[n])
471 displayer.show(other[n])
472 return _incoming(display, subreporecurse, ui, repo, source, opts)
472 return _incoming(display, subreporecurse, ui, repo, source, opts)
473
473
474 def _outgoing(ui, repo, dest, opts):
474 def _outgoing(ui, repo, dest, opts):
475 dest = ui.expandpath(dest or 'default-push', dest or 'default')
475 dest = ui.expandpath(dest or 'default-push', dest or 'default')
476 dest, branches = parseurl(dest, opts.get('branch'))
476 dest, branches = parseurl(dest, opts.get('branch'))
477 revs, checkout = addbranchrevs(repo, repo, branches, opts.get('rev'))
477 revs, checkout = addbranchrevs(repo, repo, branches, opts.get('rev'))
478 if revs:
478 if revs:
479 revs = [repo.lookup(rev) for rev in revs]
479 revs = [repo.lookup(rev) for rev in revs]
480
480
481 other = repository(remoteui(repo, opts), dest)
481 other = repository(remoteui(repo, opts), dest)
482 ui.status(_('comparing with %s\n') % url.hidepassword(dest))
482 ui.status(_('comparing with %s\n') % url.hidepassword(dest))
483 o = discovery.findoutgoing(repo, other, force=opts.get('force'))
483 o = discovery.findoutgoing(repo, other, force=opts.get('force'))
484 if not o:
484 if not o:
485 ui.status(_("no changes found\n"))
485 ui.status(_("no changes found\n"))
486 return None
486 return None
487
487
488 return repo.changelog.nodesbetween(o, revs)[0]
488 return repo.changelog.nodesbetween(o, revs)[0]
489
489
490 def outgoing(ui, repo, dest, opts):
490 def outgoing(ui, repo, dest, opts):
491 def recurse():
491 def recurse():
492 ret = 1
492 ret = 1
493 if opts.get('subrepos'):
493 if opts.get('subrepos'):
494 ctx = repo[None]
494 ctx = repo[None]
495 for subpath in sorted(ctx.substate):
495 for subpath in sorted(ctx.substate):
496 sub = ctx.sub(subpath)
496 sub = ctx.sub(subpath)
497 ret = min(ret, sub.outgoing(ui, dest, opts))
497 ret = min(ret, sub.outgoing(ui, dest, opts))
498 return ret
498 return ret
499
499
500 limit = cmdutil.loglimit(opts)
500 limit = cmdutil.loglimit(opts)
501 o = _outgoing(ui, repo, dest, opts)
501 o = _outgoing(ui, repo, dest, opts)
502 if o is None:
502 if o is None:
503 return recurse()
503 return recurse()
504
504
505 if opts.get('newest_first'):
505 if opts.get('newest_first'):
506 o.reverse()
506 o.reverse()
507 displayer = cmdutil.show_changeset(ui, repo, opts)
507 displayer = cmdutil.show_changeset(ui, repo, opts)
508 count = 0
508 count = 0
509 for n in o:
509 for n in o:
510 if limit is not None and count >= limit:
510 if limit is not None and count >= limit:
511 break
511 break
512 parents = [p for p in repo.changelog.parents(n) if p != nullid]
512 parents = [p for p in repo.changelog.parents(n) if p != nullid]
513 if opts.get('no_merges') and len(parents) == 2:
513 if opts.get('no_merges') and len(parents) == 2:
514 continue
514 continue
515 count += 1
515 count += 1
516 displayer.show(repo[n])
516 displayer.show(repo[n])
517 displayer.close()
517 displayer.close()
518 recurse()
518 recurse()
519 return 0 # exit code is zero since we found outgoing changes
519 return 0 # exit code is zero since we found outgoing changes
520
520
521 def revert(repo, node, choose):
521 def revert(repo, node, choose):
522 """revert changes to revision in node without updating dirstate"""
522 """revert changes to revision in node without updating dirstate"""
523 return mergemod.update(repo, node, False, True, choose)[3] > 0
523 return mergemod.update(repo, node, False, True, choose)[3] > 0
524
524
525 def verify(repo):
525 def verify(repo):
526 """verify the consistency of a repository"""
526 """verify the consistency of a repository"""
527 return verifymod.verify(repo)
527 return verifymod.verify(repo)
528
528
529 def remoteui(src, opts):
529 def remoteui(src, opts):
530 'build a remote ui from ui or repo and opts'
530 'build a remote ui from ui or repo and opts'
531 if hasattr(src, 'baseui'): # looks like a repository
531 if hasattr(src, 'baseui'): # looks like a repository
532 dst = src.baseui.copy() # drop repo-specific config
532 dst = src.baseui.copy() # drop repo-specific config
533 src = src.ui # copy target options from repo
533 src = src.ui # copy target options from repo
534 else: # assume it's a global ui object
534 else: # assume it's a global ui object
535 dst = src.copy() # keep all global options
535 dst = src.copy() # keep all global options
536
536
537 # copy ssh-specific options
537 # copy ssh-specific options
538 for o in 'ssh', 'remotecmd':
538 for o in 'ssh', 'remotecmd':
539 v = opts.get(o) or src.config('ui', o)
539 v = opts.get(o) or src.config('ui', o)
540 if v:
540 if v:
541 dst.setconfig("ui", o, v)
541 dst.setconfig("ui", o, v)
542
542
543 # copy bundle-specific options
543 # copy bundle-specific options
544 r = src.config('bundle', 'mainreporoot')
544 r = src.config('bundle', 'mainreporoot')
545 if r:
545 if r:
546 dst.setconfig('bundle', 'mainreporoot', r)
546 dst.setconfig('bundle', 'mainreporoot', r)
547
547
548 # copy selected local settings to the remote ui
548 # copy selected local settings to the remote ui
549 for sect in ('auth', 'http_proxy'):
549 for sect in ('auth', 'hostfingerprints', 'http_proxy'):
550 for key, val in src.configitems(sect):
550 for key, val in src.configitems(sect):
551 dst.setconfig(sect, key, val)
551 dst.setconfig(sect, key, val)
552 v = src.config('web', 'cacerts')
552 v = src.config('web', 'cacerts')
553 if v:
553 if v:
554 dst.setconfig('web', 'cacerts', util.expandpath(v))
554 dst.setconfig('web', 'cacerts', util.expandpath(v))
555
555
556 return dst
556 return dst
@@ -1,719 +1,743 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, *args, **kwargs):
261 def __init__(self, *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._data = __builtin__.open(*args, **kwargs)
265 self._data = __builtin__.open(*args, **kwargs)
266 self.read = self._data.read
266 self.read = self._data.read
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
270
271 def __len__(self):
271 def __len__(self):
272 return os.fstat(self._data.fileno()).st_size
272 return os.fstat(self._data.fileno()).st_size
273
273
274 def _gen_sendfile(connection):
274 def _gen_sendfile(connection):
275 def _sendfile(self, data):
275 def _sendfile(self, data):
276 # send a file
276 # send a file
277 if isinstance(data, httpsendfile):
277 if isinstance(data, httpsendfile):
278 # if auth required, some data sent twice, so rewind here
278 # if auth required, some data sent twice, so rewind here
279 data.seek(0)
279 data.seek(0)
280 for chunk in util.filechunkiter(data):
280 for chunk in util.filechunkiter(data):
281 connection.send(self, chunk)
281 connection.send(self, chunk)
282 else:
282 else:
283 connection.send(self, data)
283 connection.send(self, data)
284 return _sendfile
284 return _sendfile
285
285
286 has_https = hasattr(urllib2, 'HTTPSHandler')
286 has_https = hasattr(urllib2, 'HTTPSHandler')
287 if has_https:
287 if has_https:
288 try:
288 try:
289 # avoid using deprecated/broken FakeSocket in python 2.6
289 # avoid using deprecated/broken FakeSocket in python 2.6
290 import ssl
290 import ssl
291 _ssl_wrap_socket = ssl.wrap_socket
291 _ssl_wrap_socket = ssl.wrap_socket
292 CERT_REQUIRED = ssl.CERT_REQUIRED
292 CERT_REQUIRED = ssl.CERT_REQUIRED
293 except ImportError:
293 except ImportError:
294 CERT_REQUIRED = 2
294 CERT_REQUIRED = 2
295
295
296 def _ssl_wrap_socket(sock, key_file, cert_file,
296 def _ssl_wrap_socket(sock, key_file, cert_file,
297 cert_reqs=CERT_REQUIRED, ca_certs=None):
297 cert_reqs=CERT_REQUIRED, ca_certs=None):
298 if ca_certs:
298 if ca_certs:
299 raise util.Abort(_(
299 raise util.Abort(_(
300 'certificate checking requires Python 2.6'))
300 'certificate checking requires Python 2.6'))
301
301
302 ssl = socket.ssl(sock, key_file, cert_file)
302 ssl = socket.ssl(sock, key_file, cert_file)
303 return httplib.FakeSocket(sock, ssl)
303 return httplib.FakeSocket(sock, ssl)
304
304
305 try:
305 try:
306 _create_connection = socket.create_connection
306 _create_connection = socket.create_connection
307 except AttributeError:
307 except AttributeError:
308 _GLOBAL_DEFAULT_TIMEOUT = object()
308 _GLOBAL_DEFAULT_TIMEOUT = object()
309
309
310 def _create_connection(address, timeout=_GLOBAL_DEFAULT_TIMEOUT,
310 def _create_connection(address, timeout=_GLOBAL_DEFAULT_TIMEOUT,
311 source_address=None):
311 source_address=None):
312 # lifted from Python 2.6
312 # lifted from Python 2.6
313
313
314 msg = "getaddrinfo returns an empty list"
314 msg = "getaddrinfo returns an empty list"
315 host, port = address
315 host, port = address
316 for res in socket.getaddrinfo(host, port, 0, socket.SOCK_STREAM):
316 for res in socket.getaddrinfo(host, port, 0, socket.SOCK_STREAM):
317 af, socktype, proto, canonname, sa = res
317 af, socktype, proto, canonname, sa = res
318 sock = None
318 sock = None
319 try:
319 try:
320 sock = socket.socket(af, socktype, proto)
320 sock = socket.socket(af, socktype, proto)
321 if timeout is not _GLOBAL_DEFAULT_TIMEOUT:
321 if timeout is not _GLOBAL_DEFAULT_TIMEOUT:
322 sock.settimeout(timeout)
322 sock.settimeout(timeout)
323 if source_address:
323 if source_address:
324 sock.bind(source_address)
324 sock.bind(source_address)
325 sock.connect(sa)
325 sock.connect(sa)
326 return sock
326 return sock
327
327
328 except socket.error, msg:
328 except socket.error, msg:
329 if sock is not None:
329 if sock is not None:
330 sock.close()
330 sock.close()
331
331
332 raise socket.error, msg
332 raise socket.error, msg
333
333
334 class httpconnection(keepalive.HTTPConnection):
334 class httpconnection(keepalive.HTTPConnection):
335 # must be able to send big bundle as stream.
335 # must be able to send big bundle as stream.
336 send = _gen_sendfile(keepalive.HTTPConnection)
336 send = _gen_sendfile(keepalive.HTTPConnection)
337
337
338 def connect(self):
338 def connect(self):
339 if has_https and self.realhostport: # use CONNECT proxy
339 if has_https and self.realhostport: # use CONNECT proxy
340 self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
340 self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
341 self.sock.connect((self.host, self.port))
341 self.sock.connect((self.host, self.port))
342 if _generic_proxytunnel(self):
342 if _generic_proxytunnel(self):
343 # we do not support client x509 certificates
343 # we do not support client x509 certificates
344 self.sock = _ssl_wrap_socket(self.sock, None, None)
344 self.sock = _ssl_wrap_socket(self.sock, None, None)
345 else:
345 else:
346 keepalive.HTTPConnection.connect(self)
346 keepalive.HTTPConnection.connect(self)
347
347
348 def getresponse(self):
348 def getresponse(self):
349 proxyres = getattr(self, 'proxyres', None)
349 proxyres = getattr(self, 'proxyres', None)
350 if proxyres:
350 if proxyres:
351 if proxyres.will_close:
351 if proxyres.will_close:
352 self.close()
352 self.close()
353 self.proxyres = None
353 self.proxyres = None
354 return proxyres
354 return proxyres
355 return keepalive.HTTPConnection.getresponse(self)
355 return keepalive.HTTPConnection.getresponse(self)
356
356
357 # general transaction handler to support different ways to handle
357 # general transaction handler to support different ways to handle
358 # HTTPS proxying before and after Python 2.6.3.
358 # HTTPS proxying before and after Python 2.6.3.
359 def _generic_start_transaction(handler, h, req):
359 def _generic_start_transaction(handler, h, req):
360 if hasattr(req, '_tunnel_host') and req._tunnel_host:
360 if hasattr(req, '_tunnel_host') and req._tunnel_host:
361 tunnel_host = req._tunnel_host
361 tunnel_host = req._tunnel_host
362 if tunnel_host[:7] not in ['http://', 'https:/']:
362 if tunnel_host[:7] not in ['http://', 'https:/']:
363 tunnel_host = 'https://' + tunnel_host
363 tunnel_host = 'https://' + tunnel_host
364 new_tunnel = True
364 new_tunnel = True
365 else:
365 else:
366 tunnel_host = req.get_selector()
366 tunnel_host = req.get_selector()
367 new_tunnel = False
367 new_tunnel = False
368
368
369 if new_tunnel or tunnel_host == req.get_full_url(): # has proxy
369 if new_tunnel or tunnel_host == req.get_full_url(): # has proxy
370 urlparts = urlparse.urlparse(tunnel_host)
370 urlparts = urlparse.urlparse(tunnel_host)
371 if new_tunnel or urlparts[0] == 'https': # only use CONNECT for HTTPS
371 if new_tunnel or urlparts[0] == 'https': # only use CONNECT for HTTPS
372 realhostport = urlparts[1]
372 realhostport = urlparts[1]
373 if realhostport[-1] == ']' or ':' not in realhostport:
373 if realhostport[-1] == ']' or ':' not in realhostport:
374 realhostport += ':443'
374 realhostport += ':443'
375
375
376 h.realhostport = realhostport
376 h.realhostport = realhostport
377 h.headers = req.headers.copy()
377 h.headers = req.headers.copy()
378 h.headers.update(handler.parent.addheaders)
378 h.headers.update(handler.parent.addheaders)
379 return
379 return
380
380
381 h.realhostport = None
381 h.realhostport = None
382 h.headers = None
382 h.headers = None
383
383
384 def _generic_proxytunnel(self):
384 def _generic_proxytunnel(self):
385 proxyheaders = dict(
385 proxyheaders = dict(
386 [(x, self.headers[x]) for x in self.headers
386 [(x, self.headers[x]) for x in self.headers
387 if x.lower().startswith('proxy-')])
387 if x.lower().startswith('proxy-')])
388 self._set_hostport(self.host, self.port)
388 self._set_hostport(self.host, self.port)
389 self.send('CONNECT %s HTTP/1.0\r\n' % self.realhostport)
389 self.send('CONNECT %s HTTP/1.0\r\n' % self.realhostport)
390 for header in proxyheaders.iteritems():
390 for header in proxyheaders.iteritems():
391 self.send('%s: %s\r\n' % header)
391 self.send('%s: %s\r\n' % header)
392 self.send('\r\n')
392 self.send('\r\n')
393
393
394 # majority of the following code is duplicated from
394 # majority of the following code is duplicated from
395 # httplib.HTTPConnection as there are no adequate places to
395 # httplib.HTTPConnection as there are no adequate places to
396 # override functions to provide the needed functionality
396 # override functions to provide the needed functionality
397 res = self.response_class(self.sock,
397 res = self.response_class(self.sock,
398 strict=self.strict,
398 strict=self.strict,
399 method=self._method)
399 method=self._method)
400
400
401 while True:
401 while True:
402 version, status, reason = res._read_status()
402 version, status, reason = res._read_status()
403 if status != httplib.CONTINUE:
403 if status != httplib.CONTINUE:
404 break
404 break
405 while True:
405 while True:
406 skip = res.fp.readline().strip()
406 skip = res.fp.readline().strip()
407 if not skip:
407 if not skip:
408 break
408 break
409 res.status = status
409 res.status = status
410 res.reason = reason.strip()
410 res.reason = reason.strip()
411
411
412 if res.status == 200:
412 if res.status == 200:
413 while True:
413 while True:
414 line = res.fp.readline()
414 line = res.fp.readline()
415 if line == '\r\n':
415 if line == '\r\n':
416 break
416 break
417 return True
417 return True
418
418
419 if version == 'HTTP/1.0':
419 if version == 'HTTP/1.0':
420 res.version = 10
420 res.version = 10
421 elif version.startswith('HTTP/1.'):
421 elif version.startswith('HTTP/1.'):
422 res.version = 11
422 res.version = 11
423 elif version == 'HTTP/0.9':
423 elif version == 'HTTP/0.9':
424 res.version = 9
424 res.version = 9
425 else:
425 else:
426 raise httplib.UnknownProtocol(version)
426 raise httplib.UnknownProtocol(version)
427
427
428 if res.version == 9:
428 if res.version == 9:
429 res.length = None
429 res.length = None
430 res.chunked = 0
430 res.chunked = 0
431 res.will_close = 1
431 res.will_close = 1
432 res.msg = httplib.HTTPMessage(cStringIO.StringIO())
432 res.msg = httplib.HTTPMessage(cStringIO.StringIO())
433 return False
433 return False
434
434
435 res.msg = httplib.HTTPMessage(res.fp)
435 res.msg = httplib.HTTPMessage(res.fp)
436 res.msg.fp = None
436 res.msg.fp = None
437
437
438 # are we using the chunked-style of transfer encoding?
438 # are we using the chunked-style of transfer encoding?
439 trenc = res.msg.getheader('transfer-encoding')
439 trenc = res.msg.getheader('transfer-encoding')
440 if trenc and trenc.lower() == "chunked":
440 if trenc and trenc.lower() == "chunked":
441 res.chunked = 1
441 res.chunked = 1
442 res.chunk_left = None
442 res.chunk_left = None
443 else:
443 else:
444 res.chunked = 0
444 res.chunked = 0
445
445
446 # will the connection close at the end of the response?
446 # will the connection close at the end of the response?
447 res.will_close = res._check_close()
447 res.will_close = res._check_close()
448
448
449 # do we have a Content-Length?
449 # do we have a Content-Length?
450 # NOTE: RFC 2616, S4.4, #3 says we ignore this if tr_enc is "chunked"
450 # NOTE: RFC 2616, S4.4, #3 says we ignore this if tr_enc is "chunked"
451 length = res.msg.getheader('content-length')
451 length = res.msg.getheader('content-length')
452 if length and not res.chunked:
452 if length and not res.chunked:
453 try:
453 try:
454 res.length = int(length)
454 res.length = int(length)
455 except ValueError:
455 except ValueError:
456 res.length = None
456 res.length = None
457 else:
457 else:
458 if res.length < 0: # ignore nonsensical negative lengths
458 if res.length < 0: # ignore nonsensical negative lengths
459 res.length = None
459 res.length = None
460 else:
460 else:
461 res.length = None
461 res.length = None
462
462
463 # does the body have a fixed length? (of zero)
463 # does the body have a fixed length? (of zero)
464 if (status == httplib.NO_CONTENT or status == httplib.NOT_MODIFIED or
464 if (status == httplib.NO_CONTENT or status == httplib.NOT_MODIFIED or
465 100 <= status < 200 or # 1xx codes
465 100 <= status < 200 or # 1xx codes
466 res._method == 'HEAD'):
466 res._method == 'HEAD'):
467 res.length = 0
467 res.length = 0
468
468
469 # if the connection remains open, and we aren't using chunked, and
469 # if the connection remains open, and we aren't using chunked, and
470 # a content-length was not provided, then assume that the connection
470 # a content-length was not provided, then assume that the connection
471 # WILL close.
471 # WILL close.
472 if (not res.will_close and
472 if (not res.will_close and
473 not res.chunked and
473 not res.chunked and
474 res.length is None):
474 res.length is None):
475 res.will_close = 1
475 res.will_close = 1
476
476
477 self.proxyres = res
477 self.proxyres = res
478
478
479 return False
479 return False
480
480
481 class httphandler(keepalive.HTTPHandler):
481 class httphandler(keepalive.HTTPHandler):
482 def http_open(self, req):
482 def http_open(self, req):
483 return self.do_open(httpconnection, req)
483 return self.do_open(httpconnection, req)
484
484
485 def _start_transaction(self, h, req):
485 def _start_transaction(self, h, req):
486 _generic_start_transaction(self, h, req)
486 _generic_start_transaction(self, h, req)
487 return keepalive.HTTPHandler._start_transaction(self, h, req)
487 return keepalive.HTTPHandler._start_transaction(self, h, req)
488
488
489 def _verifycert(cert, hostname):
489 def _verifycert(cert, hostname):
490 '''Verify that cert (in socket.getpeercert() format) matches hostname.
490 '''Verify that cert (in socket.getpeercert() format) matches hostname.
491 CRLs is not handled.
491 CRLs is not handled.
492
492
493 Returns error message if any problems are found and None on success.
493 Returns error message if any problems are found and None on success.
494 '''
494 '''
495 if not cert:
495 if not cert:
496 return _('no certificate received')
496 return _('no certificate received')
497 dnsname = hostname.lower()
497 dnsname = hostname.lower()
498 def matchdnsname(certname):
498 def matchdnsname(certname):
499 return (certname == dnsname or
499 return (certname == dnsname or
500 '.' in dnsname and certname == '*.' + dnsname.split('.', 1)[1])
500 '.' in dnsname and certname == '*.' + dnsname.split('.', 1)[1])
501
501
502 san = cert.get('subjectAltName', [])
502 san = cert.get('subjectAltName', [])
503 if san:
503 if san:
504 certnames = [value.lower() for key, value in san if key == 'DNS']
504 certnames = [value.lower() for key, value in san if key == 'DNS']
505 for name in certnames:
505 for name in certnames:
506 if matchdnsname(name):
506 if matchdnsname(name):
507 return None
507 return None
508 return _('certificate is for %s') % ', '.join(certnames)
508 return _('certificate is for %s') % ', '.join(certnames)
509
509
510 # subject is only checked when subjectAltName is empty
510 # subject is only checked when subjectAltName is empty
511 for s in cert.get('subject', []):
511 for s in cert.get('subject', []):
512 key, value = s[0]
512 key, value = s[0]
513 if key == 'commonName':
513 if key == 'commonName':
514 try:
514 try:
515 # 'subject' entries are unicode
515 # 'subject' entries are unicode
516 certname = value.lower().encode('ascii')
516 certname = value.lower().encode('ascii')
517 except UnicodeEncodeError:
517 except UnicodeEncodeError:
518 return _('IDN in certificate not supported')
518 return _('IDN in certificate not supported')
519 if matchdnsname(certname):
519 if matchdnsname(certname):
520 return None
520 return None
521 return _('certificate is for %s') % certname
521 return _('certificate is for %s') % certname
522 return _('no commonName or subjectAltName found in certificate')
522 return _('no commonName or subjectAltName found in certificate')
523
523
524 if has_https:
524 if has_https:
525 class BetterHTTPS(httplib.HTTPSConnection):
525 class BetterHTTPS(httplib.HTTPSConnection):
526 send = keepalive.safesend
526 send = keepalive.safesend
527
527
528 def connect(self):
528 def connect(self):
529 if hasattr(self, 'ui'):
529 if hasattr(self, 'ui'):
530 cacerts = self.ui.config('web', 'cacerts')
530 cacerts = self.ui.config('web', 'cacerts')
531 if cacerts:
531 if cacerts:
532 cacerts = util.expandpath(cacerts)
532 cacerts = util.expandpath(cacerts)
533 else:
533 else:
534 cacerts = None
534 cacerts = None
535
535
536 if cacerts:
536 hostfingerprint = self.ui.config('hostfingerprints', self.host)
537 if cacerts and not hostfingerprint:
537 sock = _create_connection((self.host, self.port))
538 sock = _create_connection((self.host, self.port))
538 self.sock = _ssl_wrap_socket(sock, self.key_file,
539 self.sock = _ssl_wrap_socket(sock, self.key_file,
539 self.cert_file, cert_reqs=CERT_REQUIRED,
540 self.cert_file, cert_reqs=CERT_REQUIRED,
540 ca_certs=cacerts)
541 ca_certs=cacerts)
541 msg = _verifycert(self.sock.getpeercert(), self.host)
542 msg = _verifycert(self.sock.getpeercert(), self.host)
542 if msg:
543 if msg:
543 raise util.Abort(_('%s certificate error: %s') %
544 raise util.Abort(_('%s certificate error: %s') %
544 (self.host, msg))
545 (self.host, msg))
545 self.ui.debug('%s certificate successfully verified\n' %
546 self.ui.debug('%s certificate successfully verified\n' %
546 self.host)
547 self.host)
547 else:
548 else:
548 self.ui.warn(_("warning: %s certificate not verified "
549 "(check web.cacerts config setting)\n") %
550 self.host)
551 httplib.HTTPSConnection.connect(self)
549 httplib.HTTPSConnection.connect(self)
550 if hasattr(self.sock, 'getpeercert'):
551 peercert = self.sock.getpeercert(True)
552 peerfingerprint = util.sha1(peercert).hexdigest()
553 nicefingerprint = ":".join([peerfingerprint[x:x + 2]
554 for x in xrange(0, len(peerfingerprint), 2)])
555 if hostfingerprint:
556 if peerfingerprint.lower() != \
557 hostfingerprint.replace(':', '').lower():
558 raise util.Abort(_('invalid certificate for %s '
559 'with fingerprint %s') %
560 (self.host, nicefingerprint))
561 self.ui.debug('%s certificate matched fingerprint %s\n' %
562 (self.host, nicefingerprint))
563 else:
564 self.ui.warn(_('warning: %s certificate '
565 'with fingerprint %s not verified '
566 '(check hostfingerprints or web.cacerts '
567 'config setting)\n') %
568 (self.host, nicefingerprint))
569 else: # python 2.5 ?
570 if hostfingerprint:
571 raise util.Abort(_('no certificate for %s '
572 'with fingerprint') % self.host)
573 self.ui.warn(_('warning: %s certificate not verified '
574 '(check web.cacerts config setting)\n') %
575 self.host)
552
576
553 class httpsconnection(BetterHTTPS):
577 class httpsconnection(BetterHTTPS):
554 response_class = keepalive.HTTPResponse
578 response_class = keepalive.HTTPResponse
555 # must be able to send big bundle as stream.
579 # must be able to send big bundle as stream.
556 send = _gen_sendfile(BetterHTTPS)
580 send = _gen_sendfile(BetterHTTPS)
557 getresponse = keepalive.wrapgetresponse(httplib.HTTPSConnection)
581 getresponse = keepalive.wrapgetresponse(httplib.HTTPSConnection)
558
582
559 def connect(self):
583 def connect(self):
560 if self.realhostport: # use CONNECT proxy
584 if self.realhostport: # use CONNECT proxy
561 self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
585 self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
562 self.sock.connect((self.host, self.port))
586 self.sock.connect((self.host, self.port))
563 if _generic_proxytunnel(self):
587 if _generic_proxytunnel(self):
564 self.sock = _ssl_wrap_socket(self.sock, self.key_file,
588 self.sock = _ssl_wrap_socket(self.sock, self.key_file,
565 self.cert_file)
589 self.cert_file)
566 else:
590 else:
567 BetterHTTPS.connect(self)
591 BetterHTTPS.connect(self)
568
592
569 class httpshandler(keepalive.KeepAliveHandler, urllib2.HTTPSHandler):
593 class httpshandler(keepalive.KeepAliveHandler, urllib2.HTTPSHandler):
570 def __init__(self, ui):
594 def __init__(self, ui):
571 keepalive.KeepAliveHandler.__init__(self)
595 keepalive.KeepAliveHandler.__init__(self)
572 urllib2.HTTPSHandler.__init__(self)
596 urllib2.HTTPSHandler.__init__(self)
573 self.ui = ui
597 self.ui = ui
574 self.pwmgr = passwordmgr(self.ui)
598 self.pwmgr = passwordmgr(self.ui)
575
599
576 def _start_transaction(self, h, req):
600 def _start_transaction(self, h, req):
577 _generic_start_transaction(self, h, req)
601 _generic_start_transaction(self, h, req)
578 return keepalive.KeepAliveHandler._start_transaction(self, h, req)
602 return keepalive.KeepAliveHandler._start_transaction(self, h, req)
579
603
580 def https_open(self, req):
604 def https_open(self, req):
581 self.auth = self.pwmgr.readauthtoken(req.get_full_url())
605 self.auth = self.pwmgr.readauthtoken(req.get_full_url())
582 return self.do_open(self._makeconnection, req)
606 return self.do_open(self._makeconnection, req)
583
607
584 def _makeconnection(self, host, port=None, *args, **kwargs):
608 def _makeconnection(self, host, port=None, *args, **kwargs):
585 keyfile = None
609 keyfile = None
586 certfile = None
610 certfile = None
587
611
588 if len(args) >= 1: # key_file
612 if len(args) >= 1: # key_file
589 keyfile = args[0]
613 keyfile = args[0]
590 if len(args) >= 2: # cert_file
614 if len(args) >= 2: # cert_file
591 certfile = args[1]
615 certfile = args[1]
592 args = args[2:]
616 args = args[2:]
593
617
594 # if the user has specified different key/cert files in
618 # if the user has specified different key/cert files in
595 # hgrc, we prefer these
619 # hgrc, we prefer these
596 if self.auth and 'key' in self.auth and 'cert' in self.auth:
620 if self.auth and 'key' in self.auth and 'cert' in self.auth:
597 keyfile = self.auth['key']
621 keyfile = self.auth['key']
598 certfile = self.auth['cert']
622 certfile = self.auth['cert']
599
623
600 conn = httpsconnection(host, port, keyfile, certfile, *args, **kwargs)
624 conn = httpsconnection(host, port, keyfile, certfile, *args, **kwargs)
601 conn.ui = self.ui
625 conn.ui = self.ui
602 return conn
626 return conn
603
627
604 class httpdigestauthhandler(urllib2.HTTPDigestAuthHandler):
628 class httpdigestauthhandler(urllib2.HTTPDigestAuthHandler):
605 def __init__(self, *args, **kwargs):
629 def __init__(self, *args, **kwargs):
606 urllib2.HTTPDigestAuthHandler.__init__(self, *args, **kwargs)
630 urllib2.HTTPDigestAuthHandler.__init__(self, *args, **kwargs)
607 self.retried_req = None
631 self.retried_req = None
608
632
609 def reset_retry_count(self):
633 def reset_retry_count(self):
610 # Python 2.6.5 will call this on 401 or 407 errors and thus loop
634 # Python 2.6.5 will call this on 401 or 407 errors and thus loop
611 # forever. We disable reset_retry_count completely and reset in
635 # forever. We disable reset_retry_count completely and reset in
612 # http_error_auth_reqed instead.
636 # http_error_auth_reqed instead.
613 pass
637 pass
614
638
615 def http_error_auth_reqed(self, auth_header, host, req, headers):
639 def http_error_auth_reqed(self, auth_header, host, req, headers):
616 # Reset the retry counter once for each request.
640 # Reset the retry counter once for each request.
617 if req is not self.retried_req:
641 if req is not self.retried_req:
618 self.retried_req = req
642 self.retried_req = req
619 self.retried = 0
643 self.retried = 0
620 # In python < 2.5 AbstractDigestAuthHandler raises a ValueError if
644 # In python < 2.5 AbstractDigestAuthHandler raises a ValueError if
621 # it doesn't know about the auth type requested. This can happen if
645 # it doesn't know about the auth type requested. This can happen if
622 # somebody is using BasicAuth and types a bad password.
646 # somebody is using BasicAuth and types a bad password.
623 try:
647 try:
624 return urllib2.HTTPDigestAuthHandler.http_error_auth_reqed(
648 return urllib2.HTTPDigestAuthHandler.http_error_auth_reqed(
625 self, auth_header, host, req, headers)
649 self, auth_header, host, req, headers)
626 except ValueError, inst:
650 except ValueError, inst:
627 arg = inst.args[0]
651 arg = inst.args[0]
628 if arg.startswith("AbstractDigestAuthHandler doesn't know "):
652 if arg.startswith("AbstractDigestAuthHandler doesn't know "):
629 return
653 return
630 raise
654 raise
631
655
632 class httpbasicauthhandler(urllib2.HTTPBasicAuthHandler):
656 class httpbasicauthhandler(urllib2.HTTPBasicAuthHandler):
633 def __init__(self, *args, **kwargs):
657 def __init__(self, *args, **kwargs):
634 urllib2.HTTPBasicAuthHandler.__init__(self, *args, **kwargs)
658 urllib2.HTTPBasicAuthHandler.__init__(self, *args, **kwargs)
635 self.retried_req = None
659 self.retried_req = None
636
660
637 def reset_retry_count(self):
661 def reset_retry_count(self):
638 # Python 2.6.5 will call this on 401 or 407 errors and thus loop
662 # Python 2.6.5 will call this on 401 or 407 errors and thus loop
639 # forever. We disable reset_retry_count completely and reset in
663 # forever. We disable reset_retry_count completely and reset in
640 # http_error_auth_reqed instead.
664 # http_error_auth_reqed instead.
641 pass
665 pass
642
666
643 def http_error_auth_reqed(self, auth_header, host, req, headers):
667 def http_error_auth_reqed(self, auth_header, host, req, headers):
644 # Reset the retry counter once for each request.
668 # Reset the retry counter once for each request.
645 if req is not self.retried_req:
669 if req is not self.retried_req:
646 self.retried_req = req
670 self.retried_req = req
647 self.retried = 0
671 self.retried = 0
648 return urllib2.HTTPBasicAuthHandler.http_error_auth_reqed(
672 return urllib2.HTTPBasicAuthHandler.http_error_auth_reqed(
649 self, auth_header, host, req, headers)
673 self, auth_header, host, req, headers)
650
674
651 def getauthinfo(path):
675 def getauthinfo(path):
652 scheme, netloc, urlpath, query, frag = urlparse.urlsplit(path)
676 scheme, netloc, urlpath, query, frag = urlparse.urlsplit(path)
653 if not urlpath:
677 if not urlpath:
654 urlpath = '/'
678 urlpath = '/'
655 if scheme != 'file':
679 if scheme != 'file':
656 # XXX: why are we quoting the path again with some smart
680 # XXX: why are we quoting the path again with some smart
657 # heuristic here? Anyway, it cannot be done with file://
681 # heuristic here? Anyway, it cannot be done with file://
658 # urls since path encoding is os/fs dependent (see
682 # urls since path encoding is os/fs dependent (see
659 # urllib.pathname2url() for details).
683 # urllib.pathname2url() for details).
660 urlpath = quotepath(urlpath)
684 urlpath = quotepath(urlpath)
661 host, port, user, passwd = netlocsplit(netloc)
685 host, port, user, passwd = netlocsplit(netloc)
662
686
663 # urllib cannot handle URLs with embedded user or passwd
687 # urllib cannot handle URLs with embedded user or passwd
664 url = urlparse.urlunsplit((scheme, netlocunsplit(host, port),
688 url = urlparse.urlunsplit((scheme, netlocunsplit(host, port),
665 urlpath, query, frag))
689 urlpath, query, frag))
666 if user:
690 if user:
667 netloc = host
691 netloc = host
668 if port:
692 if port:
669 netloc += ':' + port
693 netloc += ':' + port
670 # Python < 2.4.3 uses only the netloc to search for a password
694 # Python < 2.4.3 uses only the netloc to search for a password
671 authinfo = (None, (url, netloc), user, passwd or '')
695 authinfo = (None, (url, netloc), user, passwd or '')
672 else:
696 else:
673 authinfo = None
697 authinfo = None
674 return url, authinfo
698 return url, authinfo
675
699
676 handlerfuncs = []
700 handlerfuncs = []
677
701
678 def opener(ui, authinfo=None):
702 def opener(ui, authinfo=None):
679 '''
703 '''
680 construct an opener suitable for urllib2
704 construct an opener suitable for urllib2
681 authinfo will be added to the password manager
705 authinfo will be added to the password manager
682 '''
706 '''
683 handlers = [httphandler()]
707 handlers = [httphandler()]
684 if has_https:
708 if has_https:
685 handlers.append(httpshandler(ui))
709 handlers.append(httpshandler(ui))
686
710
687 handlers.append(proxyhandler(ui))
711 handlers.append(proxyhandler(ui))
688
712
689 passmgr = passwordmgr(ui)
713 passmgr = passwordmgr(ui)
690 if authinfo is not None:
714 if authinfo is not None:
691 passmgr.add_password(*authinfo)
715 passmgr.add_password(*authinfo)
692 user, passwd = authinfo[2:4]
716 user, passwd = authinfo[2:4]
693 ui.debug('http auth: user %s, password %s\n' %
717 ui.debug('http auth: user %s, password %s\n' %
694 (user, passwd and '*' * len(passwd) or 'not set'))
718 (user, passwd and '*' * len(passwd) or 'not set'))
695
719
696 handlers.extend((httpbasicauthhandler(passmgr),
720 handlers.extend((httpbasicauthhandler(passmgr),
697 httpdigestauthhandler(passmgr)))
721 httpdigestauthhandler(passmgr)))
698 handlers.extend([h(ui, passmgr) for h in handlerfuncs])
722 handlers.extend([h(ui, passmgr) for h in handlerfuncs])
699 opener = urllib2.build_opener(*handlers)
723 opener = urllib2.build_opener(*handlers)
700
724
701 # 1.0 here is the _protocol_ version
725 # 1.0 here is the _protocol_ version
702 opener.addheaders = [('User-agent', 'mercurial/proto-1.0')]
726 opener.addheaders = [('User-agent', 'mercurial/proto-1.0')]
703 opener.addheaders.append(('Accept', 'application/mercurial-0.1'))
727 opener.addheaders.append(('Accept', 'application/mercurial-0.1'))
704 return opener
728 return opener
705
729
706 scheme_re = re.compile(r'^([a-zA-Z0-9+-.]+)://')
730 scheme_re = re.compile(r'^([a-zA-Z0-9+-.]+)://')
707
731
708 def open(ui, url, data=None):
732 def open(ui, url, data=None):
709 scheme = None
733 scheme = None
710 m = scheme_re.search(url)
734 m = scheme_re.search(url)
711 if m:
735 if m:
712 scheme = m.group(1).lower()
736 scheme = m.group(1).lower()
713 if not scheme:
737 if not scheme:
714 path = util.normpath(os.path.abspath(url))
738 path = util.normpath(os.path.abspath(url))
715 url = 'file://' + urllib.pathname2url(path)
739 url = 'file://' + urllib.pathname2url(path)
716 authinfo = None
740 authinfo = None
717 else:
741 else:
718 url, authinfo = getauthinfo(url)
742 url, authinfo = getauthinfo(url)
719 return opener(ui, authinfo).open(url, data)
743 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