Patchwork [2,of,2,v2] histedit: add 'x'/'exec' verb

login
register
mail settings
Submitter David Soria Parra
Date Sept. 17, 2014, 12:58 a.m.
Message ID <b37ac883fe2d267fdbff.1410915520@davidsp-mbp.local>
Download mbox | patch
Permalink /patch/5837/
State Changes Requested
Headers show

Comments

David Soria Parra - Sept. 17, 2014, 12:58 a.m.
# HG changeset patch
# User David Soria Parra <davidsp@fb.com>
# Date 1410900110 25200
#      Tue Sep 16 13:41:50 2014 -0700
# Node ID b37ac883fe2d267fdbff2fbfc72477738493531c
# Parent  d4e975e2707a0ea606c22ed472d56fab4fda7ae2
histedit: add 'x'/'exec' verb

Add the 'x'/'exec' verb to execute a command. As exec lives in it's own line
and doesn't have a changeset attached to but applies to the previous changeset,
we have add some special handling. In particular when we restore we don't want
to execute the command again.
Pierre-Yves David - Sept. 20, 2014, 12:57 a.m.
On 09/16/2014 05:58 PM, David Soria Parra wrote:
> # HG changeset patch
> # User David Soria Parra <davidsp@fb.com>
> # Date 1410900110 25200
> #      Tue Sep 16 13:41:50 2014 -0700
> # Node ID b37ac883fe2d267fdbff2fbfc72477738493531c
> # Parent  d4e975e2707a0ea606c22ed472d56fab4fda7ae2
> histedit: add 'x'/'exec' verb
>
> Add the 'x'/'exec' verb to execute a command. As exec lives in it's own line
> and doesn't have a changeset attached to but applies to the previous changeset,
> we have add some special handling. In particular when we restore we don't want
> to execute the command again.

This new action needs to be added to the histedit documentation.

