zsh-users
 help / color / mirror / code / Atom feed
* Detect if a script is being sourced vs executed
@ 2014-09-12 17:57 Daniel Hahler
  2014-09-12 19:05 ` Peter Stephenson
  2014-09-12 20:09 ` Kurtis Rader
  0 siblings, 2 replies; 6+ messages in thread
From: Daniel Hahler @ 2014-09-12 17:57 UTC (permalink / raw)
  To: zsh-users

I want to detect if a script is being sourced instead of being called.

This is meant for pyenv, which uses shims to delegate execution to the selected Python version.

Currently it always uses "exec" to do so, but there is a pull request to add support for scripts that are meant to be sourced (like virtualenvwrapper.sh), and then would use "source" instead of "exec" in the shim.

The PR provides this functionality for Bash, which provides a way to detect this via $BASH_SOURCE/$BASH_LINENO: https://github.com/yyuu/pyenv/pull/100/files


My current approach so far is the following, which requires Zsh 5.0.5 (for POSIX_ARGZERO) and does not work for "zsh test_source.sh" yet (a patch has been posted to zsh-workers to fix this).

I would like to do this for older Zsh versions, and in a simpler / more elegant way.


Script to be sourced (test_source.sh):

    #!/usr/bin/zsh

    echo "\$0: $0"

    sourced=0
    if [ -n "$ZSH_VERSION" ]; then
      # Use prompt expansion to get the current file.
      cur_file=${(%):-%x}

      # Fix $0:
      if (( ${+options[posixargzero]} )); then  # added in zsh 5.0.5 (2014-06-01)
        if [[ $options[posixargzero] != "on" ]]; then
          setopt posixargzero
          [ "$0" = "$cur_file" ] || sourced=1
          setopt noposixargzero
        else
          [ "$0" = "$cur_file" ] || sourced=1
        fi
      else
        echo "TODO"
      fi

    elif [ -n "$BASH_VERSION" ]; then
      [ "$0" = "$BASH_SOURCE" ] || sourced=1
    fi

    echo "sourced: $sourced"


Test script (test.sh):

    #!/usr/bin/zsh

    echo "== CALL"
    ./test_source.sh

    echo "== SOURCE"
    . ./test_source.sh

    echo "== CALL: bash"
    bash ./test_source.sh

    echo "== CALL: zsh"
    zsh ./test_source.sh

    echo "== EXEC"
    exec ./test_source.sh


There must be an easier way!?

It would be really useful, if Zsh would provide a mechanism like Bash to simplify this.


Regards,
Daniel.


^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: Detect if a script is being sourced vs executed
  2014-09-12 17:57 Detect if a script is being sourced vs executed Daniel Hahler
@ 2014-09-12 19:05 ` Peter Stephenson
  2014-09-12 23:21   ` Bart Schaefer
  2014-09-12 20:09 ` Kurtis Rader
  1 sibling, 1 reply; 6+ messages in thread
From: Peter Stephenson @ 2014-09-12 19:05 UTC (permalink / raw)
  To: zsh-users

On Fri, 12 Sep 2014 19:57:19 +0200
Daniel Hahler <dhahler@gmail.com> wrote:
> I want to detect if a script is being sourced instead of being called.

I think this is difficult for older versions of zsh, but Bart will
probably come up with something.

I was surprised to find the zsh/parameter modules series of array
parameters that allow you to trace back the functions, sourced files,
etc. being executed don't give this information, which is present
internally.  This adds $functypestack to do this.  So you need to
see if $functypestack[1] is "source".

diff --git a/Doc/Zsh/mod_parameter.yo b/Doc/Zsh/mod_parameter.yo
index 32d4796..0dde813 100644
--- a/Doc/Zsh/mod_parameter.yo
+++ b/Doc/Zsh/mod_parameter.yo
@@ -201,7 +201,10 @@ The format of each element is var(filename)tt(:)var(lineno).
 For functions autoloaded from a file in native zsh format, where only the
 body of the function occurs in the file, or for files that have been
 executed by the tt(source) or `tt(.)' builtins, the trace information is
