From 9cb032a54c02dee2e3de6392698b2faaaf281901 Mon Sep 17 00:00:00 2001 From: Daniel Hahler Date: Mon, 24 Nov 2014 18:05:31 +0100 Subject: [PATCH 01/23] Makefile: add targets for tests/*.t --- Makefile | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Makefile b/Makefile index a769734..b164795 100644 --- a/Makefile +++ b/Makefile @@ -5,3 +5,7 @@ itest: test: ZDOTDIR="${PWD}/tests" cram --shell=zsh tests + +tests/*.t: + ZDOTDIR="${PWD}/tests" cram --shell=zsh $@ +.PHONY: tests/*.t From 19d9e50650409008232e117717577a26d2b1bd9f Mon Sep 17 00:00:00 2001 From: Daniel Hahler Date: Sun, 16 Nov 2014 12:35:17 +0100 Subject: [PATCH 02/23] Set DOTENV_LOOK_UPWARDS=1 by default Change `_dotenv_hash_pair`, adding a version suffix to trigger re-authentication. Fixes https://github.com/Tarrasch/zsh-autoenv/issues/3 --- autoenv.zsh | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/autoenv.zsh b/autoenv.zsh index 60c8d03..1499103 100644 --- a/autoenv.zsh +++ b/autoenv.zsh @@ -25,8 +25,7 @@ _dotenv_stack_entered=() _dotenv_hash_pair() { local env_file=$1 - env_shasum=$(shasum $env_file | cut -d' ' -f1) - echo "$env_file:$env_shasum" + echo "$env_file:$env_shasum:1" } _dotenv_authorized_env_file() { From c1a25d724efcd22022de6940e82ad94b8b193e3e Mon Sep 17 00:00:00 2001 From: Daniel Hahler Date: Fri, 21 Nov 2014 20:07:06 +0100 Subject: [PATCH 03/23] tests: add setup script, used to be for all tests --- tests/autoenv.t | 4 +--- tests/cwd.t | 4 +--- tests/leave.t | 5 +---- tests/setup.sh | 3 +++ 4 files changed, 6 insertions(+), 10 deletions(-) create mode 100644 tests/setup.sh diff --git a/tests/autoenv.t b/tests/autoenv.t index f3ede0c..940050a 100644 --- a/tests/autoenv.t +++ b/tests/autoenv.t @@ -1,6 +1,4 @@ -Ensure we have our mocked out ENV_AUTHORIZATION_FILE - - $ [[ $ENV_AUTHORIZATION_FILE[0,4] == '/tmp' ]] || return 1 + $ source $TESTDIR/setup.sh Lets set a simple .env action diff --git a/tests/cwd.t b/tests/cwd.t index 9764e74..526ff63 100644 --- a/tests/cwd.t +++ b/tests/cwd.t @@ -1,8 +1,6 @@ Test $PWD and $_dotenv_cwd. -Ensure we have our mocked out ENV_AUTHORIZATION_FILE. - - $ [[ $ENV_AUTHORIZATION_FILE[0,4] == '/tmp' ]] || return 1 + $ source $TESTDIR/setup.sh Setup env actions / output. diff --git a/tests/leave.t b/tests/leave.t index 770b310..9a56f90 100644 --- a/tests/leave.t +++ b/tests/leave.t @@ -1,7 +1,4 @@ -Ensure we have our mocked out ENV_AUTHORIZATION_FILE - - $ [[ $ENV_AUTHORIZATION_FILE[0,4] == '/tmp' ]] || return 1 - + $ source $TESTDIR/setup.sh Lets set a simple .env action diff --git a/tests/setup.sh b/tests/setup.sh new file mode 100644 index 0000000..49b0b3e --- /dev/null +++ b/tests/setup.sh @@ -0,0 +1,3 @@ +# Ensure we have our mocked out ENV_AUTHORIZATION_FILE + +[[ $ENV_AUTHORIZATION_FILE[0,4] == '/tmp' ]] || return 1 From c12b8619520364d72fad4b07dfbabc01216665e7 Mon Sep 17 00:00:00 2001 From: Daniel Hahler Date: Fri, 21 Nov 2014 20:08:30 +0100 Subject: [PATCH 04/23] tests: inject '-t 1' to `read` during tests --- autoenv.zsh | 2 +- tests/setup.sh | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/autoenv.zsh b/autoenv.zsh index 1499103..bb395e2 100644 --- a/autoenv.zsh +++ b/autoenv.zsh @@ -51,7 +51,7 @@ _dotenv_deauthorize() { # This function can be mocked in tests _dotenv_read_answer() { local answer - read -q answer + read $=_AUTOENV_TEST_READ_ARGS -q answer echo $answer } diff --git a/tests/setup.sh b/tests/setup.sh index 49b0b3e..efa99ab 100644 --- a/tests/setup.sh +++ b/tests/setup.sh @@ -1,3 +1,6 @@ # Ensure we have our mocked out ENV_AUTHORIZATION_FILE [[ $ENV_AUTHORIZATION_FILE[0,4] == '/tmp' ]] || return 1 + +# Inject timeout for `read` while running tests. +_AUTOENV_TEST_READ_ARGS='-t 1' From 54124e128b5906425df5963ca99a8746f1dead43 Mon Sep 17 00:00:00 2001 From: Daniel Hahler Date: Sat, 15 Nov 2014 16:24:26 +0100 Subject: [PATCH 05/23] Add varstash from smartcd Source: https://github.com/cxreg/smartcd/blob/4fef3d3610873d9e8044cb5be1922fb056f4228d/lib/core/varstash --- lib/varstash | 408 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 408 insertions(+) create mode 100644 lib/varstash diff --git a/lib/varstash b/lib/varstash new file mode 100644 index 0000000..c2e26c2 --- /dev/null +++ b/lib/varstash @@ -0,0 +1,408 @@ +################################################################################ +# Stash/unstash support for per-directory variables +# +# Copyright (c) 2009,2012 Dave Olszewski +# http://github.com/cxreg/smartcd +# +# This code is released under GPL v2 and the Artistic License, and +# may be redistributed under the terms of either. +# +# +# This library allows you to save the current value of a given environment +# variable in a temporary location, so that you can modify it, and then +# later restore its original value. +# +# Note that you will need to be in the same directory you were in when you +# stashed in order to successfully unstash. This is because the temporary +# variable is derived from your current working directory's path. +# +# Usage: +# stash PATH +# export PATH=/something/else +# [...] +# unstash PATH +# +# Note that this was written for use with, and works very well with, +# smartcd. See the documentation there for examples. +# +# An alternate usage is `autostash' which will trigger autounstash when +# leaving the directory, if combined with smartcd. This reduces the amount +# of explicit configuration you need to provide: +# +# autostash PATH +# export PATH=/something/else +# +# You may also do both operations on line line, leaving only the very succinct +# +# autostash PATH=/something/else +# +# If you run stash, unstash, or varstash interactively, they will instruct +# you on how to create smartcd scripts for performing those actions +# automatically. You can affect this behavior with several variables: +# +# VARSTASH_QUIET - Set if you'd rather not see these notices +# +# VARSTASH_AUTOCONFIG - Set if you want the suggested actions to be +# performed automatically +# +# VARSTASH_AUTOEDIT - Set if you want it to set the values, but also +# give you an opportunity to edit the file +# +# If you attempt to stash the same value twice, a warning will be displayed +# and the second stash will not occur. To make it happen anyway, pass -f +# as the first argument to stash. +# +# $ stash FOO +# $ stash FOO +# You have already stashed FOO, please specify "-f" if you want to overwrite another stashed value +# $ stash -f FOO +# $ +# +# This rule is a bit different if you are assigning a value and the variable +# has already been stashed. In that case, the new value will be assigned, but +# the stash will not be overwritten. This allows for non-conflicting chained +# stash-assign rules. +# +################################################################################ + +function stash() { + if [[ $1 == "-f" ]]; then + local force=1; shift + fi + + if [[ -n $1 ]] && [[ -z $run_from_smartcd ]] && [[ -z $run_from_autostash ]]; then + local working_dir="${varstash_dir:-$(pwd)}" + local smartcd_dir="$(_smartcd_base)/scripts$working_dir" + local help_action="stashing a variable" + local help_dir=$smartcd_dir + local help_cmd="echo stash $@ >> \"$smartcd_dir/bash_enter\"" + local help_which="bash_enter" + _manual_stash_help + fi + + + while [[ -n $1 ]]; do + if [[ $1 == "alias" && $2 =~ "=" ]]; then + shift + local _stashing_alias_assign=1 + continue + fi + + local stash_expression=$1 + local stash_which=${stash_expression%%'='*} + local stash_name=$(_mangle_var $stash_which) + + # Extract the value and make it double-quote safe + local stash_value=${stash_expression#*'='} + stash_value=${stash_value//\\/\\\\} + stash_value=${stash_value//\"/\\\"} + stash_value=${stash_value//\`/\\\`} + stash_value=${stash_value//\$/\\\$} + + if [[ ( -n "$(eval echo '$__varstash_alias__'$stash_name)" || + -n "$(eval echo '$__varstash_function__'$stash_name)" || + -n "$(eval echo '$__varstash_array__'$stash_name)" || + -n "$(eval echo '$__varstash_export__'$stash_name)" || + -n "$(eval echo '$__varstash_variable__'$stash_name)" || + -n "$(eval echo '$__varstash_nostash__'$stash_name)" ) + && -z $force ]]; then + + if [[ -z $already_stashed && ${already_stashed-_} == "_" ]]; then + local already_stashed=1 + else + already_stashed=1 + fi + + if [[ $stash_which == $stash_expression ]]; then + if [[ -z $run_from_smartcd ]]; then + echo "You have already stashed $stash_which, please specify \"-f\" if you want to overwrite another stashed value" + fi + + # Skip remaining work if we're not doing an assignment + shift + continue + fi + fi + + # Handle any alias that may exist under this name + if [[ -z $already_stashed ]]; then + local alias_def="$(eval alias $stash_which 2>/dev/null)" + if [[ -n $alias_def ]]; then + alias_def=${alias_def#alias } + eval "__varstash_alias__$stash_name=\"$alias_def\"" + local stashed=1 + fi + fi + if [[ $stash_which != $stash_expression && -n $_stashing_alias_assign ]]; then + eval "alias $stash_which=\"$stash_value\"" + fi + + # Handle any function that may exist under this name + if [[ -z $already_stashed ]]; then + local function_def="$(declare -f $stash_which)" + if [[ -n $function_def ]]; then + # make function definition quote-safe. because we are going to evaluate the + # source with "echo -e", we need to double-escape the backslashes (so 1 -> 4) + function_def=${function_def//\\/\\\\\\\\} + function_def=${function_def//\"/\\\"} + function_def=${function_def//\`/\\\`} + function_def=${function_def//\$/\\\$} + eval "__varstash_function__$stash_name=\"$function_def\"" + local stashed=1 + fi + fi + + # Handle any variable that may exist under this name + local vartype="$(declare -p $stash_which 2>/dev/null)" + if [[ -n $vartype ]]; then + if [[ -n $ZSH_VERSION ]]; then + local pattern="^typeset" + else + local pattern="^declare" + fi + if [[ $vartype =~ $pattern" -a" ]]; then + # varible is an array + if [[ -z $already_stashed ]]; then + eval "__varstash_array__$stash_name=(\"\${$stash_which""[@]}\")" + fi + + elif [[ $vartype =~ $pattern" -x" ]]; then + # variable is exported + if [[ -z $already_stashed ]]; then + eval "__varstash_export__$stash_name=\"\$$stash_which\"" + fi + if [[ $stash_which != $stash_expression && -z $_stashing_alias_assign ]]; then + eval "export $stash_which=\"$stash_value\"" + fi + else + # regular variable + if [[ -z $already_stashed ]]; then + eval "__varstash_variable__$stash_name=\"\$$stash_which\"" + fi + if [[ $stash_which != $stash_expression && -z $_stashing_alias_assign ]]; then + eval "$stash_which=\"$stash_value\"" + fi + + fi + local stashed=1 + fi + + if [[ -z $stashed ]]; then + # Nothing in the variable we're stashing, but make a note that we stashed so we + # do the right thing when unstashing. Without this, we take no action on unstash + + # Zsh bug sometimes caues + # (eval):1: command not found: __varstash_nostash___tmp__home_dolszewski_src_smartcd_RANDOM_VARIABLE=1 + # fixed in zsh commit 724fd07a67f, version 4.3.14 + if [[ -z $already_stashed ]]; then + eval "__varstash_nostash__$stash_name=1" + fi + + # In the case of a previously unset variable that we're assigning too, export it + if [[ $stash_which != $stash_expression && -z $_stashing_alias_assign ]]; then + eval "export $stash_which=\"$stash_value\"" + fi + fi + + shift + unset -v _stashing_alias_assign + done +} + +function autostash() { + if [[ -n $1 ]] && [[ -z $run_from_smartcd ]]; then + local working_dir="${varstash_dir:-$(pwd)}" + local smartcd_dir="$(_smartcd_base)/scripts$working_dir" + local help_action="autostashing a variable" + local help_dir=$smartcd_dir + local help_cmd="echo autostash $@ >> \"$smartcd_dir/bash_enter\"" + local help_which="bash_enter" + _manual_stash_help + fi + + local run_from_autostash=1 + while [[ -n $1 ]]; do + if [[ $1 == "alias" && $2 =~ "=" ]]; then + shift + local _stashing_alias_assign=1 + fi + + local already_stashed= + stash "$1" + if [[ -z $already_stashed ]]; then + local autostash_name=$(_mangle_var AUTOSTASH) + local varname=${1%%'='*} + apush $autostash_name "$varname" + fi + shift + unset -v _stashing_alias_assign + done +} + +function unstash() { + if [[ -n $1 ]] && [[ -z $run_from_smartcd ]] && [[ -z $run_from_autounstash ]]; then + local working_dir=${varstash_dir:-$(pwd)} + local smartcd_dir="$(_smartcd_base)/scripts$working_dir" + local help_action="unstashing a variable" + local help_dir=$smartcd_dir + local help_cmd="echo unstash $@ >> \"$smartcd_dir/bash_leave\"" + local help_which="bash_leave" + _manual_stash_help + fi + + while [[ -n $1 ]]; do + local unstash_which=$1 + if [[ -z $unstash_which ]]; then + continue + fi + + local unstash_name=$(_mangle_var $unstash_which) + + # This bit is a little tricky. Here are the rules: + # 1) unstash any alias, function, or variable which matches + # 2) if one or more matches, but not all, delete any that did not + # 3) if none match but nostash is found, delete all + # 4) if none match and nostash not found, do nothing + + # Unstash any alias + if [[ -n "$(eval echo \$__varstash_alias__$unstash_name)" ]]; then + eval "alias $(eval echo \$__varstash_alias__$unstash_name)" + unset __varstash_alias__$unstash_name + local unstashed=1 + local unstashed_alias=1 + fi + + # Unstash any function + if [[ -n "$(eval echo \$__varstash_function__$unstash_name)" ]]; then + eval "function $(eval echo -e \"\$__varstash_function__$unstash_name\")" + unset __varstash_function__$unstash_name + local unstashed=1 + local unstashed_function=1 + fi + + # Unstash any variable + if [[ -n "$(declare -p __varstash_array__$unstash_name 2>/dev/null)" ]]; then + eval "$unstash_which=(\"\${__varstash_array__$unstash_name""[@]}\")" + unset __varstash_array__$unstash_name + local unstashed=1 + local unstashed_variable=1 + elif [[ -n "$(declare -p __varstash_export__$unstash_name 2>/dev/null)" ]]; then + eval "export $unstash_which=\"\$__varstash_export__$unstash_name\"" + unset __varstash_export__$unstash_name + local unstashed=1 + local unstashed_variable=1 + elif [[ -n "$(declare -p __varstash_variable__$unstash_name 2>/dev/null)" ]]; then + # Unset variable first to reset export + unset -v $unstash_which + eval "$unstash_which=\"\$__varstash_variable__$unstash_name\"" + unset __varstash_variable__$unstash_name + local unstashed=1 + local unstashed_variable=1 + fi + + # Unset any values which did not exist at time of stash + local nostash="$(eval echo \$__varstash_nostash__$unstash_name)" + unset __varstash_nostash__$unstash_name + if [[ ( -n "$nostash" && -z "$unstashed" ) || ( -n "$unstashed" && -z "$unstashed_alias" ) ]]; then + unalias $unstash_which 2>/dev/null + fi + if [[ ( -n "$nostash" && -z "$unstashed" ) || ( -n "$unstashed" && -z "$unstashed_function" ) ]]; then + unset -f $unstash_which 2>/dev/null + fi + if [[ ( -n "$nostash" && -z "$unstashed" ) || ( -n "$unstashed" && -z "$unstashed_variable" ) ]]; then + # Don't try to unset illegal variable names + if ! [[ $unstash_which =~ [^a-zA-Z0-9_] || $unstash_which =~ ^[0-9] ]]; then + unset -v $unstash_which + fi + fi + + shift + done +} + +function autounstash() { + # If there is anything in (mangled) variable AUTOSTASH, then unstash it + local autounstash_name=$(_mangle_var AUTOSTASH) + if (( $(alen $autounstash_name) > 0 )); then + local run_from_autounstash=1 + while (( $(alen $autounstash_name) > 0 )); do + local autounstash_var=$(afirst $autounstash_name) + ashift $autounstash_name >/dev/null + unstash $autounstash_var + done + unset $autounstash_name + fi +} + +function _mangle_var() { + local mangle_var_where="${varstash_dir:-$(pwd)}" + mangle_var_where=${mangle_var_where//[^A-Za-z0-9]/_} + local mangled_name=${1//[^A-Za-z0-9]/_} + echo "_tmp_${mangle_var_where}_${mangled_name}" +} + +function _manual_stash_help() { + # instruct user how to create bash_enter or bash_leave + if [[ -n $VARSTASH_AUTOEDIT || -n $VARSTASH_AUTOCONFIG ]]; then + if [[ -z $VARSTASH_QUIET ]]; then + echo "varstash: Automatically running $help_cmd" + fi + + if [[ ! -d $help_dir ]]; then + mkdir -p "$help_dir" + fi + eval $help_cmd + + if [[ -n $VARSTASH_AUTOEDIT ]]; then + varstash_edit $help_which + fi + elif [[ -z $VARSTASH_QUIET ]]; then + echo "############################################################################" + echo "# You are manually $help_action. To automatically perform this" + echo "# whenever you enter this directory, paste the following command(s):" + + if [[ ! -d $help_dir ]]; then + echo "mkdir -p \"$help_dir\"" + fi + echo "$help_cmd" + echo "############################################################################" + fi +} + +# A couple convenient aliases for smartcd_edit +function autostash_edit() { + varstash_edit "$@" +} + +function varstash_edit() { + local file="$1" + local dir="$2" + + if [[ -n $ZSH_VERSION ]]; then + if [[ $(type smartcd_edit) == "smartcd_edit is a shell function" ]]; then + local can_run=1 + fi + else + if [[ $(type -t smartcd_edit) == "function" ]]; then + local can_run=1 + fi + fi + + if [[ -n "$can_run" ]]; then + # XXX - no support for "--host" or "--system" with this (yet?) + _smartcd_file_check "$file" "global" "" edit "$dir" + else + echo "smartcd not loaded, cannot run smartcd_edit" + fi +} + +# Run deferred smartcd if we're waiting for it, and arrays is also loaded +if [[ -n "$smartcd_initially_deferred" && -n "$(fn_exists apush)" && -z "$SMARTCD_NOINITIAL" ]]; then + smartcd_skip_action=1 + smartcd_run_mainline=1 + smartcd cd + unset smartcd_skip_action + unset smartcd_initially_deferred +fi + +# vim: filetype=sh autoindent expandtab shiftwidth=4 softtabstop=4 From 0bcbeb5ae57882df2a13799eed6769d5ef2b4ab3 Mon Sep 17 00:00:00 2001 From: Daniel Hahler Date: Sat, 15 Nov 2014 20:01:38 +0100 Subject: [PATCH 06/23] Adopt varstash from http://github.com/cxreg/smartcd Decouple it from smartcd and consider it zsh-only. This also adds required library functions from smartcd's lib/core/arrays. --- lib/varstash | 151 +++++++++++++++------------------------------------ 1 file changed, 43 insertions(+), 108 deletions(-) diff --git a/lib/varstash b/lib/varstash index c2e26c2..9844c32 100644 --- a/lib/varstash +++ b/lib/varstash @@ -1,6 +1,8 @@ ################################################################################ # Stash/unstash support for per-directory variables # +# Adopted for zsh-autoenv. +# # Copyright (c) 2009,2012 Dave Olszewski # http://github.com/cxreg/smartcd # @@ -36,18 +38,6 @@ # # autostash PATH=/something/else # -# If you run stash, unstash, or varstash interactively, they will instruct -# you on how to create smartcd scripts for performing those actions -# automatically. You can affect this behavior with several variables: -# -# VARSTASH_QUIET - Set if you'd rather not see these notices -# -# VARSTASH_AUTOCONFIG - Set if you want the suggested actions to be -# performed automatically -# -# VARSTASH_AUTOEDIT - Set if you want it to set the values, but also -# give you an opportunity to edit the file -# # If you attempt to stash the same value twice, a warning will be displayed # and the second stash will not occur. To make it happen anyway, pass -f # as the first argument to stash. @@ -65,22 +55,51 @@ # ################################################################################ + +# Library functions, from smartcd's lib/core/arrays. {{{ +function apush() { + local var=$1; shift + eval "$var=(\${$var[@]} \"\$@\")" +} + +function alen() { + local var=$1 + + if [[ -n $var ]]; then + eval "echo \${#$var[@]}" + fi +} + +function afirst() { + setopt localoptions && setopt ksharrays + local var=$1 + + if [[ -n $var ]] && (( $(eval "echo \${#$var[@]}") >= 1 )); then + eval "echo \"\${$var""[0]}\"" + fi +} + +function ashift() { + setopt localoptions && setopt ksharrays + local var=$1 + + local _ashift_return= + + if [[ -n $var ]] && (( $(eval "echo \${#$var[@]}") >= 1 )); then + eval "_ashift_return=\"\${$var""[0]}\"" + eval "$var""[0]=()" + + echo "$_ashift_return" + fi +} +# }}} + + function stash() { if [[ $1 == "-f" ]]; then local force=1; shift fi - if [[ -n $1 ]] && [[ -z $run_from_smartcd ]] && [[ -z $run_from_autostash ]]; then - local working_dir="${varstash_dir:-$(pwd)}" - local smartcd_dir="$(_smartcd_base)/scripts$working_dir" - local help_action="stashing a variable" - local help_dir=$smartcd_dir - local help_cmd="echo stash $@ >> \"$smartcd_dir/bash_enter\"" - local help_which="bash_enter" - _manual_stash_help - fi - - while [[ -n $1 ]]; do if [[ $1 == "alias" && $2 =~ "=" ]]; then shift @@ -210,16 +229,6 @@ function stash() { } function autostash() { - if [[ -n $1 ]] && [[ -z $run_from_smartcd ]]; then - local working_dir="${varstash_dir:-$(pwd)}" - local smartcd_dir="$(_smartcd_base)/scripts$working_dir" - local help_action="autostashing a variable" - local help_dir=$smartcd_dir - local help_cmd="echo autostash $@ >> \"$smartcd_dir/bash_enter\"" - local help_which="bash_enter" - _manual_stash_help - fi - local run_from_autostash=1 while [[ -n $1 ]]; do if [[ $1 == "alias" && $2 =~ "=" ]]; then @@ -240,16 +249,6 @@ function autostash() { } function unstash() { - if [[ -n $1 ]] && [[ -z $run_from_smartcd ]] && [[ -z $run_from_autounstash ]]; then - local working_dir=${varstash_dir:-$(pwd)} - local smartcd_dir="$(_smartcd_base)/scripts$working_dir" - local help_action="unstashing a variable" - local help_dir=$smartcd_dir - local help_cmd="echo unstash $@ >> \"$smartcd_dir/bash_leave\"" - local help_which="bash_leave" - _manual_stash_help - fi - while [[ -n $1 ]]; do local unstash_which=$1 if [[ -z $unstash_which ]]; then @@ -335,74 +334,10 @@ function autounstash() { } function _mangle_var() { - local mangle_var_where="${varstash_dir:-$(pwd)}" + local mangle_var_where="${varstash_dir:-$PWD}" mangle_var_where=${mangle_var_where//[^A-Za-z0-9]/_} local mangled_name=${1//[^A-Za-z0-9]/_} echo "_tmp_${mangle_var_where}_${mangled_name}" } -function _manual_stash_help() { - # instruct user how to create bash_enter or bash_leave - if [[ -n $VARSTASH_AUTOEDIT || -n $VARSTASH_AUTOCONFIG ]]; then - if [[ -z $VARSTASH_QUIET ]]; then - echo "varstash: Automatically running $help_cmd" - fi - - if [[ ! -d $help_dir ]]; then - mkdir -p "$help_dir" - fi - eval $help_cmd - - if [[ -n $VARSTASH_AUTOEDIT ]]; then - varstash_edit $help_which - fi - elif [[ -z $VARSTASH_QUIET ]]; then - echo "############################################################################" - echo "# You are manually $help_action. To automatically perform this" - echo "# whenever you enter this directory, paste the following command(s):" - - if [[ ! -d $help_dir ]]; then - echo "mkdir -p \"$help_dir\"" - fi - echo "$help_cmd" - echo "############################################################################" - fi -} - -# A couple convenient aliases for smartcd_edit -function autostash_edit() { - varstash_edit "$@" -} - -function varstash_edit() { - local file="$1" - local dir="$2" - - if [[ -n $ZSH_VERSION ]]; then - if [[ $(type smartcd_edit) == "smartcd_edit is a shell function" ]]; then - local can_run=1 - fi - else - if [[ $(type -t smartcd_edit) == "function" ]]; then - local can_run=1 - fi - fi - - if [[ -n "$can_run" ]]; then - # XXX - no support for "--host" or "--system" with this (yet?) - _smartcd_file_check "$file" "global" "" edit "$dir" - else - echo "smartcd not loaded, cannot run smartcd_edit" - fi -} - -# Run deferred smartcd if we're waiting for it, and arrays is also loaded -if [[ -n "$smartcd_initially_deferred" && -n "$(fn_exists apush)" && -z "$SMARTCD_NOINITIAL" ]]; then - smartcd_skip_action=1 - smartcd_run_mainline=1 - smartcd cd - unset smartcd_skip_action - unset smartcd_initially_deferred -fi - # vim: filetype=sh autoindent expandtab shiftwidth=4 softtabstop=4 From 5b553ba1ed12cd66bc346817f07dd9ae280b4b2b Mon Sep 17 00:00:00 2001 From: Daniel Hahler Date: Sat, 15 Nov 2014 20:59:39 +0100 Subject: [PATCH 07/23] varstash integration Fixes: https://github.com/Tarrasch/zsh-autoenv/issues/5 --- autoenv.zsh | 22 +++++++++++++++++----- tests/varstash.t | 36 ++++++++++++++++++++++++++++++++++++ 2 files changed, 53 insertions(+), 5 deletions(-) create mode 100644 tests/varstash.t diff --git a/autoenv.zsh b/autoenv.zsh index bb395e2..a1acc36 100644 --- a/autoenv.zsh +++ b/autoenv.zsh @@ -82,14 +82,26 @@ _dotenv_check_authorized_env_file() { return 0 } +: ${_dotenv_sourced_varstash:=0} +_dotenv_this_dir=${0:A:h} + _dotenv_source() { local env_file=$1 _dotenv_event=$2 - _dotenv_cwd=$PWD + _dotenv_cwd=$3 - builtin cd -q ${env_file:h} - source $env_file + # Source varstash library once. + if [[ $_dotenv_sourced_varstash == 0 ]]; then + source $_dotenv_this_dir/lib/varstash + export _dotenv_sourced_varstash=1 + fi + # varstash_dir=${env_file:h} + + # Change to directory of env file, source it and cd back. + local new_dir=$PWD builtin cd -q $_dotenv_cwd + source $env_file + builtin cd -q $new_dir unset _dotenv_event _dotenv_cwd } @@ -103,7 +115,7 @@ _dotenv_chpwd_handler() { if ! [[ ${PWD}/ == ${prev_dir}/* ]]; then local env_file_leave=$prev_dir/$DOTENV_FILE_LEAVE if _dotenv_check_authorized_env_file $env_file_leave; then - _dotenv_source $env_file_leave leave + _dotenv_source $env_file_leave leave $prev_dir fi # Remove this entry from the stack. _dotenv_stack_entered=(${_dotenv_stack_entered#$prev_dir}) @@ -136,7 +148,7 @@ _dotenv_chpwd_handler() { _dotenv_stack_entered+=(${env_file_dir}) - _dotenv_source $env_file enter + _dotenv_source $env_file enter $PWD } autoload -U add-zsh-hook diff --git a/tests/varstash.t b/tests/varstash.t new file mode 100644 index 0000000..75a4077 --- /dev/null +++ b/tests/varstash.t @@ -0,0 +1,36 @@ +Test varstash integration. + + $ source $TESTDIR/setup.sh + +Setup test environment. + +# Defaults: +# $ DOTENV_FILE_ENTER=.env +# $ DOTENV_FILE_LEAVE=.env.leave +# $ DOTENV_HANDLE_LEAVE=1 + + $ mkdir sub + $ cd sub + $ echo "autostash FOO=baz" > $DOTENV_FILE_ENTER + $ echo "autounstash" > $DOTENV_FILE_LEAVE + +Manually create auth file + + $ echo "$PWD/$DOTENV_FILE_ENTER:$(echo $(<$DOTENV_FILE_ENTER) | shasum)" > $ENV_AUTHORIZATION_FILE + $ echo "$PWD/$DOTENV_FILE_LEAVE:$(echo $(<$DOTENV_FILE_LEAVE) | shasum)" >> $ENV_AUTHORIZATION_FILE + +Set environment variable. + + $ FOO=bar + +Activating the env stashes it and applies a new value. + + $ cd . + $ echo $FOO + baz + +Leaving the directory unstashes it. + + $ cd .. + $ echo $FOO + bar From d9529636b0661a54ca5bc2f5e99ee327c0f50d32 Mon Sep 17 00:00:00 2001 From: Daniel Hahler Date: Sun, 16 Nov 2014 11:28:43 +0100 Subject: [PATCH 08/23] Comments / doc --- autoenv.zsh | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/autoenv.zsh b/autoenv.zsh index a1acc36..b7f5976 100644 --- a/autoenv.zsh +++ b/autoenv.zsh @@ -82,7 +82,11 @@ _dotenv_check_authorized_env_file() { return 0 } +# Initialize $_dotenv_sourced_varstash, but do not overwrite an existing one +# from e.g. `exec zsh` (to reload your shell config). : ${_dotenv_sourced_varstash:=0} + +# Get directory of this file (absolute, with resolved symlinks). _dotenv_this_dir=${0:A:h} _dotenv_source() { @@ -94,8 +98,9 @@ _dotenv_source() { if [[ $_dotenv_sourced_varstash == 0 ]]; then source $_dotenv_this_dir/lib/varstash export _dotenv_sourced_varstash=1 + # NOTE: Varstash uses $PWD as default for varstash_dir, we might set it to + # ${env_file:h}. fi - # varstash_dir=${env_file:h} # Change to directory of env file, source it and cd back. local new_dir=$PWD From f31bb529dea3592390454790e0263b74d3a7a15a Mon Sep 17 00:00:00 2001 From: Daniel Hahler Date: Fri, 21 Nov 2014 20:15:08 +0100 Subject: [PATCH 09/23] s/ENV_AUTHORIZATION_FILE/AUTOENV_ENV_FILENAME/ Ref: https://github.com/Tarrasch/zsh-autoenv/issues/6 --- autoenv.zsh | 13 ++++++------- tests/.zshenv | 2 +- tests/autoenv.t | 10 +++++----- tests/cwd.t | 4 ++-- tests/setup.sh | 4 ++-- tests/varstash.t | 4 ++-- 6 files changed, 18 insertions(+), 19 deletions(-) diff --git a/autoenv.zsh b/autoenv.zsh index b7f5976..5be6c31 100644 --- a/autoenv.zsh +++ b/autoenv.zsh @@ -1,8 +1,7 @@ # Initially based on # https://github.com/joshuaclayton/dotfiles/blob/master/zsh_profile.d/autoenv.zsh -# TODO: move this to DOTENV_*?! -export ENV_AUTHORIZATION_FILE=$HOME/.env_auth +export AUTOENV_ENV_FILENAME=$HOME/.env_auth # Name of file to look for when entering directories. : ${DOTENV_FILE_ENTER:=.env} @@ -31,20 +30,20 @@ _dotenv_hash_pair() { _dotenv_authorized_env_file() { local env_file=$1 local pair=$(_dotenv_hash_pair $env_file) - test -f $ENV_AUTHORIZATION_FILE \ - && \grep -qF $pair $ENV_AUTHORIZATION_FILE + test -f $AUTOENV_ENV_FILENAME \ + && \grep -qF $pair $AUTOENV_ENV_FILENAME } _dotenv_authorize() { local env_file=$1 _dotenv_deauthorize $env_file - _dotenv_hash_pair $env_file >> $ENV_AUTHORIZATION_FILE + _dotenv_hash_pair $env_file >> $AUTOENV_ENV_FILENAME } _dotenv_deauthorize() { local env_file=$1 - if [[ -f $ENV_AUTHORIZATION_FILE ]]; then - echo $(\grep -vF $env_file $ENV_AUTHORIZATION_FILE) > $ENV_AUTHORIZATION_FILE + if [[ -f $AUTOENV_ENV_FILENAME ]]; then + echo $(\grep -vF $env_file $AUTOENV_ENV_FILENAME) > $AUTOENV_ENV_FILENAME fi } diff --git a/tests/.zshenv b/tests/.zshenv index 1c0a9d2..d70711b 100644 --- a/tests/.zshenv +++ b/tests/.zshenv @@ -1,4 +1,4 @@ test -f "$TESTDIR/.zcompdump" && rm "$TESTDIR/.zcompdump" source "$TESTDIR/../autoenv.plugin.zsh" -export ENV_AUTHORIZATION_FILE="$PWD/.env_auth" +export AUTOENV_ENV_FILENAME="$PWD/.env_auth" diff --git a/tests/autoenv.t b/tests/autoenv.t index 940050a..4750912 100644 --- a/tests/autoenv.t +++ b/tests/autoenv.t @@ -6,14 +6,14 @@ Lets set a simple .env action Manually create auth file - $ echo "$PWD/.env:$(echo echo ENTERED | shasum)" > $ENV_AUTHORIZATION_FILE + $ echo "$PWD/.env:$(echo echo ENTERED | shasum)" > $AUTOENV_ENV_FILENAME $ cd . ENTERED Now try to make it accept it $ unset _dotenv_stack_entered - $ rm $ENV_AUTHORIZATION_FILE + $ rm $AUTOENV_ENV_FILENAME $ _dotenv_read_answer() { echo 'y' } $ cd . Attempting to load unauthorized env file: /tmp/cramtests-??????/autoenv.t/.env (glob) @@ -40,8 +40,8 @@ Now lets see that it actually checks the shasum value ENTERED $ unset _dotenv_stack_entered - $ rm $ENV_AUTHORIZATION_FILE - $ echo "$PWD/.env:$(echo mischief | shasum)" > $ENV_AUTHORIZATION_FILE + $ rm $AUTOENV_ENV_FILENAME + $ echo "$PWD/.env:$(echo mischief | shasum)" > $AUTOENV_ENV_FILENAME $ cd . Attempting to load unauthorized env file: /tmp/cramtests-??????/autoenv.t/.env (glob) @@ -61,7 +61,7 @@ Now lets see that it actually checks the shasum value Now, will it take no for an answer? $ unset _dotenv_stack_entered - $ rm $ENV_AUTHORIZATION_FILE + $ rm $AUTOENV_ENV_FILENAME $ _dotenv_read_answer() { echo 'n' } $ cd . Attempting to load unauthorized env file: /tmp/cramtests-??????/autoenv.t/.env (glob) diff --git a/tests/cwd.t b/tests/cwd.t index 526ff63..99f77fe 100644 --- a/tests/cwd.t +++ b/tests/cwd.t @@ -12,8 +12,8 @@ Setup env actions / output. Manually create auth files. - $ echo "$PWD/$DOTENV_FILE_ENTER:$(echo $(<$DOTENV_FILE_ENTER) | shasum)" > $ENV_AUTHORIZATION_FILE - $ echo "$PWD/$DOTENV_FILE_LEAVE:$(echo $(<$DOTENV_FILE_LEAVE) | shasum)" >> $ENV_AUTHORIZATION_FILE + $ echo "$PWD/$DOTENV_FILE_ENTER:$(echo $(<$DOTENV_FILE_ENTER) | shasum)" > $AUTOENV_ENV_FILENAME + $ echo "$PWD/$DOTENV_FILE_LEAVE:$(echo $(<$DOTENV_FILE_LEAVE) | shasum)" >> $AUTOENV_ENV_FILENAME The actual tests. diff --git a/tests/setup.sh b/tests/setup.sh index efa99ab..b2f5aaf 100644 --- a/tests/setup.sh +++ b/tests/setup.sh @@ -1,6 +1,6 @@ -# Ensure we have our mocked out ENV_AUTHORIZATION_FILE +# Ensure we have our mocked out AUTOENV_ENV_FILENAME -[[ $ENV_AUTHORIZATION_FILE[0,4] == '/tmp' ]] || return 1 +[[ $AUTOENV_ENV_FILENAME[0,4] == '/tmp' ]] || return 1 # Inject timeout for `read` while running tests. _AUTOENV_TEST_READ_ARGS='-t 1' diff --git a/tests/varstash.t b/tests/varstash.t index 75a4077..bc49657 100644 --- a/tests/varstash.t +++ b/tests/varstash.t @@ -16,8 +16,8 @@ Setup test environment. Manually create auth file - $ echo "$PWD/$DOTENV_FILE_ENTER:$(echo $(<$DOTENV_FILE_ENTER) | shasum)" > $ENV_AUTHORIZATION_FILE - $ echo "$PWD/$DOTENV_FILE_LEAVE:$(echo $(<$DOTENV_FILE_LEAVE) | shasum)" >> $ENV_AUTHORIZATION_FILE + $ echo "$PWD/$DOTENV_FILE_ENTER:$(echo $(<$DOTENV_FILE_ENTER) | shasum)" > $AUTOENV_ENV_FILENAME + $ echo "$PWD/$DOTENV_FILE_LEAVE:$(echo $(<$DOTENV_FILE_LEAVE) | shasum)" >> $AUTOENV_ENV_FILENAME Set environment variable. From 67e80307707ca5517411abf36df1107d75111794 Mon Sep 17 00:00:00 2001 From: Daniel Hahler Date: Fri, 21 Nov 2014 23:07:53 +0100 Subject: [PATCH 10/23] tests: add and use test_autoenv_add_to_env and test_autoenv_auth_env_files Conflicts: autoenv.zsh --- autoenv.zsh | 5 +++++ tests/autoenv.t | 4 ++-- tests/cwd.t | 3 +-- tests/setup.sh | 12 ++++++++++++ tests/varstash.t | 3 +-- 5 files changed, 21 insertions(+), 6 deletions(-) diff --git a/autoenv.zsh b/autoenv.zsh index 5be6c31..317217f 100644 --- a/autoenv.zsh +++ b/autoenv.zsh @@ -24,6 +24,11 @@ _dotenv_stack_entered=() _dotenv_hash_pair() { local env_file=$1 + if (( $+2 )); then + env_shasum=$2 + else + env_shasum=$(shasum $env_file | cut -d' ' -f1) + fi echo "$env_file:$env_shasum:1" } diff --git a/tests/autoenv.t b/tests/autoenv.t index 4750912..f477c13 100644 --- a/tests/autoenv.t +++ b/tests/autoenv.t @@ -6,7 +6,7 @@ Lets set a simple .env action Manually create auth file - $ echo "$PWD/.env:$(echo echo ENTERED | shasum)" > $AUTOENV_ENV_FILENAME + $ test_autoenv_add_to_env $PWD/.env $ cd . ENTERED @@ -41,7 +41,7 @@ Now lets see that it actually checks the shasum value $ unset _dotenv_stack_entered $ rm $AUTOENV_ENV_FILENAME - $ echo "$PWD/.env:$(echo mischief | shasum)" > $AUTOENV_ENV_FILENAME + $ test_autoenv_add_to_env $PWD/.env mischief $ cd . Attempting to load unauthorized env file: /tmp/cramtests-??????/autoenv.t/.env (glob) diff --git a/tests/cwd.t b/tests/cwd.t index 99f77fe..2c5838a 100644 --- a/tests/cwd.t +++ b/tests/cwd.t @@ -12,8 +12,7 @@ Setup env actions / output. Manually create auth files. - $ echo "$PWD/$DOTENV_FILE_ENTER:$(echo $(<$DOTENV_FILE_ENTER) | shasum)" > $AUTOENV_ENV_FILENAME - $ echo "$PWD/$DOTENV_FILE_LEAVE:$(echo $(<$DOTENV_FILE_LEAVE) | shasum)" >> $AUTOENV_ENV_FILENAME + $ test_autoenv_auth_env_files The actual tests. diff --git a/tests/setup.sh b/tests/setup.sh index b2f5aaf..a7da1b4 100644 --- a/tests/setup.sh +++ b/tests/setup.sh @@ -1,6 +1,18 @@ # Ensure we have our mocked out AUTOENV_ENV_FILENAME +# (via .zshenv). [[ $AUTOENV_ENV_FILENAME[0,4] == '/tmp' ]] || return 1 # Inject timeout for `read` while running tests. _AUTOENV_TEST_READ_ARGS='-t 1' + +test_autoenv_add_to_env() { + _dotenv_hash_pair $1 $2 >> $AUTOENV_ENV_FILENAME +} + +# Add enter and leave env files to authentication file. +test_autoenv_auth_env_files() { + echo -n > $AUTOENV_ENV_FILENAME + test_autoenv_add_to_env $PWD/$DOTENV_FILE_ENTER + test_autoenv_add_to_env $PWD/$DOTENV_FILE_LEAVE +} diff --git a/tests/varstash.t b/tests/varstash.t index bc49657..c6d33f0 100644 --- a/tests/varstash.t +++ b/tests/varstash.t @@ -16,8 +16,7 @@ Setup test environment. Manually create auth file - $ echo "$PWD/$DOTENV_FILE_ENTER:$(echo $(<$DOTENV_FILE_ENTER) | shasum)" > $AUTOENV_ENV_FILENAME - $ echo "$PWD/$DOTENV_FILE_LEAVE:$(echo $(<$DOTENV_FILE_LEAVE) | shasum)" >> $AUTOENV_ENV_FILENAME + $ test_autoenv_auth_env_files Set environment variable. From dbfb8fe51948701997d4d03dd02d63c61d3dfff0 Mon Sep 17 00:00:00 2001 From: Daniel Hahler Date: Fri, 21 Nov 2014 22:33:00 +0100 Subject: [PATCH 11/23] Streamline cwd behavior while sourcing --- autoenv.zsh | 14 +++++++++++--- tests/cwd.t | 12 ++++++------ 2 files changed, 17 insertions(+), 9 deletions(-) diff --git a/autoenv.zsh b/autoenv.zsh index 317217f..19891b6 100644 --- a/autoenv.zsh +++ b/autoenv.zsh @@ -96,7 +96,9 @@ _dotenv_this_dir=${0:A:h} _dotenv_source() { local env_file=$1 _dotenv_event=$2 - _dotenv_cwd=$3 + _dotenv_envfile_dir=$3 + _dotenv_from_dir=$_dotenv_chpwd_prev_dir + _dotenv_to_dir=$PWD # Source varstash library once. if [[ $_dotenv_sourced_varstash == 0 ]]; then @@ -108,13 +110,14 @@ _dotenv_source() { # Change to directory of env file, source it and cd back. local new_dir=$PWD - builtin cd -q $_dotenv_cwd + builtin cd -q $_dotenv_envfile_dir source $env_file builtin cd -q $new_dir - unset _dotenv_event _dotenv_cwd + unset _dotenv_event _dotenv_from_dir } +_dotenv_chpwd_prev_dir=$PWD _dotenv_chpwd_handler() { local env_file="$PWD/$DOTENV_FILE_ENTER" @@ -140,11 +143,13 @@ _dotenv_chpwd_handler() { if (( $#m )); then env_file=${${m[1]}:A} else + _dotenv_chpwd_prev_dir=$PWD return fi fi if ! _dotenv_check_authorized_env_file $env_file; then + _dotenv_chpwd_prev_dir=$PWD return fi @@ -152,12 +157,15 @@ _dotenv_chpwd_handler() { # is in $_dotenv_stack_entered. local env_file_dir=${env_file:A:h} if (( ${+_dotenv_stack_entered[(r)${env_file_dir}]} )); then + _dotenv_chpwd_prev_dir=$PWD return fi _dotenv_stack_entered+=(${env_file_dir}) _dotenv_source $env_file enter $PWD + + _dotenv_chpwd_prev_dir=$PWD } autoload -U add-zsh-hook diff --git a/tests/cwd.t b/tests/cwd.t index 2c5838a..d6b3902 100644 --- a/tests/cwd.t +++ b/tests/cwd.t @@ -1,4 +1,4 @@ -Test $PWD and $_dotenv_cwd. +Test $PWD, $_dotenv_from_dir and _dotenv_to_dir. $ source $TESTDIR/setup.sh @@ -7,8 +7,8 @@ Setup env actions / output. $ DOTENV_LOOK_UPWARDS=1 $ mkdir -p sub/sub2 $ cd sub - $ echo 'echo ENTERED: cwd:${PWD:t} ${_dotenv_cwd:t}' >> .env - $ echo 'echo LEFT: cwd:${PWD:t} ${_dotenv_cwd:t}' >> .env.leave + $ echo 'echo ENTERED: PWD:${PWD:t} from:${_dotenv_from_dir:t} to:${_dotenv_to_dir:t}' > .env + $ echo 'echo LEFT: PWD:${PWD:t} from:${_dotenv_from_dir:t} to:${_dotenv_to_dir:t}' > .env.leave Manually create auth files. @@ -17,10 +17,10 @@ Manually create auth files. The actual tests. $ cd . - ENTERED: cwd:sub sub + ENTERED: PWD:sub from:sub to:sub $ cd .. - LEFT: cwd:sub cwd.t + LEFT: PWD:sub from:sub to:cwd.t $ cd sub/sub2 - ENTERED: cwd:sub sub2 + ENTERED: PWD:sub2 from:cwd.t to:sub2 From e088e83ff99453e540fb71aad0cdfe8768627d0b Mon Sep 17 00:00:00 2001 From: Daniel Hahler Date: Fri, 21 Nov 2014 22:47:45 +0100 Subject: [PATCH 12/23] Cleanup --- tests/varstash.t | 5 ----- 1 file changed, 5 deletions(-) diff --git a/tests/varstash.t b/tests/varstash.t index c6d33f0..9bce05c 100644 --- a/tests/varstash.t +++ b/tests/varstash.t @@ -4,11 +4,6 @@ Test varstash integration. Setup test environment. -# Defaults: -# $ DOTENV_FILE_ENTER=.env -# $ DOTENV_FILE_LEAVE=.env.leave -# $ DOTENV_HANDLE_LEAVE=1 - $ mkdir sub $ cd sub $ echo "autostash FOO=baz" > $DOTENV_FILE_ENTER From bcec00d2dd5e8f12fd0f6ef0e53a9e61961db5b6 Mon Sep 17 00:00:00 2001 From: Daniel Hahler Date: Fri, 21 Nov 2014 22:51:28 +0100 Subject: [PATCH 13/23] Use AUTOENV prefix - s/DOTENV_/AUTOENV_/ - s/dotenv_/autoenv_/ Ref: https://github.com/Tarrasch/zsh-autoenv/issues/6 --- autoenv.zsh | 106 +++++++++++++++++++++++------------------------ tests/autoenv.t | 12 +++--- tests/cwd.t | 8 ++-- tests/leave.t | 16 +++---- tests/setup.sh | 6 +-- tests/varstash.t | 4 +- 6 files changed, 76 insertions(+), 76 deletions(-) diff --git a/autoenv.zsh b/autoenv.zsh index 19891b6..e996ca2 100644 --- a/autoenv.zsh +++ b/autoenv.zsh @@ -4,25 +4,25 @@ export AUTOENV_ENV_FILENAME=$HOME/.env_auth # Name of file to look for when entering directories. -: ${DOTENV_FILE_ENTER:=.env} +: ${AUTOENV_FILE_ENTER:=.env} # Name of file to look for when leaving directories. -# Requires DOTENV_HANDLE_LEAVE=1. -: ${DOTENV_FILE_LEAVE:=.env.leave} +# Requires AUTOENV_HANDLE_LEAVE=1. +: ${AUTOENV_FILE_LEAVE:=.env.leave} # Look for .env in parent dirs? -: ${DOTENV_LOOK_UPWARDS:=1} +: ${AUTOENV_LOOK_UPWARDS:=1} # Handle leave events when changing away from a subtree, where an "enter" # event was handled? -: ${DOTENV_HANDLE_LEAVE:=1} +: ${AUTOENV_HANDLE_LEAVE:=1} # Internal: stack of entered (and handled) directories. -_dotenv_stack_entered=() +_autoenv_stack_entered=() -_dotenv_hash_pair() { +_autoenv_hash_pair() { local env_file=$1 if (( $+2 )); then env_shasum=$2 @@ -32,20 +32,20 @@ _dotenv_hash_pair() { echo "$env_file:$env_shasum:1" } -_dotenv_authorized_env_file() { +_autoenv_authorized_env_file() { local env_file=$1 - local pair=$(_dotenv_hash_pair $env_file) + local pair=$(_autoenv_hash_pair $env_file) test -f $AUTOENV_ENV_FILENAME \ && \grep -qF $pair $AUTOENV_ENV_FILENAME } -_dotenv_authorize() { +_autoenv_authorize() { local env_file=$1 - _dotenv_deauthorize $env_file - _dotenv_hash_pair $env_file >> $AUTOENV_ENV_FILENAME + _autoenv_deauthorize $env_file + _autoenv_hash_pair $env_file >> $AUTOENV_ENV_FILENAME } -_dotenv_deauthorize() { +_autoenv_deauthorize() { local env_file=$1 if [[ -f $AUTOENV_ENV_FILENAME ]]; then echo $(\grep -vF $env_file $AUTOENV_ENV_FILENAME) > $AUTOENV_ENV_FILENAME @@ -53,18 +53,18 @@ _dotenv_deauthorize() { } # This function can be mocked in tests -_dotenv_read_answer() { +_autoenv_read_answer() { local answer read $=_AUTOENV_TEST_READ_ARGS -q answer echo $answer } # Args: 1: absolute path to env file (resolved symlinks). -_dotenv_check_authorized_env_file() { +_autoenv_check_authorized_env_file() { if ! [[ -f $1 ]]; then return 1 fi - if ! _dotenv_authorized_env_file $1; then + if ! _autoenv_authorized_env_file $1; then echo "Attempting to load unauthorized env file: $1" echo "" echo "**********************************************" @@ -75,101 +75,101 @@ _dotenv_check_authorized_env_file() { echo "" echo -n "Would you like to authorize it? [y/N] " - local answer=$(_dotenv_read_answer) + local answer=$(_autoenv_read_answer) echo if [[ $answer != 'y' ]]; then return 1 fi - _dotenv_authorize $1 + _autoenv_authorize $1 fi return 0 } -# Initialize $_dotenv_sourced_varstash, but do not overwrite an existing one +# Initialize $_autoenv_sourced_varstash, but do not overwrite an existing one # from e.g. `exec zsh` (to reload your shell config). -: ${_dotenv_sourced_varstash:=0} +: ${_autoenv_sourced_varstash:=0} # Get directory of this file (absolute, with resolved symlinks). -_dotenv_this_dir=${0:A:h} +_autoenv_this_dir=${0:A:h} -_dotenv_source() { +_autoenv_source() { local env_file=$1 - _dotenv_event=$2 - _dotenv_envfile_dir=$3 - _dotenv_from_dir=$_dotenv_chpwd_prev_dir - _dotenv_to_dir=$PWD + _autoenv_event=$2 + _autoenv_envfile_dir=$3 + _autoenv_from_dir=$_autoenv_chpwd_prev_dir + _autoenv_to_dir=$PWD # Source varstash library once. - if [[ $_dotenv_sourced_varstash == 0 ]]; then - source $_dotenv_this_dir/lib/varstash - export _dotenv_sourced_varstash=1 + if [[ $_autoenv_sourced_varstash == 0 ]]; then + source $_autoenv_this_dir/lib/varstash + export _autoenv_sourced_varstash=1 # NOTE: Varstash uses $PWD as default for varstash_dir, we might set it to # ${env_file:h}. fi # Change to directory of env file, source it and cd back. local new_dir=$PWD - builtin cd -q $_dotenv_envfile_dir + builtin cd -q $_autoenv_envfile_dir source $env_file builtin cd -q $new_dir - unset _dotenv_event _dotenv_from_dir + unset _autoenv_event _autoenv_from_dir } -_dotenv_chpwd_prev_dir=$PWD -_dotenv_chpwd_handler() { - local env_file="$PWD/$DOTENV_FILE_ENTER" +_autoenv_chpwd_prev_dir=$PWD +_autoenv_chpwd_handler() { + local env_file="$PWD/$AUTOENV_FILE_ENTER" # Handle leave event for previously sourced env files. - if [[ $DOTENV_HANDLE_LEAVE == 1 ]] && (( $#_dotenv_stack_entered )); then - for prev_dir in ${_dotenv_stack_entered}; do + if [[ $AUTOENV_HANDLE_LEAVE == 1 ]] && (( $#_autoenv_stack_entered )); then + for prev_dir in ${_autoenv_stack_entered}; do if ! [[ ${PWD}/ == ${prev_dir}/* ]]; then - local env_file_leave=$prev_dir/$DOTENV_FILE_LEAVE - if _dotenv_check_authorized_env_file $env_file_leave; then - _dotenv_source $env_file_leave leave $prev_dir + local env_file_leave=$prev_dir/$AUTOENV_FILE_LEAVE + if _autoenv_check_authorized_env_file $env_file_leave; then + _autoenv_source $env_file_leave leave $prev_dir fi # Remove this entry from the stack. - _dotenv_stack_entered=(${_dotenv_stack_entered#$prev_dir}) + _autoenv_stack_entered=(${_autoenv_stack_entered#$prev_dir}) fi done fi - if ! [[ -f $env_file ]] && [[ $DOTENV_LOOK_UPWARDS == 1 ]]; then + if ! [[ -f $env_file ]] && [[ $AUTOENV_LOOK_UPWARDS == 1 ]]; then # Look for files in parent dirs, using an extended Zsh glob. setopt localoptions extendedglob local m - m=((../)#${DOTENV_FILE_ENTER}(N)) + m=((../)#${AUTOENV_FILE_ENTER}(N)) if (( $#m )); then env_file=${${m[1]}:A} else - _dotenv_chpwd_prev_dir=$PWD + _autoenv_chpwd_prev_dir=$PWD return fi fi - if ! _dotenv_check_authorized_env_file $env_file; then - _dotenv_chpwd_prev_dir=$PWD + if ! _autoenv_check_authorized_env_file $env_file; then + _autoenv_chpwd_prev_dir=$PWD return fi # Load the env file only once: check if $env_file's parent - # is in $_dotenv_stack_entered. + # is in $_autoenv_stack_entered. local env_file_dir=${env_file:A:h} - if (( ${+_dotenv_stack_entered[(r)${env_file_dir}]} )); then - _dotenv_chpwd_prev_dir=$PWD + if (( ${+_autoenv_stack_entered[(r)${env_file_dir}]} )); then + _autoenv_chpwd_prev_dir=$PWD return fi - _dotenv_stack_entered+=(${env_file_dir}) + _autoenv_stack_entered+=(${env_file_dir}) - _dotenv_source $env_file enter $PWD + _autoenv_source $env_file enter $PWD - _dotenv_chpwd_prev_dir=$PWD + _autoenv_chpwd_prev_dir=$PWD } autoload -U add-zsh-hook -add-zsh-hook chpwd _dotenv_chpwd_handler +add-zsh-hook chpwd _autoenv_chpwd_handler # Look in current directory already. -_dotenv_chpwd_handler +_autoenv_chpwd_handler diff --git a/tests/autoenv.t b/tests/autoenv.t index f477c13..f78560a 100644 --- a/tests/autoenv.t +++ b/tests/autoenv.t @@ -12,9 +12,9 @@ Manually create auth file Now try to make it accept it - $ unset _dotenv_stack_entered + $ unset _autoenv_stack_entered $ rm $AUTOENV_ENV_FILENAME - $ _dotenv_read_answer() { echo 'y' } + $ _autoenv_read_answer() { echo 'y' } $ cd . Attempting to load unauthorized env file: /tmp/cramtests-??????/autoenv.t/.env (glob) @@ -35,11 +35,11 @@ The last "ENTERED" is because it executed the command Now lets see that it actually checks the shasum value - $ unset _dotenv_stack_entered + $ unset _autoenv_stack_entered $ cd . ENTERED - $ unset _dotenv_stack_entered + $ unset _autoenv_stack_entered $ rm $AUTOENV_ENV_FILENAME $ test_autoenv_add_to_env $PWD/.env mischief $ cd . @@ -60,9 +60,9 @@ Now lets see that it actually checks the shasum value Now, will it take no for an answer? - $ unset _dotenv_stack_entered + $ unset _autoenv_stack_entered $ rm $AUTOENV_ENV_FILENAME - $ _dotenv_read_answer() { echo 'n' } + $ _autoenv_read_answer() { echo 'n' } $ cd . Attempting to load unauthorized env file: /tmp/cramtests-??????/autoenv.t/.env (glob) diff --git a/tests/cwd.t b/tests/cwd.t index d6b3902..e8dc6a4 100644 --- a/tests/cwd.t +++ b/tests/cwd.t @@ -1,14 +1,14 @@ -Test $PWD, $_dotenv_from_dir and _dotenv_to_dir. +Test $PWD, $_autoenv_from_dir and _autoenv_to_dir. $ source $TESTDIR/setup.sh Setup env actions / output. - $ DOTENV_LOOK_UPWARDS=1 + $ AUTOENV_LOOK_UPWARDS=1 $ mkdir -p sub/sub2 $ cd sub - $ echo 'echo ENTERED: PWD:${PWD:t} from:${_dotenv_from_dir:t} to:${_dotenv_to_dir:t}' > .env - $ echo 'echo LEFT: PWD:${PWD:t} from:${_dotenv_from_dir:t} to:${_dotenv_to_dir:t}' > .env.leave + $ echo 'echo ENTERED: PWD:${PWD:t} from:${_autoenv_from_dir:t} to:${_autoenv_to_dir:t}' > .env + $ echo 'echo LEFT: PWD:${PWD:t} from:${_autoenv_from_dir:t} to:${_autoenv_to_dir:t}' > .env.leave Manually create auth files. diff --git a/tests/leave.t b/tests/leave.t index 9a56f90..d5531b1 100644 --- a/tests/leave.t +++ b/tests/leave.t @@ -9,7 +9,7 @@ Lets set a simple .env action Change to the directory. - $ _dotenv_read_answer() { echo 'y' } + $ _autoenv_read_answer() { echo 'y' } $ cd . Attempting to load unauthorized env file: /tmp/cramtests-??????/leave.t/sub/.env (glob) @@ -25,7 +25,7 @@ Change to the directory. Leave the directory and answer "no". - $ _dotenv_read_answer() { echo 'n' } + $ _autoenv_read_answer() { echo 'n' } $ cd .. Attempting to load unauthorized env file: /tmp/cramtests-??????/leave.t/sub/.env.leave (glob) @@ -40,7 +40,7 @@ Leave the directory and answer "no". $ cd sub ENTERED - $ _dotenv_read_answer() { echo 'y' } + $ _autoenv_read_answer() { echo 'y' } $ cd .. Attempting to load unauthorized env file: /tmp/cramtests-??????/leave.t/sub/.env.leave (glob) @@ -56,7 +56,7 @@ Leave the directory and answer "no". Now check with subdirs, looking upwards. - $ DOTENV_LOOK_UPWARDS=1 + $ AUTOENV_LOOK_UPWARDS=1 $ mkdir sub/child $ cd sub/child ENTERED @@ -68,7 +68,7 @@ Now check with subdirs, looking upwards. Now check with subdirs, not looking at parent dirs. - $ DOTENV_LOOK_UPWARDS=0 + $ AUTOENV_LOOK_UPWARDS=0 $ cd sub/child $ cd .. ENTERED @@ -77,10 +77,10 @@ Now check with subdirs, not looking at parent dirs. LEFT -Test that .env is sourced only once with DOTENV_HANDLE_LEAVE=0. +Test that .env is sourced only once with AUTOENV_HANDLE_LEAVE=0. - $ unset _dotenv_stack_entered - $ DOTENV_HANDLE_LEAVE=0 + $ unset _autoenv_stack_entered + $ AUTOENV_HANDLE_LEAVE=0 $ cd sub ENTERED $ cd .. diff --git a/tests/setup.sh b/tests/setup.sh index a7da1b4..9134af0 100644 --- a/tests/setup.sh +++ b/tests/setup.sh @@ -7,12 +7,12 @@ _AUTOENV_TEST_READ_ARGS='-t 1' test_autoenv_add_to_env() { - _dotenv_hash_pair $1 $2 >> $AUTOENV_ENV_FILENAME + _autoenv_hash_pair $1 $2 >> $AUTOENV_ENV_FILENAME } # Add enter and leave env files to authentication file. test_autoenv_auth_env_files() { echo -n > $AUTOENV_ENV_FILENAME - test_autoenv_add_to_env $PWD/$DOTENV_FILE_ENTER - test_autoenv_add_to_env $PWD/$DOTENV_FILE_LEAVE + test_autoenv_add_to_env $PWD/$AUTOENV_FILE_ENTER + test_autoenv_add_to_env $PWD/$AUTOENV_FILE_LEAVE } diff --git a/tests/varstash.t b/tests/varstash.t index 9bce05c..621e93f 100644 --- a/tests/varstash.t +++ b/tests/varstash.t @@ -6,8 +6,8 @@ Setup test environment. $ mkdir sub $ cd sub - $ echo "autostash FOO=baz" > $DOTENV_FILE_ENTER - $ echo "autounstash" > $DOTENV_FILE_LEAVE + $ echo "autostash FOO=baz" > $AUTOENV_FILE_ENTER + $ echo "autounstash" > $AUTOENV_FILE_LEAVE Manually create auth file From d9ff71ac1dd62f309e4c6d669149f766cb3399ec Mon Sep 17 00:00:00 2001 From: Daniel Hahler Date: Mon, 24 Nov 2014 17:48:51 +0100 Subject: [PATCH 14/23] Some more refactoring, adding support for `autoenv_source_parent` - use file mtime with "entered" stack - fix loading of varstash; look at $functions - Refactor stack handling, add tests - Refactor `_autoenv_get_file_upwards`, add tests - tests: setup: reset AUTOENV_ENV_FILENAME --- autoenv.zsh | 130 ++++++++++++++++++++++++++-------- tests/_autoenv_stack.t | 52 ++++++++++++++ tests/_autoenv_utils.t | 15 ++++ tests/recurse-upwards.t | 150 ++++++++++++++++++++++++++++++++++++++++ tests/setup.sh | 5 +- tests/varstash.t | 6 +- 6 files changed, 326 insertions(+), 32 deletions(-) create mode 100644 tests/_autoenv_stack.t create mode 100644 tests/_autoenv_utils.t create mode 100644 tests/recurse-upwards.t diff --git a/autoenv.zsh b/autoenv.zsh index e996ca2..81a8742 100644 --- a/autoenv.zsh +++ b/autoenv.zsh @@ -18,12 +18,74 @@ export AUTOENV_ENV_FILENAME=$HOME/.env_auth : ${AUTOENV_HANDLE_LEAVE:=1} -# Internal: stack of entered (and handled) directories. +# Public helper functions, which can be used from your .env files: +# +# Source the next .env file from parent directories. +# This is useful if you want to use a base .env file for a directory subtree. +autoenv_source_parent() { + local parent_env_file=$(_autoenv_get_file_upwards $PWD) + + if [[ -n $parent_env_file ]] \ + && _autoenv_check_authorized_env_file $parent_env_file; then + + local parent_env_dir=${parent_env_file:A:h} + _autoenv_source $parent_env_file enter $parent_env_dir + fi +} + + +# Internal: stack of entered (and handled) directories. {{{ _autoenv_stack_entered=() +typeset -A _autoenv_stack_entered_mtime +_autoenv_stack_entered_mtime=() + +# Add an entry to the stack, and remember its mtime. +_autoenv_stack_entered_add() { + local env_file=$1 + + # Remove any existing entry. + _autoenv_stack_entered[$_autoenv_stack_entered[(i)$1]]=() + + # Append it to the stack, and remember its mtime. + _autoenv_stack_entered+=($env_file) + _autoenv_stack_entered_mtime[$env_file]=$(_autoenv_get_file_mtime $env_file) +} + +_autoenv_get_file_mtime() { + if [[ -f $1 ]]; then + zstat +mtime $1 + else + echo 0 + fi +} + +# Remove an entry from the stack. +_autoenv_stack_entered_remove() { + local env_file=$1 + _autoenv_stack_entered=(${_autoenv_stack_entered#$env_file}) + _autoenv_stack_entered_mtime[$env_file]= +} + +# Is the given entry already in the stack? +_autoenv_stack_entered_contains() { + local env_file=$1 + if (( ${+_autoenv_stack_entered[(r)${env_file}]} )); then + # Entry is in stack. + if [[ $_autoenv_stack_entered_mtime[$env_file] == $(_autoenv_get_file_mtime $env_file) ]]; then + # Entry has the expected mtime. + return + fi + fi + return 1 +} +# }}} + +# Load zstat module, but only its builtin `zstat`. +zmodload -F zsh/stat b:zstat _autoenv_hash_pair() { - local env_file=$1 + local env_file=${1:A} if (( $+2 )); then env_shasum=$2 else @@ -86,24 +148,20 @@ _autoenv_check_authorized_env_file() { return 0 } -# Initialize $_autoenv_sourced_varstash, but do not overwrite an existing one -# from e.g. `exec zsh` (to reload your shell config). -: ${_autoenv_sourced_varstash:=0} - # Get directory of this file (absolute, with resolved symlinks). _autoenv_this_dir=${0:A:h} _autoenv_source() { local env_file=$1 _autoenv_event=$2 - _autoenv_envfile_dir=$3 + local _autoenv_envfile_dir=$3 + _autoenv_from_dir=$_autoenv_chpwd_prev_dir _autoenv_to_dir=$PWD # Source varstash library once. - if [[ $_autoenv_sourced_varstash == 0 ]]; then + if [[ -z "$functions[(I)autostash]" ]]; then source $_autoenv_this_dir/lib/varstash - export _autoenv_sourced_varstash=1 # NOTE: Varstash uses $PWD as default for varstash_dir, we might set it to # ${env_file:h}. fi @@ -114,55 +172,69 @@ _autoenv_source() { source $env_file builtin cd -q $new_dir - unset _autoenv_event _autoenv_from_dir + # Unset vars set for enter/leave scripts. + # This should not get done for recursion (via autoenv_source_parent), + # and can be useful to have in general after autoenv was used. + # unset _autoenv_event _autoenv_from_dir _autoenv_to_dir } +_autoenv_get_file_upwards() { + local look_from=${1:-$PWD} + local look_for=${2:-$AUTOENV_FILE_ENTER} + # Look for files in parent dirs, using an extended Zsh glob. + setopt localoptions extendedglob + local m + # Y1: short-circuit: first match. + # :A: absolute path, resolving symlinks. + m=($look_from/(../)##${look_for}(NY1:A)) + if (( $#m )); then + echo $m[1] + fi +} + + _autoenv_chpwd_prev_dir=$PWD _autoenv_chpwd_handler() { local env_file="$PWD/$AUTOENV_FILE_ENTER" # Handle leave event for previously sourced env files. if [[ $AUTOENV_HANDLE_LEAVE == 1 ]] && (( $#_autoenv_stack_entered )); then - for prev_dir in ${_autoenv_stack_entered}; do + local prev_file prev_dir + for prev_file in ${_autoenv_stack_entered}; do + prev_dir=${prev_file:A:h} if ! [[ ${PWD}/ == ${prev_dir}/* ]]; then local env_file_leave=$prev_dir/$AUTOENV_FILE_LEAVE if _autoenv_check_authorized_env_file $env_file_leave; then _autoenv_source $env_file_leave leave $prev_dir fi - # Remove this entry from the stack. - _autoenv_stack_entered=(${_autoenv_stack_entered#$prev_dir}) + _autoenv_stack_entered_remove $prev_dir fi done fi if ! [[ -f $env_file ]] && [[ $AUTOENV_LOOK_UPWARDS == 1 ]]; then - # Look for files in parent dirs, using an extended Zsh glob. - setopt localoptions extendedglob - local m - m=((../)#${AUTOENV_FILE_ENTER}(N)) - if (( $#m )); then - env_file=${${m[1]}:A} - else + env_file=$(_autoenv_get_file_upwards $PWD) + if [[ -z $env_file ]]; then _autoenv_chpwd_prev_dir=$PWD return fi fi + # Load the env file only once: check if $env_file is in the stack of entered + # directories. + if _autoenv_stack_entered_contains $env_file; then + _autoenv_chpwd_prev_dir=$PWD + return + fi + if ! _autoenv_check_authorized_env_file $env_file; then _autoenv_chpwd_prev_dir=$PWD return fi - # Load the env file only once: check if $env_file's parent - # is in $_autoenv_stack_entered. - local env_file_dir=${env_file:A:h} - if (( ${+_autoenv_stack_entered[(r)${env_file_dir}]} )); then - _autoenv_chpwd_prev_dir=$PWD - return - fi - - _autoenv_stack_entered+=(${env_file_dir}) + _autoenv_stack_entered_add $env_file + # Source the enter env file. _autoenv_source $env_file enter $PWD _autoenv_chpwd_prev_dir=$PWD diff --git a/tests/_autoenv_stack.t b/tests/_autoenv_stack.t new file mode 100644 index 0000000..df1e0f9 --- /dev/null +++ b/tests/_autoenv_stack.t @@ -0,0 +1,52 @@ +Tests for internal stack handling. + + $ source $TESTDIR/setup.sh + +Non-existing entries are allowed and handled without error. + + $ _autoenv_stack_entered_add non-existing + $ echo $_autoenv_stack_entered + non-existing + +Add existing entries. + + $ mkdir -p sub/sub2 + $ touch -t 201401010101 sub/file + $ _autoenv_stack_entered_add sub + $ _autoenv_stack_entered_add sub/file + $ _autoenv_stack_entered_add sub/sub2 + $ echo $_autoenv_stack_entered + non-existing sub sub/file sub/sub2 + + $ _autoenv_stack_entered_add non-existing + $ echo $_autoenv_stack_entered + sub sub/file sub/sub2 non-existing + + $ echo ${(k)_autoenv_stack_entered} + sub sub/file sub/sub2 non-existing + + $ echo $_autoenv_stack_entered_mtime + 0 1388538060 0 0 (glob) + +Touch the file and re-add it. + + $ touch -t 201401012359 sub/file + $ _autoenv_stack_entered_add sub/file + +The mtime should have been updated. + + $ echo ${_autoenv_stack_entered_mtime[sub/file]} + 1388620740 + +It should have moved to the end of the stack. + + $ echo ${(k)_autoenv_stack_entered} + sub sub/sub2 non-existing sub/file + +Test lookup of containing elements. + + $ _autoenv_stack_entered_contains sub/file + $ _autoenv_stack_entered_contains non-existing + $ _autoenv_stack_entered_contains not-added + [1] + diff --git a/tests/_autoenv_utils.t b/tests/_autoenv_utils.t new file mode 100644 index 0000000..79c4bf1 --- /dev/null +++ b/tests/_autoenv_utils.t @@ -0,0 +1,15 @@ +Tests for internal util methods. + + $ source $TESTDIR/setup.sh + +Non-existing entries are allowed and handled without error. + + $ mkdir -p sub/sub2 + $ touch file sub/file sub/sub2/file + +Should not get the file from the current dir. + $ _autoenv_get_file_upwards . file + + $ cd sub/sub2 + $ _autoenv_get_file_upwards . file + */_autoenv_utils.t/sub/file (glob) diff --git a/tests/recurse-upwards.t b/tests/recurse-upwards.t new file mode 100644 index 0000000..508fb37 --- /dev/null +++ b/tests/recurse-upwards.t @@ -0,0 +1,150 @@ +Test recursing into parent .env files. + + $ source $TESTDIR/setup.sh + +Setup env actions / output. + + $ AUTOENV_LOOK_UPWARDS=1 + +Create env files in root dir. + + $ echo 'echo ENTERED_root: PWD:${PWD:t} from:${_autoenv_from_dir:t} to:${_autoenv_to_dir:t}' > .env + $ echo 'echo LEFT_root: PWD:${PWD:t} from:${_autoenv_from_dir:t} to:${_autoenv_to_dir:t}' > .env.leave + $ test_autoenv_auth_env_files + +Create env files in sub dir. + + $ mkdir -p sub/sub2 + $ cd sub + ENTERED_root: PWD:sub from:recurse-upwards.t to:sub + + $ echo 'echo ENTERED_sub: PWD:${PWD:t} from:${_autoenv_from_dir:t} to:${_autoenv_to_dir:t}' > .env + $ echo 'echo LEFT_sub: PWD:${PWD:t} from:${_autoenv_from_dir:t} to:${_autoenv_to_dir:t}' > .env.leave + $ test_autoenv_auth_env_files + +The actual tests. + + $ cd . + ENTERED_sub: PWD:sub from:sub to:sub + + $ cd .. + LEFT_sub: PWD:sub from:sub to:recurse-upwards.t + + $ cd sub/sub2 + ENTERED_sub: PWD:sub2 from:recurse-upwards.t to:sub2 + + $ cd .. + +Changing the .env file should re-source it. + + $ echo 'echo ENTER2' >> .env + +Set timestamp of auth file into the past, so it gets seen as new below. + + $ touch -t 201401010101 .env + + $ test_autoenv_auth_env_files + $ cd . + ENTERED_sub: PWD:sub from:sub to:sub + ENTER2 + +Add sub/sub2/.env file, with a call to autoenv_source_parent. + + $ echo -e "echo autoenv_source_parent_from_sub2:\nautoenv_source_parent\necho done_sub2\n" > sub2/.env + $ test_autoenv_add_to_env sub2/.env + $ cd sub2 + autoenv_source_parent_from_sub2: + ENTERED_sub: PWD:sub from:sub to:sub2 + ENTER2 + done_sub2 + +Move sub/.env away, now the root .env file should get sourced. + + $ mv ../.env ../.env.out + $ touch -t 201401010102 .env + $ cd . + autoenv_source_parent_from_sub2: + ENTERED_root: PWD:recurse-upwards.t from:sub2 to:sub2 + done_sub2 + $ mv ../.env.out ../.env + +Prepend call to autoenv_source_parent to sub/.env file. + + $ cd .. + $ echo -e "echo autoenv_source_parent_from_sub:\nautoenv_source_parent\n$(< .env)\necho done_sub" > .env + $ touch -t 201401010103 .env + $ test_autoenv_auth_env_files + + $ cd . + autoenv_source_parent_from_sub: + ENTERED_root: PWD:recurse-upwards.t from:sub to:sub + ENTERED_sub: PWD:sub from:sub to:sub + ENTER2 + done_sub + + +Add sub/sub2/.env file. + + $ echo -e "echo autoenv_source_parent_from_sub2:\nautoenv_source_parent\necho done_sub2\n" > sub2/.env + $ test_autoenv_add_to_env sub2/.env + $ cd sub2 + autoenv_source_parent_from_sub2: + autoenv_source_parent_from_sub: + ENTERED_root: PWD:recurse-upwards.t from:sub to:sub + ENTERED_sub: PWD:sub from:sub to:sub + ENTER2 + done_sub + done_sub2 + +Go to root. + + $ cd ../.. + LEFT_sub: PWD:sub from:sub2 to:recurse-upwards.t + ENTERED_root: PWD:recurse-upwards.t from:sub2 to:recurse-upwards.t + + +Changing the root .env should trigger re-authentication via autoenv_source_parent. + +First, let's answer "no". + + $ echo "echo NEW" > .env + $ _autoenv_read_answer() { echo 'n' } + $ cd sub + autoenv_source_parent_from_sub: + Attempting to load unauthorized env file: /tmp/cramtests-*/recurse-upwards.t/.env (glob) + + ********************************************** + + echo NEW + + ********************************************** + + Would you like to authorize it? [y/N] + ENTERED_sub: PWD:sub from:recurse-upwards.t to:sub + ENTER2 + done_sub + +Now with "yes". +This currently does not trigger re-execution of the .env file. + + $ _autoenv_read_answer() { echo 'y' } + $ cd . + +Touching the .env file will now source the parent env file. + + $ touch -t 201401010104 .env + $ cd . + autoenv_source_parent_from_sub: + Attempting to load unauthorized env file: /tmp/cramtests-*/recurse-upwards.t/.env (glob) + + ********************************************** + + echo NEW + + ********************************************** + + Would you like to authorize it? [y/N] + NEW + ENTERED_sub: PWD:sub from:sub to:sub + ENTER2 + done_sub diff --git a/tests/setup.sh b/tests/setup.sh index 9134af0..d5a4f6e 100644 --- a/tests/setup.sh +++ b/tests/setup.sh @@ -3,16 +3,19 @@ [[ $AUTOENV_ENV_FILENAME[0,4] == '/tmp' ]] || return 1 +# Reset any authentication. +echo -n > $AUTOENV_ENV_FILENAME + # Inject timeout for `read` while running tests. _AUTOENV_TEST_READ_ARGS='-t 1' +# Add file $1 (with optional hash $2) to authentication file. test_autoenv_add_to_env() { _autoenv_hash_pair $1 $2 >> $AUTOENV_ENV_FILENAME } # Add enter and leave env files to authentication file. test_autoenv_auth_env_files() { - echo -n > $AUTOENV_ENV_FILENAME test_autoenv_add_to_env $PWD/$AUTOENV_FILE_ENTER test_autoenv_add_to_env $PWD/$AUTOENV_FILE_LEAVE } diff --git a/tests/varstash.t b/tests/varstash.t index 621e93f..7458044 100644 --- a/tests/varstash.t +++ b/tests/varstash.t @@ -6,8 +6,8 @@ Setup test environment. $ mkdir sub $ cd sub - $ echo "autostash FOO=baz" > $AUTOENV_FILE_ENTER - $ echo "autounstash" > $AUTOENV_FILE_LEAVE + $ echo 'echo ENTER; autostash FOO=baz' > $AUTOENV_FILE_ENTER + $ echo 'echo LEAVE; autounstash' > $AUTOENV_FILE_LEAVE Manually create auth file @@ -20,11 +20,13 @@ Set environment variable. Activating the env stashes it and applies a new value. $ cd . + ENTER $ echo $FOO baz Leaving the directory unstashes it. $ cd .. + LEAVE $ echo $FOO bar From 6d8141d290809ce67c377e551ab6a2c39e2d7ba0 Mon Sep 17 00:00:00 2001 From: Daniel Hahler Date: Mon, 24 Nov 2014 18:51:20 +0100 Subject: [PATCH 15/23] Fix _autoenv_get_file_upwards for older Zsh --- autoenv.zsh | 29 ++++++++++++++++++++--------- 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/autoenv.zsh b/autoenv.zsh index 81a8742..c2daa07 100644 --- a/autoenv.zsh +++ b/autoenv.zsh @@ -181,15 +181,26 @@ _autoenv_source() { _autoenv_get_file_upwards() { local look_from=${1:-$PWD} local look_for=${2:-$AUTOENV_FILE_ENTER} - # Look for files in parent dirs, using an extended Zsh glob. - setopt localoptions extendedglob - local m - # Y1: short-circuit: first match. - # :A: absolute path, resolving symlinks. - m=($look_from/(../)##${look_for}(NY1:A)) - if (( $#m )); then - echo $m[1] - fi + + # Manually look in parent dirs. An extended Zsh glob should use Y1 for + # performance reasons, which is only available in zsh-5.0.5-146-g9381bb6. + local last + local parent_dir="$look_from/.." + while true; do + parent_dir=${parent_dir:A} + if [[ $parent_dir == $last ]]; then + break + fi + parent_file="${parent_dir}/${look_for}" + + if [[ -f $parent_file ]]; then + echo $parent_file + break + fi + + last=$parent_dir + parent_dir="${parent_dir}/.." + done } From 175a4eb62875fb249f23f3a0186c1c71fc4f6263 Mon Sep 17 00:00:00 2001 From: Daniel Hahler Date: Mon, 24 Nov 2014 19:03:51 +0100 Subject: [PATCH 16/23] tests: use sed to prepend to .env file --- tests/recurse-upwards.t | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/recurse-upwards.t b/tests/recurse-upwards.t index 508fb37..6a4930f 100644 --- a/tests/recurse-upwards.t +++ b/tests/recurse-upwards.t @@ -50,7 +50,7 @@ Set timestamp of auth file into the past, so it gets seen as new below. Add sub/sub2/.env file, with a call to autoenv_source_parent. - $ echo -e "echo autoenv_source_parent_from_sub2:\nautoenv_source_parent\necho done_sub2\n" > sub2/.env + $ echo "echo autoenv_source_parent_from_sub2:\nautoenv_source_parent\necho done_sub2\n" > sub2/.env $ test_autoenv_add_to_env sub2/.env $ cd sub2 autoenv_source_parent_from_sub2: @@ -71,7 +71,8 @@ Move sub/.env away, now the root .env file should get sourced. Prepend call to autoenv_source_parent to sub/.env file. $ cd .. - $ echo -e "echo autoenv_source_parent_from_sub:\nautoenv_source_parent\n$(< .env)\necho done_sub" > .env + $ sed -i -e "1s/^/echo autoenv_source_parent_from_sub:\nautoenv_source_parent\n/" .env + $ echo "echo done_sub" >> .env $ touch -t 201401010103 .env $ test_autoenv_auth_env_files From 869e679b795e08d73f46c475810666de7c4a136c Mon Sep 17 00:00:00 2001 From: Daniel Hahler Date: Mon, 24 Nov 2014 20:12:45 +0100 Subject: [PATCH 17/23] Fix handling of stack for leave, add to stack for autoenv_source_parent --- autoenv.zsh | 9 ++++++--- tests/_autoenv_stack.t | 6 ++++++ tests/recurse-upwards.t | 3 ++- 3 files changed, 14 insertions(+), 4 deletions(-) diff --git a/autoenv.zsh b/autoenv.zsh index c2daa07..9f8ae90 100644 --- a/autoenv.zsh +++ b/autoenv.zsh @@ -29,6 +29,9 @@ autoenv_source_parent() { && _autoenv_check_authorized_env_file $parent_env_file; then local parent_env_dir=${parent_env_file:A:h} + + _autoenv_stack_entered_add $parent_env_file + _autoenv_source $parent_env_file enter $parent_env_dir fi } @@ -44,7 +47,7 @@ _autoenv_stack_entered_add() { local env_file=$1 # Remove any existing entry. - _autoenv_stack_entered[$_autoenv_stack_entered[(i)$1]]=() + _autoenv_stack_entered_remove $env_file # Append it to the stack, and remember its mtime. _autoenv_stack_entered+=($env_file) @@ -62,7 +65,7 @@ _autoenv_get_file_mtime() { # Remove an entry from the stack. _autoenv_stack_entered_remove() { local env_file=$1 - _autoenv_stack_entered=(${_autoenv_stack_entered#$env_file}) + _autoenv_stack_entered[$_autoenv_stack_entered[(i)$env_file]]=() _autoenv_stack_entered_mtime[$env_file]= } @@ -218,7 +221,7 @@ _autoenv_chpwd_handler() { if _autoenv_check_authorized_env_file $env_file_leave; then _autoenv_source $env_file_leave leave $prev_dir fi - _autoenv_stack_entered_remove $prev_dir + _autoenv_stack_entered_remove $prev_file fi done fi diff --git a/tests/_autoenv_stack.t b/tests/_autoenv_stack.t index df1e0f9..6f659c6 100644 --- a/tests/_autoenv_stack.t +++ b/tests/_autoenv_stack.t @@ -50,3 +50,9 @@ Test lookup of containing elements. $ _autoenv_stack_entered_contains not-added [1] +Test removing. + + $ _autoenv_stack_entered_remove sub + $ echo ${_autoenv_stack_entered} + sub/sub2 non-existing sub/file + diff --git a/tests/recurse-upwards.t b/tests/recurse-upwards.t index 6a4930f..8d94bf3 100644 --- a/tests/recurse-upwards.t +++ b/tests/recurse-upwards.t @@ -98,10 +98,11 @@ Add sub/sub2/.env file. done_sub2 Go to root. +This should not trigger the enter event, because it was handled via +autoenv_source_parent already. $ cd ../.. LEFT_sub: PWD:sub from:sub2 to:recurse-upwards.t - ENTERED_root: PWD:recurse-upwards.t from:sub2 to:recurse-upwards.t Changing the root .env should trigger re-authentication via autoenv_source_parent. From 04e44f8244ce590830a24c1c2a9238a1599789e0 Mon Sep 17 00:00:00 2001 From: Daniel Hahler Date: Mon, 24 Nov 2014 20:19:25 +0100 Subject: [PATCH 18/23] Rename $_autoenv_this_dir to $_autoenv_source_dir --- autoenv.zsh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/autoenv.zsh b/autoenv.zsh index 9f8ae90..eb51605 100644 --- a/autoenv.zsh +++ b/autoenv.zsh @@ -152,7 +152,7 @@ _autoenv_check_authorized_env_file() { } # Get directory of this file (absolute, with resolved symlinks). -_autoenv_this_dir=${0:A:h} +_autoenv_source_dir=${0:A:h} _autoenv_source() { local env_file=$1 @@ -164,7 +164,7 @@ _autoenv_source() { # Source varstash library once. if [[ -z "$functions[(I)autostash]" ]]; then - source $_autoenv_this_dir/lib/varstash + source $_autoenv_source_dir/lib/varstash # NOTE: Varstash uses $PWD as default for varstash_dir, we might set it to # ${env_file:h}. fi From 13c0dbcd2f0b15a0a4ee9484c134153b2168c76c Mon Sep 17 00:00:00 2001 From: Daniel Hahler Date: Tue, 25 Nov 2014 14:39:43 +0100 Subject: [PATCH 19/23] Fix $PWD while sourcing .env file - should be dir of .env file --- autoenv.zsh | 4 ++-- tests/cwd.t | 2 +- tests/recurse-upwards.t | 17 +++++++++++++++-- 3 files changed, 18 insertions(+), 5 deletions(-) diff --git a/autoenv.zsh b/autoenv.zsh index eb51605..a46345f 100644 --- a/autoenv.zsh +++ b/autoenv.zsh @@ -157,7 +157,7 @@ _autoenv_source_dir=${0:A:h} _autoenv_source() { local env_file=$1 _autoenv_event=$2 - local _autoenv_envfile_dir=$3 + local _autoenv_envfile_dir=${3:-${1:A:h}} _autoenv_from_dir=$_autoenv_chpwd_prev_dir _autoenv_to_dir=$PWD @@ -249,7 +249,7 @@ _autoenv_chpwd_handler() { _autoenv_stack_entered_add $env_file # Source the enter env file. - _autoenv_source $env_file enter $PWD + _autoenv_source $env_file enter _autoenv_chpwd_prev_dir=$PWD } diff --git a/tests/cwd.t b/tests/cwd.t index e8dc6a4..ea77aa0 100644 --- a/tests/cwd.t +++ b/tests/cwd.t @@ -23,4 +23,4 @@ The actual tests. LEFT: PWD:sub from:sub to:cwd.t $ cd sub/sub2 - ENTERED: PWD:sub2 from:cwd.t to:sub2 + ENTERED: PWD:sub from:cwd.t to:sub2 diff --git a/tests/recurse-upwards.t b/tests/recurse-upwards.t index 8d94bf3..7a6f28f 100644 --- a/tests/recurse-upwards.t +++ b/tests/recurse-upwards.t @@ -16,7 +16,7 @@ Create env files in sub dir. $ mkdir -p sub/sub2 $ cd sub - ENTERED_root: PWD:sub from:recurse-upwards.t to:sub + ENTERED_root: PWD:recurse-upwards.t from:recurse-upwards.t to:sub $ echo 'echo ENTERED_sub: PWD:${PWD:t} from:${_autoenv_from_dir:t} to:${_autoenv_to_dir:t}' > .env $ echo 'echo LEFT_sub: PWD:${PWD:t} from:${_autoenv_from_dir:t} to:${_autoenv_to_dir:t}' > .env.leave @@ -31,7 +31,7 @@ The actual tests. LEFT_sub: PWD:sub from:sub to:recurse-upwards.t $ cd sub/sub2 - ENTERED_sub: PWD:sub2 from:recurse-upwards.t to:sub2 + ENTERED_sub: PWD:sub from:recurse-upwards.t to:sub2 $ cd .. @@ -150,3 +150,16 @@ Touching the .env file will now source the parent env file. ENTERED_sub: PWD:sub from:sub to:sub ENTER2 done_sub + + + $ cd .. + LEFT_sub: PWD:sub from:sub to:recurse-upwards.t + $ mkdir sub/sub2/sub3 + $ cd sub/sub2/sub3 + autoenv_source_parent_from_sub2: + autoenv_source_parent_from_sub: + NEW + ENTERED_sub: PWD:sub from:recurse-upwards.t to:sub + ENTER2 + done_sub + done_sub2 From 58409acda3c03e1165ffa78c81b72340f8b4838b Mon Sep 17 00:00:00 2001 From: Daniel Hahler Date: Wed, 26 Nov 2014 19:41:04 +0100 Subject: [PATCH 20/23] Makefile: use test by default, improve for \*.t --- Makefile | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/Makefile b/Makefile index b164795..0ffe150 100644 --- a/Makefile +++ b/Makefile @@ -1,11 +1,17 @@ .PHONY: itest test +test: + ZDOTDIR="${PWD}/tests" cram --shell=zsh -v tests + itest: ZDOTDIR="${PWD}/tests" cram -i --shell=zsh tests -test: - ZDOTDIR="${PWD}/tests" cram --shell=zsh tests +# Define targets for test files, with relative and abolute path. +# Use verbose output, which is useful with Vim's 'errorformat'. +TESTS:=$(wildcard tests/*.t) -tests/*.t: - ZDOTDIR="${PWD}/tests" cram --shell=zsh $@ -.PHONY: tests/*.t +uniq = $(if $1,$(firstword $1) $(call uniq,$(filter-out $(firstword $1),$1))) +_TESTS_REL_AND_ABS:=$(call uniq,$(abspath $(TESTS)) $(TESTS)) +$(_TESTS_REL_AND_ABS): + ZDOTDIR="${PWD}/tests" cram --shell=zsh -v $@ +.PHONY: $(_TESTS_REL_AND_ABS) From 0b941261b74ad40a24ea4613653346da5fecdd48 Mon Sep 17 00:00:00 2001 From: Daniel Hahler Date: Wed, 26 Nov 2014 19:42:57 +0100 Subject: [PATCH 21/23] Add debugging, via AUTOENV_DEBUG>1 --- autoenv.zsh | 48 +++++++++++++++++++++++++++++++++++++++++++++++- tests/.zshenv | 2 ++ 2 files changed, 49 insertions(+), 1 deletion(-) diff --git a/autoenv.zsh b/autoenv.zsh index a46345f..f105c27 100644 --- a/autoenv.zsh +++ b/autoenv.zsh @@ -17,6 +17,8 @@ export AUTOENV_ENV_FILENAME=$HOME/.env_auth # event was handled? : ${AUTOENV_HANDLE_LEAVE:=1} +# Enable debugging. Multiple levels are supported (max 2). +: ${AUTOENV_DEBUG:=0} # Public helper functions, which can be used from your .env files: # @@ -27,6 +29,7 @@ autoenv_source_parent() { if [[ -n $parent_env_file ]] \ && _autoenv_check_authorized_env_file $parent_env_file; then + _autoenv_debug "Calling autoenv_source_parent: parent_env_file:$parent_env_file" local parent_env_dir=${parent_env_file:A:h} @@ -36,7 +39,7 @@ autoenv_source_parent() { fi } - +# Internal functions. {{{ # Internal: stack of entered (and handled) directories. {{{ _autoenv_stack_entered=() typeset -A _autoenv_stack_entered_mtime @@ -46,6 +49,8 @@ _autoenv_stack_entered_mtime=() _autoenv_stack_entered_add() { local env_file=$1 + _autoenv_debug "[stack] adding: $env_file" 2 + # Remove any existing entry. _autoenv_stack_entered_remove $env_file @@ -65,6 +70,7 @@ _autoenv_get_file_mtime() { # Remove an entry from the stack. _autoenv_stack_entered_remove() { local env_file=$1 + _autoenv_debug "[stack] removing: $env_file" 2 _autoenv_stack_entered[$_autoenv_stack_entered[(i)$env_file]]=() _autoenv_stack_entered_mtime[$env_file]= } @@ -83,6 +89,35 @@ _autoenv_stack_entered_contains() { } # }}} +# Internal function for debug output. {{{ +_autoenv_debug() { + local msg=$1 + local level=${2:-1} + if [[ $AUTOENV_DEBUG -lt $level ]]; then + return + fi + # Load zsh color support. + if [[ -z $colors ]]; then + autoload colors + colors + fi + # Build $indent prefix. + local indent= + if [[ $_autoenv_debug_indent -gt 0 ]]; then + for i in {1..${_autoenv_debug_indent}}; do + indent=" $indent" + done + fi + + # Split $msg by \n (not newline). + lines=(${(ps:\\n:)msg}) + for line in $lines; do + echo -n "${fg_bold[blue]}[autoenv]${fg_no_bold[default]} " >&2 + echo ${indent}${line} >&2 + done +} +# }}} + # Load zstat module, but only its builtin `zstat`. zmodload -F zsh/stat b:zstat @@ -172,7 +207,11 @@ _autoenv_source() { # Change to directory of env file, source it and cd back. local new_dir=$PWD builtin cd -q $_autoenv_envfile_dir + _autoenv_debug "== SOURCE: ${bold_color}$env_file${reset_color}\n PWD: $PWD" + (( _autoenv_debug_indent++ )) source $env_file + (( _autoenv_debug_indent-- )) + _autoenv_debug "== END SOURCE ==" builtin cd -q $new_dir # Unset vars set for enter/leave scripts. @@ -211,6 +250,8 @@ _autoenv_chpwd_prev_dir=$PWD _autoenv_chpwd_handler() { local env_file="$PWD/$AUTOENV_FILE_ENTER" + _autoenv_debug "Calling chpwd handler: PWD=$PWD" + # Handle leave event for previously sourced env files. if [[ $AUTOENV_HANDLE_LEAVE == 1 ]] && (( $#_autoenv_stack_entered )); then local prev_file prev_dir @@ -237,6 +278,7 @@ _autoenv_chpwd_handler() { # Load the env file only once: check if $env_file is in the stack of entered # directories. if _autoenv_stack_entered_contains $env_file; then + _autoenv_debug "Already in stack: $env_file" _autoenv_chpwd_prev_dir=$PWD return fi @@ -249,10 +291,14 @@ _autoenv_chpwd_handler() { _autoenv_stack_entered_add $env_file # Source the enter env file. + _autoenv_debug "Sourcing from chpwd handler: $env_file" _autoenv_source $env_file enter _autoenv_chpwd_prev_dir=$PWD + + (( _autoenv_debug_indent++ )) } +# }}} autoload -U add-zsh-hook add-zsh-hook chpwd _autoenv_chpwd_handler diff --git a/tests/.zshenv b/tests/.zshenv index d70711b..2311e2a 100644 --- a/tests/.zshenv +++ b/tests/.zshenv @@ -1,4 +1,6 @@ test -f "$TESTDIR/.zcompdump" && rm "$TESTDIR/.zcompdump" +AUTOENV_DEBUG=0 + source "$TESTDIR/../autoenv.plugin.zsh" export AUTOENV_ENV_FILENAME="$PWD/.env_auth" From 03fd619614bef8291b7185d03aa6db7d9d928da6 Mon Sep 17 00:00:00 2001 From: Daniel Hahler Date: Thu, 27 Nov 2014 13:31:44 +0100 Subject: [PATCH 22/23] Make env_shasum local in _autoenv_hash_pair --- autoenv.zsh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/autoenv.zsh b/autoenv.zsh index f105c27..034b7fe 100644 --- a/autoenv.zsh +++ b/autoenv.zsh @@ -124,7 +124,8 @@ zmodload -F zsh/stat b:zstat _autoenv_hash_pair() { local env_file=${1:A} - if (( $+2 )); then + local env_shasum + if [[ -n $2 ]]; then env_shasum=$2 else env_shasum=$(shasum $env_file | cut -d' ' -f1) From 5e18125f04ed1f59f1c03a7a6a573d64674aed22 Mon Sep 17 00:00:00 2001 From: Daniel Hahler Date: Thu, 27 Nov 2014 13:33:04 +0100 Subject: [PATCH 23/23] Improve interactive prompt - Revert usage of "read -q" for authentication (#10) - Change format of "not authenticated" message (#9) --- autoenv.zsh | 19 +++++++++++-------- tests/autoenv.t | 39 +++++++++++++++++---------------------- tests/leave.t | 21 ++++++++++++--------- tests/recurse-upwards.t | 14 ++++++++------ tests/setup.sh | 3 --- 5 files changed, 48 insertions(+), 48 deletions(-) diff --git a/autoenv.zsh b/autoenv.zsh index 034b7fe..f770d8a 100644 --- a/autoenv.zsh +++ b/autoenv.zsh @@ -154,10 +154,14 @@ _autoenv_deauthorize() { } # This function can be mocked in tests -_autoenv_read_answer() { +_autoenv_ask_for_yes() { local answer - read $=_AUTOENV_TEST_READ_ARGS -q answer - echo $answer + read answer + if [[ $answer == "yes" ]]; then + return 0 + else + return 1 + fi } # Args: 1: absolute path to env file (resolved symlinks). @@ -166,7 +170,8 @@ _autoenv_check_authorized_env_file() { return 1 fi if ! _autoenv_authorized_env_file $1; then - echo "Attempting to load unauthorized env file: $1" + echo "Attempting to load unauthorized env file!" + command ls -l $1 echo "" echo "**********************************************" echo "" @@ -174,11 +179,9 @@ _autoenv_check_authorized_env_file() { echo "" echo "**********************************************" echo "" - echo -n "Would you like to authorize it? [y/N] " + echo -n "Would you like to authorize it? (type 'yes') " - local answer=$(_autoenv_read_answer) - echo - if [[ $answer != 'y' ]]; then + if ! _autoenv_ask_for_yes; then return 1 fi diff --git a/tests/autoenv.t b/tests/autoenv.t index f78560a..19d0592 100644 --- a/tests/autoenv.t +++ b/tests/autoenv.t @@ -14,9 +14,10 @@ Now try to make it accept it $ unset _autoenv_stack_entered $ rm $AUTOENV_ENV_FILENAME - $ _autoenv_read_answer() { echo 'y' } + $ _autoenv_ask_for_yes() { echo "yes" } $ cd . - Attempting to load unauthorized env file: /tmp/cramtests-??????/autoenv.t/.env (glob) + Attempting to load unauthorized env file! + -* /tmp/cramtests-*/autoenv.t/.env (glob) ********************************************** @@ -24,16 +25,13 @@ Now try to make it accept it ********************************************** - Would you like to authorize it? [y/N] + Would you like to authorize it? (type 'yes') yes ENTERED +The last "ENTERED" is because it executed the command. - - -The last "ENTERED" is because it executed the command - -Now lets see that it actually checks the shasum value +Now lets see that it actually checks the shasum value. $ unset _autoenv_stack_entered $ cd . @@ -43,7 +41,8 @@ Now lets see that it actually checks the shasum value $ rm $AUTOENV_ENV_FILENAME $ test_autoenv_add_to_env $PWD/.env mischief $ cd . - Attempting to load unauthorized env file: /tmp/cramtests-??????/autoenv.t/.env (glob) + Attempting to load unauthorized env file! + -* /tmp/cramtests-*/autoenv.t/.env (glob) ********************************************** @@ -51,20 +50,18 @@ Now lets see that it actually checks the shasum value ********************************************** - Would you like to authorize it? [y/N] + Would you like to authorize it? (type 'yes') yes ENTERED - - - Now, will it take no for an answer? $ unset _autoenv_stack_entered $ rm $AUTOENV_ENV_FILENAME - $ _autoenv_read_answer() { echo 'n' } + $ _autoenv_ask_for_yes() { echo "no"; return 1 } $ cd . - Attempting to load unauthorized env file: /tmp/cramtests-??????/autoenv.t/.env (glob) + Attempting to load unauthorized env file! + -* /tmp/cramtests-*/autoenv.t/.env (glob) ********************************************** @@ -72,16 +69,14 @@ Now, will it take no for an answer? ********************************************** - Would you like to authorize it? [y/N] + Would you like to authorize it? (type 'yes') no - - - -Lets also try one more time to ensure it didnt add it +Lets also try one more time to ensure it didn't add it. $ cd . - Attempting to load unauthorized env file: /tmp/cramtests-??????/autoenv.t/.env (glob) + Attempting to load unauthorized env file! + -* /tmp/cramtests-*/autoenv.t/.env (glob) ********************************************** @@ -89,4 +84,4 @@ Lets also try one more time to ensure it didnt add it ********************************************** - Would you like to authorize it? [y/N] + Would you like to authorize it? (type 'yes') no diff --git a/tests/leave.t b/tests/leave.t index d5531b1..2e4e360 100644 --- a/tests/leave.t +++ b/tests/leave.t @@ -9,9 +9,10 @@ Lets set a simple .env action Change to the directory. - $ _autoenv_read_answer() { echo 'y' } + $ _autoenv_ask_for_yes() { echo "yes"; return 0 } $ cd . - Attempting to load unauthorized env file: /tmp/cramtests-??????/leave.t/sub/.env (glob) + Attempting to load unauthorized env file! + -* /tmp/cramtests-*/leave.t/sub/.env (glob) ********************************************** @@ -19,15 +20,16 @@ Change to the directory. ********************************************** - Would you like to authorize it? [y/N] + Would you like to authorize it? (type 'yes') yes ENTERED Leave the directory and answer "no". - $ _autoenv_read_answer() { echo 'n' } + $ _autoenv_ask_for_yes() { echo "no"; return 1 } $ cd .. - Attempting to load unauthorized env file: /tmp/cramtests-??????/leave.t/sub/.env.leave (glob) + Attempting to load unauthorized env file! + -* /tmp/cramtests-*/leave.t/sub/.env.leave (glob) ********************************************** @@ -35,14 +37,15 @@ Leave the directory and answer "no". ********************************************** - Would you like to authorize it? [y/N] + Would you like to authorize it? (type 'yes') no $ cd sub ENTERED - $ _autoenv_read_answer() { echo 'y' } + $ _autoenv_ask_for_yes() { echo "yes"; return 0 } $ cd .. - Attempting to load unauthorized env file: /tmp/cramtests-??????/leave.t/sub/.env.leave (glob) + Attempting to load unauthorized env file! + -* /tmp/cramtests-*/leave.t/sub/.env.leave (glob) ********************************************** @@ -50,7 +53,7 @@ Leave the directory and answer "no". ********************************************** - Would you like to authorize it? [y/N] + Would you like to authorize it? (type 'yes') yes LEFT diff --git a/tests/recurse-upwards.t b/tests/recurse-upwards.t index 7a6f28f..f4c2780 100644 --- a/tests/recurse-upwards.t +++ b/tests/recurse-upwards.t @@ -110,10 +110,11 @@ Changing the root .env should trigger re-authentication via autoenv_source_paren First, let's answer "no". $ echo "echo NEW" > .env - $ _autoenv_read_answer() { echo 'n' } + $ _autoenv_ask_for_yes() { echo "no"; return 1 } $ cd sub autoenv_source_parent_from_sub: - Attempting to load unauthorized env file: /tmp/cramtests-*/recurse-upwards.t/.env (glob) + Attempting to load unauthorized env file! + -* /tmp/cramtests-*/recurse-upwards.t/.env (glob) ********************************************** @@ -121,7 +122,7 @@ First, let's answer "no". ********************************************** - Would you like to authorize it? [y/N] + Would you like to authorize it? (type 'yes') no ENTERED_sub: PWD:sub from:recurse-upwards.t to:sub ENTER2 done_sub @@ -129,7 +130,7 @@ First, let's answer "no". Now with "yes". This currently does not trigger re-execution of the .env file. - $ _autoenv_read_answer() { echo 'y' } + $ _autoenv_ask_for_yes() { echo "yes"; return 0 } $ cd . Touching the .env file will now source the parent env file. @@ -137,7 +138,8 @@ Touching the .env file will now source the parent env file. $ touch -t 201401010104 .env $ cd . autoenv_source_parent_from_sub: - Attempting to load unauthorized env file: /tmp/cramtests-*/recurse-upwards.t/.env (glob) + Attempting to load unauthorized env file! + -* /tmp/cramtests-*/recurse-upwards.t/.env (glob) ********************************************** @@ -145,7 +147,7 @@ Touching the .env file will now source the parent env file. ********************************************** - Would you like to authorize it? [y/N] + Would you like to authorize it? (type 'yes') yes NEW ENTERED_sub: PWD:sub from:sub to:sub ENTER2 diff --git a/tests/setup.sh b/tests/setup.sh index d5a4f6e..90bfc51 100644 --- a/tests/setup.sh +++ b/tests/setup.sh @@ -6,9 +6,6 @@ # Reset any authentication. echo -n > $AUTOENV_ENV_FILENAME -# Inject timeout for `read` while running tests. -_AUTOENV_TEST_READ_ARGS='-t 1' - # Add file $1 (with optional hash $2) to authentication file. test_autoenv_add_to_env() { _autoenv_hash_pair $1 $2 >> $AUTOENV_ENV_FILENAME