changeset 14389:909ac6b9636b

patch: stop modifying gitpatch objects gitpatch objects emitted by iterhunks() were referencing file paths unmodified from the input patch. _applydif() made them usable by modifying the gitpatch objects in-place with specified path strip level. The same modified objects were then reused by iterhunks() generator. _applydiff() now copies and update the paths which completely decouples both routines. As a side effect, the "git" event now receives only metadata about copies/renames to perform the necessary copies ahead of time. Other actions are handled in the "file" event.
author Patrick Mezard <pmezard@gmail.com>
date Thu, 19 May 2011 22:44:01 +0200
parents 37c997d21752
children ce77c275bec3
files mercurial/patch.py
diffstat 1 files changed, 17 insertions(+), 22 deletions(-) [+]
line wrap: on
line diff
--- a/mercurial/patch.py	Thu May 19 22:44:01 2011 +0200
+++ b/mercurial/patch.py	Thu May 19 22:44:01 2011 +0200
@@ -1157,7 +1157,8 @@
                 # scan whole input for git metadata
                 gitpatches = [('b/' + gp.path, gp) for gp
                               in scangitpatch(lr, x)]
-                yield 'git', [g[1] for g in gitpatches]
+                yield 'git', [g[1] for g in gitpatches
+                              if g[1].op in ('COPY', 'RENAME')]
                 gitpatches.reverse()
             afile = 'a/' + m.group(1)
             bfile = 'b/' + m.group(2)
@@ -1220,6 +1221,10 @@
                       eolmode=eolmode)
 
 def _applydiff(ui, fp, patcher, backend, changed, strip=1, eolmode='strict'):
+
+    def pstrip(p):
+        return pathstrip(p, strip - 1)[1]
+
     rejects = 0
     err = 0
     current_file = None
@@ -1239,18 +1244,19 @@
                 current_file = None
             afile, bfile, first_hunk, gp = values
             if gp:
-                changed[gp.path] = gp
+                path = pstrip(gp.path)
+                changed[path] = gp
                 if gp.op == 'DELETE':
-                    backend.unlink(gp.path)
+                    backend.unlink(path)
                     continue
                 if gp.op == 'RENAME':
-                    backend.unlink(gp.oldpath)
+                    backend.unlink(pstrip(gp.oldpath))
                 if gp.mode and not first_hunk:
                     if gp.op == 'ADD':
                         # Added files without content have no hunk and must be created
-                        backend.writelines(gp.path, [], gp.mode)
+                        backend.writelines(path, [], gp.mode)
                     else:
-                        backend.setmode(gp.path, gp.mode[0], gp.mode[1])
+                        backend.setmode(path, gp.mode[0], gp.mode[1])
             if not first_hunk:
                 continue
             try:
@@ -1266,11 +1272,7 @@
                 continue
         elif state == 'git':
             for gp in values:
-                gp.path = pathstrip(gp.path, strip - 1)[1]
-                if gp.oldpath:
-                    gp.oldpath = pathstrip(gp.oldpath, strip - 1)[1]
-                if gp.op in ('COPY', 'RENAME'):
-                    backend.copy(gp.oldpath, gp.path)
+                backend.copy(pstrip(gp.oldpath), pstrip(gp.path))
         else:
             raise util.Abort(_('unsupported parser state: %s') % state)
 
@@ -1387,25 +1389,18 @@
     try:
         changed = set()
         for state, values in iterhunks(fp):
-            if state == 'hunk':
-                continue
-            elif state == 'file':
+            if state == 'file':
                 afile, bfile, first_hunk, gp = values
                 if gp:
-                    changed.add(gp.path)
+                    changed.add(pathstrip(gp.path, strip - 1)[1])
                     if gp.op == 'RENAME':
-                        changed.add(gp.oldpath)
+                        changed.add(pathstrip(gp.oldpath, strip - 1)[1])
                 if not first_hunk:
                     continue
                 current_file, missing = selectfile(backend, afile, bfile,
                                                    first_hunk, strip)
                 changed.add(current_file)
-            elif state == 'git':
-                for gp in values:
-                    gp.path = pathstrip(gp.path, strip - 1)[1]
-                    if gp.oldpath:
-                        gp.oldpath = pathstrip(gp.oldpath, strip - 1)[1]
-            else:
+            elif state not in ('hunk', 'git'):
                 raise util.Abort(_('unsupported parser state: %s') % state)
         return changed
     finally: