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

Pierre-Yves David pierre-yves.david at ens-lyon.org
Fri Sep 19 19:57:28 CDT 2014



On 09/16/2014 05:58 PM, David Soria Parra wrote:
> # HG changeset patch
> # User David Soria Parra <davidsp at 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 ?

-- 
Pierre-Yves David


More information about the Mercurial-devel mailing list