The intent is to fix many issues involving patching when win32ext is enabled.
With win32ext, the working directory and repository files EOLs are not the same
which means that patches made on a non-win32ext host do not apply cleanly
because of EOLs discrepancies. A theorically correct approach would be
transform either the patched file or the patch content with the
encoding/decoding filters used by win32ext. This solution is tricky to
implement and invasive, instead we prefer to address the win32ext case, by
offering a way to ignore input EOLs when patching and rewriting them when
saving the patched result.
In worst case, generating diff in upgrade mode can be two times more expensive
than generating it in git mode directly: we may have to regenerate the whole
diff again whenever a git feature is detected. Also, the first diff attempt is
completely buffered instead of being streamed. That said, even without having
profiled it yet, I am convinced we can fast-path the upgrade mode if necessary
were it to be used in regular diff commands, and not only in mq where avoiding
data loss is worth the price.
With eolmode set to 'lf' or 'crlf' we avoided the hunk duplication and
normalization by reading the input patch in text mode. Dropping this
optimization simplifies code expectations for a small overhead.
The change in test-mq-eol comes from a tolerance to CRLF instead of LF for last
lines without newlines being broken by this revision. This tolerance was only
partially supported and will be added again in a better way.
EOLs in patched files are restored to their original value after
patching. We use the first EOL found in the file, files with
inconsistent EOLs will thus be normalized during this process.
The old code mapped the value of eolmode ('strict', 'crlf' or 'lf') to
eol (None, '\r\n' or '\n') at the entry point in internalpatch. The
value of eol was then used directly as the desired EOL in patchfile.
We now delay the mapping and let patchfile do it instead. This allows
for more complicated behavior where it does not make sense to map
eolmode directly to the target EOLs.
The built-in None object is a singleton and it is therefore safe to
compare memory addresses with is. It is also faster, how much depends
on the object being compared. For a simple type like str I get:
| s = "foo" | s = None
----------+-----------+----------
s == None | 0.25 usec | 0.21 usec
s is None | 0.17 usec | 0.17 usec
The context variable is either True, False or None. Abbreviate it as C
and we get the following truth table where the second column is the
original expression and the third column is the new expression:
C | C or C == None | C is not False
True | True | True
False | False | False
None | True | True
In Python, the backslash in an unrecognized escape sequence is left
behind, which makes '\.' the same as r'\.'. Relying on this feature is
quite brittle, IMHO.
Removed unnecessary string concatenation as well.
It seems like the old behaviour with different handling for commands with and
without path was intended, but I think this behaviour of util.find_exe is
better:
* Always returns existing file
* or None if command not found - no default
* Windows: Returned file thus always ends with extension from PATHEXT
This fixes http://www.selenic.com/mercurial/bts/issue1459. The change might
fix other unintended behaviour too.
Implemented as two functions: diffstat, which yields lines of text,
formatted as a usual diffstat output, and diffstatdata, which is called
inside diffstat to do real performing and yield file names with
appropriate data (numbers of added and removed lines).
This is a first step toward an svn-like patch driver and makes patchfile
monkeypatching much easier. The latter is currently required to support
in-memory patching until the code is refactored.
hg export -o outfile 1 2 3 4 had the same effect as hg -o outfile 4
This was caused by opening with 'w' instead of 'a'. This only occurs when
the filename pattern resulted in ambiguous patch filenames.
Allow status() to take contexts as well as nodes. This lets us avoid
unpacking manifests multiple times and intelligently unpack manifests
in revision order. Also, we can avoid unpacking manifests at all when
there are no changes in the working directory.
add _checklink var to dirstate
introduce dirstate.flagfunc
switch users of util.execfunc/linkfunc to flagfunc
change manifestdict.set to take a flags string
change ctx.fileflags to ctx.flags
change gitmode func to a dict
remove util.execfunc/linkfunc
The self patching of files when diffed with a backup is a bit peculiar to me.
It makes sense in mpatch, that's less clear in mercurial patching code. Let's
document and preserve it for now.
Like some renames or copy operations, binary file removal does not generate any
"file" or "hunk" action, but was not tagged as such and let iterhunk() assume
no hunk was applied for the deleted file.
Sometimes, revisions cannot be represented by a regular diff, only a git diff
would capture binary files or permission changes. diffstat cannot handle git
patches and will output "0 files changed" when fed with an empty diff. We
cannot consider the latter to be an error, unless we rewrite diffstat to handle
these correctly.
Reported and explained by Peter Arrenbrecht <peter.arrenbrecht@gmail.com>.
Following file additions were skipped but empty files were still created. This situation could lead to qrefresh losing patch information.
'hg import' fails under Python 2.3. The name of the compare function parameter in the call to list.sort() is 'cmpfunc' in Python 2.3 and
'cmp' in Python 2.4+. Passing the compare function as a named parameter is therefore problematic.
If the file is writable by the user, but owned by a different user, the
chmod will otherwise fail with "Operation not permitted".
Additionally make very sure that the file is only written if either the number
of links is <= 1 or the file was successfully removed.
Maybe this minimal COW code should be replaced by something from util.
This is now invoked by default only if ui.patch is set. Otherwise, we
use our built-in patch. If that fails because it can't find any valid
hunks, we'll fall back to trying the external patch command.
Right now, to generate the manifest of the working dir, we have to
perform a full walk of the working dir, which will be very slow,
especially if we're interested in only a small part of it.
Since we use the manifest only to find out the mode of files for git
patches, manually build an execf function to do it.
This should fix issue567.
The behaviour of find_in_path was broken for config options containing
path names, because it always searched the given path, even when not
necessary. The find_exe function is more polite: if the name passed
to it contains a path component, it just returns it.
This patch removes the "copymod" attribute from the gitpatch
class.
AFAICS, that attribute was only used to delay the copying of
renamed/copied files if there are no other changes to the target,
but in this case, if there are changes to the source, we'll end
up copying the wrong version.
This should fix issue762.
When this option is set, import will apply the patch (which must
be generated by export) to the parents specified in the patch,
and check that the node produced by the patch matches the node
ID in the patch.