view tests/test-transaction-rollback-on-sigpipe.t @ 46667:93e9f448273c

rhg: Add support for automatic fallback to Python `rhg` is a command-line application that can do a small subset of what `hg` can. It is written entirely in Rust, which avoids the cost of starting a Python interpreter and importing many Python modules. In a script that runs many `hg` commands, this cost can add up. However making users decide when to use `rhg` instead of `hg` is not practical as we want the subset of supported functionality to grow over time. Instead we introduce "fallback" behavior where, when `rhg` encounters something (a sub-command, a repository format, …) that is not implemented in Rust-only, it does nothing but silently start a subprocess of Python-based `hg` running the same command. That way `rhg` becomes a drop-in replacement for `hg` that sometimes goes faster. Whether Python is used should be an implementation detail not apparent to users (other than through speed). A new `fallback` value is added to the previously introduced `rhg.on-unsupported` configuration key. When in this mode, the new `rhg.fallback-executable` config is determine what command to use to run a Python-based `hg`. The previous `rhg.on-unsupported = abort-silent` configuration was designed to let a wrapper script call `rhg` and then fall back to `hg` based on the exit code. This is still available, but having fallback behavior built-in in rhg might be easier for users instead of leaving that script "as an exercise for the reader". Using a subprocess like this is not idea, especially when `rhg` is to be installed in `$PATH` as `hg`, since the other `hg.py` executable needs to still be available… somewhere. Eventually this could be replaced by using PyOxidizer to a have a single executable that embeds a Python interpreter, but only starts it when needed. Differential Revision: https://phab.mercurial-scm.org/D10093
author Simon Sapin <simon.sapin@octobus.net>
date Mon, 01 Mar 2021 20:36:06 +0100
parents b713e4cae2d7
children 77e73827a02d
line wrap: on
line source

Test that, when an hg push is interrupted and the remote side recieves SIGPIPE,
the remote hg is able to successfully roll back the transaction.

  $ hg init -q remote
  $ hg clone -e "\"$PYTHON\" \"$TESTDIR/dummyssh\"" -q ssh://user@dummy/`pwd`/remote local

  $ check_for_abandoned_transaction() {
  >     [ -f $TESTTMP/remote/.hg/store/journal ] && echo "Abandoned transaction!"
  > }

  $ pidfile=`pwd`/pidfile
  $ >$pidfile

  $ script() {
  >     cat >"$1"
  >     chmod +x "$1"
  > }

On the remote end, run hg, piping stdout and stderr through processes that we
know the PIDs of. We will later kill these to simulate an ssh client
disconnecting.

  $ killable_pipe=`pwd`/killable_pipe.sh
  $ script $killable_pipe <<EOF
  > #!/bin/bash
  > echo \$\$ >> $pidfile
  > exec cat
  > EOF

  $ remotecmd=`pwd`/remotecmd.sh
  $ script $remotecmd <<EOF
  > #!/bin/bash
  > hg "\$@" 1> >($killable_pipe) 2> >($killable_pipe >&2)
  > EOF

In the pretxnchangegroup hook, kill the PIDs recorded above to simulate ssh
disconnecting. Then exit nonzero, to force a transaction rollback.

  $ hook_script=`pwd`/pretxnchangegroup.sh
  $ script $hook_script <<EOF
  > #!/bin/bash
  > for pid in \$(cat $pidfile) ; do
  >   kill \$pid
  >   while kill -0 \$pid 2>/dev/null ; do
  >     sleep 0.1
  >   done
  > done
  > exit 1
  > EOF

  $ cat >remote/.hg/hgrc <<EOF
  > [hooks]
  > pretxnchangegroup.break-things=$hook_script
  > EOF

  $ cd local
  $ echo foo > foo ; hg commit -qAm "commit"
  $ hg push -q -e "\"$PYTHON\" \"$TESTDIR/dummyssh\"" --remotecmd $remotecmd 2>&1 | grep -v $killable_pipe
  abort: stream ended unexpectedly (got 0 bytes, expected 4)

  $ check_for_abandoned_transaction
  [1]