On Tue, May 31, 2016 at 11:49:10PM -0700, Junio C Hamano wrote:

> Jeff King <[email protected]> writes:
> 
> > OK, last email tonight, I promise.
> >
> > Here's the subshell version. I'm a little embarrassed not to have
> > thought of it sooner (though the other one was a fun exercise).
> >
> >     test_env () {
> >             (
> >                     while test $# -gt 0
> >                     do
> >                             case "$1" in
> >                             *=*)
> >                                     eval "${1%%=*}=\${1#*=}"
> 
> Is this an elaborate way to say 'eval "$1"', or is there anything
> more subtle going on?

Notice that the value half isn't expanded until we get inside the eval.
So:

  $ good() { eval "${1%%=*}=\${1#*=}"; }
  $ bad() { eval "$1"; }
  $ good foo="funny variable"; echo $foo
  funny variable
  $ bad foo="funny variable"
  bash: variable: command not found

> >                             *)
> >                                     "$@"
> >                                     exit
> 
> ... or 'exec "$@"'

You can't exec a function, AFAIK (and that was the point of this
exercise).

> >             )
> >     }
> 
> You can dedent the whole thing and remove the outermost {} pair.

True. I didn't know about that until recently. Is it portable
everywhere?

Here's the patch I wrote up earlier (but was too timid to send out after
my barrage of emails :) ).

It doesn't have the dedent, but I don't mind if you want to tweak it.

-- >8 --
Subject: test-lib: add in-shell "env" replacement

The one-shot environment variable syntax:

  FOO=BAR some-program

is unportable when some-program is actually a shell
function, like test_must_fail (on some shells FOO remains
set after the function returns, and on others it does not).

We sometimes get around this by using env, like:

  test_must_fail env FOO=BAR some-program

But that only works because test_must_fail's arguments are
themselves a command which can be run. You can't run:

  env FOO=BAR test_must_fail some-program

because env does not know about our shell functions. So
there is no equivalent for test_commit, for example, and one
must resort to:

  (
    FOO=BAR
    export FOO
    test_commit
  )

which is a bit verbose.  Let's add a version of "env" that
works _inside_ the shell, by creating a subshell, exporting
variables from its argument list, and running the command.

Its use is demonstrated on a currently-unportable case in
t4014.

Signed-off-by: Jeff King <[email protected]>
---
 t/t4014-format-patch.sh |  2 +-
 t/test-lib-functions.sh | 22 ++++++++++++++++++++++
 2 files changed, 23 insertions(+), 1 deletion(-)

diff --git a/t/t4014-format-patch.sh b/t/t4014-format-patch.sh
index 8049cad..805dc90 100755
--- a/t/t4014-format-patch.sh
+++ b/t/t4014-format-patch.sh
@@ -1072,7 +1072,7 @@ test_expect_success '--from omits redundant in-body 
header' '
 '
 
 test_expect_success 'in-body headers trigger content encoding' '
-       GIT_AUTHOR_NAME="éxötìc" test_commit exotic &&
+       test_env GIT_AUTHOR_NAME="éxötìc" test_commit exotic &&
        test_when_finished "git reset --hard HEAD^" &&
        git format-patch -1 --stdout --from >patch &&
        cat >expect <<-\EOF &&
diff --git a/t/test-lib-functions.sh b/t/test-lib-functions.sh
index 3978fc0..48884d5 100644
--- a/t/test-lib-functions.sh
+++ b/t/test-lib-functions.sh
@@ -939,3 +939,25 @@ mingw_read_file_strip_cr_ () {
                eval "$1=\$$1\$line"
        done
 }
+
+# Like "env FOO=BAR some-program", but run inside a subshell, which means
+# it also works for shell functions (though those functions cannot impact
+# the environment outside of the test_env invocation).
+test_env () {
+       (
+               while test $# -gt 0
+               do
+                       case "$1" in
+                       *=*)
+                               eval "${1%%=*}=\${1#*=}"
+                               eval "export ${1%%=*}"
+                               shift
+                               ;;
+                       *)
+                               "$@"
+                               exit
+                               ;;
+                       esac
+               done
+       )
+}
-- 
2.9.0.rc0.174.g479a78d

--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to