>
> diff --git a/hgext/histedit.py b/hgext/histedit.py
> --- a/hgext/histedit.py
> +++ b/hgext/histedit.py
> @@ -429,7 +429,11 @@
>           raise error.InterventionRequired(
>               _('Working copy dirty, please check the files listed above.\n'
>                 'When you are finished, run hg histedit --continue to resume.'))
> -    return ctx, []
> +
> +    newctx = repo['.']
> +    if ctx.node() != newctx.node():
> +        return newctx, [(ctx.node(), (newctx.node(),))]
> +    return newctx, []
>
>   def message(ui, repo, ctx, ha, opts):
>       oldctx = repo[ha]
> @@ -486,6 +490,8 @@
>                  'drop': drop,
>                  'm': message,
>                  'mess': message,
> +               'x': execute,
> +               'exec': execute,
>                  }
>
>   @command('histedit',
> @@ -707,7 +713,14 @@
>
>   def bootstrapcontinue(ui, repo, parentctx, rules, opts):
>       action, currentnode = rules.pop(0)
> -    ctx = repo[currentnode]
> +    if action in ['x', 'exec']:
> +        action, currentnode = rules.pop(0)
> +        # ensure we jump to the next node after an exec
> +        if action not in ['x', 'exec']:

micro nits: could be ('x', 'exec') instead of ['x, 'exec']


> +            ctx = repo[currentnode]
> +            hg.update(repo, ctx.node())
> +    else:
> +        ctx = repo[currentnode]
>
>       newchildren = gatherchildren(repo, parentctx)
>
> @@ -825,20 +838,23 @@
>           if ' ' not in r:
>               raise util.Abort(_('malformed line "%s"') % r)
>           action, rest = r.split(' ', 1)
> -        ha = rest.strip().split(' ', 1)[0]
> -        try:
> -            ha = str(repo[ha])  # ensure its a short hash
> -        except error.RepoError:
> -            raise util.Abort(_('unknown changeset %s listed') % ha)
> -        if ha not in expected:
> -            raise util.Abort(
> -                _('may not use changesets other than the ones listed'))
> -        if ha in seen:
> -            raise util.Abort(_('duplicated command for changeset %s') % ha)
> -        seen.add(ha)
> -        if action not in actiontable:
> -            raise util.Abort(_('unknown action "%s"') % action)
> -        parsed.append([action, ha])
> +        if action in ['x', 'exec']:
> +            parsed.append([action, rest])

You want to add a comment here so that future reader understand what is 
going on.


> +        else:
> +            ha = rest.strip().split(' ', 1)[0]
> +            try:
> +                ha = str(repo[ha])  # ensure its a short hash
> +            except error.RepoError:
> +                raise util.Abort(_('unknown changeset %s listed') % ha)
> +            if ha not in expected:
> +                raise util.Abort(
> +                    _('may not use changesets other than the ones listed'))
> +            if ha in seen:
> +                raise util.Abort(_('duplicated command for changeset %s') % ha)
> +            seen.add(ha)
> +            if action not in actiontable:
> +                raise util.Abort(_('unknown action "%s"') % action)
> +            parsed.append([action, ha])
>       missing = sorted(expected - seen)  # sort to stabilize output
>       if missing:
>           raise util.Abort(_('missing rules for changeset %s') % missing[0],
> diff --git a/tests/test-histedit-exec.t b/tests/test-histedit-exec.t
> new file mode 100644
> --- /dev/null
> +++ b/tests/test-histedit-exec.t
> @@ -0,0 +1,191 @@
> +  $ . "$TESTDIR/histedit-helpers.sh"
> +
> +  $ cat >> $HGRCPATH <<EOF
> +  > [extensions]
> +  > histedit=
> +  > EOF
> +
> +  $ initrepo ()
> +  > {
> +  >     hg init r
> +  >     cd r
> +  >     for x in a b c d e f ; do
> +  >         echo $x > $x
> +  >         hg add $x
> +  >         hg ci -m $x
> +  >     done
> +  > }
> +
> +  $ initrepo
> +
> +log before edit
> +
> +  $ hg log --graph
> +  @  changeset:   5:652413bf663e
> +  |  tag:         tip
> +  |  user:        test
> +  |  date:        Thu Jan 01 00:00:00 1970 +0000
> +  |  summary:     f
> +  |
> +  o  changeset:   4:e860deea161a
> +  |  user:        test
> +  |  date:        Thu Jan 01 00:00:00 1970 +0000
> +  |  summary:     e
> +  |
> +  o  changeset:   3:055a42cdd887
> +  |  user:        test
> +  |  date:        Thu Jan 01 00:00:00 1970 +0000
> +  |  summary:     d
> +  |
> +  o  changeset:   2:177f92b77385
> +  |  user:        test
> +  |  date:        Thu Jan 01 00:00:00 1970 +0000
> +  |  summary:     c
> +  |
> +  o  changeset:   1:d2ae7f538514
> +  |  user:        test
> +  |  date:        Thu Jan 01 00:00:00 1970 +0000
> +  |  summary:     b
> +  |
> +  o  changeset:   0:cb9a9f314b8b
> +     user:        test
> +     date:        Thu Jan 01 00:00:00 1970 +0000
> +     summary:     a
> +
> +
> +exec & continue should preserve hashes
> +
> +  $ hg histedit 177f92b77385 --commands - 2>&1 << EOF| fixbundle
> +  > pick 177f92b77385 c
> +  > pick 055a42cdd887 d
> +  > pick e860deea161a e
> +  > exec echo "this should be printed to stdout"
> +  > exec echo "this should be printed to stderr" >&2
> +  > pick 652413bf663e f
> +  > EOF
> +  this should be printed to stdout
> +  this should be printed to stderr
> +  0 files updated, 0 files merged, 1 files removed, 0 files unresolved
> +  0 files updated, 0 files merged, 0 files removed, 0 files unresolved
> +  1 files updated, 0 files merged, 0 files removed, 0 files unresolved
> +
> +  $ hg log --graph
> +  @  changeset:   5:652413bf663e
> +  |  tag:         tip
> +  |  user:        test
> +  |  date:        Thu Jan 01 00:00:00 1970 +0000
> +  |  summary:     f
> +  |
> +  o  changeset:   4:e860deea161a
> +  |  user:        test
> +  |  date:        Thu Jan 01 00:00:00 1970 +0000
> +  |  summary:     e
> +  |
> +  o  changeset:   3:055a42cdd887
> +  |  user:        test
> +  |  date:        Thu Jan 01 00:00:00 1970 +0000
> +  |  summary:     d
> +  |
> +  o  changeset:   2:177f92b77385
> +  |  user:        test
> +  |  date:        Thu Jan 01 00:00:00 1970 +0000
> +  |  summary:     c
> +  |
> +  o  changeset:   1:d2ae7f538514
> +  |  user:        test
> +  |  date:        Thu Jan 01 00:00:00 1970 +0000
> +  |  summary:     b
> +  |
> +  o  changeset:   0:cb9a9f314b8b
> +     user:        test
> +     date:        Thu Jan 01 00:00:00 1970 +0000
> +     summary:     a
> +
> +ensure we are properly executed in a shell
> +  $ hg histedit 177f92b77385 --commands - 2>&1 << EOF| fixbundle
> +  > pick 177f92b77385 c
> +  > pick 055a42cdd887 d
> +  > pick e860deea161a e
> +  > exec echo "foo" >/dev/null && exit 0
> +  > pick 652413bf663e f
> +  > EOF
> +  0 files updated, 0 files merged, 1 files removed, 0 files unresolved
> +  1 files updated, 0 files merged, 0 files removed, 0 files unresolved

I can we get a test testing that something actually happend during exec 
(before redirecting this something to /dev/null)


> +a failing command should drop us into the shell
> +
> +  $ hg histedit 177f92b77385 --commands - 2>&1 << EOF| fixbundle
> +  > pick 177f92b77385 c
> +  > pick 055a42cdd887 d
> +  > pick e860deea161a e
> +  > exec exit 1
> +  > pick 652413bf663e f
> +  > EOF
> +  0 files updated, 0 files merged, 1 files removed, 0 files unresolved
> +  Command 'exit 1' failed with exit status 1.
> +
> +continue should work
> +
> +  $ hg histedit --continue
> +  1 files updated, 0 files merged, 0 files removed, 0 files unresolved
> +  0 files updated, 0 files merged, 0 files removed, 0 files unresolved
> +
> +  $ hg log --template '{node|short} {desc}' --graph
> +  @  652413bf663e f
> +  |
> +  o  e860deea161a e
> +  |
> +  o  055a42cdd887 d
> +  |
> +  o  177f92b77385 c
> +  |
> +  o  d2ae7f538514 b
> +  |
> +  o  cb9a9f314b8b a
> +
> +
> +abort should work
> +
> +  $ hg histedit 177f92b77385 --commands - 2>&1 << EOF| fixbundle
> +  > pick 177f92b77385 c
> +  > pick 055a42cdd887 d
> +  > pick e860deea161a e
> +  > exec exit 1
> +  > pick 652413bf663e f
> +  > EOF
> +  0 files updated, 0 files merged, 1 files removed, 0 files unresolved
> +  Command 'exit 1' failed with exit status 1.
> +
> +  $ hg histedit --abort
> +  1 files updated, 0 files merged, 0 files removed, 0 files unresolved
> +
> +  $ hg log --template '{node|short} {desc}' --graph
> +  @  652413bf663e f
> +  |
> +  o  e860deea161a e
> +  |
> +  o  055a42cdd887 d
> +  |
> +  o  177f92b77385 c
> +  |
> +  o  d2ae7f538514 b
> +  |
> +  o  cb9a9f314b8b a
> +
> +
> +abort on a failing command, e.g when we have children
> +
> +
> +  $ hg histedit 177f92b77385 --commands - 2>&1 << EOF| fixbundle
> +  > pick 177f92b77385 c
> +  > pick 055a42cdd887 d
> +  > pick e860deea161a e
> +  > exec echo 'added' > added && hg addremove && hg commit --amend
> +  > pick 652413bf663e f
> +  > EOF
> +  abort: cannot amend changeset with children
> +  0 files updated, 0 files merged, 1 files removed, 0 files unresolved
> +
> +  $ hg id -r . -i
> +  e860deea161a

Can we get a test for:
1. rewriting history
2. appending history
3. leaving uncommited change (from clean exec run and from --continue)
4. some combination of the above ?

Patch

diff --git a/hgext/histedit.py b/hgext/histedit.py
--- a/hgext/histedit.py
+++ b/hgext/histedit.py
@@ -429,7 +429,11 @@ 
         raise error.InterventionRequired(
             _('Working copy dirty, please check the files listed above.\n'
               'When you are finished, run hg histedit --continue to resume.'))
-    return ctx, []
+
+    newctx = repo['.']
+    if ctx.node() != newctx.node():
+        return newctx, [(ctx.node(), (newctx.node(),))]
+    return newctx, []
 
 def message(ui, repo, ctx, ha, opts):
     oldctx = repo[ha]
@@ -486,6 +490,8 @@ 
                'drop': drop,
                'm': message,
                'mess': message,
+               'x': execute,
+               'exec': execute,
                }
 
 @command('histedit',
@@ -707,7 +713,14 @@ 
 
 def bootstrapcontinue(ui, repo, parentctx, rules, opts):
     action, currentnode = rules.pop(0)
-    ctx = repo[currentnode]
+    if action in ['x', 'exec']:
+        action, currentnode = rules.pop(0)
+        # ensure we jump to the next node after an exec
+        if action not in ['x', 'exec']:
+            ctx = repo[currentnode]
+            hg.update(repo, ctx.node())
+    else:
+        ctx = repo[currentnode]
 
     newchildren = gatherchildren(repo, parentctx)
 
@@ -825,20 +838,23 @@ 
         if ' ' not in r:
             raise util.Abort(_('malformed line "%s"') % r)
         action, rest = r.split(' ', 1)
-        ha = rest.strip().split(' ', 1)[0]
-        try:
-            ha = str(repo[ha])  # ensure its a short hash
-        except error.RepoError:
-            raise util.Abort(_('unknown changeset %s listed') % ha)
-        if ha not in expected:
-            raise util.Abort(
-                _('may not use changesets other than the ones listed'))
-        if ha in seen:
-            raise util.Abort(_('duplicated command for changeset %s') % ha)
-        seen.add(ha)
-        if action not in actiontable:
-            raise util.Abort(_('unknown action "%s"') % action)
-        parsed.append([action, ha])
+        if action in ['x', 'exec']:
+            parsed.append([action, rest])
+        else:
+            ha = rest.strip().split(' ', 1)[0]
+            try:
+                ha = str(repo[ha])  # ensure its a short hash
+            except error.RepoError:
+                raise util.Abort(_('unknown changeset %s listed') % ha)
+            if ha not in expected:
+                raise util.Abort(
+                    _('may not use changesets other than the ones listed'))
+            if ha in seen:
+                raise util.Abort(_('duplicated command for changeset %s') % ha)
+            seen.add(ha)
+            if action not in actiontable:
+                raise util.Abort(_('unknown action "%s"') % action)
+            parsed.append([action, ha])
     missing = sorted(expected - seen)  # sort to stabilize output
     if missing:
         raise util.Abort(_('missing rules for changeset %s') % missing[0],
diff --git a/tests/test-histedit-exec.t b/tests/test-histedit-exec.t
new file mode 100644
--- /dev/null
+++ b/tests/test-histedit-exec.t
@@ -0,0 +1,191 @@ 
+  $ . "$TESTDIR/histedit-helpers.sh"
+
+  $ cat >> $HGRCPATH <<EOF
+  > [extensions]
+  > histedit=
+  > EOF
+
+  $ initrepo ()
+  > {
+  >     hg init r
+  >     cd r
+  >     for x in a b c d e f ; do
+  >         echo $x > $x
+  >         hg add $x
+  >         hg ci -m $x
+  >     done
+  > }
+
+  $ initrepo
+
+log before edit
+
+  $ hg log --graph
+  @  changeset:   5:652413bf663e
+  |  tag:         tip
+  |  user:        test
+  |  date:        Thu Jan 01 00:00:00 1970 +0000
+  |  summary:     f
+  |
+  o  changeset:   4:e860deea161a
+  |  user:        test
+  |  date:        Thu Jan 01 00:00:00 1970 +0000
+  |  summary:     e
+  |
+  o  changeset:   3:055a42cdd887
+  |  user:        test
+  |  date:        Thu Jan 01 00:00:00 1970 +0000
+  |  summary:     d
+  |
+  o  changeset:   2:177f92b77385
+  |  user:        test
+  |  date:        Thu Jan 01 00:00:00 1970 +0000
+  |  summary:     c
+  |
+  o  changeset:   1:d2ae7f538514
+  |  user:        test
+  |  date:        Thu Jan 01 00:00:00 1970 +0000
+  |  summary:     b
+  |
+  o  changeset:   0:cb9a9f314b8b
+     user:        test
+     date:        Thu Jan 01 00:00:00 1970 +0000
+     summary:     a
+  
+
+exec & continue should preserve hashes
+
+  $ hg histedit 177f92b77385 --commands - 2>&1 << EOF| fixbundle
+  > pick 177f92b77385 c
+  > pick 055a42cdd887 d
+  > pick e860deea161a e
+  > exec echo "this should be printed to stdout"
+  > exec echo "this should be printed to stderr" >&2
+  > pick 652413bf663e f
+  > EOF
+  this should be printed to stdout
+  this should be printed to stderr
+  0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+  0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+  1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+  $ hg log --graph
+  @  changeset:   5:652413bf663e
+  |  tag:         tip
+  |  user:        test
+  |  date:        Thu Jan 01 00:00:00 1970 +0000
+  |  summary:     f
+  |
+  o  changeset:   4:e860deea161a
+  |  user:        test
+  |  date:        Thu Jan 01 00:00:00 1970 +0000
+  |  summary:     e
+  |
+  o  changeset:   3:055a42cdd887
+  |  user:        test
+  |  date:        Thu Jan 01 00:00:00 1970 +0000
+  |  summary:     d
+  |
+  o  changeset:   2:177f92b77385
+  |  user:        test
+  |  date:        Thu Jan 01 00:00:00 1970 +0000
+  |  summary:     c
+  |
+  o  changeset:   1:d2ae7f538514
+  |  user:        test
+  |  date:        Thu Jan 01 00:00:00 1970 +0000
+  |  summary:     b
+  |
+  o  changeset:   0:cb9a9f314b8b
+     user:        test
+     date:        Thu Jan 01 00:00:00 1970 +0000
+     summary:     a
+  
+ensure we are properly executed in a shell
+  $ hg histedit 177f92b77385 --commands - 2>&1 << EOF| fixbundle
+  > pick 177f92b77385 c
+  > pick 055a42cdd887 d
+  > pick e860deea161a e
+  > exec echo "foo" >/dev/null && exit 0
+  > pick 652413bf663e f
+  > EOF
+  0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+  1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+a failing command should drop us into the shell
+
+  $ hg histedit 177f92b77385 --commands - 2>&1 << EOF| fixbundle
+  > pick 177f92b77385 c
+  > pick 055a42cdd887 d
+  > pick e860deea161a e
+  > exec exit 1
+  > pick 652413bf663e f
+  > EOF
+  0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+  Command 'exit 1' failed with exit status 1.
+
+continue should work
+
+  $ hg histedit --continue
+  1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+  0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+  $ hg log --template '{node|short} {desc}' --graph
+  @  652413bf663e f
+  |
+  o  e860deea161a e
+  |
+  o  055a42cdd887 d
+  |
+  o  177f92b77385 c
+  |
+  o  d2ae7f538514 b
+  |
+  o  cb9a9f314b8b a
+  
+
+abort should work
+
+  $ hg histedit 177f92b77385 --commands - 2>&1 << EOF| fixbundle
+  > pick 177f92b77385 c
+  > pick 055a42cdd887 d
+  > pick e860deea161a e
+  > exec exit 1
+  > pick 652413bf663e f
+  > EOF
+  0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+  Command 'exit 1' failed with exit status 1.
+
+  $ hg histedit --abort
+  1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+  $ hg log --template '{node|short} {desc}' --graph
+  @  652413bf663e f
+  |
+  o  e860deea161a e
+  |
+  o  055a42cdd887 d
+  |
+  o  177f92b77385 c
+  |
+  o  d2ae7f538514 b
+  |
+  o  cb9a9f314b8b a
+  
+
+abort on a failing command, e.g when we have children
+
+
+  $ hg histedit 177f92b77385 --commands - 2>&1 << EOF| fixbundle
+  > pick 177f92b77385 c
+  > pick 055a42cdd887 d
+  > pick e860deea161a e
+  > exec echo 'added' > added && hg addremove && hg commit --amend
+  > pick 652413bf663e f
+  > EOF
+  abort: cannot amend changeset with children
+  0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+
+  $ hg id -r . -i
+  e860deea161a
+