-shown as var(filename)tt(:)var(0), since the entire file is the definition.
+shown as var(filename)tt(:)var(0), since the entire file is the
+definition.
+
+The most recent call is the first element in the array.
 
 Most users will be interested in the information in the
 tt(funcfiletrace) array instead.
@@ -221,4 +224,13 @@ The format of each element is var(name)tt(:)var(lineno).
 Callers are also shown for sourced files; the caller is the point
 where the tt(source) or `tt(.)' command was executed.
 )
+vindex(functypestack)
+item(tt(functrace))(
+This array corresponds element by element with tt(funcstack) and
+prints out `tt(source)' for a sourced file, `tt(function)' for a
+function and `tt(eval)' for an eval'd expression.  At the top
+level of execution of a series of commands, tt($functypestack[1]) is
+empty if the commands are being executed as a script, or one of the
+strings above if the commands are being executed as that type.
+)
 enditem()
diff --git a/Src/Modules/parameter.c b/Src/Modules/parameter.c
index 0385a70..02a642b 100644
--- a/Src/Modules/parameter.c
+++ b/Src/Modules/parameter.c
@@ -640,6 +640,41 @@ funcfiletracegetfn(UNUSED(Param pm))
     return ret;
 }
 
+/* Functions for the functypestack special parameter. */
+
+static char **
+functypestackgetfn(UNUSED(Param pm))
+{
+    Funcstack f;
+    int num;
+    char **ret, **p;
+
+    for (f = funcstack, num = 0; f; f = f->prev, num++);
+
+    ret = (char **) zhalloc((num + 1) * sizeof(char *));
+
+    for (f = funcstack, p = ret; f; f = f->prev, p++)
+    {
+	switch (f->tp)
+	{
+	case FS_SOURCE:
+	    *p = "source";
+	    break;
+
+	case FS_FUNC:
+	    *p = "function";
+	    break;
+
+	case FS_EVAL:
+	    *p = "eval";
+	    break;
+	}
+    }
+    *p = NULL;
+
+    return ret;
+}
+
 /* Functions for the builtins special parameter. */
 
 /**/
@@ -2046,6 +2081,8 @@ static const struct gsu_array funcsourcetrace_gsu =
 { funcsourcetracegetfn, arrsetfn, stdunsetfn };
 static const struct gsu_array funcfiletrace_gsu =
 { funcfiletracegetfn, arrsetfn, stdunsetfn };
+static const struct gsu_array functypestack_gsu =
+{ functypestackgetfn, arrsetfn, stdunsetfn };
 static const struct gsu_array reswords_gsu =
 { reswordsgetfn, arrsetfn, stdunsetfn };
 static const struct gsu_array disreswords_gsu =
@@ -2090,6 +2127,8 @@ static struct paramdef partab[] = {
 		 scanpmfunctions),
     SPECIALPMDEF("functrace", PM_ARRAY|PM_READONLY,
 	    &functrace_gsu, NULL, NULL),
+    SPECIALPMDEF("functypestack", PM_ARRAY|PM_READONLY,
+		 &functypestack_gsu, NULL, NULL),
     SPECIALPMDEF("galiases", 0,
 	    &pmgaliases_gsu, getpmgalias, scanpmgaliases),
     SPECIALPMDEF("history", PM_READONLY,

-- 
Peter Stephenson <p.w.stephenson@ntlworld.com>
Web page now at http://homepage.ntlworld.com/p.w.stephenson/


^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: Detect if a script is being sourced vs executed
  2014-09-12 17:57 Detect if a script is being sourced vs executed Daniel Hahler
  2014-09-12 19:05 ` Peter Stephenson
