diff --git a/doc/hgrc.5.txt b/doc/hgrc.5.txt --- a/doc/hgrc.5.txt +++ b/doc/hgrc.5.txt @@ -648,7 +648,10 @@ command or with Mercurial Queues extensi 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. diff --git a/mercurial/patch.py b/mercurial/patch.py --- a/mercurial/patch.py +++ b/mercurial/patch.py @@ -239,6 +239,7 @@ class linereader(object): self.fp = fp self.buf = [] self.textmode = textmode + self.eol = None def push(self, line): if line is not None: @@ -250,6 +251,11 @@ class linereader(object): 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 @@ class linereader(object): # @@ -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 @@ class patchfile(object): 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 @@ class patchfile(object): 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) diff --git a/tests/test-import-eol b/tests/test-import-eol --- a/tests/test-import-eol +++ b/tests/test-import-eol @@ -28,19 +28,35 @@ echo '\.diff' > .hgignore 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 diff --git a/tests/test-import-eol.out b/tests/test-import-eol.out --- a/tests/test-import-eol.out +++ b/tests/test-import-eol.out @@ -10,6 +10,13 @@ applying eol.diff 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