Patchwork [1,of,5,STABLE] tests: invoke printenv.py via sh -c for test portability

login
register
mail settings
Submitter Katsunori FUJIWARA
Date Oct. 28, 2016, 6:16 p.m.
Message ID <34a5f6c66bc5a13381a6.1477678606@juju>
Download mbox | patch
Permalink /patch/17213/
State Accepted
Headers show

Comments

Katsunori FUJIWARA - Oct. 28, 2016, 6:16 p.m.
# HG changeset patch
# User FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
# Date 1477676685 -32400
#      Sat Oct 29 02:44:45 2016 +0900
# Branch stable
# Node ID 34a5f6c66bc5a13381a68d08f73d858916167836
# Parent  3afde791dce192f38d8a228ed8e49397e353837e
tests: invoke printenv.py via sh -c for test portability

On Windows platform, invoking printenv.py directly via hook is
problematic, because:

  - unless binding between *.py suffix and python runtime, application
    selector dialog is displayed, and running test is blocked at each
    printenv.py invocations

  - it isn't safe to assume binding between *.py suffix and python
    runtime, because application binding is easily broken

    For example, installing IDE (VisualStudio with Python Tools, or
    so) often requires binding between source files and IDE itself.

This patch invokes printenv.py via sh -c for test portability. This is
a kind of follow up for d19787db6fe0, which eliminated explicit
"python" for printenv.py. There are already other 'sh -c "printenv.py"'
in *.t files, and this fix should be reasonable.

This changes were confirmed in cases below:

  - without any application binding for *.py suffix
  - with binding between *.py suffix and VisualStudio

This patch also replaces "echo + redirection" style with "heredoc"
style, because:

  - hook command line is parsed by cmd.exe as shell at first, and
  - single quotation can't quote arguments on cmd.exe, therefore,
  - "printenv.py foobar" should be quoted by double quotation, but
  - nested quoting (or tricky escaping) isn't readable
timeless - Nov. 4, 2016, 2:27 p.m.
I'm sure this is already in, but wouldn't it be better to use a
$PYTHON than `sh -c`?