@ 2014-09-12 20:09 ` Kurtis Rader
  1 sibling, 0 replies; 6+ messages in thread
From: Kurtis Rader @ 2014-09-12 20:09 UTC (permalink / raw)
  To: Daniel Hahler; +Cc: Zsh Users

[-- Attachment #1: Type: text/plain, Size: 2506 bytes --]

Here's an example of what I use in my scripts (zsh 5.0.2):

if [[ $ZSH_EVAL_CONTEXT == 'toplevel' ]]; then
    # We're not being sourced so run the colors command which in turn
sources
    # this script and uses its content to produce representative output.
    colors
fi


On Fri, Sep 12, 2014 at 10:57 AM, Daniel Hahler <dhahler@gmail.com> wrote:

> I want to detect if a script is being sourced instead of being called.
>
> This is meant for pyenv, which uses shims to delegate execution to the
> selected Python version.
>
> Currently it always uses "exec" to do so, but there is a pull request to
> add support for scripts that are meant to be sourced (like
> virtualenvwrapper.sh), and then would use "source" instead of "exec" in the
> shim.
>
> The PR provides this functionality for Bash, which provides a way to
> detect this via $BASH_SOURCE/$BASH_LINENO:
> https://github.com/yyuu/pyenv/pull/100/files
>
>
> My current approach so far is the following, which requires Zsh 5.0.5 (for
> POSIX_ARGZERO) and does not work for "zsh test_source.sh" yet (a patch has
> been posted to zsh-workers to fix this).
>
> I would like to do this for older Zsh versions, and in a simpler / more
> elegant way.
>
>
> Script to be sourced (test_source.sh):
>
>     #!/usr/bin/zsh
>
>     echo "\$0: $0"
>
>     sourced=0
>     if [ -n "$ZSH_VERSION" ]; then
>       # Use prompt expansion to get the current file.
>       cur_file=${(%):-%x}
>
>       # Fix $0:
>       if (( ${+options[posixargzero]} )); then  # added in zsh 5.0.5
> (2014-06-01)
>         if [[ $options[posixargzero] != "on" ]]; then
>           setopt posixargzero
>           [ "$0" = "$cur_file" ] || sourced=1
>           setopt noposixargzero
>         else
>           [ "$0" = "$cur_file" ] || sourced=1
>         fi
>       else
>         echo "TODO"
>       fi
>
>     elif [ -n "$BASH_VERSION" ]; then
>       [ "$0" = "$BASH_SOURCE" ] || sourced=1
>     fi
>
>     echo "sourced: $sourced"
>
>
> Test script (test.sh):
>
>     #!/usr/bin/zsh
>
>     echo "== CALL"
>     ./test_source.sh
>
>     echo "== SOURCE"
>     . ./test_source.sh
>
>     echo "== CALL: bash"
>     bash ./test_source.sh
>
>     echo "== CALL: zsh"
>     zsh ./test_source.sh
>
>     echo "== EXEC"
>     exec ./test_source.sh
>
>
> There must be an easier way!?
>
> It would be really useful, if Zsh would provide a mechanism like Bash to
> simplify this.
>
>
> Regards,
> Daniel.
>



-- 
Kurtis Rader
Caretaker of the exceptional canines Junior and Hank

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: Detect if a script is being sourced vs executed
  2014-09-12 19:05 ` Peter Stephenson
@ 2014-09-12 23:21   ` Bart Schaefer
  2014-09-13  8:01     ` Peter Stephenson
  0 siblings, 1 reply; 6+ messages in thread
From: Bart Schaefer @ 2014-09-12 23:21 UTC (permalink / raw)
  To: zsh-users

On Sep 12,  8:05pm, Peter Stephenson wrote:
}
} I was surprised to find the zsh/parameter modules series of array
} parameters that allow you to trace back the functions, sourced files,
} etc. being executed don't give this information, which is present
} internally.  This adds $functypestack to do this.

