Patchwork [4,of,4] revert: add flag to make revert interactive

login
register
mail settings
Submitter Laurent Charignon
Date March 18, 2015, 2:17 a.m.
Message ID <365b6d3e8e5046ab0e53.1426645056@dev919.prn2.facebook.com>
Download mbox | patch
Permalink /patch/8137/
State Accepted
Commit 521fe8287dd54bd9f1a6ea6f3cbec53c22931d2e
Headers show

Comments

Laurent Charignon - March 18, 2015, 2:17 a.m.
# HG changeset patch
# User Laurent Charignon <lcharignon@fb.com>
# Date 1426548839 25200
#      Mon Mar 16 16:33:59 2015 -0700
# Node ID 365b6d3e8e5046ab0e538686dd8cf25f73efa039
# Parent  86f9b176ee03b719c29f260776932b4263691f65
revert: add flag to make revert interactive
Matt Mackall - March 18, 2015, 9:12 p.m.
On Tue, 2015-03-17 at 19:17 -0700, Laurent Charignon wrote:
> # HG changeset patch
> # User Laurent Charignon <lcharignon@fb.com>
> # Date 1426548839 25200
> #      Mon Mar 16 16:33:59 2015 -0700
> # Node ID 365b6d3e8e5046ab0e538686dd8cf25f73efa039
> # Parent  86f9b176ee03b719c29f260776932b4263691f65
> revert: add flag to make revert interactive

These are queued for default, thanks, but I urge you to read:

http://mercurial.selenic.com/wiki/WritingTests#No_more_new_test_scripts.21
Katsunori FUJIWARA - March 19, 2015, 8:40 a.m.
At Tue, 17 Mar 2015 19:17:36 -0700,
Laurent Charignon wrote:
> 
> # HG changeset patch
> # User Laurent Charignon <lcharignon@fb.com>
> # Date 1426548839 25200
> #      Mon Mar 16 16:33:59 2015 -0700
> # Node ID 365b6d3e8e5046ab0e538686dd8cf25f73efa039
> # Parent  86f9b176ee03b719c29f260776932b4263691f65
> revert: add flag to make revert interactive

> diff --git a/tests/test-revert-interactive.t b/tests/test-revert-interactive.t
> new file mode 100644
> --- /dev/null
> +++ b/tests/test-revert-interactive.t
> @@ -0,0 +1,203 @@
> +Revert interactive tests
> +1 add and commit file f
> +2 add commit file folder1/g
> +3 add and commit file folder2/h
> +4 add and commit file folder1/i
> +5 commit change to file f
> +6 commit changes to files folder1/g folder2/h
> +7 commit changes to files folder1/g folder2/h
> +8 revert interactive to commit id 2 (line 3 above), check that folder1/i is removed and
> +9 make workdir match 7
> +10 run the same test than 8 from within folder1 and check same expectations
> +
> +  $ cat <<EOF >> $HGRCPATH
> +  > [ui]
> +  > interactive = true
> +  > [extensions]
> +  > record =
> +  > EOF
> +
> +
> +  $ mkdir -p a/{folder1,folder2}

When commands in "*.t" script files are executed on "sh" (default of
run-tests.py), "{folder1,folder2}" syntax can't be expanded as you
expected and causes failure of test-revert-interactive.t.

This should be written as "mkdir -p a/folder1 a/folder2" or so for
portability.

----------------------------------------------------------------------
[FUJIWARA Katsunori]                             foozy@lares.dti.ne.jp

Patch

diff --git a/mercurial/cmdutil.py b/mercurial/cmdutil.py
--- a/mercurial/cmdutil.py
+++ b/mercurial/cmdutil.py
@@ -3019,8 +3019,8 @@ 
         if not opts.get('dry_run'):
             needdata = ('revert', 'add', 'undelete')
             _revertprefetch(repo, ctx, *[actions[name][0] for name in needdata])
-
-            _performrevert(repo, parents, ctx, actions)
+            interactive = opts.get('interactive', False)
+            _performrevert(repo, parents, ctx, actions, interactive)
 
         # get the list of subrepos that must be reverted
         subrepomatch = scmutil.match(ctx, pats, opts)
@@ -3037,7 +3037,7 @@ 
     """Let extension changing the storage layer prefetch content"""
     pass
 
