[PATCH (review)] bisect: track the current changeset (issue3382)

Matt Mackall mpm at selenic.com
Fri Apr 20 15:19:49 CDT 2012


On Wed, 2012-04-18 at 23:37 -0700, Bryan O'Sullivan wrote:
> # HG changeset patch
> # User Bryan O'Sullivan <bryano at fb.com>
> # Date 1334817381 25200
> # Node ID 786bb91704c3694f307d66b9d062ef96b4f6a168
> # Parent  2057572031e922253988d9315f9ee04df37b829d
> bisect: track the current changeset (issue3382)
> 
> These changes allow --command and --noupdate to be used together,
> as otherwise the command cannot find out what changeset is currently
> being bisected.
> 
> Introduce a new revset feature, bisect(current), that identifies
> the changeset currently being bisected.
> 
> When running a command, set the environment variable HG_NODE to
> tell the command which changeset is being visited.
> 
> Fix a bug: the bisect state file wasn't being written before running
> commands, so a command that cared about bisect state would read
> stale data.

Can you split this up please? I'll take the bug-fix bit now.

> diff -r 2057572031e9 -r 786bb91704c3 mercurial/commands.py
> --- a/mercurial/commands.py	Wed Apr 18 21:27:35 2012 -0700
> +++ b/mercurial/commands.py	Wed Apr 18 23:36:21 2012 -0700
> @@ -514,10 +514,12 @@
>      revision as good or bad without checking it out first.
>  
>      If you supply a command, it will be used for automatic bisection.
> -    Its exit status will be used to mark revisions as good or bad:
> -    status 0 means good, 125 means to skip the revision, 127
> -    (command not found) will abort the bisection, and any other
> -    non-zero exit status means the revision is bad.
> +    The environment variable HG_NODE will contain the ID of the
> +    changeset being tested. The exit status of the command will be
> +    used to mark revisions as good or bad: status 0 means good, 125
> +    means to skip the revision, 127 (command not found) will abort the
> +    bisection, and any other non-zero exit status means the revision
> +    is bad.
>  
>      .. container:: verbose
>  
> @@ -557,6 +559,11 @@
>  
>            hg log -r "bisect(pruned)"
>  
> +      - see the changeset currently being bisected (especially useful
> +        if running with -U/--noupdate)::
> +
> +          hg log -r "bisect(current)"
> +
>        - see all changesets that took part in the current bisection::
>  
>            hg log -r "bisect(range)"
> @@ -641,9 +648,22 @@
>      if command:
>          changesets = 1
>          try:
> +            node = state['current'][0]
> +        except:
> +            if noupdate:
> +                raise util.Abort(_('current bisect revision is unknown - '
> +                                   'start a new bisect to fix'))
> +            node, p2 = repo.dirstate.parents()
> +            if p2 != nullid:
> +                raise util.Abort(_('current bisect revision is a merge'))
> +        try:
>              while changesets:
>                  # update state
> -                status = util.system(command, out=ui.fout)
> +                state['current'] = [node]
> +                hbisect.save_state(repo, state)
> +                status = util.system(command,
> +                                     environ={'HG_NODE': hex(node)},
> +                                     out=ui.fout)
>                  if status == 125:
>                      transition = "skip"
>                  elif status == 0:
> @@ -655,7 +675,7 @@
>                      raise util.Abort(_("%s killed") % command)
>                  else:
>                      transition = "bad"
> -                ctx = scmutil.revsingle(repo, rev)
> +                ctx = scmutil.revsingle(repo, rev, node)
>                  rev = None # clear for future iterations
>                  state[transition].append(ctx.node())
>                  ui.status(_('Changeset %d:%s: %s\n') % (ctx, ctx, transition))
> @@ -663,9 +683,12 @@
>                  # bisect
>                  nodes, changesets, good = hbisect.bisect(repo.changelog, state)
>                  # update to next check
> -                cmdutil.bailifchanged(repo)
> -                hg.clean(repo, nodes[0], show_stats=False)
> +                node = nodes[0]
> +                if not noupdate:
> +                    cmdutil.bailifchanged(repo)
> +                    hg.clean(repo, node, show_stats=False)
>          finally:
> +            state['current'] = [node]
>              hbisect.save_state(repo, state)
>          print_result(nodes, good)
>          return
> @@ -697,6 +720,8 @@
>              if extendnode is not None:
>                  ui.write(_("Extending search to changeset %d:%s\n"
>                           % (extendnode.rev(), extendnode)))
> +                state['current'] = [extendnode]
> +                hbisect.save_state(repo, state)
>                  if noupdate:
>                      return
>                  cmdutil.bailifchanged(repo)
> @@ -716,6 +741,8 @@
>          ui.write(_("Testing changeset %d:%s "
>                     "(%d changesets remaining, ~%d tests)\n")
>                   % (rev, short(node), changesets, tests))
> +        state['current'] = [node]
> +        hbisect.save_state(repo, state)
>          if not noupdate:
>              cmdutil.bailifchanged(repo)
>              return hg.clean(repo, node)
> diff -r 2057572031e9 -r 786bb91704c3 mercurial/hbisect.py
> --- a/mercurial/hbisect.py	Wed Apr 18 21:27:35 2012 -0700
> +++ b/mercurial/hbisect.py	Wed Apr 18 23:36:21 2012 -0700
> @@ -132,7 +132,7 @@
>  
> 
>  def load_state(repo):
> -    state = {'good': [], 'bad': [], 'skip': []}
> +    state = {'current': [], 'good': [], 'bad': [], 'skip': []}
>      if os.path.exists(repo.join("bisect.state")):
>          for l in repo.opener("bisect.state"):
>              kind, node = l[:-1].split()
> @@ -164,10 +164,11 @@
>      - ``pruned``             : csets that are goods, bads or skipped
>      - ``untested``           : csets whose fate is yet unknown
>      - ``ignored``            : csets ignored due to DAG topology
> +    - ``current``            : the cset currently being bisected
>      """
>      state = load_state(repo)
> -    if status in ('good', 'bad', 'skip'):
> -        return [repo.changelog.rev(n) for n in state[status]]
> +    if status in ('good', 'bad', 'skip', 'current'):
> +        return map(repo.changelog.rev, state[status])
>      else:
>          # In the floowing sets, we do *not* call 'bisect()' with more
>          # than one level of recusrsion, because that can be very, very
> @@ -233,6 +234,9 @@
>      if rev in get(repo, 'skip'):
>          # i18n: bisect changeset status
>          return _('skipped')
> +    if rev in get(repo, 'current'):
> +        # i18n: bisect changeset status
> +        return _('current')
>      if rev in get(repo, 'untested'):
>          # i18n: bisect changeset status
>          return _('untested')
> diff -r 2057572031e9 -r 786bb91704c3 mercurial/revset.py
> --- a/mercurial/revset.py	Wed Apr 18 21:27:35 2012 -0700
> +++ b/mercurial/revset.py	Wed Apr 18 23:36:21 2012 -0700
> @@ -289,6 +289,7 @@
>      - ``pruned``             : csets that are goods, bads or skipped
>      - ``untested``           : csets whose fate is yet unknown
>      - ``ignored``            : csets ignored due to DAG topology
> +    - ``current``            : the cset currently being bisected
>      """
>      status = getstring(x, _("bisect requires a string")).lower()
>      state = set(hbisect.get(repo, status))
> diff -r 2057572031e9 -r 786bb91704c3 tests/test-bisect.t
> --- a/tests/test-bisect.t	Wed Apr 18 21:27:35 2012 -0700
> +++ b/tests/test-bisect.t	Wed Apr 18 23:36:21 2012 -0700
> @@ -224,6 +224,7 @@
>    Testing changeset 12:1941b52820a5 (23 changesets remaining, ~4 tests)
>    1 files updated, 0 files merged, 0 files removed, 0 files unresolved
>    $ cat .hg/bisect.state
> +  current 1941b52820a544549596820a8ae006842b0e2c64
>    skip 9d7d07bc967ca98ad0600c24953fd289ad5fa991
>    skip ce8f0998e922c179e80819d5066fbe46e2998784
>    skip e7fa0811edb063f6319531f0d0a865882138e180
> @@ -396,6 +397,12 @@
>    date:        Thu Jan 01 00:00:06 1970 +0000
>    summary:     msg 6
>    
> +  $ hg log -r "bisect(current)"
> +  changeset:   5:7874a09ea728
> +  user:        test
> +  date:        Thu Jan 01 00:00:05 1970 +0000
> +  summary:     msg 5
> +  
>    $ hg log -r "bisect(skip)"
>    changeset:   1:5cd978ea5149
>    user:        test
> @@ -466,3 +473,40 @@
>    date:        Thu Jan 01 00:00:06 1970 +0000
>    summary:     msg 6
>    
> +
> +
> +test bisecting via a command without updating the working dir, and
> +ensure that the bisect state file is updated before running a test
> +command
> +
> +  $ hg update null
> +  0 files updated, 0 files merged, 1 files removed, 0 files unresolved
> +  $ cat > script.sh <<'EOF'
> +  > #!/bin/sh
> +  > test -n "$HG_NODE" || (echo HG_NODE missing; exit 127)
> +  > current="`hg log -r \"bisect(current)\" --template {node}`"
> +  > test "$current" = "$HG_NODE" || (echo current is bad: $current; exit 127)
> +  > rev="`hg log -r $HG_NODE --template {rev}`"
> +  > test "$rev" -ge 6
> +  > EOF
> +  $ chmod +x script.sh
> +  $ hg bisect -r
> +  $ hg bisect --good tip --noupdate
> +  $ hg bisect --bad 0 --noupdate
> +  Testing changeset 15:e7fa0811edb0 (31 changesets remaining, ~4 tests)
> +  $ hg bisect --command "'`pwd`/script.sh' and some params" --noupdate
> +  Changeset 15:e7fa0811edb0: good
> +  Changeset 7:03750880c6b5: good
> +  Changeset 3:b53bea5e2fcb: bad
> +  Changeset 5:7874a09ea728: bad
> +  Changeset 6:a3d5c6fdf0d3: good
> +  The first good revision is:
> +  changeset:   6:a3d5c6fdf0d3
> +  user:        test
> +  date:        Thu Jan 01 00:00:06 1970 +0000
> +  summary:     msg 6
> +  
> +
> +ensure that we still don't have a working dir
> +
> +  $ hg parents
> _______________________________________________
> Mercurial-devel mailing list
> Mercurial-devel at selenic.com
> http://selenic.com/mailman/listinfo/mercurial-devel


-- 
Mathematics is the supreme nostalgia of our time.




More information about the Mercurial-devel mailing list