Is this in some way NOT redundant with $zsh_eval_context ?  Other than
apparently being in the reverse order?

torch% source =(<<<'() { print $zsh_eval_context }')    
toplevel file shfunc
torch% source =(<<<'() { zmodload zsh/parameter; print $functypestack }')
function source


^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: Detect if a script is being sourced vs executed
  2014-09-12 23:21   ` Bart Schaefer
@ 2014-09-13  8:01     ` Peter Stephenson
  2014-09-16 19:14       ` Peter Stephenson
  0 siblings, 1 reply; 6+ messages in thread
From: Peter Stephenson @ 2014-09-13  8:01 UTC (permalink / raw)
  To: zsh-users

On 13/09/2014, Bart Schaefer <schaefer@brasslantern.com> wrote:
> On Sep 12,  8:05pm, Peter Stephenson wrote:
> }
> } I was surprised to find the zsh/parameter modules series of array
> } parameters that allow you to trace back the functions, sourced files,
> } etc. being executed don't give this information, which is present
> } internally.  This adds $functypestack to do this.
>
> Is this in some way NOT redundant with $zsh_eval_context ?  Other than
> apparently being in the reverse order?

You'rr right,  I was looking in the wrong place.  It can
be replacef simply by a cross-reference.

pws


^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: Detect if a script is being sourced vs executed
  2014-09-13  8:01     ` Peter Stephenson
@ 2014-09-16 19:14       ` Peter Stephenson
  0 siblings, 0 replies; 6+ messages in thread
From: Peter Stephenson @ 2014-09-16 19:14 UTC (permalink / raw)
  To: zsh-users

On Sat, 13 Sep 2014 09:01:21 +0100
Peter Stephenson <p.w.stephenson@ntlworld.com> wrote:
> On 13/09/2014, Bart Schaefer <schaefer@brasslantern.com> wrote:
> > On Sep 12,  8:05pm, Peter Stephenson wrote:
> > }
> > } I was surprised to find the zsh/parameter modules series of array
> > } parameters that allow you to trace back the functions, sourced files,
> > } etc. being executed don't give this information, which is present
> > } internally.  This adds $functypestack to do this.
> >
> > Is this in some way NOT redundant with $zsh_eval_context ?  Other than
> > apparently being in the reverse order?
> 
> You're right, I was looking in the wrong place.  It can
> be replaced simply by a cross-reference.

They also don't actually quite correspond -- you can get extra entries
in zsh_eval_context since it intercepts the lowest level of code
execution while the funcstack stuff is done for each applicable layer
separately.  So there's potentially some use for functypestack ---
however, it's not needed for the purpose here, where
$zsh_eval_context[-1] is good enough (it'll be either "toplevel" or
"file").

diff --git a/Doc/Zsh/mod_parameter.yo b/Doc/Zsh/mod_parameter.yo
index c157160..7886d0e 100644
--- a/Doc/Zsh/mod_parameter.yo
+++ b/Doc/Zsh/mod_parameter.yo
@@ -201,10 +201,7 @@ The format of each element is var(filename)tt(:)var(lineno).
 For functions autoloaded from a file in native zsh format, where only the
 body of the function occurs in the file, or for files that have been
 executed by the tt(source) or `tt(.)' builtins, the trace information is
-shown as var(filename)tt(:)var(0), since the entire file is the
-definition.
-
-The most recent call is the first element in the array.
+shown as var(filename)tt(:)var(0), since the entire file is the definition.
 
 Most users will be interested in the information in the
 tt(funcfiletrace) array instead.
@@ -215,6 +212,14 @@ This array contains the names of the functions, sourced files,
 and (if tt(EVAL_LINENO) is set) tt(eval) commands. currently being
 executed. The first element is the name of the function using the
 parameter.