On Fri, Oct 28, 2016 at 2:16 PM, FUJIWARA Katsunori
<foozy@lares.dti.ne.jp> wrote:
> # HG changeset patch
> # User FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
> # Date 1477676685 -32400
> #      Sat Oct 29 02:44:45 2016 +0900
> # Branch stable
> # Node ID 34a5f6c66bc5a13381a68d08f73d858916167836
> # Parent  3afde791dce192f38d8a228ed8e49397e353837e
> tests: invoke printenv.py via sh -c for test portability
>
> On Windows platform, invoking printenv.py directly via hook is
> problematic, because:
>
>   - unless binding between *.py suffix and python runtime, application
>     selector dialog is displayed, and running test is blocked at each
>     printenv.py invocations
>
>   - it isn't safe to assume binding between *.py suffix and python
>     runtime, because application binding is easily broken
>
>     For example, installing IDE (VisualStudio with Python Tools, or
>     so) often requires binding between source files and IDE itself.
>
> This patch invokes printenv.py via sh -c for test portability. This is
> a kind of follow up for d19787db6fe0, which eliminated explicit
> "python" for printenv.py. There are already other 'sh -c "printenv.py"'
> in *.t files, and this fix should be reasonable.
>
> This changes were confirmed in cases below:
>
>   - without any application binding for *.py suffix
>   - with binding between *.py suffix and VisualStudio
>
> This patch also replaces "echo + redirection" style with "heredoc"
> style, because:
>
>   - hook command line is parsed by cmd.exe as shell at first, and
>   - single quotation can't quote arguments on cmd.exe, therefore,
>   - "printenv.py foobar" should be quoted by double quotation, but
>   - nested quoting (or tricky escaping) isn't readable
>
> diff --git a/tests/test-bundle.t b/tests/test-bundle.t
> --- a/tests/test-bundle.t
> +++ b/tests/test-bundle.t
> @@ -216,8 +216,10 @@ Make sure bundlerepo doesn't leak tempfi
>
>  Pull ../full.hg into empty (with hook)
>
> -  $ echo "[hooks]" >> .hg/hgrc
> -  $ echo "changegroup = printenv.py changegroup" >> .hg/hgrc
> +  $ cat >> .hg/hgrc <<EOF
> +  > [hooks]
> +  > changegroup = sh -c "printenv.py changegroup"
> +  > EOF
>
>  doesn't work (yet ?)
>
> diff --git a/tests/test-hook.t b/tests/test-hook.t
> --- a/tests/test-hook.t
> +++ b/tests/test-hook.t
> @@ -16,9 +16,9 @@ commit hooks can see env vars
>    > precommit = sh -c  "HG_LOCAL= HG_NODE= HG_TAG= printenv.py precommit"
>    > pretxncommit = sh -c "HG_LOCAL= HG_TAG= printenv.py pretxncommit"
>    > pretxncommit.tip = hg -q tip
> -  > pre-identify = printenv.py pre-identify 1
> -  > pre-cat = printenv.py pre-cat
> -  > post-cat = printenv.py post-cat
> +  > pre-identify = sh -c "printenv.py pre-identify 1"
> +  > pre-cat = sh -c "printenv.py pre-cat"
> +  > post-cat = sh -c "printenv.py post-cat"
>    > pretxnopen = sh -c "HG_LOCAL= HG_TAG= printenv.py pretxnopen"
>    > pretxnclose = sh -c "HG_LOCAL= HG_TAG= printenv.py pretxnclose"
>    > txnclose = sh -c "HG_LOCAL= HG_TAG= printenv.py txnclose"
> @@ -47,9 +47,9 @@ changegroup hooks can see env vars
>
>    $ cat > .hg/hgrc <<EOF
>    > [hooks]
> -  > prechangegroup = printenv.py prechangegroup
> -  > changegroup = printenv.py changegroup
> -  > incoming = printenv.py incoming
> +  > prechangegroup = sh -c "printenv.py prechangegroup"
> +  > changegroup = sh -c "printenv.py changegroup"
> +  > incoming = sh -c "printenv.py incoming"
>    > EOF
>
>  pretxncommit and commit hooks can see both parents of merge
> @@ -122,7 +122,7 @@ tag hooks can see env vars
>
>    $ cd ../a
>    $ cat >> .hg/hgrc <<EOF
> -  > pretag = printenv.py pretag
> +  > pretag = sh -c "printenv.py pretag"
>    > tag = sh -c "HG_PARENT1= HG_PARENT2= printenv.py tag"
>    > EOF
>    $ hg tag -d '3 0' a
> @@ -142,7 +142,9 @@ tag hooks can see env vars
>
>  pretag hook can forbid tagging
>
> -  $ echo "pretag.forbid = printenv.py pretag.forbid 1" >> .hg/hgrc
> +  $ cat >> .hg/hgrc <<EOF
> +  > pretag.forbid = sh -c "printenv.py pretag.forbid 1"
> +  > EOF
>    $ hg tag -d '4 0' fa
>    pretag hook: HG_LOCAL=0 HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_TAG=fa
>    pretag.forbid hook: HG_LOCAL=0 HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_TAG=fa
> @@ -157,8 +159,10 @@ pretag hook can forbid tagging
>  pretxncommit hook can see changeset, can roll back txn, changeset no
>  more there after
>
> -  $ echo "pretxncommit.forbid0 = hg tip -q" >> .hg/hgrc
> -  $ echo "pretxncommit.forbid1 = printenv.py pretxncommit.forbid 1" >> .hg/hgrc
> +  $ cat >> .hg/hgrc <<EOF
> +  > pretxncommit.forbid0 = sh -c "hg tip -q"
> +  > pretxncommit.forbid1 = sh -c "printenv.py pretxncommit.forbid 1"
> +  > EOF
>    $ echo z > z
>    $ hg add z
>    $ hg -q tip
> @@ -196,7 +200,9 @@ more there after
>
>  precommit hook can prevent commit
>
> -  $ echo "precommit.forbid = printenv.py precommit.forbid 1" >> .hg/hgrc
> +  $ cat >> .hg/hgrc <<EOF
> +  > precommit.forbid = sh -c "printenv.py precommit.forbid 1"
> +  > EOF
>    $ hg commit -m 'fail' -d '4 0'
>    precommit hook: HG_PARENT1=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10
>    precommit.forbid hook: HG_PARENT1=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10
> @@ -207,14 +213,18 @@ precommit hook can prevent commit
>
>  preupdate hook can prevent update
>
> -  $ echo "preupdate = printenv.py preupdate" >> .hg/hgrc
> +  $ cat >> .hg/hgrc <<EOF
> +  > preupdate = sh -c "printenv.py preupdate"
> +  > EOF
>    $ hg update 1
>    preupdate hook: HG_PARENT1=ab228980c14d
>    0 files updated, 0 files merged, 2 files removed, 0 files unresolved
>
>  update hook
>
> -  $ echo "update = printenv.py update" >> .hg/hgrc
> +  $ cat >> .hg/hgrc <<EOF
> +  > update = sh -c "printenv.py update"
> +  > EOF
>    $ hg update
>    preupdate hook: HG_PARENT1=539e4b31b6dc
>    update hook: HG_ERROR=0 HG_PARENT1=539e4b31b6dc
> @@ -222,7 +232,9 @@ update hook
>
>  pushkey hook
>
> -  $ echo "pushkey = printenv.py pushkey" >> .hg/hgrc
> +  $ cat >> .hg/hgrc <<EOF
> +  > pushkey = sh -c "printenv.py pushkey"
> +  > EOF
>    $ cd ../b
>    $ hg bookmark -r null foo
>    $ hg push -B foo ../a
> @@ -239,7 +251,9 @@ pushkey hook
>
>  listkeys hook
>
> -  $ echo "listkeys = printenv.py listkeys" >> .hg/hgrc
> +  $ cat >> .hg/hgrc <<EOF
> +  > listkeys = sh -c "printenv.py listkeys"
> +  > EOF
>    $ hg bookmark -r null bar
>    pretxnopen hook: HG_TXNID=TXN:* HG_TXNNAME=bookmark (glob)
>    pretxnclose hook: HG_BOOKMARK_MOVED=1 HG_PENDING=$TESTTMP/a HG_TXNID=TXN:* HG_TXNNAME=bookmark (glob)
> @@ -255,7 +269,9 @@ listkeys hook
>
>  test that prepushkey can prevent incoming keys
>
> -  $ echo "prepushkey = printenv.py prepushkey.forbid 1" >> .hg/hgrc
> +  $ cat >> .hg/hgrc <<EOF
> +  > prepushkey = sh -c "printenv.py prepushkey.forbid 1"
> +  > EOF
>    $ cd ../b
>    $ hg bookmark -r null baz
>    $ hg push -B baz ../a
> @@ -273,7 +289,9 @@ test that prepushkey can prevent incomin
>
>  test that prelistkeys can prevent listing keys
>
> -  $ echo "prelistkeys = printenv.py prelistkeys.forbid 1" >> .hg/hgrc
> +  $ cat >> .hg/hgrc <<EOF
> +  > prelistkeys = sh -c "printenv.py prelistkeys.forbid 1"
> +  > EOF
>    $ hg bookmark -r null quux
>    pretxnopen hook: HG_TXNID=TXN:* HG_TXNNAME=bookmark (glob)
>    pretxnclose hook: HG_BOOKMARK_MOVED=1 HG_PENDING=$TESTTMP/a HG_TXNID=TXN:* HG_TXNNAME=bookmark (glob)
> @@ -294,7 +312,7 @@ prechangegroup hook can prevent incoming
>    3:07f3376c1e65
>    $ cat > .hg/hgrc <<EOF
>    > [hooks]
> -  > prechangegroup.forbid = printenv.py prechangegroup.forbid 1
> +  > prechangegroup.forbid = sh -c "printenv.py prechangegroup.forbid 1"
>    > EOF
>    $ hg pull ../a
>    pulling from ../a
> @@ -309,7 +327,7 @@ incoming changes no longer there after
>    $ cat > .hg/hgrc <<EOF
>    > [hooks]
>    > pretxnchangegroup.forbid0 = hg tip -q
> -  > pretxnchangegroup.forbid1 = printenv.py pretxnchangegroup.forbid 1
> +  > pretxnchangegroup.forbid1 = sh -c "printenv.py pretxnchangegroup.forbid 1"
>    > EOF
>    $ hg pull ../a
>    pulling from ../a
> @@ -332,8 +350,8 @@ outgoing hooks can see env vars
>    $ rm .hg/hgrc
>    $ cat > ../a/.hg/hgrc <<EOF
>    > [hooks]
> -  > preoutgoing = printenv.py preoutgoing
> -  > outgoing = printenv.py outgoing
> +  > preoutgoing = sh -c "printenv.py preoutgoing"
> +  > outgoing = sh -c "printenv.py outgoing"
>    > EOF
>    $ hg pull ../a
>    pulling from ../a
> @@ -351,7 +369,9 @@ outgoing hooks can see env vars
>
>  preoutgoing hook can prevent outgoing changes
>
> -  $ echo "preoutgoing.forbid = printenv.py preoutgoing.forbid 1" >> ../a/.hg/hgrc
> +  $ cat >> ../a/.hg/hgrc <<EOF
> +  > preoutgoing.forbid = sh -c "printenv.py preoutgoing.forbid 1"
> +  > EOF
>    $ hg pull ../a
>    pulling from ../a
>    searching for changes
> @@ -365,8 +385,8 @@ outgoing hooks work for local clones
>    $ cd ..
>    $ cat > a/.hg/hgrc <<EOF
>    > [hooks]
> -  > preoutgoing = printenv.py preoutgoing
> -  > outgoing = printenv.py outgoing
> +  > preoutgoing = sh -c "printenv.py preoutgoing"
> +  > outgoing = sh -c "printenv.py outgoing"
>    > EOF
>    $ hg clone a c
>    preoutgoing hook: HG_SOURCE=clone
> @@ -377,7 +397,9 @@ outgoing hooks work for local clones
>
>  preoutgoing hook can prevent outgoing changes for local clones
>
> -  $ echo "preoutgoing.forbid = printenv.py preoutgoing.forbid 1" >> a/.hg/hgrc
> +  $ cat >> a/.hg/hgrc <<EOF
> +  > preoutgoing.forbid = sh -c "printenv.py preoutgoing.forbid 1"
> +  > EOF
>    $ hg clone a zzz
>    preoutgoing hook: HG_SOURCE=clone
>    preoutgoing.forbid hook: HG_SOURCE=clone
> @@ -750,7 +772,7 @@ This also creates the `to` repo for the
>    $ cd ..
>    $ cat << EOF >> hgrc-with-post-init-hook
>    > [hooks]
> -  > post-init = printenv.py post-init
> +  > post-init = sh -c "printenv.py post-init"
>    > EOF
>    $ HGRCPATH=hgrc-with-post-init-hook hg init to
>    post-init hook: HG_ARGS=init to HG_OPTS={'insecure': None, 'remotecmd': '', 'ssh': ''} HG_PATS=['to'] HG_RESULT=0
> diff --git a/tests/test-http-bundle1.t b/tests/test-http-bundle1.t
> --- a/tests/test-http-bundle1.t
> +++ b/tests/test-http-bundle1.t
> @@ -127,8 +127,10 @@ incoming via HTTP
>  pull
>
>    $ cd copy-pull
> -  $ echo '[hooks]' >> .hg/hgrc
> -  $ echo "changegroup = printenv.py changegroup" >> .hg/hgrc
> +  $ cat >> .hg/hgrc <<EOF
> +  > [hooks]
> +  > changegroup = sh -c "printenv.py changegroup"
> +  > EOF
>    $ hg pull
>    pulling from http://localhost:$HGPORT1/
>    searching for changes
> diff --git a/tests/test-http.t b/tests/test-http.t
> --- a/tests/test-http.t
> +++ b/tests/test-http.t
> @@ -118,8 +118,10 @@ incoming via HTTP
>  pull
>
>    $ cd copy-pull
> -  $ echo '[hooks]' >> .hg/hgrc
> -  $ echo "changegroup = printenv.py changegroup" >> .hg/hgrc
> +  $ cat >> .hg/hgrc <<EOF
> +  > [hooks]
> +  > changegroup = sh -c "printenv.py changegroup"
> +  > EOF
>    $ hg pull
>    pulling from http://localhost:$HGPORT1/
>    searching for changes
> diff --git a/tests/test-https.t b/tests/test-https.t
> --- a/tests/test-https.t
> +++ b/tests/test-https.t
> @@ -203,8 +203,10 @@ Inability to verify peer certificate wil
>  pull without cacert
>
>    $ cd copy-pull
> -  $ echo '[hooks]' >> .hg/hgrc
> -  $ echo "changegroup = printenv.py changegroup" >> .hg/hgrc
> +  $ cat >> .hg/hgrc <<EOF
> +  > [hooks]
> +  > changegroup = sh -c "printenv.py changegroup"
> +  > EOF
>    $ hg pull $DISABLECACERTS
>    pulling from https://localhost:$HGPORT/
>    warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info (?)
> diff --git a/tests/test-push-http-bundle1.t b/tests/test-push-http-bundle1.t
> --- a/tests/test-push-http-bundle1.t
> +++ b/tests/test-push-http-bundle1.t
> @@ -66,10 +66,12 @@ expect authorization error: must have au
>
>  expect success
>
> -  $ echo 'allow_push = *' >> .hg/hgrc
> -  $ echo '[hooks]' >> .hg/hgrc
> -  $ echo "changegroup = printenv.py changegroup 0" >> .hg/hgrc
> -  $ echo "pushkey = printenv.py pushkey 0" >> .hg/hgrc
> +  $ cat >> .hg/hgrc <<EOF
> +  > allow_push = *
> +  > [hooks]
> +  > changegroup = sh -c "printenv.py changegroup 0"
> +  > pushkey = sh -c "printenv.py pushkey 0"
> +  > EOF
>    $ req
>    pushing to http://localhost:$HGPORT/
>    searching for changes
> @@ -151,7 +153,7 @@ expect push success, phase change failur
>    > push_ssl = false
>    > allow_push = *
>    > [hooks]
> -  > prepushkey = printenv.py prepushkey 1
> +  > prepushkey = sh -c "printenv.py prepushkey 1"
>    > EOF
>    $ req
>    pushing to http://localhost:$HGPORT/
> @@ -164,7 +166,9 @@ expect push success, phase change failur
>
>  expect phase change success
>
> -  $ echo "prepushkey = printenv.py prepushkey 0" >> .hg/hgrc
> +  $ cat >> .hg/hgrc <<EOF
> +  > prepushkey = sh -c "printenv.py prepushkey 0"
> +  > EOF
>    $ req
>    pushing to http://localhost:$HGPORT/
>    searching for changes
> diff --git a/tests/test-push-http.t b/tests/test-push-http.t
> --- a/tests/test-push-http.t
> +++ b/tests/test-push-http.t
> @@ -56,10 +56,12 @@ expect authorization error: must have au
>
>  expect success
>
> -  $ echo 'allow_push = *' >> .hg/hgrc
> -  $ echo '[hooks]' >> .hg/hgrc
> -  $ echo "changegroup = printenv.py changegroup 0" >> .hg/hgrc
> -  $ echo "pushkey = printenv.py pushkey 0" >> .hg/hgrc
> +  $ cat >> .hg/hgrc <<EOF
> +  > allow_push = *
> +  > [hooks]
> +  > changegroup = sh -c "printenv.py changegroup 0"
> +  > pushkey = sh -c "printenv.py pushkey 0"
> +  > EOF
>    $ req
>    pushing to http://localhost:$HGPORT/
>    searching for changes
> @@ -114,7 +116,7 @@ expect push success, phase change failur
>    > push_ssl = false
>    > allow_push = *
>    > [hooks]
> -  > prepushkey = printenv.py prepushkey 1
> +  > prepushkey = sh -c "printenv.py prepushkey 1"
>    > EOF
>    $ req
>    pushing to http://localhost:$HGPORT/
> @@ -133,7 +135,9 @@ expect push success, phase change failur
>
>  expect phase change success
>
> -  $ echo "prepushkey = printenv.py prepushkey 0" >> .hg/hgrc
> +  $ cat >> .hg/hgrc <<EOF
> +  > prepushkey = sh -c "printenv.py prepushkey 0"
> +  > EOF
>    $ req
>    pushing to http://localhost:$HGPORT/
>    searching for changes
> diff --git a/tests/test-ssh-bundle1.t b/tests/test-ssh-bundle1.t
> --- a/tests/test-ssh-bundle1.t
> +++ b/tests/test-ssh-bundle1.t
> @@ -38,7 +38,7 @@ configure for serving
>    > uncompressed = True
>    >
>    > [hooks]
> -  > changegroup = printenv.py changegroup-in-remote 0 ../dummylog
> +  > changegroup = sh -c "printenv.py changegroup-in-remote 0 ../dummylog"
>    > EOF
>    $ cd ..
>
> @@ -114,8 +114,10 @@ verify
>    crosschecking files in changesets and manifests
>    checking files
>    2 files, 3 changesets, 2 total revisions
> -  $ echo '[hooks]' >> .hg/hgrc
> -  $ echo "changegroup = printenv.py changegroup-in-local 0 ../dummylog" >> .hg/hgrc
> +  $ cat >> .hg/hgrc <<EOF
> +  > [hooks]
> +  > changegroup = sh -c "printenv.py changegroup-in-local 0 ../dummylog"
> +  > EOF
>
>  empty default pull
>
> diff --git a/tests/test-ssh.t b/tests/test-ssh.t
> --- a/tests/test-ssh.t
> +++ b/tests/test-ssh.t
> @@ -32,7 +32,7 @@ configure for serving
>    > uncompressed = True
>    >
>    > [hooks]
> -  > changegroup = printenv.py changegroup-in-remote 0 ../dummylog
> +  > changegroup = sh -c "printenv.py changegroup-in-remote 0 ../dummylog"
>    > EOF
>    $ cd ..
>
> @@ -108,8 +108,10 @@ verify
>    crosschecking files in changesets and manifests
>    checking files
>    2 files, 3 changesets, 2 total revisions
> -  $ echo '[hooks]' >> .hg/hgrc
> -  $ echo "changegroup = printenv.py changegroup-in-local 0 ../dummylog" >> .hg/hgrc
> +  $ cat >> .hg/hgrc <<EOF
> +  > [hooks]
> +  > changegroup = sh -c "printenv.py changegroup-in-local 0 ../dummylog"
> +  > EOF
>
>  empty default pull
>
> diff --git a/tests/test-static-http.t b/tests/test-static-http.t
> --- a/tests/test-static-http.t
> +++ b/tests/test-static-http.t
> @@ -53,8 +53,10 @@ check for HTTP opener failures when cach
>
>    $ rm .hg/cache/*
>    $ cd ../local
> -  $ echo '[hooks]' >> .hg/hgrc
> -  $ echo "changegroup = printenv.py changegroup" >> .hg/hgrc
> +  $ cat >> .hg/hgrc <<EOF
> +  > [hooks]
> +  > changegroup = sh -c "printenv.py changegroup"
> +  > EOF
>    $ hg pull
>    pulling from static-http://localhost:$HGPORT/remote
>    searching for changes
> _______________________________________________
> Mercurial-devel mailing list
> Mercurial-devel@mercurial-scm.org
> https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
Katsunori FUJIWARA - Nov. 4, 2016, 3:32 p.m.
At Fri, 4 Nov 2016 10:27:59 -0400,
timeless wrote:
> 
> I'm sure this is already in, but wouldn't it be better to use a
> $PYTHON than `sh -c`?

I don't have strong opinion for using "sh -c".

But, if we use $PYTHON instead of `sh -c` (= backing d19787db6fe0
out), we should change many "sh -c 'printenv.py'" already existing in
other test scenarios for similarity, too.

Unfortunately, just replacing "sh -c" by $PYTHON can't be applied on
some of them. For example, in test-hook.t:

  $ cat > .hg/hgrc <<EOF
  > [hooks]
  > commit = sh -c "HG_LOCAL= HG_TAG= printenv.py commit"
  > commit.b = sh -c "HG_LOCAL= HG_TAG= printenv.py commit.b"
  > precommit = sh -c  "HG_LOCAL= HG_NODE= HG_TAG= printenv.py precommit"
  > pretxncommit = sh -c "HG_LOCAL= HG_TAG= printenv.py pretxncommit"
  > pretxncommit.tip = hg -q tip
  > pre-identify = sh -c "printenv.py pre-identify 1"
  > pre-cat = sh -c "printenv.py pre-cat"
  > post-cat = sh -c "printenv.py post-cat"
  > pretxnopen = sh -c "HG_LOCAL= HG_TAG= printenv.py pretxnopen"
  > pretxnclose = sh -c "HG_LOCAL= HG_TAG= printenv.py pretxnclose"
  > txnclose = sh -c "HG_LOCAL= HG_TAG= printenv.py txnclose"
  > txnabort.0 = python:$TESTTMP/txnabort.checkargs.py:showargs
  > txnabort.1 = sh -c "HG_LOCAL= HG_TAG= printenv.py txnabort"
  > txnclose.checklock = sh -c "hg debuglock > /dev/null"
  > EOF


> On Fri, Oct 28, 2016 at 2:16 PM, FUJIWARA Katsunori
> <foozy@lares.dti.ne.jp> wrote:
> > # HG changeset patch
> > # User FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
> > # Date 1477676685 -32400
> > #      Sat Oct 29 02:44:45 2016 +0900
> > # Branch stable
> > # Node ID 34a5f6c66bc5a13381a68d08f73d858916167836
> > # Parent  3afde791dce192f38d8a228ed8e49397e353837e
> > tests: invoke printenv.py via sh -c for test portability
> >
> > On Windows platform, invoking printenv.py directly via hook is
> > problematic, because:
> >
> >   - unless binding between *.py suffix and python runtime, application
> >     selector dialog is displayed, and running test is blocked at each
> >     printenv.py invocations
> >
> >   - it isn't safe to assume binding between *.py suffix and python
> >     runtime, because application binding is easily broken
> >
> >     For example, installing IDE (VisualStudio with Python Tools, or
> >     so) often requires binding between source files and IDE itself.
> >
> > This patch invokes printenv.py via sh -c for test portability. This is
> > a kind of follow up for d19787db6fe0, which eliminated explicit
> > "python" for printenv.py. There are already other 'sh -c "printenv.py"'
> > in *.t files, and this fix should be reasonable.
> >
> > This changes were confirmed in cases below:
> >
> >   - without any application binding for *.py suffix
> >   - with binding between *.py suffix and VisualStudio
> >
> > This patch also replaces "echo + redirection" style with "heredoc"
> > style, because:
> >
> >   - hook command line is parsed by cmd.exe as shell at first, and
> >   - single quotation can't quote arguments on cmd.exe, therefore,
> >   - "printenv.py foobar" should be quoted by double quotation, but
> >   - nested quoting (or tricky escaping) isn't readable
> >
> > diff --git a/tests/test-bundle.t b/tests/test-bundle.t
> > --- a/tests/test-bundle.t
> > +++ b/tests/test-bundle.t
> > @@ -216,8 +216,10 @@ Make sure bundlerepo doesn't leak tempfi
> >
> >  Pull ../full.hg into empty (with hook)
> >
> > -  $ echo "[hooks]" >> .hg/hgrc
> > -  $ echo "changegroup = printenv.py changegroup" >> .hg/hgrc
> > +  $ cat >> .hg/hgrc <<EOF
> > +  > [hooks]
> > +  > changegroup = sh -c "printenv.py changegroup"
> > +  > EOF
> >
> >  doesn't work (yet ?)
> >
> > diff --git a/tests/test-hook.t b/tests/test-hook.t
> > --- a/tests/test-hook.t
> > +++ b/tests/test-hook.t
> > @@ -16,9 +16,9 @@ commit hooks can see env vars
> >    > precommit = sh -c  "HG_LOCAL= HG_NODE= HG_TAG= printenv.py precommit"
> >    > pretxncommit = sh -c "HG_LOCAL= HG_TAG= printenv.py pretxncommit"
> >    > pretxncommit.tip = hg -q tip
> > -  > pre-identify = printenv.py pre-identify 1
> > -  > pre-cat = printenv.py pre-cat
> > -  > post-cat = printenv.py post-cat
> > +  > pre-identify = sh -c "printenv.py pre-identify 1"
> > +  > pre-cat = sh -c "printenv.py pre-cat"
> > +  > post-cat = sh -c "printenv.py post-cat"
> >    > pretxnopen = sh -c "HG_LOCAL= HG_TAG= printenv.py pretxnopen"
> >    > pretxnclose = sh -c "HG_LOCAL= HG_TAG= printenv.py pretxnclose"
> >    > txnclose = sh -c "HG_LOCAL= HG_TAG= printenv.py txnclose"
> > @@ -47,9 +47,9 @@ changegroup hooks can see env vars
> >
> >    $ cat > .hg/hgrc <<EOF
> >    > [hooks]
> > -  > prechangegroup = printenv.py prechangegroup
> > -  > changegroup = printenv.py changegroup
> > -  > incoming = printenv.py incoming
> > +  > prechangegroup = sh -c "printenv.py prechangegroup"
> > +  > changegroup = sh -c "printenv.py changegroup"
> > +  > incoming = sh -c "printenv.py incoming"
> >    > EOF
> >
> >  pretxncommit and commit hooks can see both parents of merge
> > @@ -122,7 +122,7 @@ tag hooks can see env vars
> >
> >    $ cd ../a
> >    $ cat >> .hg/hgrc <<EOF
> > -  > pretag = printenv.py pretag
> > +  > pretag = sh -c "printenv.py pretag"
> >    > tag = sh -c "HG_PARENT1= HG_PARENT2= printenv.py tag"
> >    > EOF
> >    $ hg tag -d '3 0' a
> > @@ -142,7 +142,9 @@ tag hooks can see env vars
> >
> >  pretag hook can forbid tagging
> >
> > -  $ echo "pretag.forbid = printenv.py pretag.forbid 1" >> .hg/hgrc
> > +  $ cat >> .hg/hgrc <<EOF
> > +  > pretag.forbid = sh -c "printenv.py pretag.forbid 1"
> > +  > EOF
> >    $ hg tag -d '4 0' fa
> >    pretag hook: HG_LOCAL=0 HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_TAG=fa
> >    pretag.forbid hook: HG_LOCAL=0 HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_TAG=fa
> > @@ -157,8 +159,10 @@ pretag hook can forbid tagging
> >  pretxncommit hook can see changeset, can roll back txn, changeset no
> >  more there after
> >
> > -  $ echo "pretxncommit.forbid0 = hg tip -q" >> .hg/hgrc
> > -  $ echo "pretxncommit.forbid1 = printenv.py pretxncommit.forbid 1" >> .hg/hgrc
> > +  $ cat >> .hg/hgrc <<EOF
> > +  > pretxncommit.forbid0 = sh -c "hg tip -q"
> > +  > pretxncommit.forbid1 = sh -c "printenv.py pretxncommit.forbid 1"
> > +  > EOF
> >    $ echo z > z
> >    $ hg add z
> >    $ hg -q tip
> > @@ -196,7 +200,9 @@ more there after
> >
> >  precommit hook can prevent commit
> >
> > -  $ echo "precommit.forbid = printenv.py precommit.forbid 1" >> .hg/hgrc
> > +  $ cat >> .hg/hgrc <<EOF
> > +  > precommit.forbid = sh -c "printenv.py precommit.forbid 1"
> > +  > EOF
> >    $ hg commit -m 'fail' -d '4 0'
> >    precommit hook: HG_PARENT1=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10
> >    precommit.forbid hook: HG_PARENT1=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10
> > @@ -207,14 +213,18 @@ precommit hook can prevent commit
> >
> >  preupdate hook can prevent update
> >
> > -  $ echo "preupdate = printenv.py preupdate" >> .hg/hgrc
> > +  $ cat >> .hg/hgrc <<EOF
> > +  > preupdate = sh -c "printenv.py preupdate"
> > +  > EOF
> >    $ hg update 1
> >    preupdate hook: HG_PARENT1=ab228980c14d
> >    0 files updated, 0 files merged, 2 files removed, 0 files unresolved
> >
> >  update hook
> >
> > -  $ echo "update = printenv.py update" >> .hg/hgrc
> > +  $ cat >> .hg/hgrc <<EOF
> > +  > update = sh -c "printenv.py update"
> > +  > EOF
> >    $ hg update
> >    preupdate hook: HG_PARENT1=539e4b31b6dc
> >    update hook: HG_ERROR=0 HG_PARENT1=539e4b31b6dc
> > @@ -222,7 +232,9 @@ update hook
> >
> >  pushkey hook
> >
> > -  $ echo "pushkey = printenv.py pushkey" >> .hg/hgrc
> > +  $ cat >> .hg/hgrc <<EOF
> > +  > pushkey = sh -c "printenv.py pushkey"
> > +  > EOF
> >    $ cd ../b
> >    $ hg bookmark -r null foo
> >    $ hg push -B foo ../a
> > @@ -239,7 +251,9 @@ pushkey hook
> >
> >  listkeys hook
> >
> > -  $ echo "listkeys = printenv.py listkeys" >> .hg/hgrc
> > +  $ cat >> .hg/hgrc <<EOF
> > +  > listkeys = sh -c "printenv.py listkeys"
> > +  > EOF
> >    $ hg bookmark -r null bar
> >    pretxnopen hook: HG_TXNID=TXN:* HG_TXNNAME=bookmark (glob)
> >    pretxnclose hook: HG_BOOKMARK_MOVED=1 HG_PENDING=$TESTTMP/a HG_TXNID=TXN:* HG_TXNNAME=bookmark (glob)
> > @@ -255,7 +269,9 @@ listkeys hook
> >
> >  test that prepushkey can prevent incoming keys
> >
> > -  $ echo "prepushkey = printenv.py prepushkey.forbid 1" >> .hg/hgrc
> > +  $ cat >> .hg/hgrc <<EOF
> > +  > prepushkey = sh -c "printenv.py prepushkey.forbid 1"
> > +  > EOF
> >    $ cd ../b
> >    $ hg bookmark -r null baz
> >    $ hg push -B baz ../a
> > @@ -273,7 +289,9 @@ test that prepushkey can prevent incomin
> >
> >  test that prelistkeys can prevent listing keys
> >
> > -  $ echo "prelistkeys = printenv.py prelistkeys.forbid 1" >> .hg/hgrc
> > +  $ cat >> .hg/hgrc <<EOF
> > +  > prelistkeys = sh -c "printenv.py prelistkeys.forbid 1"
> > +  > EOF
> >    $ hg bookmark -r null quux
> >    pretxnopen hook: HG_TXNID=TXN:* HG_TXNNAME=bookmark (glob)
> >    pretxnclose hook: HG_BOOKMARK_MOVED=1 HG_PENDING=$TESTTMP/a HG_TXNID=TXN:* HG_TXNNAME=bookmark (glob)
> > @@ -294,7 +312,7 @@ prechangegroup hook can prevent incoming
> >    3:07f3376c1e65
> >    $ cat > .hg/hgrc <<EOF
> >    > [hooks]
> > -  > prechangegroup.forbid = printenv.py prechangegroup.forbid 1
> > +  > prechangegroup.forbid = sh -c "printenv.py prechangegroup.forbid 1"
> >    > EOF
> >    $ hg pull ../a
> >    pulling from ../a
> > @@ -309,7 +327,7 @@ incoming changes no longer there after
> >    $ cat > .hg/hgrc <<EOF
> >    > [hooks]
> >    > pretxnchangegroup.forbid0 = hg tip -q
> > -  > pretxnchangegroup.forbid1 = printenv.py pretxnchangegroup.forbid 1
> > +  > pretxnchangegroup.forbid1 = sh -c "printenv.py pretxnchangegroup.forbid 1"
> >    > EOF
> >    $ hg pull ../a
> >    pulling from ../a
> > @@ -332,8 +350,8 @@ outgoing hooks can see env vars
> >    $ rm .hg/hgrc
> >    $ cat > ../a/.hg/hgrc <<EOF
> >    > [hooks]
> > -  > preoutgoing = printenv.py preoutgoing
> > -  > outgoing = printenv.py outgoing
> > +  > preoutgoing = sh -c "printenv.py preoutgoing"
> > +  > outgoing = sh -c "printenv.py outgoing"
> >    > EOF
> >    $ hg pull ../a
> >    pulling from ../a
> > @@ -351,7 +369,9 @@ outgoing hooks can see env vars
> >
> >  preoutgoing hook can prevent outgoing changes
> >
> > -  $ echo "preoutgoing.forbid = printenv.py preoutgoing.forbid 1" >> ../a/.hg/hgrc
> > +  $ cat >> ../a/.hg/hgrc <<EOF
> > +  > preoutgoing.forbid = sh -c "printenv.py preoutgoing.forbid 1"
> > +  > EOF
> >    $ hg pull ../a
> >    pulling from ../a
> >    searching for changes
> > @@ -365,8 +385,8 @@ outgoing hooks work for local clones
> >    $ cd ..
> >    $ cat > a/.hg/hgrc <<EOF
> >    > [hooks]
> > -  > preoutgoing = printenv.py preoutgoing
> > -  > outgoing = printenv.py outgoing
> > +  > preoutgoing = sh -c "printenv.py preoutgoing"
> > +  > outgoing = sh -c "printenv.py outgoing"
> >    > EOF
> >    $ hg clone a c
> >    preoutgoing hook: HG_SOURCE=clone
> > @@ -377,7 +397,9 @@ outgoing hooks work for local clones
> >
> >  preoutgoing hook can prevent outgoing changes for local clones
> >
> > -  $ echo "preoutgoing.forbid = printenv.py preoutgoing.forbid 1" >> a/.hg/hgrc
> > +  $ cat >> a/.hg/hgrc <<EOF
> > +  > preoutgoing.forbid = sh -c "printenv.py preoutgoing.forbid 1"
> > +  > EOF
> >    $ hg clone a zzz
> >    preoutgoing hook: HG_SOURCE=clone
> >    preoutgoing.forbid hook: HG_SOURCE=clone
> > @@ -750,7 +772,7 @@ This also creates the `to` repo for the
> >    $ cd ..
> >    $ cat << EOF >> hgrc-with-post-init-hook
> >    > [hooks]
> > -  > post-init = printenv.py post-init
> > +  > post-init = sh -c "printenv.py post-init"
> >    > EOF
> >    $ HGRCPATH=hgrc-with-post-init-hook hg init to
> >    post-init hook: HG_ARGS=init to HG_OPTS={'insecure': None, 'remotecmd': '', 'ssh': ''} HG_PATS=['to'] HG_RESULT=0
> > diff --git a/tests/test-http-bundle1.t b/tests/test-http-bundle1.t
> > --- a/tests/test-http-bundle1.t
> > +++ b/tests/test-http-bundle1.t
> > @@ -127,8 +127,10 @@ incoming via HTTP
> >  pull
> >
> >    $ cd copy-pull
> > -  $ echo '[hooks]' >> .hg/hgrc
> > -  $ echo "changegroup = printenv.py changegroup" >> .hg/hgrc
> > +  $ cat >> .hg/hgrc <<EOF
> > +  > [hooks]
> > +  > changegroup = sh -c "printenv.py changegroup"
> > +  > EOF
> >    $ hg pull
> >    pulling from http://localhost:$HGPORT1/
> >    searching for changes
> > diff --git a/tests/test-http.t b/tests/test-http.t
> > --- a/tests/test-http.t
> > +++ b/tests/test-http.t
> > @@ -118,8 +118,10 @@ incoming via HTTP
> >  pull
> >
> >    $ cd copy-pull
> > -  $ echo '[hooks]' >> .hg/hgrc
> > -  $ echo "changegroup = printenv.py changegroup" >> .hg/hgrc
> > +  $ cat >> .hg/hgrc <<EOF
> > +  > [hooks]
> > +  > changegroup = sh -c "printenv.py changegroup"
> > +  > EOF
> >    $ hg pull
> >    pulling from http://localhost:$HGPORT1/
> >    searching for changes
> > diff --git a/tests/test-https.t b/tests/test-https.t
> > --- a/tests/test-https.t
> > +++ b/tests/test-https.t
> > @@ -203,8 +203,10 @@ Inability to verify peer certificate wil
> >  pull without cacert
> >
> >    $ cd copy-pull
> > -  $ echo '[hooks]' >> .hg/hgrc
> > -  $ echo "changegroup = printenv.py changegroup" >> .hg/hgrc
> > +  $ cat >> .hg/hgrc <<EOF
> > +  > [hooks]
> > +  > changegroup = sh -c "printenv.py changegroup"
> > +  > EOF
> >    $ hg pull $DISABLECACERTS
> >    pulling from https://localhost:$HGPORT/
> >    warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info (?)
> > diff --git a/tests/test-push-http-bundle1.t b/tests/test-push-http-bundle1.t
> > --- a/tests/test-push-http-bundle1.t
> > +++ b/tests/test-push-http-bundle1.t
> > @@ -66,10 +66,12 @@ expect authorization error: must have au
> >
> >  expect success
> >
> > -  $ echo 'allow_push = *' >> .hg/hgrc
> > -  $ echo '[hooks]' >> .hg/hgrc
> > -  $ echo "changegroup = printenv.py changegroup 0" >> .hg/hgrc
> > -  $ echo "pushkey = printenv.py pushkey 0" >> .hg/hgrc
> > +  $ cat >> .hg/hgrc <<EOF
> > +  > allow_push = *
> > +  > [hooks]
> > +  > changegroup = sh -c "printenv.py changegroup 0"
> > +  > pushkey = sh -c "printenv.py pushkey 0"
> > +  > EOF
> >    $ req
> >    pushing to http://localhost:$HGPORT/
> >    searching for changes
> > @@ -151,7 +153,7 @@ expect push success, phase change failur
> >    > push_ssl = false
> >    > allow_push = *
> >    > [hooks]
> > -  > prepushkey = printenv.py prepushkey 1
> > +  > prepushkey = sh -c "printenv.py prepushkey 1"
> >    > EOF
> >    $ req
> >    pushing to http://localhost:$HGPORT/
> > @@ -164,7 +166,9 @@ expect push success, phase change failur
> >
> >  expect phase change success
> >
> > -  $ echo "prepushkey = printenv.py prepushkey 0" >> .hg/hgrc
> > +  $ cat >> .hg/hgrc <<EOF
> > +  > prepushkey = sh -c "printenv.py prepushkey 0"
> > +  > EOF
> >    $ req
> >    pushing to http://localhost:$HGPORT/
> >    searching for changes
> > diff --git a/tests/test-push-http.t b/tests/test-push-http.t
> > --- a/tests/test-push-http.t
> > +++ b/tests/test-push-http.t
> > @@ -56,10 +56,12 @@ expect authorization error: must have au
> >
> >  expect success
> >
> > -  $ echo 'allow_push = *' >> .hg/hgrc
> > -  $ echo '[hooks]' >> .hg/hgrc
> > -  $ echo "changegroup = printenv.py changegroup 0" >> .hg/hgrc
> > -  $ echo "pushkey = printenv.py pushkey 0" >> .hg/hgrc
> > +  $ cat >> .hg/hgrc <<EOF
> > +  > allow_push = *
> > +  > [hooks]
> > +  > changegroup = sh -c "printenv.py changegroup 0"
> > +  > pushkey = sh -c "printenv.py pushkey 0"
> > +  > EOF
> >    $ req
> >    pushing to http://localhost:$HGPORT/
> >    searching for changes
> > @@ -114,7 +116,7 @@ expect push success, phase change failur
> >    > push_ssl = false
> >    > allow_push = *
> >    > [hooks]
> > -  > prepushkey = printenv.py prepushkey 1
> > +  > prepushkey = sh -c "printenv.py prepushkey 1"
> >    > EOF
> >    $ req
> >    pushing to http://localhost:$HGPORT/
> > @@ -133,7 +135,9 @@ expect push success, phase change failur
> >
> >  expect phase change success
> >
> > -  $ echo "prepushkey = printenv.py prepushkey 0" >> .hg/hgrc
> > +  $ cat >> .hg/hgrc <<EOF
> > +  > prepushkey = sh -c "printenv.py prepushkey 0"
> > +  > EOF
> >    $ req
> >    pushing to http://localhost:$HGPORT/
> >    searching for changes
> > diff --git a/tests/test-ssh-bundle1.t b/tests/test-ssh-bundle1.t
> > --- a/tests/test-ssh-bundle1.t
> > +++ b/tests/test-ssh-bundle1.t
> > @@ -38,7 +38,7 @@ configure for serving
> >    > uncompressed = True
> >    >
> >    > [hooks]
> > -  > changegroup = printenv.py changegroup-in-remote 0 ../dummylog
> > +  > changegroup = sh -c "printenv.py changegroup-in-remote 0 ../dummylog"
> >    > EOF
> >    $ cd ..
> >
> > @@ -114,8 +114,10 @@ verify
> >    crosschecking files in changesets and manifests
> >    checking files
> >    2 files, 3 changesets, 2 total revisions
> > -  $ echo '[hooks]' >> .hg/hgrc
> > -  $ echo "changegroup = printenv.py changegroup-in-local 0 ../dummylog" >> .hg/hgrc
> > +  $ cat >> .hg/hgrc <<EOF
> > +  > [hooks]
> > +  > changegroup = sh -c "printenv.py changegroup-in-local 0 ../dummylog"
> > +  > EOF
> >
> >  empty default pull
> >
> > diff --git a/tests/test-ssh.t b/tests/test-ssh.t
> > --- a/tests/test-ssh.t
> > +++ b/tests/test-ssh.t
> > @@ -32,7 +32,7 @@ configure for serving
> >    > uncompressed = True
> >    >
> >    > [hooks]
> > -  > changegroup = printenv.py changegroup-in-remote 0 ../dummylog
> > +  > changegroup = sh -c "printenv.py changegroup-in-remote 0 ../dummylog"
> >    > EOF
> >    $ cd ..
> >
> > @@ -108,8 +108,10 @@ verify
> >    crosschecking files in changesets and manifests
> >    checking files
> >    2 files, 3 changesets, 2 total revisions
> > -  $ echo '[hooks]' >> .hg/hgrc
> > -  $ echo "changegroup = printenv.py changegroup-in-local 0 ../dummylog" >> .hg/hgrc
> > +  $ cat >> .hg/hgrc <<EOF
> > +  > [hooks]
> > +  > changegroup = sh -c "printenv.py changegroup-in-local 0 ../dummylog"
> > +  > EOF
> >
> >  empty default pull
> >
> > diff --git a/tests/test-static-http.t b/tests/test-static-http.t
> > --- a/tests/test-static-http.t
> > +++ b/tests/test-static-http.t
> > @@ -53,8 +53,10 @@ check for HTTP opener failures when cach
> >
> >    $ rm .hg/cache/*
> >    $ cd ../local
> > -  $ echo '[hooks]' >> .hg/hgrc
> > -  $ echo "changegroup = printenv.py changegroup" >> .hg/hgrc
> > +  $ cat >> .hg/hgrc <<EOF
> > +  > [hooks]
> > +  > changegroup = sh -c "printenv.py changegroup"
> > +  > EOF
> >    $ hg pull
> >    pulling from static-http://localhost:$HGPORT/remote
> >    searching for changes
> > _______________________________________________
> > Mercurial-devel mailing list
> > Mercurial-devel@mercurial-scm.org
> > https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
> 

----------------------------------------------------------------------
[FUJIWARA Katsunori]                             foozy@lares.dti.ne.jp
timeless - Nov. 4, 2016, 7:20 p.m.
timeless wrote:
> I'm sure this is already in, but wouldn't it be better to use a
> $PYTHON than `sh -c`?

FUJIWARA Katsunori wrote:
> I don't have strong opinion for using "sh -c".
>
> But, if we use $PYTHON instead of `sh -c` (= backing d19787db6fe0
> out), we should change many "sh -c 'printenv.py'" already existing in
> other test scenarios for similarity, too.
>
> Unfortunately, just replacing "sh -c" by $PYTHON can't be applied on
> some of them. For example, in test-hook.t:
>
>   $ cat > .hg/hgrc <<EOF
>   > [hooks]
...
>   > txnabort.1 = sh -c "HG_LOCAL= HG_TAG= printenv.py txnabort"
This looks like a candidate for:

env .... $PYTHON ...

Patch

diff --git a/tests/test-bundle.t b/tests/test-bundle.t
--- a/tests/test-bundle.t
+++ b/tests/test-bundle.t
@@ -216,8 +216,10 @@  Make sure bundlerepo doesn't leak tempfi
 
 Pull ../full.hg into empty (with hook)
 
-  $ echo "[hooks]" >> .hg/hgrc
-  $ echo "changegroup = printenv.py changegroup" >> .hg/hgrc
+  $ cat >> .hg/hgrc <<EOF
+  > [hooks]
+  > changegroup = sh -c "printenv.py changegroup"
+  > EOF
 
 doesn't work (yet ?)
 
diff --git a/tests/test-hook.t b/tests/test-hook.t
--- a/tests/test-hook.t
+++ b/tests/test-hook.t
@@ -16,9 +16,9 @@  commit hooks can see env vars
   > precommit = sh -c  "HG_LOCAL= HG_NODE= HG_TAG= printenv.py precommit"
   > pretxncommit = sh -c "HG_LOCAL= HG_TAG= printenv.py pretxncommit"
   > pretxncommit.tip = hg -q tip
-  > pre-identify = printenv.py pre-identify 1
-  > pre-cat = printenv.py pre-cat
-  > post-cat = printenv.py post-cat
+  > pre-identify = sh -c "printenv.py pre-identify 1"
+  > pre-cat = sh -c "printenv.py pre-cat"
+  > post-cat = sh -c "printenv.py post-cat"
   > pretxnopen = sh -c "HG_LOCAL= HG_TAG= printenv.py pretxnopen"
   > pretxnclose = sh -c "HG_LOCAL= HG_TAG= printenv.py pretxnclose"
   > txnclose = sh -c "HG_LOCAL= HG_TAG= printenv.py txnclose"
@@ -47,9 +47,9 @@  changegroup hooks can see env vars
 
   $ cat > .hg/hgrc <<EOF
   > [hooks]
-  > prechangegroup = printenv.py prechangegroup
-  > changegroup = printenv.py changegroup
-  > incoming = printenv.py incoming
+  > prechangegroup = sh -c "printenv.py prechangegroup"
+  > changegroup = sh -c "printenv.py changegroup"
+  > incoming = sh -c "printenv.py incoming"
   > EOF
 
 pretxncommit and commit hooks can see both parents of merge
@@ -122,7 +122,7 @@  tag hooks can see env vars
 
   $ cd ../a
   $ cat >> .hg/hgrc <<EOF
-  > pretag = printenv.py pretag
+  > pretag = sh -c "printenv.py pretag"
   > tag = sh -c "HG_PARENT1= HG_PARENT2= printenv.py tag"
   > EOF
   $ hg tag -d '3 0' a
@@ -142,7 +142,9 @@  tag hooks can see env vars
 
 pretag hook can forbid tagging
 
-  $ echo "pretag.forbid = printenv.py pretag.forbid 1" >> .hg/hgrc
+  $ cat >> .hg/hgrc <<EOF
+  > pretag.forbid = sh -c "printenv.py pretag.forbid 1"
+  > EOF
   $ hg tag -d '4 0' fa
   pretag hook: HG_LOCAL=0 HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_TAG=fa
   pretag.forbid hook: HG_LOCAL=0 HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_TAG=fa
@@ -157,8 +159,10 @@  pretag hook can forbid tagging
 pretxncommit hook can see changeset, can roll back txn, changeset no
 more there after
 
-  $ echo "pretxncommit.forbid0 = hg tip -q" >> .hg/hgrc
-  $ echo "pretxncommit.forbid1 = printenv.py pretxncommit.forbid 1" >> .hg/hgrc
+  $ cat >> .hg/hgrc <<EOF
+  > pretxncommit.forbid0 = sh -c "hg tip -q"
+  > pretxncommit.forbid1 = sh -c "printenv.py pretxncommit.forbid 1"
+  > EOF
   $ echo z > z
   $ hg add z
   $ hg -q tip
@@ -196,7 +200,9 @@  more there after
 
 precommit hook can prevent commit
 
-  $ echo "precommit.forbid = printenv.py precommit.forbid 1" >> .hg/hgrc
+  $ cat >> .hg/hgrc <<EOF
+  > precommit.forbid = sh -c "printenv.py precommit.forbid 1"
+  > EOF
   $ hg commit -m 'fail' -d '4 0'
   precommit hook: HG_PARENT1=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10
   precommit.forbid hook: HG_PARENT1=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10
@@ -207,14 +213,18 @@  precommit hook can prevent commit
 
 preupdate hook can prevent update
 
-  $ echo "preupdate = printenv.py preupdate" >> .hg/hgrc
+  $ cat >> .hg/hgrc <<EOF
+  > preupdate = sh -c "printenv.py preupdate"
+  > EOF
   $ hg update 1
   preupdate hook: HG_PARENT1=ab228980c14d
   0 files updated, 0 files merged, 2 files removed, 0 files unresolved
 
 update hook
 
-  $ echo "update = printenv.py update" >> .hg/hgrc
+  $ cat >> .hg/hgrc <<EOF
+  > update = sh -c "printenv.py update"
+  > EOF
   $ hg update
   preupdate hook: HG_PARENT1=539e4b31b6dc
   update hook: HG_ERROR=0 HG_PARENT1=539e4b31b6dc
@@ -222,7 +232,9 @@  update hook
 
 pushkey hook
 
-  $ echo "pushkey = printenv.py pushkey" >> .hg/hgrc
+  $ cat >> .hg/hgrc <<EOF
+  > pushkey = sh -c "printenv.py pushkey"
+  > EOF
   $ cd ../b
   $ hg bookmark -r null foo
   $ hg push -B foo ../a
@@ -239,7 +251,9 @@  pushkey hook
 
 listkeys hook
 
-  $ echo "listkeys = printenv.py listkeys" >> .hg/hgrc
+  $ cat >> .hg/hgrc <<EOF
+  > listkeys = sh -c "printenv.py listkeys"
+  > EOF
   $ hg bookmark -r null bar
   pretxnopen hook: HG_TXNID=TXN:* HG_TXNNAME=bookmark (glob)
   pretxnclose hook: HG_BOOKMARK_MOVED=1 HG_PENDING=$TESTTMP/a HG_TXNID=TXN:* HG_TXNNAME=bookmark (glob)
@@ -255,7 +269,9 @@  listkeys hook
 
 test that prepushkey can prevent incoming keys
 
-  $ echo "prepushkey = printenv.py prepushkey.forbid 1" >> .hg/hgrc
+  $ cat >> .hg/hgrc <<EOF
+  > prepushkey = sh -c "printenv.py prepushkey.forbid 1"
+  > EOF
   $ cd ../b
   $ hg bookmark -r null baz
   $ hg push -B baz ../a
@@ -273,7 +289,9 @@  test that prepushkey can prevent incomin
 
 test that prelistkeys can prevent listing keys
 
-  $ echo "prelistkeys = printenv.py prelistkeys.forbid 1" >> .hg/hgrc
+  $ cat >> .hg/hgrc <<EOF
+  > prelistkeys = sh -c "printenv.py prelistkeys.forbid 1"
+  > EOF
   $ hg bookmark -r null quux
   pretxnopen hook: HG_TXNID=TXN:* HG_TXNNAME=bookmark (glob)
   pretxnclose hook: HG_BOOKMARK_MOVED=1 HG_PENDING=$TESTTMP/a HG_TXNID=TXN:* HG_TXNNAME=bookmark (glob)
@@ -294,7 +312,7 @@  prechangegroup hook can prevent incoming
   3:07f3376c1e65
   $ cat > .hg/hgrc <<EOF
   > [hooks]
-  > prechangegroup.forbid = printenv.py prechangegroup.forbid 1
+  > prechangegroup.forbid = sh -c "printenv.py prechangegroup.forbid 1"
   > EOF
   $ hg pull ../a
   pulling from ../a
@@ -309,7 +327,7 @@  incoming changes no longer there after
   $ cat > .hg/hgrc <<EOF
   > [hooks]
   > pretxnchangegroup.forbid0 = hg tip -q
-  > pretxnchangegroup.forbid1 = printenv.py pretxnchangegroup.forbid 1
+  > pretxnchangegroup.forbid1 = sh -c "printenv.py pretxnchangegroup.forbid 1"
   > EOF
   $ hg pull ../a
   pulling from ../a
@@ -332,8 +350,8 @@  outgoing hooks can see env vars
   $ rm .hg/hgrc
   $ cat > ../a/.hg/hgrc <<EOF
   > [hooks]
-  > preoutgoing = printenv.py preoutgoing
-  > outgoing = printenv.py outgoing
+  > preoutgoing = sh -c "printenv.py preoutgoing"
+  > outgoing = sh -c "printenv.py outgoing"
   > EOF
   $ hg pull ../a
   pulling from ../a
@@ -351,7 +369,9 @@  outgoing hooks can see env vars
 
 preoutgoing hook can prevent outgoing changes
 
-  $ echo "preoutgoing.forbid = printenv.py preoutgoing.forbid 1" >> ../a/.hg/hgrc
+  $ cat >> ../a/.hg/hgrc <<EOF
+  > preoutgoing.forbid = sh -c "printenv.py preoutgoing.forbid 1"
+  > EOF
   $ hg pull ../a
   pulling from ../a
   searching for changes
@@ -365,8 +385,8 @@  outgoing hooks work for local clones
   $ cd ..
   $ cat > a/.hg/hgrc <<EOF
   > [hooks]
-  > preoutgoing = printenv.py preoutgoing
-  > outgoing = printenv.py outgoing
+  > preoutgoing = sh -c "printenv.py preoutgoing"
+  > outgoing = sh -c "printenv.py outgoing"
   > EOF
   $ hg clone a c
   preoutgoing hook: HG_SOURCE=clone
@@ -377,7 +397,9 @@  outgoing hooks work for local clones
 
 preoutgoing hook can prevent outgoing changes for local clones
 
-  $ echo "preoutgoing.forbid = printenv.py preoutgoing.forbid 1" >> a/.hg/hgrc
+  $ cat >> a/.hg/hgrc <<EOF
+  > preoutgoing.forbid = sh -c "printenv.py preoutgoing.forbid 1"
+  > EOF
   $ hg clone a zzz
   preoutgoing hook: HG_SOURCE=clone
   preoutgoing.forbid hook: HG_SOURCE=clone
@@ -750,7 +772,7 @@  This also creates the `to` repo for the 
   $ cd ..
   $ cat << EOF >> hgrc-with-post-init-hook
   > [hooks]
-  > post-init = printenv.py post-init
+  > post-init = sh -c "printenv.py post-init"
   > EOF
   $ HGRCPATH=hgrc-with-post-init-hook hg init to
   post-init hook: HG_ARGS=init to HG_OPTS={'insecure': None, 'remotecmd': '', 'ssh': ''} HG_PATS=['to'] HG_RESULT=0
diff --git a/tests/test-http-bundle1.t b/tests/test-http-bundle1.t
--- a/tests/test-http-bundle1.t
+++ b/tests/test-http-bundle1.t
@@ -127,8 +127,10 @@  incoming via HTTP
 pull
 
   $ cd copy-pull
-  $ echo '[hooks]' >> .hg/hgrc
-  $ echo "changegroup = printenv.py changegroup" >> .hg/hgrc
+  $ cat >> .hg/hgrc <<EOF
+  > [hooks]
+  > changegroup = sh -c "printenv.py changegroup"
+  > EOF
   $ hg pull
   pulling from http://localhost:$HGPORT1/
   searching for changes
diff --git a/tests/test-http.t b/tests/test-http.t
--- a/tests/test-http.t
+++ b/tests/test-http.t
@@ -118,8 +118,10 @@  incoming via HTTP
 pull
 
   $ cd copy-pull
-  $ echo '[hooks]' >> .hg/hgrc
-  $ echo "changegroup = printenv.py changegroup" >> .hg/hgrc
+  $ cat >> .hg/hgrc <<EOF
+  > [hooks]
+  > changegroup = sh -c "printenv.py changegroup"
+  > EOF
   $ hg pull
   pulling from http://localhost:$HGPORT1/
   searching for changes
diff --git a/tests/test-https.t b/tests/test-https.t
--- a/tests/test-https.t
+++ b/tests/test-https.t
@@ -203,8 +203,10 @@  Inability to verify peer certificate wil
 pull without cacert
 
   $ cd copy-pull
-  $ echo '[hooks]' >> .hg/hgrc
-  $ echo "changegroup = printenv.py changegroup" >> .hg/hgrc
+  $ cat >> .hg/hgrc <<EOF
+  > [hooks]
+  > changegroup = sh -c "printenv.py changegroup"
+  > EOF
   $ hg pull $DISABLECACERTS
   pulling from https://localhost:$HGPORT/
   warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info (?)
diff --git a/tests/test-push-http-bundle1.t b/tests/test-push-http-bundle1.t
--- a/tests/test-push-http-bundle1.t
+++ b/tests/test-push-http-bundle1.t
@@ -66,10 +66,12 @@  expect authorization error: must have au
 
 expect success
 
-  $ echo 'allow_push = *' >> .hg/hgrc
-  $ echo '[hooks]' >> .hg/hgrc
-  $ echo "changegroup = printenv.py changegroup 0" >> .hg/hgrc
-  $ echo "pushkey = printenv.py pushkey 0" >> .hg/hgrc
+  $ cat >> .hg/hgrc <<EOF
+  > allow_push = *
+  > [hooks]
+  > changegroup = sh -c "printenv.py changegroup 0"
+  > pushkey = sh -c "printenv.py pushkey 0"
+  > EOF
   $ req
   pushing to http://localhost:$HGPORT/
   searching for changes
@@ -151,7 +153,7 @@  expect push success, phase change failur
   > push_ssl = false
   > allow_push = *
   > [hooks]
-  > prepushkey = printenv.py prepushkey 1
+  > prepushkey = sh -c "printenv.py prepushkey 1"
   > EOF
   $ req
   pushing to http://localhost:$HGPORT/
@@ -164,7 +166,9 @@  expect push success, phase change failur
 
 expect phase change success
 
-  $ echo "prepushkey = printenv.py prepushkey 0" >> .hg/hgrc
+  $ cat >> .hg/hgrc <<EOF
+  > prepushkey = sh -c "printenv.py prepushkey 0"
+  > EOF
   $ req
   pushing to http://localhost:$HGPORT/
   searching for changes
diff --git a/tests/test-push-http.t b/tests/test-push-http.t
--- a/tests/test-push-http.t
+++ b/tests/test-push-http.t
@@ -56,10 +56,12 @@  expect authorization error: must have au
 
 expect success
 
-  $ echo 'allow_push = *' >> .hg/hgrc
-  $ echo '[hooks]' >> .hg/hgrc
-  $ echo "changegroup = printenv.py changegroup 0" >> .hg/hgrc
-  $ echo "pushkey = printenv.py pushkey 0" >> .hg/hgrc
+  $ cat >> .hg/hgrc <<EOF
+  > allow_push = *
+  > [hooks]
+  > changegroup = sh -c "printenv.py changegroup 0"
+  > pushkey = sh -c "printenv.py pushkey 0"
+  > EOF
   $ req
   pushing to http://localhost:$HGPORT/
   searching for changes
@@ -114,7 +116,7 @@  expect push success, phase change failur
   > push_ssl = false
   > allow_push = *
   > [hooks]
-  > prepushkey = printenv.py prepushkey 1
+  > prepushkey = sh -c "printenv.py prepushkey 1"
   > EOF
   $ req
   pushing to http://localhost:$HGPORT/
@@ -133,7 +135,9 @@  expect push success, phase change failur
 
 expect phase change success
 
-  $ echo "prepushkey = printenv.py prepushkey 0" >> .hg/hgrc
+  $ cat >> .hg/hgrc <<EOF
+  > prepushkey = sh -c "printenv.py prepushkey 0"
+  > EOF
   $ req
   pushing to http://localhost:$HGPORT/
   searching for changes
diff --git a/tests/test-ssh-bundle1.t b/tests/test-ssh-bundle1.t
--- a/tests/test-ssh-bundle1.t
+++ b/tests/test-ssh-bundle1.t
@@ -38,7 +38,7 @@  configure for serving
   > uncompressed = True
   > 
   > [hooks]
-  > changegroup = printenv.py changegroup-in-remote 0 ../dummylog
+  > changegroup = sh -c "printenv.py changegroup-in-remote 0 ../dummylog"
   > EOF
   $ cd ..
 
@@ -114,8 +114,10 @@  verify
   crosschecking files in changesets and manifests
   checking files
   2 files, 3 changesets, 2 total revisions
-  $ echo '[hooks]' >> .hg/hgrc
-  $ echo "changegroup = printenv.py changegroup-in-local 0 ../dummylog" >> .hg/hgrc
+  $ cat >> .hg/hgrc <<EOF
+  > [hooks]
+  > changegroup = sh -c "printenv.py changegroup-in-local 0 ../dummylog"
+  > EOF
 
 empty default pull
 
diff --git a/tests/test-ssh.t b/tests/test-ssh.t
--- a/tests/test-ssh.t
+++ b/tests/test-ssh.t
@@ -32,7 +32,7 @@  configure for serving
   > uncompressed = True
   > 
   > [hooks]
-  > changegroup = printenv.py changegroup-in-remote 0 ../dummylog
+  > changegroup = sh -c "printenv.py changegroup-in-remote 0 ../dummylog"
   > EOF
   $ cd ..
 
@@ -108,8 +108,10 @@  verify
   crosschecking files in changesets and manifests
   checking files
   2 files, 3 changesets, 2 total revisions
-  $ echo '[hooks]' >> .hg/hgrc
-  $ echo "changegroup = printenv.py changegroup-in-local 0 ../dummylog" >> .hg/hgrc
+  $ cat >> .hg/hgrc <<EOF
+  > [hooks]
+  > changegroup = sh -c "printenv.py changegroup-in-local 0 ../dummylog"
+  > EOF
 
 empty default pull
 
diff --git a/tests/test-static-http.t b/tests/test-static-http.t
--- a/tests/test-static-http.t
+++ b/tests/test-static-http.t
@@ -53,8 +53,10 @@  check for HTTP opener failures when cach
 
   $ rm .hg/cache/*
   $ cd ../local
-  $ echo '[hooks]' >> .hg/hgrc
-  $ echo "changegroup = printenv.py changegroup" >> .hg/hgrc
+  $ cat >> .hg/hgrc <<EOF
+  > [hooks]
+  > changegroup = sh -c "printenv.py changegroup"
+  > EOF
   $ hg pull
   pulling from static-http://localhost:$HGPORT/remote
   searching for changes