[PATCH] histedit: add support for exec/x command to histedit (issue4036)
Augie Fackler
raf at durin42.com
Thu Sep 10 09:39:38 CDT 2015
On Wed, Sep 09, 2015 at 06:04:58PM +0200, liscju wrote:
> # HG changeset patch
> # User liscju <piotr.listkiewicz at gmail.com>
> # Date 1441363832 -7200
> # Fri Sep 04 12:50:32 2015 +0200
> # Node ID 4ee403abb436e0f177dc149be13a598a61db14b8
> # Parent fd9b1262f0e4fbcec1f66f01839bf3d4ee4cff59
> histedit: add support for exec/x command to histedit (issue4036)
This is a good start on the feature, but this at a minimum will need
some tests added and a few nits corrected. I fear there may be some
tricky edge cases exposed when you start writing tests too (see below
for an issue related to 'hg commit --amend' that I suspect you'll trip
on.)
>
> Point of this command is to be able to do some automatic munging
> on one or several commits in a series.
>
> The basic contract is that it receives a clean working copy and is
> expected to leave a clean working copy if it exits 0. If either
> the command leaves the working copy dirty, or it exits non-zero,
> the histedit stops to give opportunity for user intervention.
>
> Behavior is undefined if it updates to some completely unrelated
> portion of history.
Can it abort instead? Undefined behavior in my history editing tools
feels...risky.
>
> Exec command functionality is implemented in exec_ class. It is
> overriding fromrule class method to deal with initializing
> object in different way than other histeditactions. It takes
> state and cmd instead of state and node id of next changeset
> action to perform on.
>
> Run method of exec_ class at first updates to parent of current
> changeset,apply it and commit to obtain copy of current changeset
> in current directory. It is done to let cmd ammend to this changeset
typo: amend has only one m, not two.
> and correctly perform changing history containing this changeset.
Related: there are some bugs around doing 'hg amend' in the middle of
a stream. Might need to fix those or otherwise defend against that
bug: http://bz.selenic.com/show_bug.cgi?id=4800
>
> In run method locks are released right before running command to
> allow running hg commands inside it.
>
> diff -r fd9b1262f0e4 -r 4ee403abb436 hgext/histedit.py
> --- a/hgext/histedit.py Sat Aug 22 15:21:45 2015 -0700
> +++ b/hgext/histedit.py Fri Sep 04 12:50:32 2015 +0200
> @@ -199,6 +199,7 @@
> # r, roll = like fold, but discard this commit's description
> # d, drop = remove commit from history
> # m, mess = edit commit message without changing commit content
Might be worth breaking this next line into another section, eg:
#
# Between changes you can add this:
# x, exec = run command (the rest of the line) using shell
> +# x, exec = run command (the rest of the line) using shell
> #
> """)
>
> @@ -498,6 +499,46 @@
> editor=editor)
> return repo.commitctx(new)
>
> +class exec_(histeditaction):
> + def __init__(self, state, node, cmd):
> + super(exec_, self).__init__(state, node)
> + self.repo = state.repo
> + self.cmd = cmd
> +
> + @classmethod
> + def fromrule(cls, state, cmd):
> + return cls(state, state.parentctxnode, cmd)
> +
> + def getinterventionmsg(self, errormsg):
> + return _(errormsg + "\n" +
> + 'Make changes as needed, you may commit or record as needed '
> + 'now.\nWhen you are finished, run hg histedit --continue to '
> + 'resume.')
This construction *might* be bad for internationalization, I'm not
sure. Either way, you need to wrap the string here in _().
> +
> + def run(self):
> + hg.update(self.repo, self.repo[self.node].parents()[0])
> + applychanges(self.repo.ui, self.repo, self.repo[self.node], {})
> + self.continuedirty()
> +
> + release(self.state.lock, self.state.wlock)
> + return_code = self.repo.ui.system(self.cmd)
> + self.state.wlock = self.repo.wlock()
> + self.state.lock = self.repo.lock()
> +
> + if return_code == 0:
> + s = self.repo.status(unknown=True)
> + if s.modified or s.added or s.removed or s.deleted or s.unknown:
Unknown files shouldn't be considered dirty? Look later in
histedit.py for the call to continuedirty().
Might be worth teasing that out into a _dirtywc(repo) method to prevent future inconsistencies.
> + raise error.InterventionRequired(
> + self.getinterventionmsg(
> + "Working copy dirty after exec %s" % self.cmd))
missing _()
> + else:
> + ctx = self.repo["."]
> + return ctx, [(self.node, (ctx.node(),))]
> + else:
> + raise error.InterventionRequired(
> + self.getinterventionmsg(
> + 'Return code of %s is nonzero.' % self.cmd))
missing _()
Also, maybe (ab)use %r here so self.cmd gets placed in quotes. Also I think
the "is" should be "was" here. Maybe show the return code in the
output too?
> +
> class pick(histeditaction):
> def run(self):
> rulectx = self.repo[self.node]
> @@ -650,6 +691,8 @@
> 'drop': drop,
> 'm': message,
> 'mess': message,
> + 'x': exec_,
> + 'exec': exec_,
> }
>
> @command('histedit',
> @@ -983,21 +1026,24 @@
> if ' ' not in r:
> raise util.Abort(_('malformed line "%s"') % r)
> action, rest = r.split(' ', 1)
> - ha = rest.strip().split(' ', 1)[0]
> - try:
> - ha = repo[ha].hex()
> - except error.RepoError:
> - raise util.Abort(_('unknown changeset %s listed') % ha[:12])
> - 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[:12])
> - seen.add(ha)
> - if action not in actiontable:
> - raise util.Abort(_('unknown action "%s"') % action)
> - parsed.append([action, ha])
> + if action == "x" or action == "exec":
> + parsed.append([action, rest])
> + else:
> + ha = rest.strip().split(' ', 1)[0]
> + try:
> + ha = repo[ha].hex()
> + except error.RepoError:
> + raise util.Abort(_('unknown changeset %s listed') % ha[:12])
> + 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[:12])
> + 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') %
> diff -r fd9b1262f0e4 -r 4ee403abb436 tests/test-histedit-arguments.t
> --- a/tests/test-histedit-arguments.t Sat Aug 22 15:21:45 2015 -0700
> +++ b/tests/test-histedit-arguments.t Fri Sep 04 12:50:32 2015 +0200
> @@ -70,6 +70,7 @@
> # r, roll = like fold, but discard this commit's description
> # d, drop = remove commit from history
> # m, mess = edit commit message without changing commit content
> + # x, exec = run command (the rest of the line) using shell
> #
> 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
>
> @@ -293,6 +294,7 @@
> # r, roll = like fold, but discard this commit's description
> # d, drop = remove commit from history
> # m, mess = edit commit message without changing commit content
> + # x, exec = run command (the rest of the line) using shell
> #
> 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
>
> diff -r fd9b1262f0e4 -r 4ee403abb436 tests/test-histedit-bookmark-motion.t
> --- a/tests/test-histedit-bookmark-motion.t Sat Aug 22 15:21:45 2015 -0700
> +++ b/tests/test-histedit-bookmark-motion.t Fri Sep 04 12:50:32 2015 +0200
> @@ -76,6 +76,7 @@
> # r, roll = like fold, but discard this commit's description
> # d, drop = remove commit from history
> # m, mess = edit commit message without changing commit content
> + # x, exec = run command (the rest of the line) using shell
> #
> 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
> $ hg histedit 1 --commands - --verbose << EOF | grep histedit
> @@ -137,6 +138,7 @@
> # r, roll = like fold, but discard this commit's description
> # d, drop = remove commit from history
> # m, mess = edit commit message without changing commit content
> + # x, exec = run command (the rest of the line) using shell
> #
> 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
> $ hg histedit 1 --commands - --verbose << EOF | grep histedit
> diff -r fd9b1262f0e4 -r 4ee403abb436 tests/test-histedit-commute.t
> --- a/tests/test-histedit-commute.t Sat Aug 22 15:21:45 2015 -0700
> +++ b/tests/test-histedit-commute.t Fri Sep 04 12:50:32 2015 +0200
> @@ -70,6 +70,7 @@
> # r, roll = like fold, but discard this commit's description
> # d, drop = remove commit from history
> # m, mess = edit commit message without changing commit content
> + # x, exec = run command (the rest of the line) using shell
> #
> 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
>
> @@ -348,6 +349,7 @@
> # r, roll = like fold, but discard this commit's description
> # d, drop = remove commit from history
> # m, mess = edit commit message without changing commit content
> + # x, exec = run command (the rest of the line) using shell
> #
> 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
>
> diff -r fd9b1262f0e4 -r 4ee403abb436 tests/test-histedit-obsolete.t
> --- a/tests/test-histedit-obsolete.t Sat Aug 22 15:21:45 2015 -0700
> +++ b/tests/test-histedit-obsolete.t Fri Sep 04 12:50:32 2015 +0200
> @@ -55,6 +55,7 @@
> # r, roll = like fold, but discard this commit's description
> # d, drop = remove commit from history
> # m, mess = edit commit message without changing commit content
> + # x, exec = run command (the rest of the line) using shell
> #
> 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
> $ hg histedit 1 --commands - --verbose <<EOF | grep histedit
> diff -r fd9b1262f0e4 -r 4ee403abb436 tests/test-histedit-outgoing.t
> --- a/tests/test-histedit-outgoing.t Sat Aug 22 15:21:45 2015 -0700
> +++ b/tests/test-histedit-outgoing.t Fri Sep 04 12:50:32 2015 +0200
> @@ -52,6 +52,7 @@
> # r, roll = like fold, but discard this commit's description
> # d, drop = remove commit from history
> # m, mess = edit commit message without changing commit content
> + # x, exec = run command (the rest of the line) using shell
> #
> 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
> $ cd ..
> @@ -84,6 +85,7 @@
> # r, roll = like fold, but discard this commit's description
> # d, drop = remove commit from history
> # m, mess = edit commit message without changing commit content
> + # x, exec = run command (the rest of the line) using shell
> #
> 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
> $ cd ..
> @@ -108,6 +110,7 @@
> # r, roll = like fold, but discard this commit's description
> # d, drop = remove commit from history
> # m, mess = edit commit message without changing commit content
> + # x, exec = run command (the rest of the line) using shell
> #
> 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
>
> _______________________________________________
> Mercurial-devel mailing list
> Mercurial-devel at selenic.com
> https://selenic.com/mailman/listinfo/mercurial-devel
More information about the Mercurial-devel
mailing list