+
+The standard shell array tt(zsh_eval_context) can be used to
+determine the type of shell construct being executed at each depth:
+note, however, that is in the opposite order, with the most recent
+item last, and it is more detailed, for example including an
+entry for tt(toplevel), the main shell code being executed
+either interactively or from a script, which is not present
+in tt($funcstack).
 )
 vindex(functrace)
 item(tt(functrace))(
@@ -224,13 +229,4 @@ The format of each element is var(name)tt(:)var(lineno).
 Callers are also shown for sourced files; the caller is the point
 where the tt(source) or `tt(.)' command was executed.
 )
-vindex(functypestack)
-item(tt(functypestack))(
-This array corresponds element by element with tt(funcstack).
-Each element contains `tt(source)' for a sourced file, `tt(function)'
-for a function and `tt(eval)' for an tt(eval)'d expression.  At the top
-level of execution of a series of commands, tt($functypestack[1]) is
-empty if the commands are being executed as a script, or one of the
-previous strings if the commands are being executed as that type.
-)
 enditem()
diff --git a/Src/Modules/parameter.c b/Src/Modules/parameter.c
index 02a642b..0385a70 100644
--- a/Src/Modules/parameter.c
+++ b/Src/Modules/parameter.c
@@ -640,41 +640,6 @@ funcfiletracegetfn(UNUSED(Param pm))
     return ret;
 }
 
-/* Functions for the functypestack special parameter. */
-
-static char **
-functypestackgetfn(UNUSED(Param pm))
-{
-    Funcstack f;
-    int num;
-    char **ret, **p;
-
-    for (f = funcstack, num = 0; f; f = f->prev, num++);
-
-    ret = (char **) zhalloc((num + 1) * sizeof(char *));
-
-    for (f = funcstack, p = ret; f; f = f->prev, p++)
-    {
-	switch (f->tp)
-	{
-	case FS_SOURCE:
-	    *p = "source";
-	    break;
-
-	case FS_FUNC:
-	    *p = "function";
-	    break;
-
-	case FS_EVAL:
-	    *p = "eval";
-	    break;
-	}
-    }
-    *p = NULL;
-
-    return ret;
-}
-
 /* Functions for the builtins special parameter. */
 
 /**/
@@ -2081,8 +2046,6 @@ static const struct gsu_array funcsourcetrace_gsu =
 { funcsourcetracegetfn, arrsetfn, stdunsetfn };
 static const struct gsu_array funcfiletrace_gsu =
 { funcfiletracegetfn, arrsetfn, stdunsetfn };
-static const struct gsu_array functypestack_gsu =
-{ functypestackgetfn, arrsetfn, stdunsetfn };
 static const struct gsu_array reswords_gsu =
 { reswordsgetfn, arrsetfn, stdunsetfn };
 static const struct gsu_array disreswords_gsu =
@@ -2127,8 +2090,6 @@ static struct paramdef partab[] = {
 		 scanpmfunctions),
     SPECIALPMDEF("functrace", PM_ARRAY|PM_READONLY,
 	    &functrace_gsu, NULL, NULL),
-    SPECIALPMDEF("functypestack", PM_ARRAY|PM_READONLY,
-		 &functypestack_gsu, NULL, NULL),
     SPECIALPMDEF("galiases", 0,
 	    &pmgaliases_gsu, getpmgalias, scanpmgaliases),
     SPECIALPMDEF("history", PM_READONLY,

-- 
Peter Stephenson <p.w.stephenson@ntlworld.com>
Web page now at http://homepage.ntlworld.com/p.w.stephenson/


^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2014-09-16 19:20 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-09-12 17:57 Detect if a script is being sourced vs executed Daniel Hahler
2014-09-12 19:05 ` Peter Stephenson
2014-09-12 23:21   ` Bart Schaefer
2014-09-13  8:01     ` Peter Stephenson
2014-09-16 19:14       ` Peter Stephenson
2014-09-12 20:09 ` Kurtis Rader

Code repositories for project(s) associated with this public inbox

	https://git.vuxu.org/mirror/zsh/

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).