##// END OF EJS Templates
patch: implement patch.eol=auto mode...
Martin Geisler -
r10102:1720d70c default
parent child Browse files
Show More
@@ -1,955 +1,958 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) ``C:\Mercurial\Mercurial.ini``
75 | (Windows) ``C:\Mercurial\Mercurial.ini``
76 | (Windows) ``HKEY_LOCAL_MACHINE\SOFTWARE\Mercurial``
76 | (Windows) ``HKEY_LOCAL_MACHINE\SOFTWARE\Mercurial``
77 | (Windows) ``<install-dir>\Mercurial.ini``
77 | (Windows) ``<install-dir>\Mercurial.ini``
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.
84 be read.
85
85
86 Syntax
86 Syntax
87 ------
87 ------
88
88
89 A configuration file consists of sections, led by a ``[section]`` header
89 A configuration file consists of sections, led by a ``[section]`` header
90 and followed by ``name = value`` entries::
90 and followed by ``name = value`` entries::
91
91
92 [spam]
92 [spam]
93 eggs=ham
93 eggs=ham
94 green=
94 green=
95 eggs
95 eggs
96
96
97 Each line contains one entry. If the lines that follow are indented,
97 Each line contains one entry. If the lines that follow are indented,
98 they are treated as continuations of that entry. Leading whitespace is
98 they are treated as continuations of that entry. Leading whitespace is
99 removed from values. Empty lines are skipped. Lines beginning with
99 removed from values. Empty lines are skipped. Lines beginning with
100 ``#`` or ``;`` are ignored and may be used to provide comments.
100 ``#`` or ``;`` are ignored and may be used to provide comments.
101
101
102 A line of the form ``%include file`` will include ``file`` into the
102 A line of the form ``%include file`` will include ``file`` into the
103 current configuration file. The inclusion is recursive, which means
103 current configuration file. The inclusion is recursive, which means
104 that included files can include other files. Filenames are relative to
104 that included files can include other files. Filenames are relative to
105 the configuration file in which the ``%include`` directive is found.
105 the configuration file in which the ``%include`` directive is found.
106
106
107 A line with ``%unset name`` will remove ``name`` from the current
107 A line with ``%unset name`` will remove ``name`` from the current
108 section, if it has been set previously.
108 section, if it has been set previously.
109
109
110
110
111 Sections
111 Sections
112 --------
112 --------
113
113
114 This section describes the different sections that may appear in a
114 This section describes the different sections that may appear in a
115 Mercurial "hgrc" file, the purpose of each section, its possible keys,
115 Mercurial "hgrc" file, the purpose of each section, its possible keys,
116 and their possible values.
116 and their possible values.
117
117
118 ``alias``
118 ``alias``
119 """""""""
119 """""""""
120 Defines command aliases.
120 Defines command aliases.
121 Aliases allow you to define your own commands in terms of other
121 Aliases allow you to define your own commands in terms of other
122 commands (or aliases), optionally including arguments.
122 commands (or aliases), optionally including arguments.
123
123
124 Alias definitions consist of lines of the form::
124 Alias definitions consist of lines of the form::
125
125
126 <alias> = <command> [<argument]...
126 <alias> = <command> [<argument]...
127
127
128 For example, this definition::
128 For example, this definition::
129
129
130 latest = log --limit 5
130 latest = log --limit 5
131
131
132 creates a new command ``latest`` that shows only the five most recent
132 creates a new command ``latest`` that shows only the five most recent
133 changesets. You can define subsequent aliases using earlier ones::
133 changesets. You can define subsequent aliases using earlier ones::
134
134
135 stable5 = latest -b stable
135 stable5 = latest -b stable
136
136
137 .. note:: It is possible to create aliases with the same names as
137 .. note:: It is possible to create aliases with the same names as
138 existing commands, which will then override the original
138 existing commands, which will then override the original
139 definitions. This is almost always a bad idea!
139 definitions. This is almost always a bad idea!
140
140
141
141
142 ``auth``
142 ``auth``
143 """"""""
143 """"""""
144 Authentication credentials for HTTP authentication. Each line has
144 Authentication credentials for HTTP authentication. Each line has
145 the following format::
145 the following format::
146
146
147 <name>.<argument> = <value>
147 <name>.<argument> = <value>
148
148
149 where ``<name>`` is used to group arguments into authentication
149 where ``<name>`` is used to group arguments into authentication
150 entries. Example::
150 entries. Example::
151
151
152 foo.prefix = hg.intevation.org/mercurial
152 foo.prefix = hg.intevation.org/mercurial
153 foo.username = foo
153 foo.username = foo
154 foo.password = bar
154 foo.password = bar
155 foo.schemes = http https
155 foo.schemes = http https
156
156
157 bar.prefix = secure.example.org
157 bar.prefix = secure.example.org
158 bar.key = path/to/file.key
158 bar.key = path/to/file.key
159 bar.cert = path/to/file.cert
159 bar.cert = path/to/file.cert
160 bar.schemes = https
160 bar.schemes = https
161
161
162 Supported arguments:
162 Supported arguments:
163
163
164 ``prefix``
164 ``prefix``
165 Either ``*`` or a URI prefix with or without the scheme part.
165 Either ``*`` or a URI prefix with or without the scheme part.
166 The authentication entry with the longest matching prefix is used
166 The authentication entry with the longest matching prefix is used
167 (where ``*`` matches everything and counts as a match of length
167 (where ``*`` matches everything and counts as a match of length
168 1). If the prefix doesn't include a scheme, the match is performed
168 1). If the prefix doesn't include a scheme, the match is performed
169 against the URI with its scheme stripped as well, and the schemes
169 against the URI with its scheme stripped as well, and the schemes
170 argument, q.v., is then subsequently consulted.
170 argument, q.v., is then subsequently consulted.
171 ``username``
171 ``username``
172 Optional. Username to authenticate with. If not given, and the
172 Optional. Username to authenticate with. If not given, and the
173 remote site requires basic or digest authentication, the user
173 remote site requires basic or digest authentication, the user
174 will be prompted for it.
174 will be prompted for it.
175 ``password``
175 ``password``
176 Optional. Password to authenticate with. If not given, and the
176 Optional. Password to authenticate with. If not given, and the
177 remote site requires basic or digest authentication, the user
177 remote site requires basic or digest authentication, the user
178 will be prompted for it.
178 will be prompted for it.
179 ``key``
179 ``key``
180 Optional. PEM encoded client certificate key file.
180 Optional. PEM encoded client certificate key file.
181 ``cert``
181 ``cert``
182 Optional. PEM encoded client certificate chain file.
182 Optional. PEM encoded client certificate chain file.
183 ``schemes``
183 ``schemes``
184 Optional. Space separated list of URI schemes to use this
184 Optional. Space separated list of URI schemes to use this
185 authentication entry with. Only used if the prefix doesn't include
185 authentication entry with. Only used if the prefix doesn't include
186 a scheme. Supported schemes are http and https. They will match
186 a scheme. Supported schemes are http and https. They will match
187 static-http and static-https respectively, as well.
187 static-http and static-https respectively, as well.
188 Default: https.
188 Default: https.
189
189
190 If no suitable authentication entry is found, the user is prompted
190 If no suitable authentication entry is found, the user is prompted
191 for credentials as usual if required by the remote.
191 for credentials as usual if required by the remote.
192
192
193
193
194 ``decode/encode``
194 ``decode/encode``
195 """""""""""""""""
195 """""""""""""""""
196 Filters for transforming files on checkout/checkin. This would
196 Filters for transforming files on checkout/checkin. This would
197 typically be used for newline processing or other
197 typically be used for newline processing or other
198 localization/canonicalization of files.
198 localization/canonicalization of files.
199
199
200 Filters consist of a filter pattern followed by a filter command.
200 Filters consist of a filter pattern followed by a filter command.
201 Filter patterns are globs by default, rooted at the repository root.
201 Filter patterns are globs by default, rooted at the repository root.
202 For example, to match any file ending in ``.txt`` in the root
202 For example, to match any file ending in ``.txt`` in the root
203 directory only, use the pattern ``*.txt``. To match any file ending
203 directory only, use the pattern ``*.txt``. To match any file ending
204 in ``.c`` anywhere in the repository, use the pattern ``**.c``.
204 in ``.c`` anywhere in the repository, use the pattern ``**.c``.
205
205
206 The filter command can start with a specifier, either ``pipe:`` or
206 The filter command can start with a specifier, either ``pipe:`` or
207 ``tempfile:``. If no specifier is given, ``pipe:`` is used by default.
207 ``tempfile:``. If no specifier is given, ``pipe:`` is used by default.
208
208
209 A ``pipe:`` command must accept data on stdin and return the transformed
209 A ``pipe:`` command must accept data on stdin and return the transformed
210 data on stdout.
210 data on stdout.
211
211
212 Pipe example::
212 Pipe example::
213
213
214 [encode]
214 [encode]
215 # uncompress gzip files on checkin to improve delta compression
215 # uncompress gzip files on checkin to improve delta compression
216 # note: not necessarily a good idea, just an example
216 # note: not necessarily a good idea, just an example
217 *.gz = pipe: gunzip
217 *.gz = pipe: gunzip
218
218
219 [decode]
219 [decode]
220 # recompress gzip files when writing them to the working dir (we
220 # recompress gzip files when writing them to the working dir (we
221 # can safely omit "pipe:", because it's the default)
221 # can safely omit "pipe:", because it's the default)
222 *.gz = gzip
222 *.gz = gzip
223
223
224 A ``tempfile:`` command is a template. The string ``INFILE`` is replaced
224 A ``tempfile:`` command is a template. The string ``INFILE`` is replaced
225 with the name of a temporary file that contains the data to be
225 with the name of a temporary file that contains the data to be
226 filtered by the command. The string ``OUTFILE`` is replaced with the name
226 filtered by the command. The string ``OUTFILE`` is replaced with the name
227 of an empty temporary file, where the filtered data must be written by
227 of an empty temporary file, where the filtered data must be written by
228 the command.
228 the command.
229
229
230 .. note:: The tempfile mechanism is recommended for Windows systems,
230 .. note:: The tempfile mechanism is recommended for Windows systems,
231 where the standard shell I/O redirection operators often have
231 where the standard shell I/O redirection operators often have
232 strange effects and may corrupt the contents of your files.
232 strange effects and may corrupt the contents of your files.
233
233
234 The most common usage is for LF <-> CRLF translation on Windows. For
234 The most common usage is for LF <-> CRLF translation on Windows. For
235 this, use the "smart" converters which check for binary files::
235 this, use the "smart" converters which check for binary files::
236
236
237 [extensions]
237 [extensions]
238 hgext.win32text =
238 hgext.win32text =
239 [encode]
239 [encode]
240 ** = cleverencode:
240 ** = cleverencode:
241 [decode]
241 [decode]
242 ** = cleverdecode:
242 ** = cleverdecode:
243
243
244 or if you only want to translate certain files::
244 or if you only want to translate certain files::
245
245
246 [extensions]
246 [extensions]
247 hgext.win32text =
247 hgext.win32text =
248 [encode]
248 [encode]
249 **.txt = dumbencode:
249 **.txt = dumbencode:
250 [decode]
250 [decode]
251 **.txt = dumbdecode:
251 **.txt = dumbdecode:
252
252
253
253
254 ``defaults``
254 ``defaults``
255 """"""""""""
255 """"""""""""
256
256
257 (defaults are deprecated. Don't use them. Use aliases instead)
257 (defaults are deprecated. Don't use them. Use aliases instead)
258
258
259 Use the ``[defaults]`` section to define command defaults, i.e. the
259 Use the ``[defaults]`` section to define command defaults, i.e. the
260 default options/arguments to pass to the specified commands.
260 default options/arguments to pass to the specified commands.
261
261
262 The following example makes ``hg log`` run in verbose mode, and ``hg
262 The following example makes ``hg log`` run in verbose mode, and ``hg
263 status`` show only the modified files, by default::
263 status`` show only the modified files, by default::
264
264
265 [defaults]
265 [defaults]
266 log = -v
266 log = -v
267 status = -m
267 status = -m
268
268
269 The actual commands, instead of their aliases, must be used when
269 The actual commands, instead of their aliases, must be used when
270 defining command defaults. The command defaults will also be applied
270 defining command defaults. The command defaults will also be applied
271 to the aliases of the commands defined.
271 to the aliases of the commands defined.
272
272
273
273
274 ``diff``
274 ``diff``
275 """"""""
275 """"""""
276
276
277 Settings used when displaying diffs. They are all Boolean and
277 Settings used when displaying diffs. They are all Boolean and
278 defaults to False.
278 defaults to False.
279
279
280 ``git``
280 ``git``
281 Use git extended diff format.
281 Use git extended diff format.
282 ``nodates``
282 ``nodates``
283 Don't include dates in diff headers.
283 Don't include dates in diff headers.
284 ``showfunc``
284 ``showfunc``
285 Show which function each change is in.
285 Show which function each change is in.
286 ``ignorews``
286 ``ignorews``
287 Ignore white space when comparing lines.
287 Ignore white space when comparing lines.
288 ``ignorewsamount``
288 ``ignorewsamount``
289 Ignore changes in the amount of white space.
289 Ignore changes in the amount of white space.
290 ``ignoreblanklines``
290 ``ignoreblanklines``
291 Ignore changes whose lines are all blank.
291 Ignore changes whose lines are all blank.
292
292
293 ``email``
293 ``email``
294 """""""""
294 """""""""
295 Settings for extensions that send email messages.
295 Settings for extensions that send email messages.
296
296
297 ``from``
297 ``from``
298 Optional. Email address to use in "From" header and SMTP envelope
298 Optional. Email address to use in "From" header and SMTP envelope
299 of outgoing messages.
299 of outgoing messages.
300 ``to``
300 ``to``
301 Optional. Comma-separated list of recipients' email addresses.
301 Optional. Comma-separated list of recipients' email addresses.
302 ``cc``
302 ``cc``
303 Optional. Comma-separated list of carbon copy recipients'
303 Optional. Comma-separated list of carbon copy recipients'
304 email addresses.
304 email addresses.
305 ``bcc``
305 ``bcc``
306 Optional. Comma-separated list of blind carbon copy recipients'
306 Optional. Comma-separated list of blind carbon copy recipients'
307 email addresses. Cannot be set interactively.
307 email addresses. Cannot be set interactively.
308 ``method``
308 ``method``
309 Optional. Method to use to send email messages. If value is ``smtp``
309 Optional. Method to use to send email messages. If value is ``smtp``
310 (default), use SMTP (see the SMTP_ section for configuration).
310 (default), use SMTP (see the SMTP_ section for configuration).
311 Otherwise, use as name of program to run that acts like sendmail
311 Otherwise, use as name of program to run that acts like sendmail
312 (takes ``-f`` option for sender, list of recipients on command line,
312 (takes ``-f`` option for sender, list of recipients on command line,
313 message on stdin). Normally, setting this to ``sendmail`` or
313 message on stdin). Normally, setting this to ``sendmail`` or
314 ``/usr/sbin/sendmail`` is enough to use sendmail to send messages.
314 ``/usr/sbin/sendmail`` is enough to use sendmail to send messages.
315 ``charsets``
315 ``charsets``
316 Optional. Comma-separated list of character sets considered
316 Optional. Comma-separated list of character sets considered
317 convenient for recipients. Addresses, headers, and parts not
317 convenient for recipients. Addresses, headers, and parts not
318 containing patches of outgoing messages will be encoded in the
318 containing patches of outgoing messages will be encoded in the
319 first character set to which conversion from local encoding
319 first character set to which conversion from local encoding
320 (``$HGENCODING``, ``ui.fallbackencoding``) succeeds. If correct
320 (``$HGENCODING``, ``ui.fallbackencoding``) succeeds. If correct
321 conversion fails, the text in question is sent as is. Defaults to
321 conversion fails, the text in question is sent as is. Defaults to
322 empty (explicit) list.
322 empty (explicit) list.
323
323
324 Order of outgoing email character sets:
324 Order of outgoing email character sets:
325
325
326 1. ``us-ascii``: always first, regardless of settings
326 1. ``us-ascii``: always first, regardless of settings
327 2. ``email.charsets``: in order given by user
327 2. ``email.charsets``: in order given by user
328 3. ``ui.fallbackencoding``: if not in email.charsets
328 3. ``ui.fallbackencoding``: if not in email.charsets
329 4. ``$HGENCODING``: if not in email.charsets
329 4. ``$HGENCODING``: if not in email.charsets
330 5. ``utf-8``: always last, regardless of settings
330 5. ``utf-8``: always last, regardless of settings
331
331
332 Email example::
332 Email example::
333
333
334 [email]
334 [email]
335 from = Joseph User <joe.user@example.com>
335 from = Joseph User <joe.user@example.com>
336 method = /usr/sbin/sendmail
336 method = /usr/sbin/sendmail
337 # charsets for western Europeans
337 # charsets for western Europeans
338 # us-ascii, utf-8 omitted, as they are tried first and last
338 # us-ascii, utf-8 omitted, as they are tried first and last
339 charsets = iso-8859-1, iso-8859-15, windows-1252
339 charsets = iso-8859-1, iso-8859-15, windows-1252
340
340
341
341
342 ``extensions``
342 ``extensions``
343 """"""""""""""
343 """"""""""""""
344
344
345 Mercurial has an extension mechanism for adding new features. To
345 Mercurial has an extension mechanism for adding new features. To
346 enable an extension, create an entry for it in this section.
346 enable an extension, create an entry for it in this section.
347
347
348 If you know that the extension is already in Python's search path,
348 If you know that the extension is already in Python's search path,
349 you can give the name of the module, followed by ``=``, with nothing
349 you can give the name of the module, followed by ``=``, with nothing
350 after the ``=``.
350 after the ``=``.
351
351
352 Otherwise, give a name that you choose, followed by ``=``, followed by
352 Otherwise, give a name that you choose, followed by ``=``, followed by
353 the path to the ``.py`` file (including the file name extension) that
353 the path to the ``.py`` file (including the file name extension) that
354 defines the extension.
354 defines the extension.
355
355
356 To explicitly disable an extension that is enabled in an hgrc of
356 To explicitly disable an extension that is enabled in an hgrc of
357 broader scope, prepend its path with ``!``, as in
357 broader scope, prepend its path with ``!``, as in
358 ``hgext.foo = !/ext/path`` or ``hgext.foo = !`` when path is not
358 ``hgext.foo = !/ext/path`` or ``hgext.foo = !`` when path is not
359 supplied.
359 supplied.
360
360
361 Example for ``~/.hgrc``::
361 Example for ``~/.hgrc``::
362
362
363 [extensions]
363 [extensions]
364 # (the mq extension will get loaded from Mercurial's path)
364 # (the mq extension will get loaded from Mercurial's path)
365 hgext.mq =
365 hgext.mq =
366 # (this extension will get loaded from the file specified)
366 # (this extension will get loaded from the file specified)
367 myfeature = ~/.hgext/myfeature.py
367 myfeature = ~/.hgext/myfeature.py
368
368
369
369
370 ``format``
370 ``format``
371 """"""""""
371 """"""""""
372
372
373 ``usestore``
373 ``usestore``
374 Enable or disable the "store" repository format which improves
374 Enable or disable the "store" repository format which improves
375 compatibility with systems that fold case or otherwise mangle
375 compatibility with systems that fold case or otherwise mangle
376 filenames. Enabled by default. Disabling this option will allow
376 filenames. Enabled by default. Disabling this option will allow
377 you to store longer filenames in some situations at the expense of
377 you to store longer filenames in some situations at the expense of
378 compatibility and ensures that the on-disk format of newly created
378 compatibility and ensures that the on-disk format of newly created
379 repositories will be compatible with Mercurial before version 0.9.4.
379 repositories will be compatible with Mercurial before version 0.9.4.
380
380
381 ``usefncache``
381 ``usefncache``
382 Enable or disable the "fncache" repository format which enhances
382 Enable or disable the "fncache" repository format which enhances
383 the "store" repository format (which has to be enabled to use
383 the "store" repository format (which has to be enabled to use
384 fncache) to allow longer filenames and avoids using Windows
384 fncache) to allow longer filenames and avoids using Windows
385 reserved names, e.g. "nul". Enabled by default. Disabling this
385 reserved names, e.g. "nul". Enabled by default. Disabling this
386 option ensures that the on-disk format of newly created
386 option ensures that the on-disk format of newly created
387 repositories will be compatible with Mercurial before version 1.1.
387 repositories will be compatible with Mercurial before version 1.1.
388
388
389 ``merge-patterns``
389 ``merge-patterns``
390 """"""""""""""""""
390 """"""""""""""""""
391
391
392 This section specifies merge tools to associate with particular file
392 This section specifies merge tools to associate with particular file
393 patterns. Tools matched here will take precedence over the default
393 patterns. Tools matched here will take precedence over the default
394 merge tool. Patterns are globs by default, rooted at the repository
394 merge tool. Patterns are globs by default, rooted at the repository
395 root.
395 root.
396
396
397 Example::
397 Example::
398
398
399 [merge-patterns]
399 [merge-patterns]
400 **.c = kdiff3
400 **.c = kdiff3
401 **.jpg = myimgmerge
401 **.jpg = myimgmerge
402
402
403 ``merge-tools``
403 ``merge-tools``
404 """""""""""""""
404 """""""""""""""
405
405
406 This section configures external merge tools to use for file-level
406 This section configures external merge tools to use for file-level
407 merges.
407 merges.
408
408
409 Example ``~/.hgrc``::
409 Example ``~/.hgrc``::
410
410
411 [merge-tools]
411 [merge-tools]
412 # Override stock tool location
412 # Override stock tool location
413 kdiff3.executable = ~/bin/kdiff3
413 kdiff3.executable = ~/bin/kdiff3
414 # Specify command line
414 # Specify command line
415 kdiff3.args = $base $local $other -o $output
415 kdiff3.args = $base $local $other -o $output
416 # Give higher priority
416 # Give higher priority
417 kdiff3.priority = 1
417 kdiff3.priority = 1
418
418
419 # Define new tool
419 # Define new tool
420 myHtmlTool.args = -m $local $other $base $output
420 myHtmlTool.args = -m $local $other $base $output
421 myHtmlTool.regkey = Software\FooSoftware\HtmlMerge
421 myHtmlTool.regkey = Software\FooSoftware\HtmlMerge
422 myHtmlTool.priority = 1
422 myHtmlTool.priority = 1
423
423
424 Supported arguments:
424 Supported arguments:
425
425
426 ``priority``
426 ``priority``
427 The priority in which to evaluate this tool.
427 The priority in which to evaluate this tool.
428 Default: 0.
428 Default: 0.
429 ``executable``
429 ``executable``
430 Either just the name of the executable or its pathname.
430 Either just the name of the executable or its pathname.
431 Default: the tool name.
431 Default: the tool name.
432 ``args``
432 ``args``
433 The arguments to pass to the tool executable. You can refer to the
433 The arguments to pass to the tool executable. You can refer to the
434 files being merged as well as the output file through these
434 files being merged as well as the output file through these
435 variables: ``$base``, ``$local``, ``$other``, ``$output``.
435 variables: ``$base``, ``$local``, ``$other``, ``$output``.
436 Default: ``$local $base $other``
436 Default: ``$local $base $other``
437 ``premerge``
437 ``premerge``
438 Attempt to run internal non-interactive 3-way merge tool before
438 Attempt to run internal non-interactive 3-way merge tool before
439 launching external tool.
439 launching external tool.
440 Default: True
440 Default: True
441 ``binary``
441 ``binary``
442 This tool can merge binary files. Defaults to False, unless tool
442 This tool can merge binary files. Defaults to False, unless tool
443 was selected by file pattern match.
443 was selected by file pattern match.
444 ``symlink``
444 ``symlink``
445 This tool can merge symlinks. Defaults to False, even if tool was
445 This tool can merge symlinks. Defaults to False, even if tool was
446 selected by file pattern match.
446 selected by file pattern match.
447 ``checkconflicts``
447 ``checkconflicts``
448 Check whether there are conflicts even though the tool reported
448 Check whether there are conflicts even though the tool reported
449 success.
449 success.
450 Default: False
450 Default: False
451 ``checkchanged``
451 ``checkchanged``
452 Check whether outputs were written even though the tool reported
452 Check whether outputs were written even though the tool reported
453 success.
453 success.
454 Default: False
454 Default: False
455 ``fixeol``
455 ``fixeol``
456 Attempt to fix up EOL changes caused by the merge tool.
456 Attempt to fix up EOL changes caused by the merge tool.
457 Default: False
457 Default: False
458 ``gui``
458 ``gui``
459 This tool requires a graphical interface to run. Default: False
459 This tool requires a graphical interface to run. Default: False
460 ``regkey``
460 ``regkey``
461 Windows registry key which describes install location of this
461 Windows registry key which describes install location of this
462 tool. Mercurial will search for this key first under
462 tool. Mercurial will search for this key first under
463 ``HKEY_CURRENT_USER`` and then under ``HKEY_LOCAL_MACHINE``.
463 ``HKEY_CURRENT_USER`` and then under ``HKEY_LOCAL_MACHINE``.
464 Default: None
464 Default: None
465 ``regname``
465 ``regname``
466 Name of value to read from specified registry key. Defaults to the
466 Name of value to read from specified registry key. Defaults to the
467 unnamed (default) value.
467 unnamed (default) value.
468 ``regappend``
468 ``regappend``
469 String to append to the value read from the registry, typically
469 String to append to the value read from the registry, typically
470 the executable name of the tool.
470 the executable name of the tool.
471 Default: None
471 Default: None
472
472
473
473
474 ``hooks``
474 ``hooks``
475 """""""""
475 """""""""
476 Commands or Python functions that get automatically executed by
476 Commands or Python functions that get automatically executed by
477 various actions such as starting or finishing a commit. Multiple
477 various actions such as starting or finishing a commit. Multiple
478 hooks can be run for the same action by appending a suffix to the
478 hooks can be run for the same action by appending a suffix to the
479 action. Overriding a site-wide hook can be done by changing its
479 action. Overriding a site-wide hook can be done by changing its
480 value or setting it to an empty string.
480 value or setting it to an empty string.
481
481
482 Example ``.hg/hgrc``::
482 Example ``.hg/hgrc``::
483
483
484 [hooks]
484 [hooks]
485 # update working directory after adding changesets
485 # update working directory after adding changesets
486 changegroup.update = hg update
486 changegroup.update = hg update
487 # do not use the site-wide hook
487 # do not use the site-wide hook
488 incoming =
488 incoming =
489 incoming.email = /my/email/hook
489 incoming.email = /my/email/hook
490 incoming.autobuild = /my/build/hook
490 incoming.autobuild = /my/build/hook
491
491
492 Most hooks are run with environment variables set that give useful
492 Most hooks are run with environment variables set that give useful
493 additional information. For each hook below, the environment
493 additional information. For each hook below, the environment
494 variables it is passed are listed with names of the form ``$HG_foo``.
494 variables it is passed are listed with names of the form ``$HG_foo``.
495
495
496 ``changegroup``
496 ``changegroup``
497 Run after a changegroup has been added via push, pull or unbundle.
497 Run after a changegroup has been added via push, pull or unbundle.
498 ID of the first new changeset is in ``$HG_NODE``. URL from which
498 ID of the first new changeset is in ``$HG_NODE``. URL from which
499 changes came is in ``$HG_URL``.
499 changes came is in ``$HG_URL``.
500 ``commit``
500 ``commit``
501 Run after a changeset has been created in the local repository. ID
501 Run after a changeset has been created in the local repository. ID
502 of the newly created changeset is in ``$HG_NODE``. Parent changeset
502 of the newly created changeset is in ``$HG_NODE``. Parent changeset
503 IDs are in ``$HG_PARENT1`` and ``$HG_PARENT2``.
503 IDs are in ``$HG_PARENT1`` and ``$HG_PARENT2``.
504 ``incoming``
504 ``incoming``
505 Run after a changeset has been pulled, pushed, or unbundled into
505 Run after a changeset has been pulled, pushed, or unbundled into
506 the local repository. The ID of the newly arrived changeset is in
506 the local repository. The ID of the newly arrived changeset is in
507 ``$HG_NODE``. URL that was source of changes came is in ``$HG_URL``.
507 ``$HG_NODE``. URL that was source of changes came is in ``$HG_URL``.
508 ``outgoing``
508 ``outgoing``
509 Run after sending changes from local repository to another. ID of
509 Run after sending changes from local repository to another. ID of
510 first changeset sent is in ``$HG_NODE``. Source of operation is in
510 first changeset sent is in ``$HG_NODE``. Source of operation is in
511 ``$HG_SOURCE``; see "preoutgoing" hook for description.
511 ``$HG_SOURCE``; see "preoutgoing" hook for description.
512 ``post-<command>``
512 ``post-<command>``
513 Run after successful invocations of the associated command. The
513 Run after successful invocations of the associated command. The
514 contents of the command line are passed as ``$HG_ARGS`` and the result
514 contents of the command line are passed as ``$HG_ARGS`` and the result
515 code in ``$HG_RESULT``. Hook failure is ignored.
515 code in ``$HG_RESULT``. Hook failure is ignored.
516 ``pre-<command>``
516 ``pre-<command>``
517 Run before executing the associated command. The contents of the
517 Run before executing the associated command. The contents of the
518 command line are passed as ``$HG_ARGS``. If the hook returns failure,
518 command line are passed as ``$HG_ARGS``. If the hook returns failure,
519 the command doesn't execute and Mercurial returns the failure
519 the command doesn't execute and Mercurial returns the failure
520 code.
520 code.
521 ``prechangegroup``
521 ``prechangegroup``
522 Run before a changegroup is added via push, pull or unbundle. Exit
522 Run before a changegroup is added via push, pull or unbundle. Exit
523 status 0 allows the changegroup to proceed. Non-zero status will
523 status 0 allows the changegroup to proceed. Non-zero status will
524 cause the push, pull or unbundle to fail. URL from which changes
524 cause the push, pull or unbundle to fail. URL from which changes
525 will come is in ``$HG_URL``.
525 will come is in ``$HG_URL``.
526 ``precommit``
526 ``precommit``
527 Run before starting a local commit. Exit status 0 allows the
527 Run before starting a local commit. Exit status 0 allows the
528 commit to proceed. Non-zero status will cause the commit to fail.
528 commit to proceed. Non-zero status will cause the commit to fail.
529 Parent changeset IDs are in ``$HG_PARENT1`` and ``$HG_PARENT2``.
529 Parent changeset IDs are in ``$HG_PARENT1`` and ``$HG_PARENT2``.
530 ``preoutgoing``
530 ``preoutgoing``
531 Run before collecting changes to send from the local repository to
531 Run before collecting changes to send from the local repository to
532 another. Non-zero status will cause failure. This lets you prevent
532 another. Non-zero status will cause failure. This lets you prevent
533 pull over HTTP or SSH. Also prevents against local pull, push
533 pull over HTTP or SSH. Also prevents against local pull, push
534 (outbound) or bundle commands, but not effective, since you can
534 (outbound) or bundle commands, but not effective, since you can
535 just copy files instead then. Source of operation is in
535 just copy files instead then. Source of operation is in
536 ``$HG_SOURCE``. If "serve", operation is happening on behalf of remote
536 ``$HG_SOURCE``. If "serve", operation is happening on behalf of remote
537 SSH or HTTP repository. If "push", "pull" or "bundle", operation
537 SSH or HTTP repository. If "push", "pull" or "bundle", operation
538 is happening on behalf of repository on same system.
538 is happening on behalf of repository on same system.
539 ``pretag``
539 ``pretag``
540 Run before creating a tag. Exit status 0 allows the tag to be
540 Run before creating a tag. Exit status 0 allows the tag to be
541 created. Non-zero status will cause the tag to fail. ID of
541 created. Non-zero status will cause the tag to fail. ID of
542 changeset to tag is in ``$HG_NODE``. Name of tag is in ``$HG_TAG``. Tag is
542 changeset to tag is in ``$HG_NODE``. Name of tag is in ``$HG_TAG``. Tag is
543 local if ``$HG_LOCAL=1``, in repository if ``$HG_LOCAL=0``.
543 local if ``$HG_LOCAL=1``, in repository if ``$HG_LOCAL=0``.
544 ``pretxnchangegroup``
544 ``pretxnchangegroup``
545 Run after a changegroup has been added via push, pull or unbundle,
545 Run after a changegroup has been added via push, pull or unbundle,
546 but before the transaction has been committed. Changegroup is
546 but before the transaction has been committed. Changegroup is
547 visible to hook program. This lets you validate incoming changes
547 visible to hook program. This lets you validate incoming changes
548 before accepting them. Passed the ID of the first new changeset in
548 before accepting them. Passed the ID of the first new changeset in
549 ``$HG_NODE``. Exit status 0 allows the transaction to commit. Non-zero
549 ``$HG_NODE``. Exit status 0 allows the transaction to commit. Non-zero
550 status will cause the transaction to be rolled back and the push,
550 status will cause the transaction to be rolled back and the push,
551 pull or unbundle will fail. URL that was source of changes is in
551 pull or unbundle will fail. URL that was source of changes is in
552 ``$HG_URL``.
552 ``$HG_URL``.
553 ``pretxncommit``
553 ``pretxncommit``
554 Run after a changeset has been created but the transaction not yet
554 Run after a changeset has been created but the transaction not yet
555 committed. Changeset is visible to hook program. This lets you
555 committed. Changeset is visible to hook program. This lets you
556 validate commit message and changes. Exit status 0 allows the
556 validate commit message and changes. Exit status 0 allows the
557 commit to proceed. Non-zero status will cause the transaction to
557 commit to proceed. Non-zero status will cause the transaction to
558 be rolled back. ID of changeset is in ``$HG_NODE``. Parent changeset
558 be rolled back. ID of changeset is in ``$HG_NODE``. Parent changeset
559 IDs are in ``$HG_PARENT1`` and ``$HG_PARENT2``.
559 IDs are in ``$HG_PARENT1`` and ``$HG_PARENT2``.
560 ``preupdate``
560 ``preupdate``
561 Run before updating the working directory. Exit status 0 allows
561 Run before updating the working directory. Exit status 0 allows
562 the update to proceed. Non-zero status will prevent the update.
562 the update to proceed. Non-zero status will prevent the update.
563 Changeset ID of first new parent is in ``$HG_PARENT1``. If merge, ID
563 Changeset ID of first new parent is in ``$HG_PARENT1``. If merge, ID
564 of second new parent is in ``$HG_PARENT2``.
564 of second new parent is in ``$HG_PARENT2``.
565 ``tag``
565 ``tag``
566 Run after a tag is created. ID of tagged changeset is in ``$HG_NODE``.
566 Run after a tag is created. ID of tagged changeset is in ``$HG_NODE``.
567 Name of tag is in ``$HG_TAG``. Tag is local if ``$HG_LOCAL=1``, in
567 Name of tag is in ``$HG_TAG``. Tag is local if ``$HG_LOCAL=1``, in
568 repository if ``$HG_LOCAL=0``.
568 repository if ``$HG_LOCAL=0``.
569 ``update``
569 ``update``
570 Run after updating the working directory. Changeset ID of first
570 Run after updating the working directory. Changeset ID of first
571 new parent is in ``$HG_PARENT1``. If merge, ID of second new parent is
571 new parent is in ``$HG_PARENT1``. If merge, ID of second new parent is
572 in ``$HG_PARENT2``. If the update succeeded, ``$HG_ERROR=0``. If the
572 in ``$HG_PARENT2``. If the update succeeded, ``$HG_ERROR=0``. If the
573 update failed (e.g. because conflicts not resolved), ``$HG_ERROR=1``.
573 update failed (e.g. because conflicts not resolved), ``$HG_ERROR=1``.
574
574
575 .. note:: It is generally better to use standard hooks rather than the
575 .. note:: It is generally better to use standard hooks rather than the
576 generic pre- and post- command hooks as they are guaranteed to be
576 generic pre- and post- command hooks as they are guaranteed to be
577 called in the appropriate contexts for influencing transactions.
577 called in the appropriate contexts for influencing transactions.
578 Also, hooks like "commit" will be called in all contexts that
578 Also, hooks like "commit" will be called in all contexts that
579 generate a commit (e.g. tag) and not just the commit command.
579 generate a commit (e.g. tag) and not just the commit command.
580
580
581 .. note:: Environment variables with empty values may not be passed to
581 .. note:: Environment variables with empty values may not be passed to
582 hooks on platforms such as Windows. As an example, ``$HG_PARENT2``
582 hooks on platforms such as Windows. As an example, ``$HG_PARENT2``
583 will have an empty value under Unix-like platforms for non-merge
583 will have an empty value under Unix-like platforms for non-merge
584 changesets, while it will not be available at all under Windows.
584 changesets, while it will not be available at all under Windows.
585
585
586 The syntax for Python hooks is as follows::
586 The syntax for Python hooks is as follows::
587
587
588 hookname = python:modulename.submodule.callable
588 hookname = python:modulename.submodule.callable
589 hookname = python:/path/to/python/module.py:callable
589 hookname = python:/path/to/python/module.py:callable
590
590
591 Python hooks are run within the Mercurial process. Each hook is
591 Python hooks are run within the Mercurial process. Each hook is
592 called with at least three keyword arguments: a ui object (keyword
592 called with at least three keyword arguments: a ui object (keyword
593 ``ui``), a repository object (keyword ``repo``), and a ``hooktype``
593 ``ui``), a repository object (keyword ``repo``), and a ``hooktype``
594 keyword that tells what kind of hook is used. Arguments listed as
594 keyword that tells what kind of hook is used. Arguments listed as
595 environment variables above are passed as keyword arguments, with no
595 environment variables above are passed as keyword arguments, with no
596 ``HG_`` prefix, and names in lower case.
596 ``HG_`` prefix, and names in lower case.
597
597
598 If a Python hook returns a "true" value or raises an exception, this
598 If a Python hook returns a "true" value or raises an exception, this
599 is treated as a failure.
599 is treated as a failure.
600
600
601
601
602 ``http_proxy``
602 ``http_proxy``
603 """"""""""""""
603 """"""""""""""
604 Used to access web-based Mercurial repositories through a HTTP
604 Used to access web-based Mercurial repositories through a HTTP
605 proxy.
605 proxy.
606
606
607 ``host``
607 ``host``
608 Host name and (optional) port of the proxy server, for example
608 Host name and (optional) port of the proxy server, for example
609 "myproxy:8000".
609 "myproxy:8000".
610 ``no``
610 ``no``
611 Optional. Comma-separated list of host names that should bypass
611 Optional. Comma-separated list of host names that should bypass
612 the proxy.
612 the proxy.
613 ``passwd``
613 ``passwd``
614 Optional. Password to authenticate with at the proxy server.
614 Optional. Password to authenticate with at the proxy server.
615 ``user``
615 ``user``
616 Optional. User name to authenticate with at the proxy server.
616 Optional. User name to authenticate with at the proxy server.
617
617
618 ``smtp``
618 ``smtp``
619 """"""""
619 """"""""
620 Configuration for extensions that need to send email messages.
620 Configuration for extensions that need to send email messages.
621
621
622 ``host``
622 ``host``
623 Host name of mail server, e.g. "mail.example.com".
623 Host name of mail server, e.g. "mail.example.com".
624 ``port``
624 ``port``
625 Optional. Port to connect to on mail server. Default: 25.
625 Optional. Port to connect to on mail server. Default: 25.
626 ``tls``
626 ``tls``
627 Optional. Whether to connect to mail server using TLS. True or
627 Optional. Whether to connect to mail server using TLS. True or
628 False. Default: False.
628 False. Default: False.
629 ``username``
629 ``username``
630 Optional. User name to authenticate to SMTP server with. If
630 Optional. User name to authenticate to SMTP server with. If
631 username is specified, password must also be specified.
631 username is specified, password must also be specified.
632 Default: none.
632 Default: none.
633 ``password``
633 ``password``
634 Optional. Password to authenticate to SMTP server with. If
634 Optional. Password to authenticate to SMTP server with. If
635 username is specified, password must also be specified.
635 username is specified, password must also be specified.
636 Default: none.
636 Default: none.
637 ``local_hostname``
637 ``local_hostname``
638 Optional. It's the hostname that the sender can use to identify
638 Optional. It's the hostname that the sender can use to identify
639 itself to the MTA.
639 itself to the MTA.
640
640
641
641
642 ``patch``
642 ``patch``
643 """""""""
643 """""""""
644 Settings used when applying patches, for instance through the 'import'
644 Settings used when applying patches, for instance through the 'import'
645 command or with Mercurial Queues extension.
645 command or with Mercurial Queues extension.
646
646
647 ``eol``
647 ``eol``
648 When set to 'strict' patch content and patched files end of lines
648 When set to 'strict' patch content and patched files end of lines
649 are preserved. When set to ``lf`` or ``crlf``, both files end of lines
649 are preserved. When set to ``lf`` or ``crlf``, both files end of lines
650 are ignored when patching and the result line endings are
650 are ignored when patching and the result line endings are
651 normalized to either LF (Unix) or CRLF (Windows).
651 normalized to either LF (Unix) or CRLF (Windows). When set to
652 ``auto``, end of lines are again ignored while patching but line
653 endings in patched files are normalized to their original setting
654 on a per-file basis.
652 Default: strict.
655 Default: strict.
653
656
654
657
655 ``paths``
658 ``paths``
656 """""""""
659 """""""""
657 Assigns symbolic names to repositories. The left side is the
660 Assigns symbolic names to repositories. The left side is the
658 symbolic name, and the right gives the directory or URL that is the
661 symbolic name, and the right gives the directory or URL that is the
659 location of the repository. Default paths can be declared by setting
662 location of the repository. Default paths can be declared by setting
660 the following entries.
663 the following entries.
661
664
662 ``default``
665 ``default``
663 Directory or URL to use when pulling if no source is specified.
666 Directory or URL to use when pulling if no source is specified.
664 Default is set to repository from which the current repository was
667 Default is set to repository from which the current repository was
665 cloned.
668 cloned.
666 ``default-push``
669 ``default-push``
667 Optional. Directory or URL to use when pushing if no destination
670 Optional. Directory or URL to use when pushing if no destination
668 is specified.
671 is specified.
669
672
670
673
671 ``profiling``
674 ``profiling``
672 """""""""""""
675 """""""""""""
673 Specifies profiling format and file output. In this section
676 Specifies profiling format and file output. In this section
674 description, 'profiling data' stands for the raw data collected
677 description, 'profiling data' stands for the raw data collected
675 during profiling, while 'profiling report' stands for a statistical
678 during profiling, while 'profiling report' stands for a statistical
676 text report generated from the profiling data. The profiling is done
679 text report generated from the profiling data. The profiling is done
677 using lsprof.
680 using lsprof.
678
681
679 ``format``
682 ``format``
680 Profiling format.
683 Profiling format.
681 Default: text.
684 Default: text.
682
685
683 ``text``
686 ``text``
684 Generate a profiling report. When saving to a file, it should be
687 Generate a profiling report. When saving to a file, it should be
685 noted that only the report is saved, and the profiling data is
688 noted that only the report is saved, and the profiling data is
686 not kept.
689 not kept.
687 ``kcachegrind``
690 ``kcachegrind``
688 Format profiling data for kcachegrind use: when saving to a
691 Format profiling data for kcachegrind use: when saving to a
689 file, the generated file can directly be loaded into
692 file, the generated file can directly be loaded into
690 kcachegrind.
693 kcachegrind.
691 ``output``
694 ``output``
692 File path where profiling data or report should be saved. If the
695 File path where profiling data or report should be saved. If the
693 file exists, it is replaced. Default: None, data is printed on
696 file exists, it is replaced. Default: None, data is printed on
694 stderr
697 stderr
695
698
696 ``server``
699 ``server``
697 """"""""""
700 """"""""""
698 Controls generic server settings.
701 Controls generic server settings.
699
702
700 ``uncompressed``
703 ``uncompressed``
701 Whether to allow clients to clone a repository using the
704 Whether to allow clients to clone a repository using the
702 uncompressed streaming protocol. This transfers about 40% more
705 uncompressed streaming protocol. This transfers about 40% more
703 data than a regular clone, but uses less memory and CPU on both
706 data than a regular clone, but uses less memory and CPU on both
704 server and client. Over a LAN (100 Mbps or better) or a very fast
707 server and client. Over a LAN (100 Mbps or better) or a very fast
705 WAN, an uncompressed streaming clone is a lot faster (~10x) than a
708 WAN, an uncompressed streaming clone is a lot faster (~10x) than a
706 regular clone. Over most WAN connections (anything slower than
709 regular clone. Over most WAN connections (anything slower than
707 about 6 Mbps), uncompressed streaming is slower, because of the
710 about 6 Mbps), uncompressed streaming is slower, because of the
708 extra data transfer overhead. Default is False.
711 extra data transfer overhead. Default is False.
709
712
710
713
711 ``trusted``
714 ``trusted``
712 """""""""""
715 """""""""""
713 For security reasons, Mercurial will not use the settings in the
716 For security reasons, Mercurial will not use the settings in the
714 ``.hg/hgrc`` file from a repository if it doesn't belong to a trusted
717 ``.hg/hgrc`` file from a repository if it doesn't belong to a trusted
715 user or to a trusted group. The main exception is the web interface,
718 user or to a trusted group. The main exception is the web interface,
716 which automatically uses some safe settings, since it's common to
719 which automatically uses some safe settings, since it's common to
717 serve repositories from different users.
720 serve repositories from different users.
718
721
719 This section specifies what users and groups are trusted. The
722 This section specifies what users and groups are trusted. The
720 current user is always trusted. To trust everybody, list a user or a
723 current user is always trusted. To trust everybody, list a user or a
721 group with name ``*``.
724 group with name ``*``.
722
725
723 ``users``
726 ``users``
724 Comma-separated list of trusted users.
727 Comma-separated list of trusted users.
725 ``groups``
728 ``groups``
726 Comma-separated list of trusted groups.
729 Comma-separated list of trusted groups.
727
730
728
731
729 ``ui``
732 ``ui``
730 """"""
733 """"""
731
734
732 User interface controls.
735 User interface controls.
733
736
734 ``archivemeta``
737 ``archivemeta``
735 Whether to include the .hg_archival.txt file containing meta data
738 Whether to include the .hg_archival.txt file containing meta data
736 (hashes for the repository base and for tip) in archives created
739 (hashes for the repository base and for tip) in archives created
737 by the hg archive command or downloaded via hgweb.
740 by the hg archive command or downloaded via hgweb.
738 Default is True.
741 Default is True.
739 ``askusername``
742 ``askusername``
740 Whether to prompt for a username when committing. If True, and
743 Whether to prompt for a username when committing. If True, and
741 neither ``$HGUSER`` nor ``$EMAIL`` has been specified, then the user will
744 neither ``$HGUSER`` nor ``$EMAIL`` has been specified, then the user will
742 be prompted to enter a username. If no username is entered, the
745 be prompted to enter a username. If no username is entered, the
743 default ``USER@HOST`` is used instead.
746 default ``USER@HOST`` is used instead.
744 Default is False.
747 Default is False.
745 ``debug``
748 ``debug``
746 Print debugging information. True or False. Default is False.
749 Print debugging information. True or False. Default is False.
747 ``editor``
750 ``editor``
748 The editor to use during a commit. Default is ``$EDITOR`` or ``vi``.
751 The editor to use during a commit. Default is ``$EDITOR`` or ``vi``.
749 ``fallbackencoding``
752 ``fallbackencoding``
750 Encoding to try if it's not possible to decode the changelog using
753 Encoding to try if it's not possible to decode the changelog using
751 UTF-8. Default is ISO-8859-1.
754 UTF-8. Default is ISO-8859-1.
752 ``ignore``
755 ``ignore``
753 A file to read per-user ignore patterns from. This file should be
756 A file to read per-user ignore patterns from. This file should be
754 in the same format as a repository-wide .hgignore file. This
757 in the same format as a repository-wide .hgignore file. This
755 option supports hook syntax, so if you want to specify multiple
758 option supports hook syntax, so if you want to specify multiple
756 ignore files, you can do so by setting something like
759 ignore files, you can do so by setting something like
757 ``ignore.other = ~/.hgignore2``. For details of the ignore file
760 ``ignore.other = ~/.hgignore2``. For details of the ignore file
758 format, see the |hgignore(5)|_ man page.
761 format, see the |hgignore(5)|_ man page.
759 ``interactive``
762 ``interactive``
760 Allow to prompt the user. True or False. Default is True.
763 Allow to prompt the user. True or False. Default is True.
761 ``logtemplate``
764 ``logtemplate``
762 Template string for commands that print changesets.
765 Template string for commands that print changesets.
763 ``merge``
766 ``merge``
764 The conflict resolution program to use during a manual merge.
767 The conflict resolution program to use during a manual merge.
765 There are some internal tools available:
768 There are some internal tools available:
766
769
767 ``internal:local``
770 ``internal:local``
768 keep the local version
771 keep the local version
769 ``internal:other``
772 ``internal:other``
770 use the other version
773 use the other version
771 ``internal:merge``
774 ``internal:merge``
772 use the internal non-interactive merge tool
775 use the internal non-interactive merge tool
773 ``internal:fail``
776 ``internal:fail``
774 fail to merge
777 fail to merge
775
778
776 For more information on configuring merge tools see the
779 For more information on configuring merge tools see the
777 merge-tools_ section.
780 merge-tools_ section.
778
781
779 ``patch``
782 ``patch``
780 command to use to apply patches. Look for ``gpatch`` or ``patch`` in
783 command to use to apply patches. Look for ``gpatch`` or ``patch`` in
781 PATH if unset.
784 PATH if unset.
782 ``quiet``
785 ``quiet``
783 Reduce the amount of output printed. True or False. Default is False.
786 Reduce the amount of output printed. True or False. Default is False.
784 ``remotecmd``
787 ``remotecmd``
785 remote command to use for clone/push/pull operations. Default is ``hg``.
788 remote command to use for clone/push/pull operations. Default is ``hg``.
786 ``report_untrusted``
789 ``report_untrusted``
787 Warn if a ``.hg/hgrc`` file is ignored due to not being owned by a
790 Warn if a ``.hg/hgrc`` file is ignored due to not being owned by a
788 trusted user or group. True or False. Default is True.
791 trusted user or group. True or False. Default is True.
789 ``slash``
792 ``slash``
790 Display paths using a slash (``/``) as the path separator. This
793 Display paths using a slash (``/``) as the path separator. This
791 only makes a difference on systems where the default path
794 only makes a difference on systems where the default path
792 separator is not the slash character (e.g. Windows uses the
795 separator is not the slash character (e.g. Windows uses the
793 backslash character (``\``)).
796 backslash character (``\``)).
794 Default is False.
797 Default is False.
795 ``ssh``
798 ``ssh``
796 command to use for SSH connections. Default is ``ssh``.
799 command to use for SSH connections. Default is ``ssh``.
797 ``strict``
800 ``strict``
798 Require exact command names, instead of allowing unambiguous
801 Require exact command names, instead of allowing unambiguous
799 abbreviations. True or False. Default is False.
802 abbreviations. True or False. Default is False.
800 ``style``
803 ``style``
801 Name of style to use for command output.
804 Name of style to use for command output.
802 ``timeout``
805 ``timeout``
803 The timeout used when a lock is held (in seconds), a negative value
806 The timeout used when a lock is held (in seconds), a negative value
804 means no timeout. Default is 600.
807 means no timeout. Default is 600.
805 ``traceback``
808 ``traceback``
806 Mercurial always prints a traceback when an unknown exception
809 Mercurial always prints a traceback when an unknown exception
807 occurs. Setting this to True will make Mercurial print a traceback
810 occurs. Setting this to True will make Mercurial print a traceback
808 on all exceptions, even those recognized by Mercurial (such as
811 on all exceptions, even those recognized by Mercurial (such as
809 IOError or MemoryError). Default is False.
812 IOError or MemoryError). Default is False.
810 ``username``
813 ``username``
811 The committer of a changeset created when running "commit".
814 The committer of a changeset created when running "commit".
812 Typically a person's name and email address, e.g. ``Fred Widget
815 Typically a person's name and email address, e.g. ``Fred Widget
813 <fred@example.com>``. Default is ``$EMAIL`` or ``username@hostname``. If
816 <fred@example.com>``. Default is ``$EMAIL`` or ``username@hostname``. If
814 the username in hgrc is empty, it has to be specified manually or
817 the username in hgrc is empty, it has to be specified manually or
815 in a different hgrc file (e.g. ``$HOME/.hgrc``, if the admin set
818 in a different hgrc file (e.g. ``$HOME/.hgrc``, if the admin set
816 ``username =`` in the system hgrc).
819 ``username =`` in the system hgrc).
817 ``verbose``
820 ``verbose``
818 Increase the amount of output printed. True or False. Default is False.
821 Increase the amount of output printed. True or False. Default is False.
819
822
820
823
821 ``web``
824 ``web``
822 """""""
825 """""""
823 Web interface configuration.
826 Web interface configuration.
824
827
825 ``accesslog``
828 ``accesslog``
826 Where to output the access log. Default is stdout.
829 Where to output the access log. Default is stdout.
827 ``address``
830 ``address``
828 Interface address to bind to. Default is all.
831 Interface address to bind to. Default is all.
829 ``allow_archive``
832 ``allow_archive``
830 List of archive format (bz2, gz, zip) allowed for downloading.
833 List of archive format (bz2, gz, zip) allowed for downloading.
831 Default is empty.
834 Default is empty.
832 ``allowbz2``
835 ``allowbz2``
833 (DEPRECATED) Whether to allow .tar.bz2 downloading of repository
836 (DEPRECATED) Whether to allow .tar.bz2 downloading of repository
834 revisions.
837 revisions.
835 Default is False.
838 Default is False.
836 ``allowgz``
839 ``allowgz``
837 (DEPRECATED) Whether to allow .tar.gz downloading of repository
840 (DEPRECATED) Whether to allow .tar.gz downloading of repository
838 revisions.
841 revisions.
839 Default is False.
842 Default is False.
840 ``allowpull``
843 ``allowpull``
841 Whether to allow pulling from the repository. Default is True.
844 Whether to allow pulling from the repository. Default is True.
842 ``allow_push``
845 ``allow_push``
843 Whether to allow pushing to the repository. If empty or not set,
846 Whether to allow pushing to the repository. If empty or not set,
844 push is not allowed. If the special value ``*``, any remote user can
847 push is not allowed. If the special value ``*``, any remote user can
845 push, including unauthenticated users. Otherwise, the remote user
848 push, including unauthenticated users. Otherwise, the remote user
846 must have been authenticated, and the authenticated user name must
849 must have been authenticated, and the authenticated user name must
847 be present in this list (separated by whitespace or ``,``). The
850 be present in this list (separated by whitespace or ``,``). The
848 contents of the allow_push list are examined after the deny_push
851 contents of the allow_push list are examined after the deny_push
849 list.
852 list.
850 ``allow_read``
853 ``allow_read``
851 If the user has not already been denied repository access due to
854 If the user has not already been denied repository access due to
852 the contents of deny_read, this list determines whether to grant
855 the contents of deny_read, this list determines whether to grant
853 repository access to the user. If this list is not empty, and the
856 repository access to the user. If this list is not empty, and the
854 user is unauthenticated or not present in the list (separated by
857 user is unauthenticated or not present in the list (separated by
855 whitespace or ``,``), then access is denied for the user. If the
858 whitespace or ``,``), then access is denied for the user. If the
856 list is empty or not set, then access is permitted to all users by
859 list is empty or not set, then access is permitted to all users by
857 default. Setting allow_read to the special value ``*`` is equivalent
860 default. Setting allow_read to the special value ``*`` is equivalent
858 to it not being set (i.e. access is permitted to all users). The
861 to it not being set (i.e. access is permitted to all users). The
859 contents of the allow_read list are examined after the deny_read
862 contents of the allow_read list are examined after the deny_read
860 list.
863 list.
861 ``allowzip``
864 ``allowzip``
862 (DEPRECATED) Whether to allow .zip downloading of repository
865 (DEPRECATED) Whether to allow .zip downloading of repository
863 revisions. Default is False. This feature creates temporary files.
866 revisions. Default is False. This feature creates temporary files.
864 ``baseurl``
867 ``baseurl``
865 Base URL to use when publishing URLs in other locations, so
868 Base URL to use when publishing URLs in other locations, so
866 third-party tools like email notification hooks can construct
869 third-party tools like email notification hooks can construct
867 URLs. Example: ``http://hgserver/repos/``.
870 URLs. Example: ``http://hgserver/repos/``.
868 ``contact``
871 ``contact``
869 Name or email address of the person in charge of the repository.
872 Name or email address of the person in charge of the repository.
870 Defaults to ui.username or ``$EMAIL`` or "unknown" if unset or empty.
873 Defaults to ui.username or ``$EMAIL`` or "unknown" if unset or empty.
871 ``deny_push``
874 ``deny_push``
872 Whether to deny pushing to the repository. If empty or not set,
875 Whether to deny pushing to the repository. If empty or not set,
873 push is not denied. If the special value ``*``, all remote users are
876 push is not denied. If the special value ``*``, all remote users are
874 denied push. Otherwise, unauthenticated users are all denied, and
877 denied push. Otherwise, unauthenticated users are all denied, and
875 any authenticated user name present in this list (separated by
878 any authenticated user name present in this list (separated by
876 whitespace or ``,``) is also denied. The contents of the deny_push
879 whitespace or ``,``) is also denied. The contents of the deny_push
877 list are examined before the allow_push list.
880 list are examined before the allow_push list.
878 ``deny_read``
881 ``deny_read``
879 Whether to deny reading/viewing of the repository. If this list is
882 Whether to deny reading/viewing of the repository. If this list is
880 not empty, unauthenticated users are all denied, and any
883 not empty, unauthenticated users are all denied, and any
881 authenticated user name present in this list (separated by
884 authenticated user name present in this list (separated by
882 whitespace or ``,``) is also denied access to the repository. If set
885 whitespace or ``,``) is also denied access to the repository. If set
883 to the special value ``*``, all remote users are denied access
886 to the special value ``*``, all remote users are denied access
884 (rarely needed ;). If deny_read is empty or not set, the
887 (rarely needed ;). If deny_read is empty or not set, the
885 determination of repository access depends on the presence and
888 determination of repository access depends on the presence and
886 content of the allow_read list (see description). If both
889 content of the allow_read list (see description). If both
887 deny_read and allow_read are empty or not set, then access is
890 deny_read and allow_read are empty or not set, then access is
888 permitted to all users by default. If the repository is being
891 permitted to all users by default. If the repository is being
889 served via hgwebdir, denied users will not be able to see it in
892 served via hgwebdir, denied users will not be able to see it in
890 the list of repositories. The contents of the deny_read list have
893 the list of repositories. The contents of the deny_read list have
891 priority over (are examined before) the contents of the allow_read
894 priority over (are examined before) the contents of the allow_read
892 list.
895 list.
893 ``descend``
896 ``descend``
894 hgwebdir indexes will not descend into subdirectories. Only repositories
897 hgwebdir indexes will not descend into subdirectories. Only repositories
895 directly in the current path will be shown (other repositories are still
898 directly in the current path will be shown (other repositories are still
896 available from the index corresponding to their containing path).
899 available from the index corresponding to their containing path).
897 ``description``
900 ``description``
898 Textual description of the repository's purpose or contents.
901 Textual description of the repository's purpose or contents.
899 Default is "unknown".
902 Default is "unknown".
900 ``encoding``
903 ``encoding``
901 Character encoding name.
904 Character encoding name.
902 Example: "UTF-8"
905 Example: "UTF-8"
903 ``errorlog``
906 ``errorlog``
904 Where to output the error log. Default is stderr.
907 Where to output the error log. Default is stderr.
905 ``hidden``
908 ``hidden``
906 Whether to hide the repository in the hgwebdir index.
909 Whether to hide the repository in the hgwebdir index.
907 Default is False.
910 Default is False.
908 ``ipv6``
911 ``ipv6``
909 Whether to use IPv6. Default is False.
912 Whether to use IPv6. Default is False.
910 ``name``
913 ``name``
911 Repository name to use in the web interface. Default is current
914 Repository name to use in the web interface. Default is current
912 working directory.
915 working directory.
913 ``maxchanges``
916 ``maxchanges``
914 Maximum number of changes to list on the changelog. Default is 10.
917 Maximum number of changes to list on the changelog. Default is 10.
915 ``maxfiles``
918 ``maxfiles``
916 Maximum number of files to list per changeset. Default is 10.
919 Maximum number of files to list per changeset. Default is 10.
917 ``port``
920 ``port``
918 Port to listen on. Default is 8000.
921 Port to listen on. Default is 8000.
919 ``prefix``
922 ``prefix``
920 Prefix path to serve from. Default is '' (server root).
923 Prefix path to serve from. Default is '' (server root).
921 ``push_ssl``
924 ``push_ssl``
922 Whether to require that inbound pushes be transported over SSL to
925 Whether to require that inbound pushes be transported over SSL to
923 prevent password sniffing. Default is True.
926 prevent password sniffing. Default is True.
924 ``staticurl``
927 ``staticurl``
925 Base URL to use for static files. If unset, static files (e.g. the
928 Base URL to use for static files. If unset, static files (e.g. the
926 hgicon.png favicon) will be served by the CGI script itself. Use
929 hgicon.png favicon) will be served by the CGI script itself. Use
927 this setting to serve them directly with the HTTP server.
930 this setting to serve them directly with the HTTP server.
928 Example: ``http://hgserver/static/``.
931 Example: ``http://hgserver/static/``.
929 ``stripes``
932 ``stripes``
930 How many lines a "zebra stripe" should span in multiline output.
933 How many lines a "zebra stripe" should span in multiline output.
931 Default is 1; set to 0 to disable.
934 Default is 1; set to 0 to disable.
932 ``style``
935 ``style``
933 Which template map style to use.
936 Which template map style to use.
934 ``templates``
937 ``templates``
935 Where to find the HTML templates. Default is install path.
938 Where to find the HTML templates. Default is install path.
936
939
937
940
938 Author
941 Author
939 ------
942 ------
940 Bryan O'Sullivan <bos@serpentine.com>.
943 Bryan O'Sullivan <bos@serpentine.com>.
941
944
942 Mercurial was written by Matt Mackall <mpm@selenic.com>.
945 Mercurial was written by Matt Mackall <mpm@selenic.com>.
943
946
944 See Also
947 See Also
945 --------
948 --------
946 |hg(1)|_, |hgignore(5)|_
949 |hg(1)|_, |hgignore(5)|_
947
950
948 Copying
951 Copying
949 -------
952 -------
950 This manual page is copyright 2005 Bryan O'Sullivan.
953 This manual page is copyright 2005 Bryan O'Sullivan.
951 Mercurial is copyright 2005-2009 Matt Mackall.
954 Mercurial is copyright 2005-2009 Matt Mackall.
952 Free use of this software is granted under the terms of the GNU General
955 Free use of this software is granted under the terms of the GNU General
953 Public License version 2.
956 Public License version 2.
954
957
955 .. include:: common.txt
958 .. include:: common.txt
@@ -1,1431 +1,1447 b''
1 # patch.py - patch file parsing routines
1 # patch.py - patch file parsing routines
2 #
2 #
3 # Copyright 2006 Brendan Cully <brendan@kublai.com>
3 # Copyright 2006 Brendan Cully <brendan@kublai.com>
4 # Copyright 2007 Chris Mason <chris.mason@oracle.com>
4 # Copyright 2007 Chris Mason <chris.mason@oracle.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, incorporated herein by reference.
7 # GNU General Public License version 2, incorporated herein by reference.
8
8
9 from i18n import _
9 from i18n import _
10 from node import hex, nullid, short
10 from node import hex, nullid, short
11 import base85, cmdutil, mdiff, util, diffhelpers, copies
11 import base85, cmdutil, mdiff, util, diffhelpers, copies
12 import cStringIO, email.Parser, os, re
12 import cStringIO, email.Parser, os, re
13 import sys, tempfile, zlib
13 import sys, tempfile, zlib
14
14
15 gitre = re.compile('diff --git a/(.*) b/(.*)')
15 gitre = re.compile('diff --git a/(.*) b/(.*)')
16
16
17 class PatchError(Exception):
17 class PatchError(Exception):
18 pass
18 pass
19
19
20 class NoHunks(PatchError):
20 class NoHunks(PatchError):
21 pass
21 pass
22
22
23 # helper functions
23 # helper functions
24
24
25 def copyfile(src, dst, basedir):
25 def copyfile(src, dst, basedir):
26 abssrc, absdst = [util.canonpath(basedir, basedir, x) for x in [src, dst]]
26 abssrc, absdst = [util.canonpath(basedir, basedir, x) for x in [src, dst]]
27 if os.path.exists(absdst):
27 if os.path.exists(absdst):
28 raise util.Abort(_("cannot create %s: destination already exists") %
28 raise util.Abort(_("cannot create %s: destination already exists") %
29 dst)
29 dst)
30
30
31 dstdir = os.path.dirname(absdst)
31 dstdir = os.path.dirname(absdst)
32 if dstdir and not os.path.isdir(dstdir):
32 if dstdir and not os.path.isdir(dstdir):
33 try:
33 try:
34 os.makedirs(dstdir)
34 os.makedirs(dstdir)
35 except IOError:
35 except IOError:
36 raise util.Abort(
36 raise util.Abort(
37 _("cannot create %s: unable to create destination directory")
37 _("cannot create %s: unable to create destination directory")
38 % dst)
38 % dst)
39
39
40 util.copyfile(abssrc, absdst)
40 util.copyfile(abssrc, absdst)
41
41
42 # public functions
42 # public functions
43
43
44 def extract(ui, fileobj):
44 def extract(ui, fileobj):
45 '''extract patch from data read from fileobj.
45 '''extract patch from data read from fileobj.
46
46
47 patch can be a normal patch or contained in an email message.
47 patch can be a normal patch or contained in an email message.
48
48
49 return tuple (filename, message, user, date, node, p1, p2).
49 return tuple (filename, message, user, date, node, p1, p2).
50 Any item in the returned tuple can be None. If filename is None,
50 Any item in the returned tuple can be None. If filename is None,
51 fileobj did not contain a patch. Caller must unlink filename when done.'''
51 fileobj did not contain a patch. Caller must unlink filename when done.'''
52
52
53 # attempt to detect the start of a patch
53 # attempt to detect the start of a patch
54 # (this heuristic is borrowed from quilt)
54 # (this heuristic is borrowed from quilt)
55 diffre = re.compile(r'^(?:Index:[ \t]|diff[ \t]|RCS file: |'
55 diffre = re.compile(r'^(?:Index:[ \t]|diff[ \t]|RCS file: |'
56 r'retrieving revision [0-9]+(\.[0-9]+)*$|'
56 r'retrieving revision [0-9]+(\.[0-9]+)*$|'
57 r'(---|\*\*\*)[ \t])', re.MULTILINE)
57 r'(---|\*\*\*)[ \t])', re.MULTILINE)
58
58
59 fd, tmpname = tempfile.mkstemp(prefix='hg-patch-')
59 fd, tmpname = tempfile.mkstemp(prefix='hg-patch-')
60 tmpfp = os.fdopen(fd, 'w')
60 tmpfp = os.fdopen(fd, 'w')
61 try:
61 try:
62 msg = email.Parser.Parser().parse(fileobj)
62 msg = email.Parser.Parser().parse(fileobj)
63
63
64 subject = msg['Subject']
64 subject = msg['Subject']
65 user = msg['From']
65 user = msg['From']
66 if not subject and not user:
66 if not subject and not user:
67 # Not an email, restore parsed headers if any
67 # Not an email, restore parsed headers if any
68 subject = '\n'.join(': '.join(h) for h in msg.items()) + '\n'
68 subject = '\n'.join(': '.join(h) for h in msg.items()) + '\n'
69
69
70 gitsendmail = 'git-send-email' in msg.get('X-Mailer', '')
70 gitsendmail = 'git-send-email' in msg.get('X-Mailer', '')
71 # should try to parse msg['Date']
71 # should try to parse msg['Date']
72 date = None
72 date = None
73 nodeid = None
73 nodeid = None
74 branch = None
74 branch = None
75 parents = []
75 parents = []
76
76
77 if subject:
77 if subject:
78 if subject.startswith('[PATCH'):
78 if subject.startswith('[PATCH'):
79 pend = subject.find(']')
79 pend = subject.find(']')
80 if pend >= 0:
80 if pend >= 0:
81 subject = subject[pend+1:].lstrip()
81 subject = subject[pend+1:].lstrip()
82 subject = subject.replace('\n\t', ' ')
82 subject = subject.replace('\n\t', ' ')
83 ui.debug('Subject: %s\n' % subject)
83 ui.debug('Subject: %s\n' % subject)
84 if user:
84 if user:
85 ui.debug('From: %s\n' % user)
85 ui.debug('From: %s\n' % user)
86 diffs_seen = 0
86 diffs_seen = 0
87 ok_types = ('text/plain', 'text/x-diff', 'text/x-patch')
87 ok_types = ('text/plain', 'text/x-diff', 'text/x-patch')
88 message = ''
88 message = ''
89 for part in msg.walk():
89 for part in msg.walk():
90 content_type = part.get_content_type()
90 content_type = part.get_content_type()
91 ui.debug('Content-Type: %s\n' % content_type)
91 ui.debug('Content-Type: %s\n' % content_type)
92 if content_type not in ok_types:
92 if content_type not in ok_types:
93 continue
93 continue
94 payload = part.get_payload(decode=True)
94 payload = part.get_payload(decode=True)
95 m = diffre.search(payload)
95 m = diffre.search(payload)
96 if m:
96 if m:
97 hgpatch = False
97 hgpatch = False
98 ignoretext = False
98 ignoretext = False
99
99
100 ui.debug('found patch at byte %d\n' % m.start(0))
100 ui.debug('found patch at byte %d\n' % m.start(0))
101 diffs_seen += 1
101 diffs_seen += 1
102 cfp = cStringIO.StringIO()
102 cfp = cStringIO.StringIO()
103 for line in payload[:m.start(0)].splitlines():
103 for line in payload[:m.start(0)].splitlines():
104 if line.startswith('# HG changeset patch'):
104 if line.startswith('# HG changeset patch'):
105 ui.debug('patch generated by hg export\n')
105 ui.debug('patch generated by hg export\n')
106 hgpatch = True
106 hgpatch = True
107 # drop earlier commit message content
107 # drop earlier commit message content
108 cfp.seek(0)
108 cfp.seek(0)
109 cfp.truncate()
109 cfp.truncate()
110 subject = None
110 subject = None
111 elif hgpatch:
111 elif hgpatch:
112 if line.startswith('# User '):
112 if line.startswith('# User '):
113 user = line[7:]
113 user = line[7:]
114 ui.debug('From: %s\n' % user)
114 ui.debug('From: %s\n' % user)
115 elif line.startswith("# Date "):
115 elif line.startswith("# Date "):
116 date = line[7:]
116 date = line[7:]
117 elif line.startswith("# Branch "):
117 elif line.startswith("# Branch "):
118 branch = line[9:]
118 branch = line[9:]
119 elif line.startswith("# Node ID "):
119 elif line.startswith("# Node ID "):
120 nodeid = line[10:]
120 nodeid = line[10:]
121 elif line.startswith("# Parent "):
121 elif line.startswith("# Parent "):
122 parents.append(line[10:])
122 parents.append(line[10:])
123 elif line == '---' and gitsendmail:
123 elif line == '---' and gitsendmail:
124 ignoretext = True
124 ignoretext = True
125 if not line.startswith('# ') and not ignoretext:
125 if not line.startswith('# ') and not ignoretext:
126 cfp.write(line)
126 cfp.write(line)
127 cfp.write('\n')
127 cfp.write('\n')
128 message = cfp.getvalue()
128 message = cfp.getvalue()
129 if tmpfp:
129 if tmpfp:
130 tmpfp.write(payload)
130 tmpfp.write(payload)
131 if not payload.endswith('\n'):
131 if not payload.endswith('\n'):
132 tmpfp.write('\n')
132 tmpfp.write('\n')
133 elif not diffs_seen and message and content_type == 'text/plain':
133 elif not diffs_seen and message and content_type == 'text/plain':
134 message += '\n' + payload
134 message += '\n' + payload
135 except:
135 except:
136 tmpfp.close()
136 tmpfp.close()
137 os.unlink(tmpname)
137 os.unlink(tmpname)
138 raise
138 raise
139
139
140 if subject and not message.startswith(subject):
140 if subject and not message.startswith(subject):
141 message = '%s\n%s' % (subject, message)
141 message = '%s\n%s' % (subject, message)
142 tmpfp.close()
142 tmpfp.close()
143 if not diffs_seen:
143 if not diffs_seen:
144 os.unlink(tmpname)
144 os.unlink(tmpname)
145 return None, message, user, date, branch, None, None, None
145 return None, message, user, date, branch, None, None, None
146 p1 = parents and parents.pop(0) or None
146 p1 = parents and parents.pop(0) or None
147 p2 = parents and parents.pop(0) or None
147 p2 = parents and parents.pop(0) or None
148 return tmpname, message, user, date, branch, nodeid, p1, p2
148 return tmpname, message, user, date, branch, nodeid, p1, p2
149
149
150 GP_PATCH = 1 << 0 # we have to run patch
150 GP_PATCH = 1 << 0 # we have to run patch
151 GP_FILTER = 1 << 1 # there's some copy/rename operation
151 GP_FILTER = 1 << 1 # there's some copy/rename operation
152 GP_BINARY = 1 << 2 # there's a binary patch
152 GP_BINARY = 1 << 2 # there's a binary patch
153
153
154 class patchmeta(object):
154 class patchmeta(object):
155 """Patched file metadata
155 """Patched file metadata
156
156
157 'op' is the performed operation within ADD, DELETE, RENAME, MODIFY
157 'op' is the performed operation within ADD, DELETE, RENAME, MODIFY
158 or COPY. 'path' is patched file path. 'oldpath' is set to the
158 or COPY. 'path' is patched file path. 'oldpath' is set to the
159 origin file when 'op' is either COPY or RENAME, None otherwise. If
159 origin file when 'op' is either COPY or RENAME, None otherwise. If
160 file mode is changed, 'mode' is a tuple (islink, isexec) where
160 file mode is changed, 'mode' is a tuple (islink, isexec) where
161 'islink' is True if the file is a symlink and 'isexec' is True if
161 'islink' is True if the file is a symlink and 'isexec' is True if
162 the file is executable. Otherwise, 'mode' is None.
162 the file is executable. Otherwise, 'mode' is None.
163 """
163 """
164 def __init__(self, path):
164 def __init__(self, path):
165 self.path = path
165 self.path = path
166 self.oldpath = None
166 self.oldpath = None
167 self.mode = None
167 self.mode = None
168 self.op = 'MODIFY'
168 self.op = 'MODIFY'
169 self.lineno = 0
169 self.lineno = 0
170 self.binary = False
170 self.binary = False
171
171
172 def setmode(self, mode):
172 def setmode(self, mode):
173 islink = mode & 020000
173 islink = mode & 020000
174 isexec = mode & 0100
174 isexec = mode & 0100
175 self.mode = (islink, isexec)
175 self.mode = (islink, isexec)
176
176
177 def readgitpatch(lr):
177 def readgitpatch(lr):
178 """extract git-style metadata about patches from <patchname>"""
178 """extract git-style metadata about patches from <patchname>"""
179
179
180 # Filter patch for git information
180 # Filter patch for git information
181 gp = None
181 gp = None
182 gitpatches = []
182 gitpatches = []
183 # Can have a git patch with only metadata, causing patch to complain
183 # Can have a git patch with only metadata, causing patch to complain
184 dopatch = 0
184 dopatch = 0
185
185
186 lineno = 0
186 lineno = 0
187 for line in lr:
187 for line in lr:
188 lineno += 1
188 lineno += 1
189 line = line.rstrip(' \r\n')
189 line = line.rstrip(' \r\n')
190 if line.startswith('diff --git'):
190 if line.startswith('diff --git'):
191 m = gitre.match(line)
191 m = gitre.match(line)
192 if m:
192 if m:
193 if gp:
193 if gp:
194 gitpatches.append(gp)
194 gitpatches.append(gp)
195 dst = m.group(2)
195 dst = m.group(2)
196 gp = patchmeta(dst)
196 gp = patchmeta(dst)
197 gp.lineno = lineno
197 gp.lineno = lineno
198 elif gp:
198 elif gp:
199 if line.startswith('--- '):
199 if line.startswith('--- '):
200 if gp.op in ('COPY', 'RENAME'):
200 if gp.op in ('COPY', 'RENAME'):
201 dopatch |= GP_FILTER
201 dopatch |= GP_FILTER
202 gitpatches.append(gp)
202 gitpatches.append(gp)
203 gp = None
203 gp = None
204 dopatch |= GP_PATCH
204 dopatch |= GP_PATCH
205 continue
205 continue
206 if line.startswith('rename from '):
206 if line.startswith('rename from '):
207 gp.op = 'RENAME'
207 gp.op = 'RENAME'
208 gp.oldpath = line[12:]
208 gp.oldpath = line[12:]
209 elif line.startswith('rename to '):
209 elif line.startswith('rename to '):
210 gp.path = line[10:]
210 gp.path = line[10:]
211 elif line.startswith('copy from '):
211 elif line.startswith('copy from '):
212 gp.op = 'COPY'
212 gp.op = 'COPY'
213 gp.oldpath = line[10:]
213 gp.oldpath = line[10:]
214 elif line.startswith('copy to '):
214 elif line.startswith('copy to '):
215 gp.path = line[8:]
215 gp.path = line[8:]
216 elif line.startswith('deleted file'):
216 elif line.startswith('deleted file'):
217 gp.op = 'DELETE'
217 gp.op = 'DELETE'
218 # is the deleted file a symlink?
218 # is the deleted file a symlink?
219 gp.setmode(int(line[-6:], 8))
219 gp.setmode(int(line[-6:], 8))
220 elif line.startswith('new file mode '):
220 elif line.startswith('new file mode '):
221 gp.op = 'ADD'
221 gp.op = 'ADD'
222 gp.setmode(int(line[-6:], 8))
222 gp.setmode(int(line[-6:], 8))
223 elif line.startswith('new mode '):
223 elif line.startswith('new mode '):
224 gp.setmode(int(line[-6:], 8))
224 gp.setmode(int(line[-6:], 8))
225 elif line.startswith('GIT binary patch'):
225 elif line.startswith('GIT binary patch'):
226 dopatch |= GP_BINARY
226 dopatch |= GP_BINARY
227 gp.binary = True
227 gp.binary = True
228 if gp:
228 if gp:
229 gitpatches.append(gp)
229 gitpatches.append(gp)
230
230
231 if not gitpatches:
231 if not gitpatches:
232 dopatch = GP_PATCH
232 dopatch = GP_PATCH
233
233
234 return (dopatch, gitpatches)
234 return (dopatch, gitpatches)
235
235
236 class linereader(object):
236 class linereader(object):
237 # simple class to allow pushing lines back into the input stream
237 # simple class to allow pushing lines back into the input stream
238 def __init__(self, fp, textmode=False):
238 def __init__(self, fp, textmode=False):
239 self.fp = fp
239 self.fp = fp
240 self.buf = []
240 self.buf = []
241 self.textmode = textmode
241 self.textmode = textmode
242 self.eol = None
242
243
243 def push(self, line):
244 def push(self, line):
244 if line is not None:
245 if line is not None:
245 self.buf.append(line)
246 self.buf.append(line)
246
247
247 def readline(self):
248 def readline(self):
248 if self.buf:
249 if self.buf:
249 l = self.buf[0]
250 l = self.buf[0]
250 del self.buf[0]
251 del self.buf[0]
251 return l
252 return l
252 l = self.fp.readline()
253 l = self.fp.readline()
254 if not self.eol:
255 if l.endswith('\r\n'):
256 self.eol = '\r\n'
257 elif l.endswith('\n'):
258 self.eol = '\n'
253 if self.textmode and l.endswith('\r\n'):
259 if self.textmode and l.endswith('\r\n'):
254 l = l[:-2] + '\n'
260 l = l[:-2] + '\n'
255 return l
261 return l
256
262
257 def __iter__(self):
263 def __iter__(self):
258 while 1:
264 while 1:
259 l = self.readline()
265 l = self.readline()
260 if not l:
266 if not l:
261 break
267 break
262 yield l
268 yield l
263
269
264 # @@ -start,len +start,len @@ or @@ -start +start @@ if len is 1
270 # @@ -start,len +start,len @@ or @@ -start +start @@ if len is 1
265 unidesc = re.compile('@@ -(\d+)(,(\d+))? \+(\d+)(,(\d+))? @@')
271 unidesc = re.compile('@@ -(\d+)(,(\d+))? \+(\d+)(,(\d+))? @@')
266 contextdesc = re.compile('(---|\*\*\*) (\d+)(,(\d+))? (---|\*\*\*)')
272 contextdesc = re.compile('(---|\*\*\*) (\d+)(,(\d+))? (---|\*\*\*)')
267 eolmodes = ['strict', 'crlf', 'lf']
273 eolmodes = ['strict', 'crlf', 'lf', 'auto']
268
274
269 class patchfile(object):
275 class patchfile(object):
270 def __init__(self, ui, fname, opener, missing=False, eolmode='strict'):
276 def __init__(self, ui, fname, opener, missing=False, eolmode='strict'):
271 self.fname = fname
277 self.fname = fname
272 self.eolmode = eolmode
278 self.eolmode = eolmode
273 self.eol = {'strict': None, 'crlf': '\r\n', 'lf': '\n'}[eolmode]
279 self.eol = None
274 self.opener = opener
280 self.opener = opener
275 self.ui = ui
281 self.ui = ui
276 self.lines = []
282 self.lines = []
277 self.exists = False
283 self.exists = False
278 self.missing = missing
284 self.missing = missing
279 if not missing:
285 if not missing:
280 try:
286 try:
281 self.lines = self.readlines(fname)
287 self.lines = self.readlines(fname)
282 self.exists = True
288 self.exists = True
283 except IOError:
289 except IOError:
284 pass
290 pass
285 else:
291 else:
286 self.ui.warn(_("unable to find '%s' for patching\n") % self.fname)
292 self.ui.warn(_("unable to find '%s' for patching\n") % self.fname)
287
293
288 self.hash = {}
294 self.hash = {}
289 self.dirty = 0
295 self.dirty = 0
290 self.offset = 0
296 self.offset = 0
291 self.rej = []
297 self.rej = []
292 self.fileprinted = False
298 self.fileprinted = False
293 self.printfile(False)
299 self.printfile(False)
294 self.hunks = 0
300 self.hunks = 0
295
301
296 def readlines(self, fname):
302 def readlines(self, fname):
297 if os.path.islink(fname):
303 if os.path.islink(fname):
298 return [os.readlink(fname)]
304 return [os.readlink(fname)]
299 fp = self.opener(fname, 'r')
305 fp = self.opener(fname, 'r')
300 try:
306 try:
301 return list(linereader(fp, self.eolmode != 'strict'))
307 lr = linereader(fp, self.eolmode != 'strict')
308 lines = list(lr)
309 self.eol = lr.eol
310 return lines
302 finally:
311 finally:
303 fp.close()
312 fp.close()
304
313
305 def writelines(self, fname, lines):
314 def writelines(self, fname, lines):
306 # Ensure supplied data ends in fname, being a regular file or
315 # Ensure supplied data ends in fname, being a regular file or
307 # a symlink. updatedir() will -too magically- take care of
316 # a symlink. updatedir() will -too magically- take care of
308 # setting it to the proper type afterwards.
317 # setting it to the proper type afterwards.
309 islink = os.path.islink(fname)
318 islink = os.path.islink(fname)
310 if islink:
319 if islink:
311 fp = cStringIO.StringIO()
320 fp = cStringIO.StringIO()
312 else:
321 else:
313 fp = self.opener(fname, 'w')
322 fp = self.opener(fname, 'w')
314 try:
323 try:
315 if self.eol and self.eol != '\n':
324 if self.eolmode == 'auto' and self.eol:
325 eol = self.eol
326 elif self.eolmode == 'crlf':
327 eol = '\r\n'
328 else:
329 eol = '\n'
330
331 if self.eolmode != 'strict' and eol != '\n':
316 for l in lines:
332 for l in lines:
317 if l and l[-1] == '\n':
333 if l and l[-1] == '\n':
318 l = l[:-1] + self.eol
334 l = l[:-1] + eol
319 fp.write(l)
335 fp.write(l)
320 else:
336 else:
321 fp.writelines(lines)
337 fp.writelines(lines)
322 if islink:
338 if islink:
323 self.opener.symlink(fp.getvalue(), fname)
339 self.opener.symlink(fp.getvalue(), fname)
324 finally:
340 finally:
325 fp.close()
341 fp.close()
326
342
327 def unlink(self, fname):
343 def unlink(self, fname):
328 os.unlink(fname)
344 os.unlink(fname)
329
345
330 def printfile(self, warn):
346 def printfile(self, warn):
331 if self.fileprinted:
347 if self.fileprinted:
332 return
348 return
333 if warn or self.ui.verbose:
349 if warn or self.ui.verbose:
334 self.fileprinted = True
350 self.fileprinted = True
335 s = _("patching file %s\n") % self.fname
351 s = _("patching file %s\n") % self.fname
336 if warn:
352 if warn:
337 self.ui.warn(s)
353 self.ui.warn(s)
338 else:
354 else:
339 self.ui.note(s)
355 self.ui.note(s)
340
356
341
357
342 def findlines(self, l, linenum):
358 def findlines(self, l, linenum):
343 # looks through the hash and finds candidate lines. The
359 # looks through the hash and finds candidate lines. The
344 # result is a list of line numbers sorted based on distance
360 # result is a list of line numbers sorted based on distance
345 # from linenum
361 # from linenum
346
362
347 cand = self.hash.get(l, [])
363 cand = self.hash.get(l, [])
348 if len(cand) > 1:
364 if len(cand) > 1:
349 # resort our list of potentials forward then back.
365 # resort our list of potentials forward then back.
350 cand.sort(key=lambda x: abs(x - linenum))
366 cand.sort(key=lambda x: abs(x - linenum))
351 return cand
367 return cand
352
368
353 def hashlines(self):
369 def hashlines(self):
354 self.hash = {}
370 self.hash = {}
355 for x, s in enumerate(self.lines):
371 for x, s in enumerate(self.lines):
356 self.hash.setdefault(s, []).append(x)
372 self.hash.setdefault(s, []).append(x)
357
373
358 def write_rej(self):
374 def write_rej(self):
359 # our rejects are a little different from patch(1). This always
375 # our rejects are a little different from patch(1). This always
360 # creates rejects in the same form as the original patch. A file
376 # creates rejects in the same form as the original patch. A file
361 # header is inserted so that you can run the reject through patch again
377 # header is inserted so that you can run the reject through patch again
362 # without having to type the filename.
378 # without having to type the filename.
363
379
364 if not self.rej:
380 if not self.rej:
365 return
381 return
366
382
367 fname = self.fname + ".rej"
383 fname = self.fname + ".rej"
368 self.ui.warn(
384 self.ui.warn(
369 _("%d out of %d hunks FAILED -- saving rejects to file %s\n") %
385 _("%d out of %d hunks FAILED -- saving rejects to file %s\n") %
370 (len(self.rej), self.hunks, fname))
386 (len(self.rej), self.hunks, fname))
371
387
372 def rejlines():
388 def rejlines():
373 base = os.path.basename(self.fname)
389 base = os.path.basename(self.fname)
374 yield "--- %s\n+++ %s\n" % (base, base)
390 yield "--- %s\n+++ %s\n" % (base, base)
375 for x in self.rej:
391 for x in self.rej:
376 for l in x.hunk:
392 for l in x.hunk:
377 yield l
393 yield l
378 if l[-1] != '\n':
394 if l[-1] != '\n':
379 yield "\n\ No newline at end of file\n"
395 yield "\n\ No newline at end of file\n"
380
396
381 self.writelines(fname, rejlines())
397 self.writelines(fname, rejlines())
382
398
383 def write(self, dest=None):
399 def write(self, dest=None):
384 if not self.dirty:
400 if not self.dirty:
385 return
401 return
386 if not dest:
402 if not dest:
387 dest = self.fname
403 dest = self.fname
388 self.writelines(dest, self.lines)
404 self.writelines(dest, self.lines)
389
405
390 def close(self):
406 def close(self):
391 self.write()
407 self.write()
392 self.write_rej()
408 self.write_rej()
393
409
394 def apply(self, h):
410 def apply(self, h):
395 if not h.complete():
411 if not h.complete():
396 raise PatchError(_("bad hunk #%d %s (%d %d %d %d)") %
412 raise PatchError(_("bad hunk #%d %s (%d %d %d %d)") %
397 (h.number, h.desc, len(h.a), h.lena, len(h.b),
413 (h.number, h.desc, len(h.a), h.lena, len(h.b),
398 h.lenb))
414 h.lenb))
399
415
400 self.hunks += 1
416 self.hunks += 1
401
417
402 if self.missing:
418 if self.missing:
403 self.rej.append(h)
419 self.rej.append(h)
404 return -1
420 return -1
405
421
406 if self.exists and h.createfile():
422 if self.exists and h.createfile():
407 self.ui.warn(_("file %s already exists\n") % self.fname)
423 self.ui.warn(_("file %s already exists\n") % self.fname)
408 self.rej.append(h)
424 self.rej.append(h)
409 return -1
425 return -1
410
426
411 if isinstance(h, binhunk):
427 if isinstance(h, binhunk):
412 if h.rmfile():
428 if h.rmfile():
413 self.unlink(self.fname)
429 self.unlink(self.fname)
414 else:
430 else:
415 self.lines[:] = h.new()
431 self.lines[:] = h.new()
416 self.offset += len(h.new())
432 self.offset += len(h.new())
417 self.dirty = 1
433 self.dirty = 1
418 return 0
434 return 0
419
435
420 # fast case first, no offsets, no fuzz
436 # fast case first, no offsets, no fuzz
421 old = h.old()
437 old = h.old()
422 # patch starts counting at 1 unless we are adding the file
438 # patch starts counting at 1 unless we are adding the file
423 if h.starta == 0:
439 if h.starta == 0:
424 start = 0
440 start = 0
425 else:
441 else:
426 start = h.starta + self.offset - 1
442 start = h.starta + self.offset - 1
427 orig_start = start
443 orig_start = start
428 if diffhelpers.testhunk(old, self.lines, start) == 0:
444 if diffhelpers.testhunk(old, self.lines, start) == 0:
429 if h.rmfile():
445 if h.rmfile():
430 self.unlink(self.fname)
446 self.unlink(self.fname)
431 else:
447 else:
432 self.lines[start : start + h.lena] = h.new()
448 self.lines[start : start + h.lena] = h.new()
433 self.offset += h.lenb - h.lena
449 self.offset += h.lenb - h.lena
434 self.dirty = 1
450 self.dirty = 1
435 return 0
451 return 0
436
452
437 # ok, we couldn't match the hunk. Lets look for offsets and fuzz it
453 # ok, we couldn't match the hunk. Lets look for offsets and fuzz it
438 self.hashlines()
454 self.hashlines()
439 if h.hunk[-1][0] != ' ':
455 if h.hunk[-1][0] != ' ':
440 # if the hunk tried to put something at the bottom of the file
456 # if the hunk tried to put something at the bottom of the file
441 # override the start line and use eof here
457 # override the start line and use eof here
442 search_start = len(self.lines)
458 search_start = len(self.lines)
443 else:
459 else:
444 search_start = orig_start
460 search_start = orig_start
445
461
446 for fuzzlen in xrange(3):
462 for fuzzlen in xrange(3):
447 for toponly in [ True, False ]:
463 for toponly in [ True, False ]:
448 old = h.old(fuzzlen, toponly)
464 old = h.old(fuzzlen, toponly)
449
465
450 cand = self.findlines(old[0][1:], search_start)
466 cand = self.findlines(old[0][1:], search_start)
451 for l in cand:
467 for l in cand:
452 if diffhelpers.testhunk(old, self.lines, l) == 0:
468 if diffhelpers.testhunk(old, self.lines, l) == 0:
453 newlines = h.new(fuzzlen, toponly)
469 newlines = h.new(fuzzlen, toponly)
454 self.lines[l : l + len(old)] = newlines
470 self.lines[l : l + len(old)] = newlines
455 self.offset += len(newlines) - len(old)
471 self.offset += len(newlines) - len(old)
456 self.dirty = 1
472 self.dirty = 1
457 if fuzzlen:
473 if fuzzlen:
458 fuzzstr = "with fuzz %d " % fuzzlen
474 fuzzstr = "with fuzz %d " % fuzzlen
459 f = self.ui.warn
475 f = self.ui.warn
460 self.printfile(True)
476 self.printfile(True)
461 else:
477 else:
462 fuzzstr = ""
478 fuzzstr = ""
463 f = self.ui.note
479 f = self.ui.note
464 offset = l - orig_start - fuzzlen
480 offset = l - orig_start - fuzzlen
465 if offset == 1:
481 if offset == 1:
466 msg = _("Hunk #%d succeeded at %d %s"
482 msg = _("Hunk #%d succeeded at %d %s"
467 "(offset %d line).\n")
483 "(offset %d line).\n")
468 else:
484 else:
469 msg = _("Hunk #%d succeeded at %d %s"
485 msg = _("Hunk #%d succeeded at %d %s"
470 "(offset %d lines).\n")
486 "(offset %d lines).\n")
471 f(msg % (h.number, l+1, fuzzstr, offset))
487 f(msg % (h.number, l+1, fuzzstr, offset))
472 return fuzzlen
488 return fuzzlen
473 self.printfile(True)
489 self.printfile(True)
474 self.ui.warn(_("Hunk #%d FAILED at %d\n") % (h.number, orig_start))
490 self.ui.warn(_("Hunk #%d FAILED at %d\n") % (h.number, orig_start))
475 self.rej.append(h)
491 self.rej.append(h)
476 return -1
492 return -1
477
493
478 class hunk(object):
494 class hunk(object):
479 def __init__(self, desc, num, lr, context, create=False, remove=False):
495 def __init__(self, desc, num, lr, context, create=False, remove=False):
480 self.number = num
496 self.number = num
481 self.desc = desc
497 self.desc = desc
482 self.hunk = [ desc ]
498 self.hunk = [ desc ]
483 self.a = []
499 self.a = []
484 self.b = []
500 self.b = []
485 self.starta = self.lena = None
501 self.starta = self.lena = None
486 self.startb = self.lenb = None
502 self.startb = self.lenb = None
487 if context:
503 if context:
488 self.read_context_hunk(lr)
504 self.read_context_hunk(lr)
489 else:
505 else:
490 self.read_unified_hunk(lr)
506 self.read_unified_hunk(lr)
491 self.create = create
507 self.create = create
492 self.remove = remove and not create
508 self.remove = remove and not create
493
509
494 def read_unified_hunk(self, lr):
510 def read_unified_hunk(self, lr):
495 m = unidesc.match(self.desc)
511 m = unidesc.match(self.desc)
496 if not m:
512 if not m:
497 raise PatchError(_("bad hunk #%d") % self.number)
513 raise PatchError(_("bad hunk #%d") % self.number)
498 self.starta, foo, self.lena, self.startb, foo2, self.lenb = m.groups()
514 self.starta, foo, self.lena, self.startb, foo2, self.lenb = m.groups()
499 if self.lena is None:
515 if self.lena is None:
500 self.lena = 1
516 self.lena = 1
501 else:
517 else:
502 self.lena = int(self.lena)
518 self.lena = int(self.lena)
503 if self.lenb is None:
519 if self.lenb is None:
504 self.lenb = 1
520 self.lenb = 1
505 else:
521 else:
506 self.lenb = int(self.lenb)
522 self.lenb = int(self.lenb)
507 self.starta = int(self.starta)
523 self.starta = int(self.starta)
508 self.startb = int(self.startb)
524 self.startb = int(self.startb)
509 diffhelpers.addlines(lr, self.hunk, self.lena, self.lenb, self.a, self.b)
525 diffhelpers.addlines(lr, self.hunk, self.lena, self.lenb, self.a, self.b)
510 # if we hit eof before finishing out the hunk, the last line will
526 # if we hit eof before finishing out the hunk, the last line will
511 # be zero length. Lets try to fix it up.
527 # be zero length. Lets try to fix it up.
512 while len(self.hunk[-1]) == 0:
528 while len(self.hunk[-1]) == 0:
513 del self.hunk[-1]
529 del self.hunk[-1]
514 del self.a[-1]
530 del self.a[-1]
515 del self.b[-1]
531 del self.b[-1]
516 self.lena -= 1
532 self.lena -= 1
517 self.lenb -= 1
533 self.lenb -= 1
518
534
519 def read_context_hunk(self, lr):
535 def read_context_hunk(self, lr):
520 self.desc = lr.readline()
536 self.desc = lr.readline()
521 m = contextdesc.match(self.desc)
537 m = contextdesc.match(self.desc)
522 if not m:
538 if not m:
523 raise PatchError(_("bad hunk #%d") % self.number)
539 raise PatchError(_("bad hunk #%d") % self.number)
524 foo, self.starta, foo2, aend, foo3 = m.groups()
540 foo, self.starta, foo2, aend, foo3 = m.groups()
525 self.starta = int(self.starta)
541 self.starta = int(self.starta)
526 if aend is None:
542 if aend is None:
527 aend = self.starta
543 aend = self.starta
528 self.lena = int(aend) - self.starta
544 self.lena = int(aend) - self.starta
529 if self.starta:
545 if self.starta:
530 self.lena += 1
546 self.lena += 1
531 for x in xrange(self.lena):
547 for x in xrange(self.lena):
532 l = lr.readline()
548 l = lr.readline()
533 if l.startswith('---'):
549 if l.startswith('---'):
534 lr.push(l)
550 lr.push(l)
535 break
551 break
536 s = l[2:]
552 s = l[2:]
537 if l.startswith('- ') or l.startswith('! '):
553 if l.startswith('- ') or l.startswith('! '):
538 u = '-' + s
554 u = '-' + s
539 elif l.startswith(' '):
555 elif l.startswith(' '):
540 u = ' ' + s
556 u = ' ' + s
541 else:
557 else:
542 raise PatchError(_("bad hunk #%d old text line %d") %
558 raise PatchError(_("bad hunk #%d old text line %d") %
543 (self.number, x))
559 (self.number, x))
544 self.a.append(u)
560 self.a.append(u)
545 self.hunk.append(u)
561 self.hunk.append(u)
546
562
547 l = lr.readline()
563 l = lr.readline()
548 if l.startswith('\ '):
564 if l.startswith('\ '):
549 s = self.a[-1][:-1]
565 s = self.a[-1][:-1]
550 self.a[-1] = s
566 self.a[-1] = s
551 self.hunk[-1] = s
567 self.hunk[-1] = s
552 l = lr.readline()
568 l = lr.readline()
553 m = contextdesc.match(l)
569 m = contextdesc.match(l)
554 if not m:
570 if not m:
555 raise PatchError(_("bad hunk #%d") % self.number)
571 raise PatchError(_("bad hunk #%d") % self.number)
556 foo, self.startb, foo2, bend, foo3 = m.groups()
572 foo, self.startb, foo2, bend, foo3 = m.groups()
557 self.startb = int(self.startb)
573 self.startb = int(self.startb)
558 if bend is None:
574 if bend is None:
559 bend = self.startb
575 bend = self.startb
560 self.lenb = int(bend) - self.startb
576 self.lenb = int(bend) - self.startb
561 if self.startb:
577 if self.startb:
562 self.lenb += 1
578 self.lenb += 1
563 hunki = 1
579 hunki = 1
564 for x in xrange(self.lenb):
580 for x in xrange(self.lenb):
565 l = lr.readline()
581 l = lr.readline()
566 if l.startswith('\ '):
582 if l.startswith('\ '):
567 s = self.b[-1][:-1]
583 s = self.b[-1][:-1]
568 self.b[-1] = s
584 self.b[-1] = s
569 self.hunk[hunki-1] = s
585 self.hunk[hunki-1] = s
570 continue
586 continue
571 if not l:
587 if not l:
572 lr.push(l)
588 lr.push(l)
573 break
589 break
574 s = l[2:]
590 s = l[2:]
575 if l.startswith('+ ') or l.startswith('! '):
591 if l.startswith('+ ') or l.startswith('! '):
576 u = '+' + s
592 u = '+' + s
577 elif l.startswith(' '):
593 elif l.startswith(' '):
578 u = ' ' + s
594 u = ' ' + s
579 elif len(self.b) == 0:
595 elif len(self.b) == 0:
580 # this can happen when the hunk does not add any lines
596 # this can happen when the hunk does not add any lines
581 lr.push(l)
597 lr.push(l)
582 break
598 break
583 else:
599 else:
584 raise PatchError(_("bad hunk #%d old text line %d") %
600 raise PatchError(_("bad hunk #%d old text line %d") %
585 (self.number, x))
601 (self.number, x))
586 self.b.append(s)
602 self.b.append(s)
587 while True:
603 while True:
588 if hunki >= len(self.hunk):
604 if hunki >= len(self.hunk):
589 h = ""
605 h = ""
590 else:
606 else:
591 h = self.hunk[hunki]
607 h = self.hunk[hunki]
592 hunki += 1
608 hunki += 1
593 if h == u:
609 if h == u:
594 break
610 break
595 elif h.startswith('-'):
611 elif h.startswith('-'):
596 continue
612 continue
597 else:
613 else:
598 self.hunk.insert(hunki-1, u)
614 self.hunk.insert(hunki-1, u)
599 break
615 break
600
616
601 if not self.a:
617 if not self.a:
602 # this happens when lines were only added to the hunk
618 # this happens when lines were only added to the hunk
603 for x in self.hunk:
619 for x in self.hunk:
604 if x.startswith('-') or x.startswith(' '):
620 if x.startswith('-') or x.startswith(' '):
605 self.a.append(x)
621 self.a.append(x)
606 if not self.b:
622 if not self.b:
607 # this happens when lines were only deleted from the hunk
623 # this happens when lines were only deleted from the hunk
608 for x in self.hunk:
624 for x in self.hunk:
609 if x.startswith('+') or x.startswith(' '):
625 if x.startswith('+') or x.startswith(' '):
610 self.b.append(x[1:])
626 self.b.append(x[1:])
611 # @@ -start,len +start,len @@
627 # @@ -start,len +start,len @@
612 self.desc = "@@ -%d,%d +%d,%d @@\n" % (self.starta, self.lena,
628 self.desc = "@@ -%d,%d +%d,%d @@\n" % (self.starta, self.lena,
613 self.startb, self.lenb)
629 self.startb, self.lenb)
614 self.hunk[0] = self.desc
630 self.hunk[0] = self.desc
615
631
616 def fix_newline(self):
632 def fix_newline(self):
617 diffhelpers.fix_newline(self.hunk, self.a, self.b)
633 diffhelpers.fix_newline(self.hunk, self.a, self.b)
618
634
619 def complete(self):
635 def complete(self):
620 return len(self.a) == self.lena and len(self.b) == self.lenb
636 return len(self.a) == self.lena and len(self.b) == self.lenb
621
637
622 def createfile(self):
638 def createfile(self):
623 return self.starta == 0 and self.lena == 0 and self.create
639 return self.starta == 0 and self.lena == 0 and self.create
624
640
625 def rmfile(self):
641 def rmfile(self):
626 return self.startb == 0 and self.lenb == 0 and self.remove
642 return self.startb == 0 and self.lenb == 0 and self.remove
627
643
628 def fuzzit(self, l, fuzz, toponly):
644 def fuzzit(self, l, fuzz, toponly):
629 # this removes context lines from the top and bottom of list 'l'. It
645 # this removes context lines from the top and bottom of list 'l'. It
630 # checks the hunk to make sure only context lines are removed, and then
646 # checks the hunk to make sure only context lines are removed, and then
631 # returns a new shortened list of lines.
647 # returns a new shortened list of lines.
632 fuzz = min(fuzz, len(l)-1)
648 fuzz = min(fuzz, len(l)-1)
633 if fuzz:
649 if fuzz:
634 top = 0
650 top = 0
635 bot = 0
651 bot = 0
636 hlen = len(self.hunk)
652 hlen = len(self.hunk)
637 for x in xrange(hlen-1):
653 for x in xrange(hlen-1):
638 # the hunk starts with the @@ line, so use x+1
654 # the hunk starts with the @@ line, so use x+1
639 if self.hunk[x+1][0] == ' ':
655 if self.hunk[x+1][0] == ' ':
640 top += 1
656 top += 1
641 else:
657 else:
642 break
658 break
643 if not toponly:
659 if not toponly:
644 for x in xrange(hlen-1):
660 for x in xrange(hlen-1):
645 if self.hunk[hlen-bot-1][0] == ' ':
661 if self.hunk[hlen-bot-1][0] == ' ':
646 bot += 1
662 bot += 1
647 else:
663 else:
648 break
664 break
649
665
650 # top and bot now count context in the hunk
666 # top and bot now count context in the hunk
651 # adjust them if either one is short
667 # adjust them if either one is short
652 context = max(top, bot, 3)
668 context = max(top, bot, 3)
653 if bot < context:
669 if bot < context:
654 bot = max(0, fuzz - (context - bot))
670 bot = max(0, fuzz - (context - bot))
655 else:
671 else:
656 bot = min(fuzz, bot)
672 bot = min(fuzz, bot)
657 if top < context:
673 if top < context:
658 top = max(0, fuzz - (context - top))
674 top = max(0, fuzz - (context - top))
659 else:
675 else:
660 top = min(fuzz, top)
676 top = min(fuzz, top)
661
677
662 return l[top:len(l)-bot]
678 return l[top:len(l)-bot]
663 return l
679 return l
664
680
665 def old(self, fuzz=0, toponly=False):
681 def old(self, fuzz=0, toponly=False):
666 return self.fuzzit(self.a, fuzz, toponly)
682 return self.fuzzit(self.a, fuzz, toponly)
667
683
668 def newctrl(self):
684 def newctrl(self):
669 res = []
685 res = []
670 for x in self.hunk:
686 for x in self.hunk:
671 c = x[0]
687 c = x[0]
672 if c == ' ' or c == '+':
688 if c == ' ' or c == '+':
673 res.append(x)
689 res.append(x)
674 return res
690 return res
675
691
676 def new(self, fuzz=0, toponly=False):
692 def new(self, fuzz=0, toponly=False):
677 return self.fuzzit(self.b, fuzz, toponly)
693 return self.fuzzit(self.b, fuzz, toponly)
678
694
679 class binhunk:
695 class binhunk:
680 'A binary patch file. Only understands literals so far.'
696 'A binary patch file. Only understands literals so far.'
681 def __init__(self, gitpatch):
697 def __init__(self, gitpatch):
682 self.gitpatch = gitpatch
698 self.gitpatch = gitpatch
683 self.text = None
699 self.text = None
684 self.hunk = ['GIT binary patch\n']
700 self.hunk = ['GIT binary patch\n']
685
701
686 def createfile(self):
702 def createfile(self):
687 return self.gitpatch.op in ('ADD', 'RENAME', 'COPY')
703 return self.gitpatch.op in ('ADD', 'RENAME', 'COPY')
688
704
689 def rmfile(self):
705 def rmfile(self):
690 return self.gitpatch.op == 'DELETE'
706 return self.gitpatch.op == 'DELETE'
691
707
692 def complete(self):
708 def complete(self):
693 return self.text is not None
709 return self.text is not None
694
710
695 def new(self):
711 def new(self):
696 return [self.text]
712 return [self.text]
697
713
698 def extract(self, lr):
714 def extract(self, lr):
699 line = lr.readline()
715 line = lr.readline()
700 self.hunk.append(line)
716 self.hunk.append(line)
701 while line and not line.startswith('literal '):
717 while line and not line.startswith('literal '):
702 line = lr.readline()
718 line = lr.readline()
703 self.hunk.append(line)
719 self.hunk.append(line)
704 if not line:
720 if not line:
705 raise PatchError(_('could not extract binary patch'))
721 raise PatchError(_('could not extract binary patch'))
706 size = int(line[8:].rstrip())
722 size = int(line[8:].rstrip())
707 dec = []
723 dec = []
708 line = lr.readline()
724 line = lr.readline()
709 self.hunk.append(line)
725 self.hunk.append(line)
710 while len(line) > 1:
726 while len(line) > 1:
711 l = line[0]
727 l = line[0]
712 if l <= 'Z' and l >= 'A':
728 if l <= 'Z' and l >= 'A':
713 l = ord(l) - ord('A') + 1
729 l = ord(l) - ord('A') + 1
714 else:
730 else:
715 l = ord(l) - ord('a') + 27
731 l = ord(l) - ord('a') + 27
716 dec.append(base85.b85decode(line[1:-1])[:l])
732 dec.append(base85.b85decode(line[1:-1])[:l])
717 line = lr.readline()
733 line = lr.readline()
718 self.hunk.append(line)
734 self.hunk.append(line)
719 text = zlib.decompress(''.join(dec))
735 text = zlib.decompress(''.join(dec))
720 if len(text) != size:
736 if len(text) != size:
721 raise PatchError(_('binary patch is %d bytes, not %d') %
737 raise PatchError(_('binary patch is %d bytes, not %d') %
722 len(text), size)
738 len(text), size)
723 self.text = text
739 self.text = text
724
740
725 def parsefilename(str):
741 def parsefilename(str):
726 # --- filename \t|space stuff
742 # --- filename \t|space stuff
727 s = str[4:].rstrip('\r\n')
743 s = str[4:].rstrip('\r\n')
728 i = s.find('\t')
744 i = s.find('\t')
729 if i < 0:
745 if i < 0:
730 i = s.find(' ')
746 i = s.find(' ')
731 if i < 0:
747 if i < 0:
732 return s
748 return s
733 return s[:i]
749 return s[:i]
734
750
735 def selectfile(afile_orig, bfile_orig, hunk, strip):
751 def selectfile(afile_orig, bfile_orig, hunk, strip):
736 def pathstrip(path, count=1):
752 def pathstrip(path, count=1):
737 pathlen = len(path)
753 pathlen = len(path)
738 i = 0
754 i = 0
739 if count == 0:
755 if count == 0:
740 return '', path.rstrip()
756 return '', path.rstrip()
741 while count > 0:
757 while count > 0:
742 i = path.find('/', i)
758 i = path.find('/', i)
743 if i == -1:
759 if i == -1:
744 raise PatchError(_("unable to strip away %d dirs from %s") %
760 raise PatchError(_("unable to strip away %d dirs from %s") %
745 (count, path))
761 (count, path))
746 i += 1
762 i += 1
747 # consume '//' in the path
763 # consume '//' in the path
748 while i < pathlen - 1 and path[i] == '/':
764 while i < pathlen - 1 and path[i] == '/':
749 i += 1
765 i += 1
750 count -= 1
766 count -= 1
751 return path[:i].lstrip(), path[i:].rstrip()
767 return path[:i].lstrip(), path[i:].rstrip()
752
768
753 nulla = afile_orig == "/dev/null"
769 nulla = afile_orig == "/dev/null"
754 nullb = bfile_orig == "/dev/null"
770 nullb = bfile_orig == "/dev/null"
755 abase, afile = pathstrip(afile_orig, strip)
771 abase, afile = pathstrip(afile_orig, strip)
756 gooda = not nulla and util.lexists(afile)
772 gooda = not nulla and util.lexists(afile)
757 bbase, bfile = pathstrip(bfile_orig, strip)
773 bbase, bfile = pathstrip(bfile_orig, strip)
758 if afile == bfile:
774 if afile == bfile:
759 goodb = gooda
775 goodb = gooda
760 else:
776 else:
761 goodb = not nullb and os.path.exists(bfile)
777 goodb = not nullb and os.path.exists(bfile)
762 createfunc = hunk.createfile
778 createfunc = hunk.createfile
763 missing = not goodb and not gooda and not createfunc()
779 missing = not goodb and not gooda and not createfunc()
764
780
765 # some diff programs apparently produce create patches where the
781 # some diff programs apparently produce create patches where the
766 # afile is not /dev/null, but rather the same name as the bfile
782 # afile is not /dev/null, but rather the same name as the bfile
767 if missing and afile == bfile:
783 if missing and afile == bfile:
768 # this isn't very pretty
784 # this isn't very pretty
769 hunk.create = True
785 hunk.create = True
770 if createfunc():
786 if createfunc():
771 missing = False
787 missing = False
772 else:
788 else:
773 hunk.create = False
789 hunk.create = False
774
790
775 # If afile is "a/b/foo" and bfile is "a/b/foo.orig" we assume the
791 # If afile is "a/b/foo" and bfile is "a/b/foo.orig" we assume the
776 # diff is between a file and its backup. In this case, the original
792 # diff is between a file and its backup. In this case, the original
777 # file should be patched (see original mpatch code).
793 # file should be patched (see original mpatch code).
778 isbackup = (abase == bbase and bfile.startswith(afile))
794 isbackup = (abase == bbase and bfile.startswith(afile))
779 fname = None
795 fname = None
780 if not missing:
796 if not missing:
781 if gooda and goodb:
797 if gooda and goodb:
782 fname = isbackup and afile or bfile
798 fname = isbackup and afile or bfile
783 elif gooda:
799 elif gooda:
784 fname = afile
800 fname = afile
785
801
786 if not fname:
802 if not fname:
787 if not nullb:
803 if not nullb:
788 fname = isbackup and afile or bfile
804 fname = isbackup and afile or bfile
789 elif not nulla:
805 elif not nulla:
790 fname = afile
806 fname = afile
791 else:
807 else:
792 raise PatchError(_("undefined source and destination files"))
808 raise PatchError(_("undefined source and destination files"))
793
809
794 return fname, missing
810 return fname, missing
795
811
796 def scangitpatch(lr, firstline):
812 def scangitpatch(lr, firstline):
797 """
813 """
798 Git patches can emit:
814 Git patches can emit:
799 - rename a to b
815 - rename a to b
800 - change b
816 - change b
801 - copy a to c
817 - copy a to c
802 - change c
818 - change c
803
819
804 We cannot apply this sequence as-is, the renamed 'a' could not be
820 We cannot apply this sequence as-is, the renamed 'a' could not be
805 found for it would have been renamed already. And we cannot copy
821 found for it would have been renamed already. And we cannot copy
806 from 'b' instead because 'b' would have been changed already. So
822 from 'b' instead because 'b' would have been changed already. So
807 we scan the git patch for copy and rename commands so we can
823 we scan the git patch for copy and rename commands so we can
808 perform the copies ahead of time.
824 perform the copies ahead of time.
809 """
825 """
810 pos = 0
826 pos = 0
811 try:
827 try:
812 pos = lr.fp.tell()
828 pos = lr.fp.tell()
813 fp = lr.fp
829 fp = lr.fp
814 except IOError:
830 except IOError:
815 fp = cStringIO.StringIO(lr.fp.read())
831 fp = cStringIO.StringIO(lr.fp.read())
816 gitlr = linereader(fp, lr.textmode)
832 gitlr = linereader(fp, lr.textmode)
817 gitlr.push(firstline)
833 gitlr.push(firstline)
818 (dopatch, gitpatches) = readgitpatch(gitlr)
834 (dopatch, gitpatches) = readgitpatch(gitlr)
819 fp.seek(pos)
835 fp.seek(pos)
820 return dopatch, gitpatches
836 return dopatch, gitpatches
821
837
822 def iterhunks(ui, fp, sourcefile=None, textmode=False):
838 def iterhunks(ui, fp, sourcefile=None, textmode=False):
823 """Read a patch and yield the following events:
839 """Read a patch and yield the following events:
824 - ("file", afile, bfile, firsthunk): select a new target file.
840 - ("file", afile, bfile, firsthunk): select a new target file.
825 - ("hunk", hunk): a new hunk is ready to be applied, follows a
841 - ("hunk", hunk): a new hunk is ready to be applied, follows a
826 "file" event.
842 "file" event.
827 - ("git", gitchanges): current diff is in git format, gitchanges
843 - ("git", gitchanges): current diff is in git format, gitchanges
828 maps filenames to gitpatch records. Unique event.
844 maps filenames to gitpatch records. Unique event.
829
845
830 If textmode is True, input line-endings are normalized to LF.
846 If textmode is True, input line-endings are normalized to LF.
831 """
847 """
832 changed = {}
848 changed = {}
833 current_hunk = None
849 current_hunk = None
834 afile = ""
850 afile = ""
835 bfile = ""
851 bfile = ""
836 state = None
852 state = None
837 hunknum = 0
853 hunknum = 0
838 emitfile = False
854 emitfile = False
839 git = False
855 git = False
840
856
841 # our states
857 # our states
842 BFILE = 1
858 BFILE = 1
843 context = None
859 context = None
844 lr = linereader(fp, textmode)
860 lr = linereader(fp, textmode)
845 dopatch = True
861 dopatch = True
846 # gitworkdone is True if a git operation (copy, rename, ...) was
862 # gitworkdone is True if a git operation (copy, rename, ...) was
847 # performed already for the current file. Useful when the file
863 # performed already for the current file. Useful when the file
848 # section may have no hunk.
864 # section may have no hunk.
849 gitworkdone = False
865 gitworkdone = False
850
866
851 while True:
867 while True:
852 newfile = False
868 newfile = False
853 x = lr.readline()
869 x = lr.readline()
854 if not x:
870 if not x:
855 break
871 break
856 if current_hunk:
872 if current_hunk:
857 if x.startswith('\ '):
873 if x.startswith('\ '):
858 current_hunk.fix_newline()
874 current_hunk.fix_newline()
859 yield 'hunk', current_hunk
875 yield 'hunk', current_hunk
860 current_hunk = None
876 current_hunk = None
861 gitworkdone = False
877 gitworkdone = False
862 if ((sourcefile or state == BFILE) and ((not context and x[0] == '@') or
878 if ((sourcefile or state == BFILE) and ((not context and x[0] == '@') or
863 ((context is not False) and x.startswith('***************')))):
879 ((context is not False) and x.startswith('***************')))):
864 try:
880 try:
865 if context is None and x.startswith('***************'):
881 if context is None and x.startswith('***************'):
866 context = True
882 context = True
867 gpatch = changed.get(bfile)
883 gpatch = changed.get(bfile)
868 create = afile == '/dev/null' or gpatch and gpatch.op == 'ADD'
884 create = afile == '/dev/null' or gpatch and gpatch.op == 'ADD'
869 remove = bfile == '/dev/null' or gpatch and gpatch.op == 'DELETE'
885 remove = bfile == '/dev/null' or gpatch and gpatch.op == 'DELETE'
870 current_hunk = hunk(x, hunknum + 1, lr, context, create, remove)
886 current_hunk = hunk(x, hunknum + 1, lr, context, create, remove)
871 except PatchError, err:
887 except PatchError, err:
872 ui.debug(err)
888 ui.debug(err)
873 current_hunk = None
889 current_hunk = None
874 continue
890 continue
875 hunknum += 1
891 hunknum += 1
876 if emitfile:
892 if emitfile:
877 emitfile = False
893 emitfile = False
878 yield 'file', (afile, bfile, current_hunk)
894 yield 'file', (afile, bfile, current_hunk)
879 elif state == BFILE and x.startswith('GIT binary patch'):
895 elif state == BFILE and x.startswith('GIT binary patch'):
880 current_hunk = binhunk(changed[bfile])
896 current_hunk = binhunk(changed[bfile])
881 hunknum += 1
897 hunknum += 1
882 if emitfile:
898 if emitfile:
883 emitfile = False
899 emitfile = False
884 yield 'file', ('a/' + afile, 'b/' + bfile, current_hunk)
900 yield 'file', ('a/' + afile, 'b/' + bfile, current_hunk)
885 current_hunk.extract(lr)
901 current_hunk.extract(lr)
886 elif x.startswith('diff --git'):
902 elif x.startswith('diff --git'):
887 # check for git diff, scanning the whole patch file if needed
903 # check for git diff, scanning the whole patch file if needed
888 m = gitre.match(x)
904 m = gitre.match(x)
889 if m:
905 if m:
890 afile, bfile = m.group(1, 2)
906 afile, bfile = m.group(1, 2)
891 if not git:
907 if not git:
892 git = True
908 git = True
893 dopatch, gitpatches = scangitpatch(lr, x)
909 dopatch, gitpatches = scangitpatch(lr, x)
894 yield 'git', gitpatches
910 yield 'git', gitpatches
895 for gp in gitpatches:
911 for gp in gitpatches:
896 changed[gp.path] = gp
912 changed[gp.path] = gp
897 # else error?
913 # else error?
898 # copy/rename + modify should modify target, not source
914 # copy/rename + modify should modify target, not source
899 gp = changed.get(bfile)
915 gp = changed.get(bfile)
900 if gp and gp.op in ('COPY', 'DELETE', 'RENAME', 'ADD'):
916 if gp and gp.op in ('COPY', 'DELETE', 'RENAME', 'ADD'):
901 afile = bfile
917 afile = bfile
902 gitworkdone = True
918 gitworkdone = True
903 newfile = True
919 newfile = True
904 elif x.startswith('---'):
920 elif x.startswith('---'):
905 # check for a unified diff
921 # check for a unified diff
906 l2 = lr.readline()
922 l2 = lr.readline()
907 if not l2.startswith('+++'):
923 if not l2.startswith('+++'):
908 lr.push(l2)
924 lr.push(l2)
909 continue
925 continue
910 newfile = True
926 newfile = True
911 context = False
927 context = False
912 afile = parsefilename(x)
928 afile = parsefilename(x)
913 bfile = parsefilename(l2)
929 bfile = parsefilename(l2)
914 elif x.startswith('***'):
930 elif x.startswith('***'):
915 # check for a context diff
931 # check for a context diff
916 l2 = lr.readline()
932 l2 = lr.readline()
917 if not l2.startswith('---'):
933 if not l2.startswith('---'):
918 lr.push(l2)
934 lr.push(l2)
919 continue
935 continue
920 l3 = lr.readline()
936 l3 = lr.readline()
921 lr.push(l3)
937 lr.push(l3)
922 if not l3.startswith("***************"):
938 if not l3.startswith("***************"):
923 lr.push(l2)
939 lr.push(l2)
924 continue
940 continue
925 newfile = True
941 newfile = True
926 context = True
942 context = True
927 afile = parsefilename(x)
943 afile = parsefilename(x)
928 bfile = parsefilename(l2)
944 bfile = parsefilename(l2)
929
945
930 if newfile:
946 if newfile:
931 emitfile = True
947 emitfile = True
932 state = BFILE
948 state = BFILE
933 hunknum = 0
949 hunknum = 0
934 if current_hunk:
950 if current_hunk:
935 if current_hunk.complete():
951 if current_hunk.complete():
936 yield 'hunk', current_hunk
952 yield 'hunk', current_hunk
937 else:
953 else:
938 raise PatchError(_("malformed patch %s %s") % (afile,
954 raise PatchError(_("malformed patch %s %s") % (afile,
939 current_hunk.desc))
955 current_hunk.desc))
940
956
941 if hunknum == 0 and dopatch and not gitworkdone:
957 if hunknum == 0 and dopatch and not gitworkdone:
942 raise NoHunks
958 raise NoHunks
943
959
944 def applydiff(ui, fp, changed, strip=1, sourcefile=None, eolmode='strict'):
960 def applydiff(ui, fp, changed, strip=1, sourcefile=None, eolmode='strict'):
945 """
961 """
946 Reads a patch from fp and tries to apply it.
962 Reads a patch from fp and tries to apply it.
947
963
948 The dict 'changed' is filled in with all of the filenames changed
964 The dict 'changed' is filled in with all of the filenames changed
949 by the patch. Returns 0 for a clean patch, -1 if any rejects were
965 by the patch. Returns 0 for a clean patch, -1 if any rejects were
950 found and 1 if there was any fuzz.
966 found and 1 if there was any fuzz.
951
967
952 If 'eolmode' is 'strict', the patch content and patched file are
968 If 'eolmode' is 'strict', the patch content and patched file are
953 read in binary mode. Otherwise, line endings are ignored when
969 read in binary mode. Otherwise, line endings are ignored when
954 patching then normalized according to 'eolmode'.
970 patching then normalized according to 'eolmode'.
955 """
971 """
956 rejects = 0
972 rejects = 0
957 err = 0
973 err = 0
958 current_file = None
974 current_file = None
959 gitpatches = None
975 gitpatches = None
960 opener = util.opener(os.getcwd())
976 opener = util.opener(os.getcwd())
961 textmode = eolmode != 'strict'
977 textmode = eolmode != 'strict'
962
978
963 def closefile():
979 def closefile():
964 if not current_file:
980 if not current_file:
965 return 0
981 return 0
966 current_file.close()
982 current_file.close()
967 return len(current_file.rej)
983 return len(current_file.rej)
968
984
969 for state, values in iterhunks(ui, fp, sourcefile, textmode):
985 for state, values in iterhunks(ui, fp, sourcefile, textmode):
970 if state == 'hunk':
986 if state == 'hunk':
971 if not current_file:
987 if not current_file:
972 continue
988 continue
973 current_hunk = values
989 current_hunk = values
974 ret = current_file.apply(current_hunk)
990 ret = current_file.apply(current_hunk)
975 if ret >= 0:
991 if ret >= 0:
976 changed.setdefault(current_file.fname, None)
992 changed.setdefault(current_file.fname, None)
977 if ret > 0:
993 if ret > 0:
978 err = 1
994 err = 1
979 elif state == 'file':
995 elif state == 'file':
980 rejects += closefile()
996 rejects += closefile()
981 afile, bfile, first_hunk = values
997 afile, bfile, first_hunk = values
982 try:
998 try:
983 if sourcefile:
999 if sourcefile:
984 current_file = patchfile(ui, sourcefile, opener, eolmode=eolmode)
1000 current_file = patchfile(ui, sourcefile, opener, eolmode=eolmode)
985 else:
1001 else:
986 current_file, missing = selectfile(afile, bfile, first_hunk,
1002 current_file, missing = selectfile(afile, bfile, first_hunk,
987 strip)
1003 strip)
988 current_file = patchfile(ui, current_file, opener, missing, eolmode)
1004 current_file = patchfile(ui, current_file, opener, missing, eolmode)
989 except PatchError, err:
1005 except PatchError, err:
990 ui.warn(str(err) + '\n')
1006 ui.warn(str(err) + '\n')
991 current_file, current_hunk = None, None
1007 current_file, current_hunk = None, None
992 rejects += 1
1008 rejects += 1
993 continue
1009 continue
994 elif state == 'git':
1010 elif state == 'git':
995 gitpatches = values
1011 gitpatches = values
996 cwd = os.getcwd()
1012 cwd = os.getcwd()
997 for gp in gitpatches:
1013 for gp in gitpatches:
998 if gp.op in ('COPY', 'RENAME'):
1014 if gp.op in ('COPY', 'RENAME'):
999 copyfile(gp.oldpath, gp.path, cwd)
1015 copyfile(gp.oldpath, gp.path, cwd)
1000 changed[gp.path] = gp
1016 changed[gp.path] = gp
1001 else:
1017 else:
1002 raise util.Abort(_('unsupported parser state: %s') % state)
1018 raise util.Abort(_('unsupported parser state: %s') % state)
1003
1019
1004 rejects += closefile()
1020 rejects += closefile()
1005
1021
1006 if rejects:
1022 if rejects:
1007 return -1
1023 return -1
1008 return err
1024 return err
1009
1025
1010 def diffopts(ui, opts=None, untrusted=False):
1026 def diffopts(ui, opts=None, untrusted=False):
1011 def get(key, name=None, getter=ui.configbool):
1027 def get(key, name=None, getter=ui.configbool):
1012 return ((opts and opts.get(key)) or
1028 return ((opts and opts.get(key)) or
1013 getter('diff', name or key, None, untrusted=untrusted))
1029 getter('diff', name or key, None, untrusted=untrusted))
1014 return mdiff.diffopts(
1030 return mdiff.diffopts(
1015 text=opts and opts.get('text'),
1031 text=opts and opts.get('text'),
1016 git=get('git'),
1032 git=get('git'),
1017 nodates=get('nodates'),
1033 nodates=get('nodates'),
1018 showfunc=get('show_function', 'showfunc'),
1034 showfunc=get('show_function', 'showfunc'),
1019 ignorews=get('ignore_all_space', 'ignorews'),
1035 ignorews=get('ignore_all_space', 'ignorews'),
1020 ignorewsamount=get('ignore_space_change', 'ignorewsamount'),
1036 ignorewsamount=get('ignore_space_change', 'ignorewsamount'),
1021 ignoreblanklines=get('ignore_blank_lines', 'ignoreblanklines'),
1037 ignoreblanklines=get('ignore_blank_lines', 'ignoreblanklines'),
1022 context=get('unified', getter=ui.config))
1038 context=get('unified', getter=ui.config))
1023
1039
1024 def updatedir(ui, repo, patches, similarity=0):
1040 def updatedir(ui, repo, patches, similarity=0):
1025 '''Update dirstate after patch application according to metadata'''
1041 '''Update dirstate after patch application according to metadata'''
1026 if not patches:
1042 if not patches:
1027 return
1043 return
1028 copies = []
1044 copies = []
1029 removes = set()
1045 removes = set()
1030 cfiles = patches.keys()
1046 cfiles = patches.keys()
1031 cwd = repo.getcwd()
1047 cwd = repo.getcwd()
1032 if cwd:
1048 if cwd:
1033 cfiles = [util.pathto(repo.root, cwd, f) for f in patches.keys()]
1049 cfiles = [util.pathto(repo.root, cwd, f) for f in patches.keys()]
1034 for f in patches:
1050 for f in patches:
1035 gp = patches[f]
1051 gp = patches[f]
1036 if not gp:
1052 if not gp:
1037 continue
1053 continue
1038 if gp.op == 'RENAME':
1054 if gp.op == 'RENAME':
1039 copies.append((gp.oldpath, gp.path))
1055 copies.append((gp.oldpath, gp.path))
1040 removes.add(gp.oldpath)
1056 removes.add(gp.oldpath)
1041 elif gp.op == 'COPY':
1057 elif gp.op == 'COPY':
1042 copies.append((gp.oldpath, gp.path))
1058 copies.append((gp.oldpath, gp.path))
1043 elif gp.op == 'DELETE':
1059 elif gp.op == 'DELETE':
1044 removes.add(gp.path)
1060 removes.add(gp.path)
1045 for src, dst in copies:
1061 for src, dst in copies:
1046 repo.copy(src, dst)
1062 repo.copy(src, dst)
1047 if (not similarity) and removes:
1063 if (not similarity) and removes:
1048 repo.remove(sorted(removes), True)
1064 repo.remove(sorted(removes), True)
1049 for f in patches:
1065 for f in patches:
1050 gp = patches[f]
1066 gp = patches[f]
1051 if gp and gp.mode:
1067 if gp and gp.mode:
1052 islink, isexec = gp.mode
1068 islink, isexec = gp.mode
1053 dst = repo.wjoin(gp.path)
1069 dst = repo.wjoin(gp.path)
1054 # patch won't create empty files
1070 # patch won't create empty files
1055 if gp.op == 'ADD' and not os.path.exists(dst):
1071 if gp.op == 'ADD' and not os.path.exists(dst):
1056 flags = (isexec and 'x' or '') + (islink and 'l' or '')
1072 flags = (isexec and 'x' or '') + (islink and 'l' or '')
1057 repo.wwrite(gp.path, '', flags)
1073 repo.wwrite(gp.path, '', flags)
1058 elif gp.op != 'DELETE':
1074 elif gp.op != 'DELETE':
1059 util.set_flags(dst, islink, isexec)
1075 util.set_flags(dst, islink, isexec)
1060 cmdutil.addremove(repo, cfiles, similarity=similarity)
1076 cmdutil.addremove(repo, cfiles, similarity=similarity)
1061 files = patches.keys()
1077 files = patches.keys()
1062 files.extend([r for r in removes if r not in files])
1078 files.extend([r for r in removes if r not in files])
1063 return sorted(files)
1079 return sorted(files)
1064
1080
1065 def externalpatch(patcher, args, patchname, ui, strip, cwd, files):
1081 def externalpatch(patcher, args, patchname, ui, strip, cwd, files):
1066 """use <patcher> to apply <patchname> to the working directory.
1082 """use <patcher> to apply <patchname> to the working directory.
1067 returns whether patch was applied with fuzz factor."""
1083 returns whether patch was applied with fuzz factor."""
1068
1084
1069 fuzz = False
1085 fuzz = False
1070 if cwd:
1086 if cwd:
1071 args.append('-d %s' % util.shellquote(cwd))
1087 args.append('-d %s' % util.shellquote(cwd))
1072 fp = util.popen('%s %s -p%d < %s' % (patcher, ' '.join(args), strip,
1088 fp = util.popen('%s %s -p%d < %s' % (patcher, ' '.join(args), strip,
1073 util.shellquote(patchname)))
1089 util.shellquote(patchname)))
1074
1090
1075 for line in fp:
1091 for line in fp:
1076 line = line.rstrip()
1092 line = line.rstrip()
1077 ui.note(line + '\n')
1093 ui.note(line + '\n')
1078 if line.startswith('patching file '):
1094 if line.startswith('patching file '):
1079 pf = util.parse_patch_output(line)
1095 pf = util.parse_patch_output(line)
1080 printed_file = False
1096 printed_file = False
1081 files.setdefault(pf, None)
1097 files.setdefault(pf, None)
1082 elif line.find('with fuzz') >= 0:
1098 elif line.find('with fuzz') >= 0:
1083 fuzz = True
1099 fuzz = True
1084 if not printed_file:
1100 if not printed_file:
1085 ui.warn(pf + '\n')
1101 ui.warn(pf + '\n')
1086 printed_file = True
1102 printed_file = True
1087 ui.warn(line + '\n')
1103 ui.warn(line + '\n')
1088 elif line.find('saving rejects to file') >= 0:
1104 elif line.find('saving rejects to file') >= 0:
1089 ui.warn(line + '\n')
1105 ui.warn(line + '\n')
1090 elif line.find('FAILED') >= 0:
1106 elif line.find('FAILED') >= 0:
1091 if not printed_file:
1107 if not printed_file:
1092 ui.warn(pf + '\n')
1108 ui.warn(pf + '\n')
1093 printed_file = True
1109 printed_file = True
1094 ui.warn(line + '\n')
1110 ui.warn(line + '\n')
1095 code = fp.close()
1111 code = fp.close()
1096 if code:
1112 if code:
1097 raise PatchError(_("patch command failed: %s") %
1113 raise PatchError(_("patch command failed: %s") %
1098 util.explain_exit(code)[0])
1114 util.explain_exit(code)[0])
1099 return fuzz
1115 return fuzz
1100
1116
1101 def internalpatch(patchobj, ui, strip, cwd, files=None, eolmode='strict'):
1117 def internalpatch(patchobj, ui, strip, cwd, files=None, eolmode='strict'):
1102 """use builtin patch to apply <patchobj> to the working directory.
1118 """use builtin patch to apply <patchobj> to the working directory.
1103 returns whether patch was applied with fuzz factor."""
1119 returns whether patch was applied with fuzz factor."""
1104
1120
1105 if files is None:
1121 if files is None:
1106 files = {}
1122 files = {}
1107 if eolmode is None:
1123 if eolmode is None:
1108 eolmode = ui.config('patch', 'eol', 'strict')
1124 eolmode = ui.config('patch', 'eol', 'strict')
1109 if eolmode.lower() not in eolmodes:
1125 if eolmode.lower() not in eolmodes:
1110 raise util.Abort(_('Unsupported line endings type: %s') % eolmode)
1126 raise util.Abort(_('Unsupported line endings type: %s') % eolmode)
1111 eolmode = eolmode.lower()
1127 eolmode = eolmode.lower()
1112
1128
1113 try:
1129 try:
1114 fp = open(patchobj, 'rb')
1130 fp = open(patchobj, 'rb')
1115 except TypeError:
1131 except TypeError:
1116 fp = patchobj
1132 fp = patchobj
1117 if cwd:
1133 if cwd:
1118 curdir = os.getcwd()
1134 curdir = os.getcwd()
1119 os.chdir(cwd)
1135 os.chdir(cwd)
1120 try:
1136 try:
1121 ret = applydiff(ui, fp, files, strip=strip, eolmode=eolmode)
1137 ret = applydiff(ui, fp, files, strip=strip, eolmode=eolmode)
1122 finally:
1138 finally:
1123 if cwd:
1139 if cwd:
1124 os.chdir(curdir)
1140 os.chdir(curdir)
1125 if ret < 0:
1141 if ret < 0:
1126 raise PatchError
1142 raise PatchError
1127 return ret > 0
1143 return ret > 0
1128
1144
1129 def patch(patchname, ui, strip=1, cwd=None, files=None, eolmode='strict'):
1145 def patch(patchname, ui, strip=1, cwd=None, files=None, eolmode='strict'):
1130 """Apply <patchname> to the working directory.
1146 """Apply <patchname> to the working directory.
1131
1147
1132 'eolmode' specifies how end of lines should be handled. It can be:
1148 'eolmode' specifies how end of lines should be handled. It can be:
1133 - 'strict': inputs are read in binary mode, EOLs are preserved
1149 - 'strict': inputs are read in binary mode, EOLs are preserved
1134 - 'crlf': EOLs are ignored when patching and reset to CRLF
1150 - 'crlf': EOLs are ignored when patching and reset to CRLF
1135 - 'lf': EOLs are ignored when patching and reset to LF
1151 - 'lf': EOLs are ignored when patching and reset to LF
1136 - None: get it from user settings, default to 'strict'
1152 - None: get it from user settings, default to 'strict'
1137 'eolmode' is ignored when using an external patcher program.
1153 'eolmode' is ignored when using an external patcher program.
1138
1154
1139 Returns whether patch was applied with fuzz factor.
1155 Returns whether patch was applied with fuzz factor.
1140 """
1156 """
1141 patcher = ui.config('ui', 'patch')
1157 patcher = ui.config('ui', 'patch')
1142 args = []
1158 args = []
1143 if files is None:
1159 if files is None:
1144 files = {}
1160 files = {}
1145 try:
1161 try:
1146 if patcher:
1162 if patcher:
1147 return externalpatch(patcher, args, patchname, ui, strip, cwd,
1163 return externalpatch(patcher, args, patchname, ui, strip, cwd,
1148 files)
1164 files)
1149 else:
1165 else:
1150 try:
1166 try:
1151 return internalpatch(patchname, ui, strip, cwd, files, eolmode)
1167 return internalpatch(patchname, ui, strip, cwd, files, eolmode)
1152 except NoHunks:
1168 except NoHunks:
1153 patcher = util.find_exe('gpatch') or util.find_exe('patch') or 'patch'
1169 patcher = util.find_exe('gpatch') or util.find_exe('patch') or 'patch'
1154 ui.debug('no valid hunks found; trying with %r instead\n' %
1170 ui.debug('no valid hunks found; trying with %r instead\n' %
1155 patcher)
1171 patcher)
1156 if util.needbinarypatch():
1172 if util.needbinarypatch():
1157 args.append('--binary')
1173 args.append('--binary')
1158 return externalpatch(patcher, args, patchname, ui, strip, cwd,
1174 return externalpatch(patcher, args, patchname, ui, strip, cwd,
1159 files)
1175 files)
1160 except PatchError, err:
1176 except PatchError, err:
1161 s = str(err)
1177 s = str(err)
1162 if s:
1178 if s:
1163 raise util.Abort(s)
1179 raise util.Abort(s)
1164 else:
1180 else:
1165 raise util.Abort(_('patch failed to apply'))
1181 raise util.Abort(_('patch failed to apply'))
1166
1182
1167 def b85diff(to, tn):
1183 def b85diff(to, tn):
1168 '''print base85-encoded binary diff'''
1184 '''print base85-encoded binary diff'''
1169 def gitindex(text):
1185 def gitindex(text):
1170 if not text:
1186 if not text:
1171 return '0' * 40
1187 return '0' * 40
1172 l = len(text)
1188 l = len(text)
1173 s = util.sha1('blob %d\0' % l)
1189 s = util.sha1('blob %d\0' % l)
1174 s.update(text)
1190 s.update(text)
1175 return s.hexdigest()
1191 return s.hexdigest()
1176
1192
1177 def fmtline(line):
1193 def fmtline(line):
1178 l = len(line)
1194 l = len(line)
1179 if l <= 26:
1195 if l <= 26:
1180 l = chr(ord('A') + l - 1)
1196 l = chr(ord('A') + l - 1)
1181 else:
1197 else:
1182 l = chr(l - 26 + ord('a') - 1)
1198 l = chr(l - 26 + ord('a') - 1)
1183 return '%c%s\n' % (l, base85.b85encode(line, True))
1199 return '%c%s\n' % (l, base85.b85encode(line, True))
1184
1200
1185 def chunk(text, csize=52):
1201 def chunk(text, csize=52):
1186 l = len(text)
1202 l = len(text)
1187 i = 0
1203 i = 0
1188 while i < l:
1204 while i < l:
1189 yield text[i:i+csize]
1205 yield text[i:i+csize]
1190 i += csize
1206 i += csize
1191
1207
1192 tohash = gitindex(to)
1208 tohash = gitindex(to)
1193 tnhash = gitindex(tn)
1209 tnhash = gitindex(tn)
1194 if tohash == tnhash:
1210 if tohash == tnhash:
1195 return ""
1211 return ""
1196
1212
1197 # TODO: deltas
1213 # TODO: deltas
1198 ret = ['index %s..%s\nGIT binary patch\nliteral %s\n' %
1214 ret = ['index %s..%s\nGIT binary patch\nliteral %s\n' %
1199 (tohash, tnhash, len(tn))]
1215 (tohash, tnhash, len(tn))]
1200 for l in chunk(zlib.compress(tn)):
1216 for l in chunk(zlib.compress(tn)):
1201 ret.append(fmtline(l))
1217 ret.append(fmtline(l))
1202 ret.append('\n')
1218 ret.append('\n')
1203 return ''.join(ret)
1219 return ''.join(ret)
1204
1220
1205 def _addmodehdr(header, omode, nmode):
1221 def _addmodehdr(header, omode, nmode):
1206 if omode != nmode:
1222 if omode != nmode:
1207 header.append('old mode %s\n' % omode)
1223 header.append('old mode %s\n' % omode)
1208 header.append('new mode %s\n' % nmode)
1224 header.append('new mode %s\n' % nmode)
1209
1225
1210 def diff(repo, node1=None, node2=None, match=None, changes=None, opts=None):
1226 def diff(repo, node1=None, node2=None, match=None, changes=None, opts=None):
1211 '''yields diff of changes to files between two nodes, or node and
1227 '''yields diff of changes to files between two nodes, or node and
1212 working directory.
1228 working directory.
1213
1229
1214 if node1 is None, use first dirstate parent instead.
1230 if node1 is None, use first dirstate parent instead.
1215 if node2 is None, compare node1 with working directory.'''
1231 if node2 is None, compare node1 with working directory.'''
1216
1232
1217 if opts is None:
1233 if opts is None:
1218 opts = mdiff.defaultopts
1234 opts = mdiff.defaultopts
1219
1235
1220 if not node1 and not node2:
1236 if not node1 and not node2:
1221 node1 = repo.dirstate.parents()[0]
1237 node1 = repo.dirstate.parents()[0]
1222
1238
1223 def lrugetfilectx():
1239 def lrugetfilectx():
1224 cache = {}
1240 cache = {}
1225 order = []
1241 order = []
1226 def getfilectx(f, ctx):
1242 def getfilectx(f, ctx):
1227 fctx = ctx.filectx(f, filelog=cache.get(f))
1243 fctx = ctx.filectx(f, filelog=cache.get(f))
1228 if f not in cache:
1244 if f not in cache:
1229 if len(cache) > 20:
1245 if len(cache) > 20:
1230 del cache[order.pop(0)]
1246 del cache[order.pop(0)]
1231 cache[f] = fctx.filelog()
1247 cache[f] = fctx.filelog()
1232 else:
1248 else:
1233 order.remove(f)
1249 order.remove(f)
1234 order.append(f)
1250 order.append(f)
1235 return fctx
1251 return fctx
1236 return getfilectx
1252 return getfilectx
1237 getfilectx = lrugetfilectx()
1253 getfilectx = lrugetfilectx()
1238
1254
1239 ctx1 = repo[node1]
1255 ctx1 = repo[node1]
1240 ctx2 = repo[node2]
1256 ctx2 = repo[node2]
1241
1257
1242 if not changes:
1258 if not changes:
1243 changes = repo.status(ctx1, ctx2, match=match)
1259 changes = repo.status(ctx1, ctx2, match=match)
1244 modified, added, removed = changes[:3]
1260 modified, added, removed = changes[:3]
1245
1261
1246 if not modified and not added and not removed:
1262 if not modified and not added and not removed:
1247 return
1263 return
1248
1264
1249 date1 = util.datestr(ctx1.date())
1265 date1 = util.datestr(ctx1.date())
1250 man1 = ctx1.manifest()
1266 man1 = ctx1.manifest()
1251
1267
1252 if repo.ui.quiet:
1268 if repo.ui.quiet:
1253 r = None
1269 r = None
1254 else:
1270 else:
1255 hexfunc = repo.ui.debugflag and hex or short
1271 hexfunc = repo.ui.debugflag and hex or short
1256 r = [hexfunc(node) for node in [node1, node2] if node]
1272 r = [hexfunc(node) for node in [node1, node2] if node]
1257
1273
1258 if opts.git:
1274 if opts.git:
1259 copy, diverge = copies.copies(repo, ctx1, ctx2, repo[nullid])
1275 copy, diverge = copies.copies(repo, ctx1, ctx2, repo[nullid])
1260 copy = copy.copy()
1276 copy = copy.copy()
1261 for k, v in copy.items():
1277 for k, v in copy.items():
1262 copy[v] = k
1278 copy[v] = k
1263
1279
1264 gone = set()
1280 gone = set()
1265 gitmode = {'l': '120000', 'x': '100755', '': '100644'}
1281 gitmode = {'l': '120000', 'x': '100755', '': '100644'}
1266
1282
1267 for f in sorted(modified + added + removed):
1283 for f in sorted(modified + added + removed):
1268 to = None
1284 to = None
1269 tn = None
1285 tn = None
1270 dodiff = True
1286 dodiff = True
1271 header = []
1287 header = []
1272 if f in man1:
1288 if f in man1:
1273 to = getfilectx(f, ctx1).data()
1289 to = getfilectx(f, ctx1).data()
1274 if f not in removed:
1290 if f not in removed:
1275 tn = getfilectx(f, ctx2).data()
1291 tn = getfilectx(f, ctx2).data()
1276 a, b = f, f
1292 a, b = f, f
1277 if opts.git:
1293 if opts.git:
1278 if f in added:
1294 if f in added:
1279 mode = gitmode[ctx2.flags(f)]
1295 mode = gitmode[ctx2.flags(f)]
1280 if f in copy:
1296 if f in copy:
1281 a = copy[f]
1297 a = copy[f]
1282 omode = gitmode[man1.flags(a)]
1298 omode = gitmode[man1.flags(a)]
1283 _addmodehdr(header, omode, mode)
1299 _addmodehdr(header, omode, mode)
1284 if a in removed and a not in gone:
1300 if a in removed and a not in gone:
1285 op = 'rename'
1301 op = 'rename'
1286 gone.add(a)
1302 gone.add(a)
1287 else:
1303 else:
1288 op = 'copy'
1304 op = 'copy'
1289 header.append('%s from %s\n' % (op, a))
1305 header.append('%s from %s\n' % (op, a))
1290 header.append('%s to %s\n' % (op, f))
1306 header.append('%s to %s\n' % (op, f))
1291 to = getfilectx(a, ctx1).data()
1307 to = getfilectx(a, ctx1).data()
1292 else:
1308 else:
1293 header.append('new file mode %s\n' % mode)
1309 header.append('new file mode %s\n' % mode)
1294 if util.binary(tn):
1310 if util.binary(tn):
1295 dodiff = 'binary'
1311 dodiff = 'binary'
1296 elif f in removed:
1312 elif f in removed:
1297 # have we already reported a copy above?
1313 # have we already reported a copy above?
1298 if f in copy and copy[f] in added and copy[copy[f]] == f:
1314 if f in copy and copy[f] in added and copy[copy[f]] == f:
1299 dodiff = False
1315 dodiff = False
1300 else:
1316 else:
1301 header.append('deleted file mode %s\n' %
1317 header.append('deleted file mode %s\n' %
1302 gitmode[man1.flags(f)])
1318 gitmode[man1.flags(f)])
1303 else:
1319 else:
1304 omode = gitmode[man1.flags(f)]
1320 omode = gitmode[man1.flags(f)]
1305 nmode = gitmode[ctx2.flags(f)]
1321 nmode = gitmode[ctx2.flags(f)]
1306 _addmodehdr(header, omode, nmode)
1322 _addmodehdr(header, omode, nmode)
1307 if util.binary(to) or util.binary(tn):
1323 if util.binary(to) or util.binary(tn):
1308 dodiff = 'binary'
1324 dodiff = 'binary'
1309 r = None
1325 r = None
1310 header.insert(0, mdiff.diffline(r, a, b, opts))
1326 header.insert(0, mdiff.diffline(r, a, b, opts))
1311 if dodiff:
1327 if dodiff:
1312 if dodiff == 'binary':
1328 if dodiff == 'binary':
1313 text = b85diff(to, tn)
1329 text = b85diff(to, tn)
1314 else:
1330 else:
1315 text = mdiff.unidiff(to, date1,
1331 text = mdiff.unidiff(to, date1,
1316 # ctx2 date may be dynamic
1332 # ctx2 date may be dynamic
1317 tn, util.datestr(ctx2.date()),
1333 tn, util.datestr(ctx2.date()),
1318 a, b, r, opts=opts)
1334 a, b, r, opts=opts)
1319 if header and (text or len(header) > 1):
1335 if header and (text or len(header) > 1):
1320 yield ''.join(header)
1336 yield ''.join(header)
1321 if text:
1337 if text:
1322 yield text
1338 yield text
1323
1339
1324 def export(repo, revs, template='hg-%h.patch', fp=None, switch_parent=False,
1340 def export(repo, revs, template='hg-%h.patch', fp=None, switch_parent=False,
1325 opts=None):
1341 opts=None):
1326 '''export changesets as hg patches.'''
1342 '''export changesets as hg patches.'''
1327
1343
1328 total = len(revs)
1344 total = len(revs)
1329 revwidth = max([len(str(rev)) for rev in revs])
1345 revwidth = max([len(str(rev)) for rev in revs])
1330
1346
1331 def single(rev, seqno, fp):
1347 def single(rev, seqno, fp):
1332 ctx = repo[rev]
1348 ctx = repo[rev]
1333 node = ctx.node()
1349 node = ctx.node()
1334 parents = [p.node() for p in ctx.parents() if p]
1350 parents = [p.node() for p in ctx.parents() if p]
1335 branch = ctx.branch()
1351 branch = ctx.branch()
1336 if switch_parent:
1352 if switch_parent:
1337 parents.reverse()
1353 parents.reverse()
1338 prev = (parents and parents[0]) or nullid
1354 prev = (parents and parents[0]) or nullid
1339
1355
1340 if not fp:
1356 if not fp:
1341 fp = cmdutil.make_file(repo, template, node, total=total,
1357 fp = cmdutil.make_file(repo, template, node, total=total,
1342 seqno=seqno, revwidth=revwidth,
1358 seqno=seqno, revwidth=revwidth,
1343 mode='ab')
1359 mode='ab')
1344 if fp != sys.stdout and hasattr(fp, 'name'):
1360 if fp != sys.stdout and hasattr(fp, 'name'):
1345 repo.ui.note("%s\n" % fp.name)
1361 repo.ui.note("%s\n" % fp.name)
1346
1362
1347 fp.write("# HG changeset patch\n")
1363 fp.write("# HG changeset patch\n")
1348 fp.write("# User %s\n" % ctx.user())
1364 fp.write("# User %s\n" % ctx.user())
1349 fp.write("# Date %d %d\n" % ctx.date())
1365 fp.write("# Date %d %d\n" % ctx.date())
1350 if branch and (branch != 'default'):
1366 if branch and (branch != 'default'):
1351 fp.write("# Branch %s\n" % branch)
1367 fp.write("# Branch %s\n" % branch)
1352 fp.write("# Node ID %s\n" % hex(node))
1368 fp.write("# Node ID %s\n" % hex(node))
1353 fp.write("# Parent %s\n" % hex(prev))
1369 fp.write("# Parent %s\n" % hex(prev))
1354 if len(parents) > 1:
1370 if len(parents) > 1:
1355 fp.write("# Parent %s\n" % hex(parents[1]))
1371 fp.write("# Parent %s\n" % hex(parents[1]))
1356 fp.write(ctx.description().rstrip())
1372 fp.write(ctx.description().rstrip())
1357 fp.write("\n\n")
1373 fp.write("\n\n")
1358
1374
1359 for chunk in diff(repo, prev, node, opts=opts):
1375 for chunk in diff(repo, prev, node, opts=opts):
1360 fp.write(chunk)
1376 fp.write(chunk)
1361
1377
1362 for seqno, rev in enumerate(revs):
1378 for seqno, rev in enumerate(revs):
1363 single(rev, seqno+1, fp)
1379 single(rev, seqno+1, fp)
1364
1380
1365 def diffstatdata(lines):
1381 def diffstatdata(lines):
1366 filename, adds, removes = None, 0, 0
1382 filename, adds, removes = None, 0, 0
1367 for line in lines:
1383 for line in lines:
1368 if line.startswith('diff'):
1384 if line.startswith('diff'):
1369 if filename:
1385 if filename:
1370 isbinary = adds == 0 and removes == 0
1386 isbinary = adds == 0 and removes == 0
1371 yield (filename, adds, removes, isbinary)
1387 yield (filename, adds, removes, isbinary)
1372 # set numbers to 0 anyway when starting new file
1388 # set numbers to 0 anyway when starting new file
1373 adds, removes = 0, 0
1389 adds, removes = 0, 0
1374 if line.startswith('diff --git'):
1390 if line.startswith('diff --git'):
1375 filename = gitre.search(line).group(1)
1391 filename = gitre.search(line).group(1)
1376 else:
1392 else:
1377 # format: "diff -r ... -r ... filename"
1393 # format: "diff -r ... -r ... filename"
1378 filename = line.split(None, 5)[-1]
1394 filename = line.split(None, 5)[-1]
1379 elif line.startswith('+') and not line.startswith('+++'):
1395 elif line.startswith('+') and not line.startswith('+++'):
1380 adds += 1
1396 adds += 1
1381 elif line.startswith('-') and not line.startswith('---'):
1397 elif line.startswith('-') and not line.startswith('---'):
1382 removes += 1
1398 removes += 1
1383 if filename:
1399 if filename:
1384 isbinary = adds == 0 and removes == 0
1400 isbinary = adds == 0 and removes == 0
1385 yield (filename, adds, removes, isbinary)
1401 yield (filename, adds, removes, isbinary)
1386
1402
1387 def diffstat(lines, width=80, git=False):
1403 def diffstat(lines, width=80, git=False):
1388 output = []
1404 output = []
1389 stats = list(diffstatdata(lines))
1405 stats = list(diffstatdata(lines))
1390
1406
1391 maxtotal, maxname = 0, 0
1407 maxtotal, maxname = 0, 0
1392 totaladds, totalremoves = 0, 0
1408 totaladds, totalremoves = 0, 0
1393 hasbinary = False
1409 hasbinary = False
1394 for filename, adds, removes, isbinary in stats:
1410 for filename, adds, removes, isbinary in stats:
1395 totaladds += adds
1411 totaladds += adds
1396 totalremoves += removes
1412 totalremoves += removes
1397 maxname = max(maxname, len(filename))
1413 maxname = max(maxname, len(filename))
1398 maxtotal = max(maxtotal, adds+removes)
1414 maxtotal = max(maxtotal, adds+removes)
1399 if isbinary:
1415 if isbinary:
1400 hasbinary = True
1416 hasbinary = True
1401
1417
1402 countwidth = len(str(maxtotal))
1418 countwidth = len(str(maxtotal))
1403 if hasbinary and countwidth < 3:
1419 if hasbinary and countwidth < 3:
1404 countwidth = 3
1420 countwidth = 3
1405 graphwidth = width - countwidth - maxname - 6
1421 graphwidth = width - countwidth - maxname - 6
1406 if graphwidth < 10:
1422 if graphwidth < 10:
1407 graphwidth = 10
1423 graphwidth = 10
1408
1424
1409 def scale(i):
1425 def scale(i):
1410 if maxtotal <= graphwidth:
1426 if maxtotal <= graphwidth:
1411 return i
1427 return i
1412 # If diffstat runs out of room it doesn't print anything,
1428 # If diffstat runs out of room it doesn't print anything,
1413 # which isn't very useful, so always print at least one + or -
1429 # which isn't very useful, so always print at least one + or -
1414 # if there were at least some changes.
1430 # if there were at least some changes.
1415 return max(i * graphwidth // maxtotal, int(bool(i)))
1431 return max(i * graphwidth // maxtotal, int(bool(i)))
1416
1432
1417 for filename, adds, removes, isbinary in stats:
1433 for filename, adds, removes, isbinary in stats:
1418 if git and isbinary:
1434 if git and isbinary:
1419 count = 'Bin'
1435 count = 'Bin'
1420 else:
1436 else:
1421 count = adds + removes
1437 count = adds + removes
1422 pluses = '+' * scale(adds)
1438 pluses = '+' * scale(adds)
1423 minuses = '-' * scale(removes)
1439 minuses = '-' * scale(removes)
1424 output.append(' %-*s | %*s %s%s\n' % (maxname, filename, countwidth,
1440 output.append(' %-*s | %*s %s%s\n' % (maxname, filename, countwidth,
1425 count, pluses, minuses))
1441 count, pluses, minuses))
1426
1442
1427 if stats:
1443 if stats:
1428 output.append(_(' %d files changed, %d insertions(+), %d deletions(-)\n')
1444 output.append(_(' %d files changed, %d insertions(+), %d deletions(-)\n')
1429 % (len(stats), totaladds, totalremoves))
1445 % (len(stats), totaladds, totalremoves))
1430
1446
1431 return ''.join(output)
1447 return ''.join(output)
@@ -1,54 +1,70 b''
1 #!/bin/sh
1 #!/bin/sh
2
2
3 cat > makepatch.py <<EOF
3 cat > makepatch.py <<EOF
4 f = file('eol.diff', 'wb')
4 f = file('eol.diff', 'wb')
5 w = f.write
5 w = f.write
6 w('test message\n')
6 w('test message\n')
7 w('diff --git a/a b/a\n')
7 w('diff --git a/a b/a\n')
8 w('--- a/a\n')
8 w('--- a/a\n')
9 w('+++ b/a\n')
9 w('+++ b/a\n')
10 w('@@ -1,5 +1,5 @@\n')
10 w('@@ -1,5 +1,5 @@\n')
11 w(' a\n')
11 w(' a\n')
12 w('-bbb\r\n')
12 w('-bbb\r\n')
13 w('+yyyy\r\n')
13 w('+yyyy\r\n')
14 w(' cc\r\n')
14 w(' cc\r\n')
15 w(' \n')
15 w(' \n')
16 w(' d\n')
16 w(' d\n')
17 w('-e\n')
17 w('-e\n')
18 w('\ No newline at end of file\n')
18 w('\ No newline at end of file\n')
19 w('+z\r\n')
19 w('+z\r\n')
20 w('\ No newline at end of file\r\n')
20 w('\ No newline at end of file\r\n')
21 EOF
21 EOF
22
22
23 hg init repo
23 hg init repo
24 cd repo
24 cd repo
25 echo '\.diff' > .hgignore
25 echo '\.diff' > .hgignore
26
26
27 # Test different --eol values
27 # Test different --eol values
28 python -c 'file("a", "wb").write("a\nbbb\ncc\n\nd\ne")'
28 python -c 'file("a", "wb").write("a\nbbb\ncc\n\nd\ne")'
29 hg ci -Am adda
29 hg ci -Am adda
30 python ../makepatch.py
30 python ../makepatch.py
31
31 echo % invalid eol
32 echo % invalid eol
32 hg --config patch.eol='LFCR' import eol.diff
33 hg --config patch.eol='LFCR' import eol.diff
33 hg revert -a
34 hg revert -a
35
34 echo % force LF
36 echo % force LF
35 hg --traceback --config patch.eol='LF' import eol.diff
37 hg --traceback --config patch.eol='LF' import eol.diff
36 python -c 'print repr(file("a","rb").read())'
38 python -c 'print repr(file("a","rb").read())'
37 hg st
39 hg st
40
38 echo % force CRLF
41 echo % force CRLF
39 hg up -C 0
42 hg up -C 0
40 hg --traceback --config patch.eol='CRLF' import eol.diff
43 hg --traceback --config patch.eol='CRLF' import eol.diff
41 python -c 'print repr(file("a","rb").read())'
44 python -c 'print repr(file("a","rb").read())'
42 hg st
45 hg st
43
46
47 echo % auto EOL on LF file
48 hg up -C 0
49 hg --traceback --config patch.eol='auto' import eol.diff
50 python -c 'print repr(file("a","rb").read())'
51 hg st
52
53 echo % auto EOL on CRLF file
54 python -c 'file("a", "wb").write("a\r\nbbb\r\ncc\r\n\r\nd\r\ne")'
55 hg commit -m 'switch EOLs in a'
56 hg --traceback --config patch.eol='auto' import eol.diff
57 python -c 'print repr(file("a","rb").read())'
58 hg st
59
44 # Test --eol and binary patches
60 # Test --eol and binary patches
45 python -c 'file("b", "wb").write("a\x00\nb")'
61 python -c 'file("b", "wb").write("a\x00\nb")'
46 hg ci -Am addb
62 hg ci -Am addb
47 python -c 'file("b", "wb").write("a\x00\nc")'
63 python -c 'file("b", "wb").write("a\x00\nc")'
48 hg diff --git > bin.diff
64 hg diff --git > bin.diff
49 hg revert --no-backup b
65 hg revert --no-backup b
50 echo % binary patch with --eol
66 echo % binary patch with --eol
51 hg import --config patch.eol='CRLF' -m changeb bin.diff
67 hg import --config patch.eol='CRLF' -m changeb bin.diff
52 python -c 'print repr(file("b","rb").read())'
68 python -c 'print repr(file("b","rb").read())'
53 hg st
69 hg st
54 cd ..
70 cd ..
@@ -1,16 +1,23 b''
1 adding .hgignore
1 adding .hgignore
2 adding a
2 adding a
3 % invalid eol
3 % invalid eol
4 applying eol.diff
4 applying eol.diff
5 abort: Unsupported line endings type: LFCR
5 abort: Unsupported line endings type: LFCR
6 % force LF
6 % force LF
7 applying eol.diff
7 applying eol.diff
8 'a\nyyyy\ncc\n\nd\ne'
8 'a\nyyyy\ncc\n\nd\ne'
9 % force CRLF
9 % force CRLF
10 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
10 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
11 applying eol.diff
11 applying eol.diff
12 'a\r\nyyyy\r\ncc\r\n\r\nd\r\ne'
12 'a\r\nyyyy\r\ncc\r\n\r\nd\r\ne'
13 % auto EOL on LF file
14 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
15 applying eol.diff
16 'a\nyyyy\ncc\n\nd\ne'
17 % auto EOL on CRLF file
18 applying eol.diff
19 'a\r\nyyyy\r\ncc\r\n\r\nd\r\ne'
13 adding b
20 adding b
14 % binary patch with --eol
21 % binary patch with --eol
15 applying bin.diff
22 applying bin.diff
16 'a\x00\nc'
23 'a\x00\nc'
General Comments 0
You need to be logged in to leave comments. Login now