-def _performrevert(repo, parents, ctx, actions):
+def _performrevert(repo, parents, ctx, actions, interactive=False):
     """function that actually perform all the actions computed for revert
 
     This is an independent function to let extension to plug in and react to
@@ -3071,10 +3071,40 @@ 
             normal = repo.dirstate.normallookup
         else:
             normal = repo.dirstate.normal
-    for f in actions['revert'][0]:
-        checkout(f)
-        if normal:
-            normal(f)
+
+    if interactive:
+        # Prompt the user for changes to revert
+        torevert = [repo.wjoin(f) for f in actions['revert'][0]]
+        m = scmutil.match(ctx, torevert, {})
+        diff = patch.diff(repo, None, ctx.node(), m)
+        originalchunks = patch.parsepatch(diff)
+        try:
+            chunks = recordfilter(repo.ui, originalchunks)
+        except patch.PatchError, err:
+            raise util.Abort(_('error parsing patch: %s') % err)
+
+        # Apply changes
+        fp = cStringIO.StringIO()
+        for c in chunks:
+            c.write(fp)
+        dopatch = fp.tell()
+        fp.seek(0)
+        if dopatch:
+            try:
+                patch.internalpatch(repo.ui, repo, fp, 1, eolmode=None)
+            except patch.PatchError, err:
+                raise util.Abort(str(err))
+        del fp
+
+        for f in actions['revert'][0]:
+            if normal:
+                normal(f)
+
+    else:
+        for f in actions['revert'][0]:
+            checkout(f)
+            if normal:
+                normal(f)
 
     for f in actions['add'][0]:
         checkout(f)
diff --git a/mercurial/commands.py b/mercurial/commands.py
--- a/mercurial/commands.py
+++ b/mercurial/commands.py
@@ -5375,6 +5375,7 @@ 
     ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
     ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
     ('C', 'no-backup', None, _('do not save backup copies of files')),
+    ('i', 'interactive', None, _('interactively select the changes')),
     ] + walkopts + dryrunopts,
     _('[OPTION]... [-r REV] [NAME]...'))
 def revert(ui, repo, *pats, **opts):
diff --git a/tests/test-completion.t b/tests/test-completion.t
--- a/tests/test-completion.t
+++ b/tests/test-completion.t
@@ -279,7 +279,7 @@ 
   recover: 
   rename: after, force, include, exclude, dry-run
   resolve: all, list, mark, unmark, no-status, tool, include, exclude, template
-  revert: all, date, rev, no-backup, include, exclude, dry-run
+  revert: all, date, rev, no-backup, interactive, include, exclude, dry-run
   rollback: dry-run, force
   root: 
   tag: force, local, rev, remove, edit, message, date, user
diff --git a/tests/test-revert-interactive.t b/tests/test-revert-interactive.t
new file mode 100644
--- /dev/null
+++ b/tests/test-revert-interactive.t
@@ -0,0 +1,203 @@ 
+Revert interactive tests
+1 add and commit file f
+2 add commit file folder1/g
+3 add and commit file folder2/h
+4 add and commit file folder1/i
+5 commit change to file f
+6 commit changes to files folder1/g folder2/h
+7 commit changes to files folder1/g folder2/h
+8 revert interactive to commit id 2 (line 3 above), check that folder1/i is removed and
+9 make workdir match 7
+10 run the same test than 8 from within folder1 and check same expectations
+
+  $ cat <<EOF >> $HGRCPATH
+  > [ui]
+  > interactive = true
+  > [extensions]
+  > record =
+  > EOF
+
+
+  $ mkdir -p a/{folder1,folder2}
+  $ cd a
+  $ hg init
+  $ seq 1 5 > f ; hg add f ; hg commit -m "adding f"
+  $ seq 1 5 > folder1/g ; hg add folder1/g ; hg commit -m "adding folder1/g"
+  $ seq 1 5 > folder2/h ; hg add folder2/h ; hg commit -m "adding folder2/h"
+  $ seq 1 5 > folder1/i ; hg add folder1/i ; hg commit -m "adding folder1/i"
+  $ echo "a" > f ; seq 1 5 >> f ; echo "b" >> f ; hg commit -m "modifying f"
+  $ echo "c" > folder1/g ; seq 1 5 >> folder1/g ; echo "d" >> folder1/g ; hg commit -m "modifying folder1/g"
+  $ echo "e" > folder2/h ; seq 1 5 >> folder2/h ; echo "f" >> folder2/h ; hg commit -m "modifying folder2/h"
+  $ hg tip
+  changeset:   6:59dd6e4ab63a
+  tag:         tip
+  user:        test
+  date:        Thu Jan 01 00:00:00 1970 +0000
+  summary:     modifying folder2/h
+  
+  $ hg revert -i -r 2 --all -- << EOF
+  > y
+  > y
+  > y
+  > y
+  > y
+  > n
+  > n
+  > EOF
+  reverting f
+  reverting folder1/g (glob)
+  removing folder1/i (glob)
+  reverting folder2/h (glob)
+  diff -r 89ac3d72e4a4 f
+  2 hunks, 2 lines changed
+  examine changes to 'f'? [Ynesfdaq?] y
+  
+  @@ -1,6 +1,5 @@
+  -a
+   1
+   2
+   3
+   4
+   5
+  record change 1/6 to 'f'? [Ynesfdaq?] y
+  
+  @@ -2,6 +1,5 @@
+   1
+   2
+   3
+   4
+   5
+  -b
+  record change 2/6 to 'f'? [Ynesfdaq?] y
+  
+  diff -r 89ac3d72e4a4 folder1/g
+  2 hunks, 2 lines changed
+  examine changes to 'folder1/g'? [Ynesfdaq?] y
+  
+  @@ -1,6 +1,5 @@
+  -c
+   1
+   2
+   3
+   4
+   5
+  record change 3/6 to 'folder1/g'? [Ynesfdaq?] y
+  
+  @@ -2,6 +1,5 @@
+   1
+   2
+   3
+   4
+   5
+  -d
+  record change 4/6 to 'folder1/g'? [Ynesfdaq?] n
+  
+  diff -r 89ac3d72e4a4 folder2/h
+  2 hunks, 2 lines changed
+  examine changes to 'folder2/h'? [Ynesfdaq?] n
+  
+  $ cat f
+  1
+  2
+  3
+  4
+  5
+  $ cat folder1/g
+  1
+  2
+  3
+  4
+  5
+  d
+  $ cat folder2/h
+  e
+  1
+  2
+  3
+  4
+  5
+  f
+  $ hg update -C 6
+  3 files updated, 0 files merged, 0 files removed, 0 files unresolved
+  $ hg revert -i -r 2 --all -- << EOF
+  > y
+  > y
+  > y
+  > y
+  > y
+  > n
+  > n
+  > EOF
+  reverting f
+  reverting folder1/g (glob)
+  removing folder1/i (glob)
+  reverting folder2/h (glob)
+  diff -r 89ac3d72e4a4 f
+  2 hunks, 2 lines changed
+  examine changes to 'f'? [Ynesfdaq?] y
+  
+  @@ -1,6 +1,5 @@
+  -a
+   1
+   2
+   3
+   4
+   5
+  record change 1/6 to 'f'? [Ynesfdaq?] y
+  
+  @@ -2,6 +1,5 @@
+   1
+   2
+   3
+   4
+   5
+  -b
+  record change 2/6 to 'f'? [Ynesfdaq?] y
+  
+  diff -r 89ac3d72e4a4 folder1/g
+  2 hunks, 2 lines changed
+  examine changes to 'folder1/g'? [Ynesfdaq?] y
+  
+  @@ -1,6 +1,5 @@
+  -c
+   1
+   2
+   3
+   4
+   5
+  record change 3/6 to 'folder1/g'? [Ynesfdaq?] y
+  
+  @@ -2,6 +1,5 @@
+   1
+   2
+   3
+   4
+   5
+  -d
+  record change 4/6 to 'folder1/g'? [Ynesfdaq?] n
+  
+  diff -r 89ac3d72e4a4 folder2/h
+  2 hunks, 2 lines changed
+  examine changes to 'folder2/h'? [Ynesfdaq?] n
+  
+  $ cat f
+  1
+  2
+  3
+  4
+  5
+  $ cat folder1/g
+  1
+  2
+  3
+  4
+  5
+  d
+  $ cat folder2/h
+  e
+  1
+  2
+  3
+  4
+  5
+  f