hgext3rd/evolve/cmdrewrite.py
changeset 3661 61fdd25542a6
parent 3660 f018656ca3bf
child 3670 1043e9c54355
--- a/hgext3rd/evolve/cmdrewrite.py	Sun Mar 18 23:48:06 2018 +0530
+++ b/hgext3rd/evolve/cmdrewrite.py	Wed Apr 11 07:23:34 2018 +0200
@@ -168,24 +168,7 @@
                                          match=matcher,
                                          opts=diffopts):
                 fp.write(chunk)
-
-        fp.seek(0)
-        newpatch = ui.edit(fp.getvalue(), old.user(), action="diff")
-
-        afp = stringio()
-        afp.write(newpatch)
-        if pats:
-            # write rest of the files in the patch
-            restmatcher = scmutil.match(old, [], opts={'exclude': pats})
-            for chunk, label in patch.diffui(repo, p1.node(), old.node(),
-                                             match=restmatcher,
-                                             opts=diffopts):
-                    afp.write(chunk)
-
-        afp.seek(0)
-        # write the patch to repo and get the newnode
-        newnode = _writepatch(ui, repo, old, afp)
-
+        newnode = _editandapply(ui, repo, pats, old, p1, fp, diffopts)
         if newnode == old.node():
             raise error.Abort(_("nothing changed"))
         metadata = {}
@@ -201,6 +184,44 @@
         tr.release()
         lockmod.release(lock, wlock)
 
+def _editandapply(ui, repo, pats, old, p1, fp, diffopts):
+    RETRYCHOICE = _('try to fix the patch (yn)?$$ &Yes $$ &No')
+    newnode = None
+    while newnode is None:
+        fp.seek(0)
+        previous_patch = fp.getvalue()
+        newpatch = ui.edit(fp.getvalue(), old.user(), action="diff")
+
+        afp = stringio()
+        afp.write(newpatch)
+        if pats:
+            # write rest of the files in the patch
+            restmatcher = scmutil.match(old, [], opts={'exclude': pats})
+            for chunk, label in patch.diffui(repo, p1.node(), old.node(),
+                                             match=restmatcher,
+                                             opts=diffopts):
+                    afp.write(chunk)
+
+        user_patch = afp.getvalue()
+        if user_patch == previous_patch:
+            raise error.Abort(_("patch unchanged"))
+        afp.seek(0)
+        # write the patch to repo and get the newnode
+        try:
+            newnode = _writepatch(ui, repo, old, afp)
+        except patch.PatchError as err:
+            ui.write_err(_("failed to apply edited patch: %s\n") % err)
+            defaultchoice = 0 # yes
+            if not ui.interactive:
+                defaultchoice = 1 # no
+            if ui.promptchoice(RETRYCHOICE, default=defaultchoice):
+                raise error.Abort(_("Could not apply amended path"))
+            else:
+                # consider a third choice where we restore the original patch
+                fp = stringio()
+                fp.write(user_patch)
+    return newnode
+
 def _writepatch(ui, repo, old, fp):
     """utility function to use filestore and patchrepo to apply a patch to the
     repository with metadata being extracted from the patch"""
@@ -219,14 +240,10 @@
     fp.seek(0)
     try:
         files = set()
-        try:
-            patch.patchrepo(ui, repo, pold, store, fp, 1, '',
-                            files=files, eolmode=None)
-        except patch.PatchError as err:
-            raise error.Abort(str(err))
-
-        finally:
-            del fp
+        # beware: next line may raise a PatchError to be handled by the caller
+        # of this function
+        patch.patchrepo(ui, repo, pold, store, fp, 1, '',
+                        files=files, eolmode=None)
 
         memctx = context.memctx(repo, parents, message, files=files,
                                 filectxfn=store,