diff mercurial/cmdutil.py @ 42568:f9da9d5f3f5a

graft: moved abortgraft and readgraft to cmdutil This patch moves `abortgraft` and `readgraft` to `cmdutil`. Various callers are updated accordingly. This is done because these serve as ulitlity functions for command `graft` and so that new functions regarding graft can be built from them. Differential Revision: https://phab.mercurial-scm.org/D6608
author Taapas Agrawal <taapas2897@gmail.com>
date Sat, 06 Jul 2019 22:19:36 +0530
parents 0231032729c4
children ceb31d96d3ae
line wrap: on
line diff
--- a/mercurial/cmdutil.py	Thu Jun 20 14:33:42 2019 -0400
+++ b/mercurial/cmdutil.py	Sat Jul 06 22:19:36 2019 +0530
@@ -38,6 +38,7 @@
     pathutil,
     phases,
     pycompat,
+    repair,
     revlog,
     rewriteutil,
     scmutil,
@@ -3345,3 +3346,67 @@
     if after[1]:
         hint = after[0]
     raise error.Abort(_('no %s in progress') % task, hint=hint)
+
+def abortgraft(ui, repo, graftstate):
+    """abort the interrupted graft and rollbacks to the state before interrupted
+    graft"""
+    if not graftstate.exists():
+        raise error.Abort(_("no interrupted graft to abort"))
+    statedata = readgraftstate(repo, graftstate)
+    newnodes = statedata.get('newnodes')
+    if newnodes is None:
+        # and old graft state which does not have all the data required to abort
+        # the graft
+        raise error.Abort(_("cannot abort using an old graftstate"))
+
+    # changeset from which graft operation was started
+    if len(newnodes) > 0:
+        startctx = repo[newnodes[0]].p1()
+    else:
+        startctx = repo['.']
+    # whether to strip or not
+    cleanup = False
+    from . import hg
+    if newnodes:
+        newnodes = [repo[r].rev() for r in newnodes]
+        cleanup = True
+        # checking that none of the newnodes turned public or is public
+        immutable = [c for c in newnodes if not repo[c].mutable()]
+        if immutable:
+            repo.ui.warn(_("cannot clean up public changesets %s\n")
+                         % ', '.join(bytes(repo[r]) for r in immutable),
+                         hint=_("see 'hg help phases' for details"))
+            cleanup = False
+
+        # checking that no new nodes are created on top of grafted revs
+        desc = set(repo.changelog.descendants(newnodes))
+        if desc - set(newnodes):
+            repo.ui.warn(_("new changesets detected on destination "
+                           "branch, can't strip\n"))
+            cleanup = False
+
+        if cleanup:
+            with repo.wlock(), repo.lock():
+                hg.updaterepo(repo, startctx.node(), overwrite=True)
+                # stripping the new nodes created
+                strippoints = [c.node() for c in repo.set("roots(%ld)",
+                                                          newnodes)]
+                repair.strip(repo.ui, repo, strippoints, backup=False)
+
+    if not cleanup:
+        # we don't update to the startnode if we can't strip
+        startctx = repo['.']
+        hg.updaterepo(repo, startctx.node(), overwrite=True)
+
+    ui.status(_("graft aborted\n"))
+    ui.status(_("working directory is now at %s\n") % startctx.hex()[:12])
+    graftstate.delete()
+    return 0
+
+def readgraftstate(repo, graftstate):
+    """read the graft state file and return a dict of the data stored in it"""
+    try:
+        return graftstate.read()
+    except error.CorruptedState:
+        nodes = repo.vfs.read('graftstate').splitlines()
+        return {'nodes': nodes}