Commits

rcohen committed 3b6d23d

Save the parent rev when shelving and use it to unshelve with merge tech instead of patching.

Comments (0)

Files changed (1)

 """
 
 from mercurial.i18n import _
-from mercurial import commands, cmdutil, hg, patch, util
-from mercurial import extensions, fancyopts
+from mercurial import commands, cmdutil, hg, patch, util, error
+from mercurial import extensions, fancyopts, simplemerge
 from mercurial.node import hex, bin
 import cStringIO, os, re, errno, tempfile, sys
 
         fp2.write('%s' % self.currentpatch)
         fp2.close()
 
-    def patch(self, repo, patchfile):
-        """actually applies a patch; copied from mq"""
-        files = {}
-        try:
-            fuzz = patch.patch(self.join(patchfile), self.ui, strip = 1,
-                               cwd = repo.root, files = files)
-        except Exception, inst:
-            self.ui.note(str(inst) + '\n')
-            if not self.ui.verbose:
-                self.ui.warn('patch failed, unable to continue (try -v)\n')
-            return (False, files, False)
-
-        return (True, files, fuzz)
-
     def check_localchanges(self, repo, force=False):
         """guards against local changes; copied from mq"""
         m, a, r, d = repo.status()[:4]
                 raise util.Abort(_('local changes found'))
         return m, a, r, d
 
+    def _applypatch(self, repo, patchfile, sim, force=False, **opts):
+        """applies a patch the old fashioned way."""
+        files, success = {}, True
+        try:
+            fuzz = patch.patch(self.join(patchfile), self.ui, strip = 1,
+                               cwd = repo.root, files = files)
+            patch.updatedir(self.ui, repo, files, similarity = sim/100.)
+        except Exception, inst:
+            self.ui.note(str(inst) + '\n')
+            if not self.ui.verbose:
+                self.ui.warn('patch failed, unable to continue (try -v)\n')
+            success = False
+        return success
+
+    def _applymerge(self, repo, patchfile, sim, name, parent, force=False, **opts):
+        """applies a patch using fancy merge technology."""
+        def smwrapper(orig, *args, **opts):
+            opts['label'] = ['local', 'shelf:%s' % name]
+            orig(*args, **opts)
+        smo = extensions.wrapfunction(simplemerge, 'simplemerge', smwrapper)
+
+        def savediff():
+            opts['git'] = True
+            fp = opener('.saved', 'w')
+            for chunk in patch.diff(repo, head, None,
+                                     opts=patch.diffopts(self.ui, opts)):
+                fp.write(chunk)
+            fp.close()
+
+        try:
+            mq = extensions.find('mq')
+        except KeyError:
+            raise util.Abort(_("'mq' extension not loaded"))
+        opener = util.opener('.hg/attic')
+        quiet = self.ui.quiet
+        self.ui.quiet = True
+        whead, phead = None, None
+        success = False
+        try:
+            head = repo.dirstate.parents()[0]
+            # Save the open changes
+            n = repo.commit(None, 'temp', 'hgattic', force=1)
+            savediff()
+            whead = repo.heads(None)[0]
+            # Set the workspace to match the base version for patching
+            hg.clean(repo, parent)
+            files = {}
+            patch.patch(patchfile, self.ui, strip=1, files=files)
+            patch.updatedir(self.ui, repo, files, similarity=sim/100.)
+            n = repo.commit(None, 'temp', 'hgattic', force=1)
+            phead = repo.heads(None)[0]
+            # Merge the working copy with the patched copy
+            if parent != whead:
+                hg.merge(repo, whead, force=True)
+            savediff()
+            success = True
+        finally:
+            simplemerge.simplemerge = smo
+            hg.clean(repo, head)
+            strip_opts = {'backup': False, 'nobackup': True, 'force': False}
+            if whead and head != whead:
+                mq.strip(self.ui, repo, whead, **strip_opts)
+            if phead and head != phead:
+                mq.strip(self.ui, repo, phead, **strip_opts)
+            if not success:
+                self._applypatch(repo, '.saved', sim, force, **opts)
+            self.ui.quiet = quiet
+        if success:
+            success = self._applypatch(repo, '.saved', sim, force, **opts)
+        return success
+
     def apply(self, repo, patchfile, sim, force=False, **opts):
         """applies a patch and manages repo and attic state"""
         self.check_localchanges(repo, force)
-        (success, files, fuzz) = self.patch(repo, patchfile)
+        data = patch.extract(self.ui, open(self.join(patchfile), 'r'))
+        tmpname, message, user, date, branch, nodeid, p1, p2 = data
+        merge = False
+        try:
+            if p1 and repo[p1]:
+                merge = True
+            try:
+                mq = extensions.find('mq')
+            except KeyError:
+                merge = False
+        except error.RepoError:
+            pass
+        if merge:
+            success = self._applymerge(repo, tmpname, sim, patchfile, p1,
+                                        force=force, **opts)
+        else:
+            success = self._applypatch(repo, tmpname, sim,
+                                        force=force, **opts)
+        os.unlink(tmpname)
         if success:
-            if files:
-                patch.updatedir(self.ui, repo, files, similarity = sim/100.)
             self.applied = patchfile
             self.currentpatch = patchfile
             self.persiststate()
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.