patch: implement patch.eol=auto mode
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.
--- a/doc/hgrc.5.txt Sun Dec 20 17:18:02 2009 +0100
+++ b/doc/hgrc.5.txt Sun Dec 20 17:18:04 2009 +0100
@@ -648,7 +648,10 @@
When set to 'strict' patch content and patched files end of lines
are preserved. When set to ``lf`` or ``crlf``, both files end of lines
are ignored when patching and the result line endings are
- normalized to either LF (Unix) or CRLF (Windows).
+ normalized to either LF (Unix) or CRLF (Windows). When set to
+ ``auto``, end of lines are again ignored while patching but line
+ endings in patched files are normalized to their original setting
+ on a per-file basis.
Default: strict.
--- a/mercurial/patch.py Sun Dec 20 17:18:02 2009 +0100
+++ b/mercurial/patch.py Sun Dec 20 17:18:04 2009 +0100
@@ -239,6 +239,7 @@
self.fp = fp
self.buf = []
self.textmode = textmode
+ self.eol = None
def push(self, line):
if line is not None:
@@ -250,6 +251,11 @@
del self.buf[0]
return l
l = self.fp.readline()
+ if not self.eol:
+ if l.endswith('\r\n'):
+ self.eol = '\r\n'
+ elif l.endswith('\n'):
+ self.eol = '\n'
if self.textmode and l.endswith('\r\n'):
l = l[:-2] + '\n'
return l
@@ -264,13 +270,13 @@
# @@ -start,len +start,len @@ or @@ -start +start @@ if len is 1
unidesc = re.compile('@@ -(\d+)(,(\d+))? \+(\d+)(,(\d+))? @@')
contextdesc = re.compile('(---|\*\*\*) (\d+)(,(\d+))? (---|\*\*\*)')
-eolmodes = ['strict', 'crlf', 'lf']
+eolmodes = ['strict', 'crlf', 'lf', 'auto']
class patchfile(object):
def __init__(self, ui, fname, opener, missing=False, eolmode='strict'):
self.fname = fname
self.eolmode = eolmode
- self.eol = {'strict': None, 'crlf': '\r\n', 'lf': '\n'}[eolmode]
+ self.eol = None
self.opener = opener
self.ui = ui
self.lines = []
@@ -298,7 +304,10 @@
return [os.readlink(fname)]
fp = self.opener(fname, 'r')
try:
- return list(linereader(fp, self.eolmode != 'strict'))
+ lr = linereader(fp, self.eolmode != 'strict')
+ lines = list(lr)
+ self.eol = lr.eol
+ return lines
finally:
fp.close()
@@ -312,10 +321,17 @@
else:
fp = self.opener(fname, 'w')
try:
- if self.eol and self.eol != '\n':
+ if self.eolmode == 'auto' and self.eol:
+ eol = self.eol
+ elif self.eolmode == 'crlf':
+ eol = '\r\n'
+ else:
+ eol = '\n'
+
+ if self.eolmode != 'strict' and eol != '\n':
for l in lines:
if l and l[-1] == '\n':
- l = l[:-1] + self.eol
+ l = l[:-1] + eol
fp.write(l)
else:
fp.writelines(lines)
--- a/tests/test-import-eol Sun Dec 20 17:18:02 2009 +0100
+++ b/tests/test-import-eol Sun Dec 20 17:18:04 2009 +0100
@@ -28,19 +28,35 @@
python -c 'file("a", "wb").write("a\nbbb\ncc\n\nd\ne")'
hg ci -Am adda
python ../makepatch.py
+
echo % invalid eol
hg --config patch.eol='LFCR' import eol.diff
hg revert -a
+
echo % force LF
hg --traceback --config patch.eol='LF' import eol.diff
python -c 'print repr(file("a","rb").read())'
hg st
+
echo % force CRLF
hg up -C 0
hg --traceback --config patch.eol='CRLF' import eol.diff
python -c 'print repr(file("a","rb").read())'
hg st
+echo % auto EOL on LF file
+hg up -C 0
+hg --traceback --config patch.eol='auto' import eol.diff
+python -c 'print repr(file("a","rb").read())'
+hg st
+
+echo % auto EOL on CRLF file
+python -c 'file("a", "wb").write("a\r\nbbb\r\ncc\r\n\r\nd\r\ne")'
+hg commit -m 'switch EOLs in a'
+hg --traceback --config patch.eol='auto' import eol.diff
+python -c 'print repr(file("a","rb").read())'
+hg st
+
# Test --eol and binary patches
python -c 'file("b", "wb").write("a\x00\nb")'
hg ci -Am addb
--- a/tests/test-import-eol.out Sun Dec 20 17:18:02 2009 +0100
+++ b/tests/test-import-eol.out Sun Dec 20 17:18:04 2009 +0100
@@ -10,6 +10,13 @@
1 files updated, 0 files merged, 0 files removed, 0 files unresolved
applying eol.diff
'a\r\nyyyy\r\ncc\r\n\r\nd\r\ne'
+% auto EOL on LF file
+1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+applying eol.diff
+'a\nyyyy\ncc\n\nd\ne'
+% auto EOL on CRLF file
+applying eol.diff
+'a\r\nyyyy\r\ncc\r\n\r\nd\r\ne'
adding b
% binary patch with --eol
applying bin.diff