diff mercurial/patch.py @ 10127:d8214e944b84

patch: fix eolmode=auto with new files If target file does not exist or has no eol, current code was normalizing eols to LF. Preserve patch file eols instead.
author Patrick Mezard <pmezard@gmail.com>
date Wed, 23 Dec 2009 19:31:47 +0100
parents 1720d70cd6d4
children ea7c392f2b08
line wrap: on
line diff
--- a/mercurial/patch.py	Wed Dec 23 19:18:03 2009 +0100
+++ b/mercurial/patch.py	Wed Dec 23 19:31:47 2009 +0100
@@ -321,14 +321,14 @@
         else:
             fp = self.opener(fname, 'w')
         try:
-            if self.eolmode == 'auto' and self.eol:
+            if self.eolmode == 'auto':
                 eol = self.eol
             elif self.eolmode == 'crlf':
                 eol = '\r\n'
             else:
                 eol = '\n'
 
-            if self.eolmode != 'strict' and eol != '\n':
+            if self.eolmode != 'strict' and eol and eol != '\n':
                 for l in lines:
                     if l and l[-1] == '\n':
                         l = l[:-1] + eol
@@ -433,6 +433,15 @@
                 self.dirty = 1
             return 0
 
+        horig = h
+        if self.eolmode == 'auto' and self.eol:
+            # If eolmode == 'auto' and target file exists and has line
+            # endings we have to normalize input data before patching.
+            # Otherwise, patchfile operates in 'strict' mode. If
+            # eolmode is set to 'crlf' or 'lf', input hunk is already
+            # normalized to avoid data copy.
+            h = h.getnormalized()
+
         # fast case first, no offsets, no fuzz
         old = h.old()
         # patch starts counting at 1 unless we are adding the file
@@ -488,7 +497,7 @@
                         return fuzzlen
         self.printfile(True)
         self.ui.warn(_("Hunk #%d FAILED at %d\n") % (h.number, orig_start))
-        self.rej.append(h)
+        self.rej.append(horig)
         return -1
 
 class hunk(object):
@@ -500,13 +509,39 @@
         self.b = []
         self.starta = self.lena = None
         self.startb = self.lenb = None
-        if context:
-            self.read_context_hunk(lr)
-        else:
-            self.read_unified_hunk(lr)
+        if lr is not None:
+            if context:
+                self.read_context_hunk(lr)
+            else:
+                self.read_unified_hunk(lr)
         self.create = create
         self.remove = remove and not create
 
+    def getnormalized(self):
+        """Return a copy with line endings normalized to LF."""
+
+        def normalize(lines):
+            nlines = []
+            for line in lines:
+                if line.endswith('\r\n'):
+                    line = line[:-2] + '\n'
+                nlines.append(line)
+            return nlines
+
+        # Dummy object, it is rebuilt manually
+        nh = hunk(self.desc, self.number, None, None, False, False)
+        nh.number = self.number
+        nh.desc = self.desc
+        nh.a = normalize(self.a)
+        nh.b = normalize(self.b)
+        nh.starta = self.starta
+        nh.startb = self.startb
+        nh.lena = self.lena
+        nh.lenb = self.lenb
+        nh.create = self.create
+        nh.remove = self.remove
+        return nh
+
     def read_unified_hunk(self, lr):
         m = unidesc.match(self.desc)
         if not m:
@@ -974,7 +1009,10 @@
     current_file = None
     gitpatches = None
     opener = util.opener(os.getcwd())
-    textmode = eolmode != 'strict'
+    # In 'auto' mode, we must preserve original eols if target file
+    # eols are undefined. Otherwise, hunk data will be normalized
+    # later.
+    textmode = eolmode not in ('strict', 'auto')
 
     def closefile():
         if not current_file: