From 1e60c98e4a8e7a31c3329c738631b04fdd607dfe Mon Sep 17 00:00:00 2001 From: Daniel Hahler Date: Sat, 15 Nov 2014 13:59:42 +0100 Subject: [PATCH 01/72] Use escaped grep command, skipping aliases --- autoenv.zsh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/autoenv.zsh b/autoenv.zsh index ff8b4a7..bb001aa 100644 --- a/autoenv.zsh +++ b/autoenv.zsh @@ -24,7 +24,7 @@ _dotenv_authorize() { _dotenv_deauthorize() { env_file=$1 - echo $(grep -Gv $env_file $ENV_AUTHORIZATION_FILE) > $ENV_AUTHORIZATION_FILE + echo $(\grep -Gv $env_file $ENV_AUTHORIZATION_FILE) > $ENV_AUTHORIZATION_FILE } _dotenv_print_unauthorized_message() { From 41625bf31cb960e8e86ce03bc013cad14fdf96e8 Mon Sep 17 00:00:00 2001 From: Daniel Hahler Date: Sat, 15 Nov 2014 14:49:48 +0100 Subject: [PATCH 02/72] Use 'local' in functions --- autoenv.zsh | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/autoenv.zsh b/autoenv.zsh index bb001aa..51ccca0 100644 --- a/autoenv.zsh +++ b/autoenv.zsh @@ -4,26 +4,26 @@ export ENV_AUTHORIZATION_FILE=$HOME/.env_auth _dotenv_hash_pair() { - env_file=$1 + local env_file=$1 env_shasum=$(shasum $env_file | cut -d' ' -f1) echo "$env_file:$env_shasum" } _dotenv_authorized_env_file() { - env_file=$1 - pair=$(_dotenv_hash_pair $env_file) + local env_file=$1 + local pair=$(_dotenv_hash_pair $env_file) touch $ENV_AUTHORIZATION_FILE \grep -Gq $pair $ENV_AUTHORIZATION_FILE } _dotenv_authorize() { - env_file=$1 + local env_file=$1 _dotenv_deauthorize $env_file _dotenv_hash_pair $env_file >> $ENV_AUTHORIZATION_FILE } _dotenv_deauthorize() { - env_file=$1 + local env_file=$1 echo $(\grep -Gv $env_file $ENV_AUTHORIZATION_FILE) > $ENV_AUTHORIZATION_FILE } From 4676713bc6539f5bdf3a26cb21b6091ddf8b1451 Mon Sep 17 00:00:00 2001 From: Daniel Hahler Date: Sat, 15 Nov 2014 15:08:52 +0100 Subject: [PATCH 03/72] Various improvements - Support for leave event, via DOTENV_FILE_LEAVE and _dotenv_event (can use DOTENV_FILE_LEAVE=$DOTENV_FILE_ENTER). - Support for searching upwards for $DOTENV_FILE_ENTER (#3). - Source .env only once per session, but re-source when leave events are enabled (#1). - Trigger the machinery when the script gets sourced, for the current dir (#2). --- autoenv.zsh | 95 +++++++++++++++++++++++++++++++++++++++---------- tests/autoenv.t | 47 +++++++++++++----------- tests/leave.t | 80 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 183 insertions(+), 39 deletions(-) create mode 100644 tests/leave.t diff --git a/autoenv.zsh b/autoenv.zsh index 51ccca0..313378b 100644 --- a/autoenv.zsh +++ b/autoenv.zsh @@ -1,8 +1,19 @@ # Stolen from # https://github.com/joshuaclayton/dotfiles/blob/master/zsh_profile.d/autoenv.zsh +# TODO: move this to DOTENV_*?! export ENV_AUTHORIZATION_FILE=$HOME/.env_auth +: ${DOTENV_FILE_ENTER:=.env} +: ${DOTENV_FILE_LEAVE:=.env.leave} + +# Look for .env in parent dirs? +: ${DOTENV_LOOK_UPWARDS:=0} + +# Handle leave events, when leaving ? +: ${DOTENV_HANDLE_LEAVE:=1} + + _dotenv_hash_pair() { local env_file=$1 env_shasum=$(shasum $env_file | cut -d' ' -f1) @@ -28,7 +39,7 @@ _dotenv_deauthorize() { } _dotenv_print_unauthorized_message() { - echo "Attempting to load unauthorized env: $1" + echo "Attempting to load unauthorized env file: $1" echo "" echo "**********************************************" echo "" @@ -36,35 +47,83 @@ _dotenv_print_unauthorized_message() { echo "" echo "**********************************************" echo "" - echo "Would you like to authorize it? (y/n)" + echo -n "Would you like to authorize it? [y/N] " } # This function can be mocked in tests _dotenv_read_answer() { - read answer + local answer + read -q answer + echo $answer } -_dotenv_source_env() { - local env_file="$PWD/.env" +_dotenv_check_authorized_env_file() { + if ! _dotenv_authorized_env_file $1; then + _dotenv_print_unauthorized_message $1 - if [[ -f $env_file ]] - then - if _dotenv_authorized_env_file $env_file - then - source $env_file - return 0 + local answer=$(_dotenv_read_answer) + echo + if [[ $answer != 'y' ]]; then + return 1 fi - _dotenv_print_unauthorized_message $env_file + _dotenv_authorize $1 + fi + return 0 +} - _dotenv_read_answer +_dotenv_stack_entered=() - if [[ $answer == 'y' ]] - then - _dotenv_authorize $env_file - source $env_file +_dotenv_chpwd_handler() { + local env_file="$PWD/$DOTENV_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 ! [[ ${PWD}/ == ${prev_dir}/* ]]; then + local env_file_leave=$prev_dir/$DOTENV_FILE_LEAVE + if _dotenv_check_authorized_env_file $env_file_leave; then + _dotenv_event=leave + source $env_file_leave + unset _dotenv_event + fi + # Remove this entry from the stack. + _dotenv_stack_entered=(${_dotenv_stack_entered#$prev_dir}) + fi + done + fi + + if ! [[ -f $env_file ]] && [[ $DOTENV_LOOK_UPWARDS == 1 ]]; then + setopt localoptions extendedglob + local m + m=((../)#${DOTENV_FILE_ENTER}(N)) + if (( $#m )); then + env_file=$m[1] fi fi + + if ! [[ -f $env_file ]]; then + return + fi + + if ! _dotenv_check_authorized_env_file $env_file; then + return + fi + + # Load the env file only once. + if (( ${+_dotenv_stack_entered[(r)${env_file:A:h}]} )); then + return + fi + + _dotenv_stack_entered+=(${env_file:A:h}) + + _dotenv_event=enter + source $env_file + unset _dotenv_event } -chpwd_functions=($chpwd_functions _dotenv_source_env) +autoload -U add-zsh-hook +add-zsh-hook chpwd _dotenv_chpwd_handler + +# Look in current directory already. +_dotenv_chpwd_handler diff --git a/tests/autoenv.t b/tests/autoenv.t index c4f1f41..f3ede0c 100644 --- a/tests/autoenv.t +++ b/tests/autoenv.t @@ -4,53 +4,57 @@ Ensure we have our mocked out ENV_AUTHORIZATION_FILE Lets set a simple .env action - $ echo 'echo blah' >> .env + $ echo 'echo ENTERED' >> .env Manually create auth file - $ echo "$PWD/.env:$(echo echo blah | shasum)" > $ENV_AUTHORIZATION_FILE + $ echo "$PWD/.env:$(echo echo ENTERED | shasum)" > $ENV_AUTHORIZATION_FILE $ cd . - blah + ENTERED Now try to make it accept it + $ unset _dotenv_stack_entered $ rm $ENV_AUTHORIZATION_FILE - $ _dotenv_read_answer() { answer='y' } + $ _dotenv_read_answer() { echo 'y' } $ cd . - Attempting to load unauthorized env: /tmp/cramtests-??????/autoenv.t/.env (glob) + Attempting to load unauthorized env file: /tmp/cramtests-??????/autoenv.t/.env (glob) ********************************************** - echo blah + echo ENTERED ********************************************** - Would you like to authorize it? (y/n) - blah + Would you like to authorize it? [y/N] + ENTERED -The last "blah" 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 + $ unset _dotenv_stack_entered $ cd . - blah + ENTERED + + $ unset _dotenv_stack_entered $ rm $ENV_AUTHORIZATION_FILE $ echo "$PWD/.env:$(echo mischief | shasum)" > $ENV_AUTHORIZATION_FILE $ cd . - Attempting to load unauthorized env: /tmp/cramtests-??????/autoenv.t/.env (glob) + Attempting to load unauthorized env file: /tmp/cramtests-??????/autoenv.t/.env (glob) ********************************************** - echo blah + echo ENTERED ********************************************** - Would you like to authorize it? (y/n) - blah + Would you like to authorize it? [y/N] + ENTERED @@ -58,18 +62,19 @@ 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 - $ _dotenv_read_answer() { answer='n' } + $ _dotenv_read_answer() { echo 'n' } $ cd . - Attempting to load unauthorized env: /tmp/cramtests-??????/autoenv.t/.env (glob) + Attempting to load unauthorized env file: /tmp/cramtests-??????/autoenv.t/.env (glob) ********************************************** - echo blah + echo ENTERED ********************************************** - Would you like to authorize it? (y/n) + Would you like to authorize it? [y/N] @@ -78,12 +83,12 @@ Now, will it take no for an answer? Lets also try one more time to ensure it didnt add it $ cd . - Attempting to load unauthorized env: /tmp/cramtests-??????/autoenv.t/.env (glob) + Attempting to load unauthorized env file: /tmp/cramtests-??????/autoenv.t/.env (glob) ********************************************** - echo blah + echo ENTERED ********************************************** - Would you like to authorize it? (y/n) + Would you like to authorize it? [y/N] diff --git a/tests/leave.t b/tests/leave.t new file mode 100644 index 0000000..2954878 --- /dev/null +++ b/tests/leave.t @@ -0,0 +1,80 @@ +Ensure we have our mocked out ENV_AUTHORIZATION_FILE + + $ [[ $ENV_AUTHORIZATION_FILE[0,4] == '/tmp' ]] || return 1 + + +Lets set a simple .env action + + $ mkdir sub + $ cd sub + $ echo 'echo ENTERED' >> .env + $ echo 'echo LEFT' >> .env.leave + +Change to the directory. + + $ _dotenv_read_answer() { echo 'y' } + $ cd . + Attempting to load unauthorized env file: /tmp/cramtests-??????/leave.t/sub/.env (glob) + + ********************************************** + + echo ENTERED + + ********************************************** + + Would you like to authorize it? [y/N] + ENTERED + + +Leave the directory and answer "no". + + $ _dotenv_read_answer() { echo 'n' } + $ cd .. + Attempting to load unauthorized env file: /tmp/cramtests-??????/leave.t/sub/.env.leave (glob) + + ********************************************** + + echo LEFT + + ********************************************** + + Would you like to authorize it? [y/N] + + + $ cd sub + ENTERED + $ _dotenv_read_answer() { echo 'y' } + $ cd .. + Attempting to load unauthorized env file: /tmp/cramtests-??????/leave.t/sub/.env.leave (glob) + + ********************************************** + + echo LEFT + + ********************************************** + + Would you like to authorize it? [y/N] + LEFT + + +Now check with subdirs, looking upwards. + + $ DOTENV_LOOK_UPWARDS=1 + $ mkdir sub/child + $ cd sub/child + ENTERED + $ cd . + $ cd .. + $ cd .. + LEFT + + +Now check with subdirs, not looking at parent dirs. + + $ DOTENV_LOOK_UPWARDS=0 + $ cd sub/child + $ cd .. + ENTERED + $ cd child + $ cd ../.. + LEFT From 1d3e5b69a7ed2ec112f47f6b684534c727a02fa7 Mon Sep 17 00:00:00 2001 From: Daniel Hahler Date: Sat, 15 Nov 2014 15:25:20 +0100 Subject: [PATCH 04/72] Add a test for DOTENV_HANDLE_LEAVE=0 --- tests/leave.t | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/tests/leave.t b/tests/leave.t index 2954878..770b310 100644 --- a/tests/leave.t +++ b/tests/leave.t @@ -78,3 +78,13 @@ Now check with subdirs, not looking at parent dirs. $ cd child $ cd ../.. LEFT + + +Test that .env is sourced only once with DOTENV_HANDLE_LEAVE=0. + + $ unset _dotenv_stack_entered + $ DOTENV_HANDLE_LEAVE=0 + $ cd sub + ENTERED + $ cd .. + $ cd sub From 4662727a22d4235d54377d53f838ef373cf51206 Mon Sep 17 00:00:00 2001 From: Daniel Hahler Date: Sat, 15 Nov 2014 15:48:57 +0100 Subject: [PATCH 05/72] Cleanup, and fixes (absolute path for env_file) --- autoenv.zsh | 55 ++++++++++++++++++++++++++++------------------------- 1 file changed, 29 insertions(+), 26 deletions(-) diff --git a/autoenv.zsh b/autoenv.zsh index 313378b..265482b 100644 --- a/autoenv.zsh +++ b/autoenv.zsh @@ -1,19 +1,28 @@ -# Stolen from +# 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 +# Name of file to look for when entering directories. : ${DOTENV_FILE_ENTER:=.env} + +# Name of file to look for when leaving directories. +# Requires DOTENV_HANDLE_LEAVE=1. : ${DOTENV_FILE_LEAVE:=.env.leave} # Look for .env in parent dirs? : ${DOTENV_LOOK_UPWARDS:=0} -# Handle leave events, when leaving ? +# Handle leave events when changing away from a subtree, where an "enter" +# event was handled? : ${DOTENV_HANDLE_LEAVE:=1} +# Internal: stack of entered (and handled) directories. +_dotenv_stack_entered=() + + _dotenv_hash_pair() { local env_file=$1 env_shasum=$(shasum $env_file | cut -d' ' -f1) @@ -23,8 +32,8 @@ _dotenv_hash_pair() { _dotenv_authorized_env_file() { local env_file=$1 local pair=$(_dotenv_hash_pair $env_file) - touch $ENV_AUTHORIZATION_FILE - \grep -Gq $pair $ENV_AUTHORIZATION_FILE + test -f $ENV_AUTHORIZATION_FILE \ + && \grep -qF $pair $ENV_AUTHORIZATION_FILE } _dotenv_authorize() { @@ -35,19 +44,9 @@ _dotenv_authorize() { _dotenv_deauthorize() { local env_file=$1 - echo $(\grep -Gv $env_file $ENV_AUTHORIZATION_FILE) > $ENV_AUTHORIZATION_FILE -} - -_dotenv_print_unauthorized_message() { - echo "Attempting to load unauthorized env file: $1" - echo "" - echo "**********************************************" - echo "" - cat $1 - echo "" - echo "**********************************************" - echo "" - echo -n "Would you like to authorize it? [y/N] " + if [[ -f $ENV_AUTHORIZATION_FILE ]]; then + echo $(\grep -vF $env_file $ENV_AUTHORIZATION_FILE) > $ENV_AUTHORIZATION_FILE + fi } # This function can be mocked in tests @@ -59,7 +58,15 @@ _dotenv_read_answer() { _dotenv_check_authorized_env_file() { if ! _dotenv_authorized_env_file $1; then - _dotenv_print_unauthorized_message $1 + echo "Attempting to load unauthorized env file: $1" + echo "" + echo "**********************************************" + echo "" + cat $1 + echo "" + echo "**********************************************" + echo "" + echo -n "Would you like to authorize it? [y/N] " local answer=$(_dotenv_read_answer) echo @@ -72,8 +79,6 @@ _dotenv_check_authorized_env_file() { return 0 } -_dotenv_stack_entered=() - _dotenv_chpwd_handler() { local env_file="$PWD/$DOTENV_FILE_ENTER" @@ -98,15 +103,13 @@ _dotenv_chpwd_handler() { local m m=((../)#${DOTENV_FILE_ENTER}(N)) if (( $#m )); then - env_file=$m[1] + env_file=${${m[1]}:A} + else + return fi fi - if ! [[ -f $env_file ]]; then - return - fi - - if ! _dotenv_check_authorized_env_file $env_file; then + if ! [[ -f $env_file ]] || ! _dotenv_check_authorized_env_file $env_file; then return fi From d114d0a0ea09c4ad53c244e7c1f6b31c47f0d14e Mon Sep 17 00:00:00 2001 From: Daniel Hahler Date: Sat, 15 Nov 2014 16:09:02 +0100 Subject: [PATCH 06/72] Check for file existence in _dotenv_check_authorized_env_file --- autoenv.zsh | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/autoenv.zsh b/autoenv.zsh index 265482b..fe1fa87 100644 --- a/autoenv.zsh +++ b/autoenv.zsh @@ -57,6 +57,9 @@ _dotenv_read_answer() { } _dotenv_check_authorized_env_file() { + if ! [[ -f $1 ]]; then + return 1 + fi if ! _dotenv_authorized_env_file $1; then echo "Attempting to load unauthorized env file: $1" echo "" @@ -109,7 +112,7 @@ _dotenv_chpwd_handler() { fi fi - if ! [[ -f $env_file ]] || ! _dotenv_check_authorized_env_file $env_file; then + if ! _dotenv_check_authorized_env_file $env_file; then return fi From a37b0bc3f500c062dedd5881a788d97743bdfa0a Mon Sep 17 00:00:00 2001 From: Daniel Hahler Date: Sat, 15 Nov 2014 16:09:37 +0100 Subject: [PATCH 07/72] Wrap sourcing in _dotenv_source: chdir and set _dotenv_cwd=$PWD --- autoenv.zsh | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/autoenv.zsh b/autoenv.zsh index fe1fa87..4fcde08 100644 --- a/autoenv.zsh +++ b/autoenv.zsh @@ -82,6 +82,18 @@ _dotenv_check_authorized_env_file() { return 0 } +_dotenv_source() { + local env_file=$1 + _dotenv_event=$2 + _dotenv_cwd=$PWD + + cd -q ${env_file:h} + source $env_file + cd -q - + + unset _dotenv_event _dotenv_cwd +} + _dotenv_chpwd_handler() { local env_file="$PWD/$DOTENV_FILE_ENTER" @@ -91,9 +103,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_event=leave - source $env_file_leave - unset _dotenv_event + _dotenv_source $env_file_leave leave fi # Remove this entry from the stack. _dotenv_stack_entered=(${_dotenv_stack_entered#$prev_dir}) @@ -123,9 +133,7 @@ _dotenv_chpwd_handler() { _dotenv_stack_entered+=(${env_file:A:h}) - _dotenv_event=enter - source $env_file - unset _dotenv_event + _dotenv_source $env_file enter } autoload -U add-zsh-hook From 71ed15679b24f74385010bd710780811deed4ab0 Mon Sep 17 00:00:00 2001 From: Daniel Hahler Date: Sat, 15 Nov 2014 17:04:36 +0100 Subject: [PATCH 08/72] _dotenv_source: use 'builtin cd' and stored dir instead of 'cd -' --- autoenv.zsh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/autoenv.zsh b/autoenv.zsh index 4fcde08..a09e57b 100644 --- a/autoenv.zsh +++ b/autoenv.zsh @@ -87,9 +87,9 @@ _dotenv_source() { _dotenv_event=$2 _dotenv_cwd=$PWD - cd -q ${env_file:h} + builtin cd -q ${env_file:h} source $env_file - cd -q - + builtin cd -q $_dotenv_cwd unset _dotenv_event _dotenv_cwd } From 64bbb2f305b1819727c35f75b759c3c2dfe49163 Mon Sep 17 00:00:00 2001 From: Daniel Hahler Date: Sun, 16 Nov 2014 11:39:10 +0100 Subject: [PATCH 09/72] doc / small refactoring according to feedback --- autoenv.zsh | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/autoenv.zsh b/autoenv.zsh index a09e57b..723fe60 100644 --- a/autoenv.zsh +++ b/autoenv.zsh @@ -56,6 +56,7 @@ _dotenv_read_answer() { echo $answer } +# Args: 1: absolute path to env file (resolved symlinks). _dotenv_check_authorized_env_file() { if ! [[ -f $1 ]]; then return 1 @@ -112,6 +113,7 @@ _dotenv_chpwd_handler() { fi if ! [[ -f $env_file ]] && [[ $DOTENV_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)) @@ -126,12 +128,14 @@ _dotenv_chpwd_handler() { return fi - # Load the env file only once. - if (( ${+_dotenv_stack_entered[(r)${env_file:A:h}]} )); then + # Load the env file only once: check if $env_file's parent + # is in $_dotenv_stack_entered. + local env_file_dir=${env_file:A:h} + if (( ${+_dotenv_stack_entered[(r)${env_file_dir}]} )); then return fi - _dotenv_stack_entered+=(${env_file:A:h}) + _dotenv_stack_entered+=(${env_file_dir}) _dotenv_source $env_file enter } From 98f0ec81feee458c9a112993cbc4c76fb2625203 Mon Sep 17 00:00:00 2001 From: Daniel Hahler Date: Sun, 16 Nov 2014 11:40:09 +0100 Subject: [PATCH 10/72] Use 'test' as target for tests (common sense) --- .travis.yml | 2 +- Makefile | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index b56caf2..00828ba 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,4 +4,4 @@ python: before_script: - "sudo apt-get install zsh" install: "sudo pip install cram" -script: "make tests" +script: "make test" diff --git a/Makefile b/Makefile index bed40b1..a769734 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ -.PHONY: itests tests +.PHONY: itest test -itests: +itest: ZDOTDIR="${PWD}/tests" cram -i --shell=zsh tests -tests: +test: ZDOTDIR="${PWD}/tests" cram --shell=zsh tests From b25f6b14dc58fb1b374407805a7df1d4870bc4fc Mon Sep 17 00:00:00 2001 From: Daniel Hahler Date: Sun, 16 Nov 2014 12:05:16 +0100 Subject: [PATCH 11/72] Add tests for $PWD during enter and leave events --- tests/cwd.t | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 tests/cwd.t diff --git a/tests/cwd.t b/tests/cwd.t new file mode 100644 index 0000000..9764e74 --- /dev/null +++ b/tests/cwd.t @@ -0,0 +1,29 @@ +Test $PWD and $_dotenv_cwd. + +Ensure we have our mocked out ENV_AUTHORIZATION_FILE. + + $ [[ $ENV_AUTHORIZATION_FILE[0,4] == '/tmp' ]] || return 1 + +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 + +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 + +The actual tests. + + $ cd . + ENTERED: cwd:sub sub + + $ cd .. + LEFT: cwd:sub cwd.t + + $ cd sub/sub2 + ENTERED: cwd:sub sub2 From f8a9942968f9fa2644c223c26eb0a92411d806c3 Mon Sep 17 00:00:00 2001 From: Daniel Hahler Date: Sun, 16 Nov 2014 12:35:17 +0100 Subject: [PATCH 12/72] Set DOTENV_LOOK_UPWARDS=1 by default Fixes https://github.com/Tarrasch/zsh-autoenv/issues/3 --- autoenv.zsh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/autoenv.zsh b/autoenv.zsh index 723fe60..60c8d03 100644 --- a/autoenv.zsh +++ b/autoenv.zsh @@ -12,7 +12,7 @@ export ENV_AUTHORIZATION_FILE=$HOME/.env_auth : ${DOTENV_FILE_LEAVE:=.env.leave} # Look for .env in parent dirs? -: ${DOTENV_LOOK_UPWARDS:=0} +: ${DOTENV_LOOK_UPWARDS:=1} # Handle leave events when changing away from a subtree, where an "enter" # event was handled? From 9cb032a54c02dee2e3de6392698b2faaaf281901 Mon Sep 17 00:00:00 2001 From: Daniel Hahler Date: Mon, 24 Nov 2014 18:05:31 +0100 Subject: [PATCH 13/72] 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 14/72] 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 15/72] 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 16/72] 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 17/72] 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 18/72] 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 19/72] 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 20/72] 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 21/72] 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 22/72] 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 23/72] 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 24/72] 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 25/72] 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 26/72] 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 27/72] 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 28/72] 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 29/72] 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 30/72] 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 31/72] 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 32/72] 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 33/72] 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 34/72] 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 35/72] 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 From d2f447e44513080b23303432587fa813d3586224 Mon Sep 17 00:00:00 2001 From: Daniel Hahler Date: Sat, 29 Nov 2014 13:56:28 +0100 Subject: [PATCH 36/72] Use ${PWD:A} when checking for leave event Use the absolute path when comparing to the absolute path of the previously entered dirs. --- autoenv.zsh | 2 +- tests/cwd.t | 11 +++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/autoenv.zsh b/autoenv.zsh index f770d8a..1211f9c 100644 --- a/autoenv.zsh +++ b/autoenv.zsh @@ -261,7 +261,7 @@ _autoenv_chpwd_handler() { local prev_file prev_dir for prev_file in ${_autoenv_stack_entered}; do prev_dir=${prev_file:A:h} - if ! [[ ${PWD}/ == ${prev_dir}/* ]]; then + if ! [[ ${PWD:A}/ == ${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 diff --git a/tests/cwd.t b/tests/cwd.t index ea77aa0..32687c2 100644 --- a/tests/cwd.t +++ b/tests/cwd.t @@ -24,3 +24,14 @@ The actual tests. $ cd sub/sub2 ENTERED: PWD:sub from:cwd.t to:sub2 + +Check that symlinked dirs get handled correctly. + + $ cd ../.. + LEFT: PWD:sub from:sub2 to:cwd.t + $ ln -s sub sub_linked + $ cd sub_linked + ENTERED: PWD:sub from:cwd.t to:sub_linked + $ cd sub2 + ENTERED: PWD:sub from:sub_linked to:sub2 + $ cd . From 364c0fbb2aa7b072832bb61e1d4562ac1f0e4b7b Mon Sep 17 00:00:00 2001 From: Daniel Hahler Date: Tue, 2 Dec 2014 18:49:23 +0100 Subject: [PATCH 37/72] Remove underscore prefix from vars provided for .env files Fixes https://github.com/Tarrasch/zsh-autoenv/issues/11 --- autoenv.zsh | 8 ++++---- tests/cwd.t | 18 +++++++++--------- tests/recurse-upwards.t | 8 ++++---- 3 files changed, 17 insertions(+), 17 deletions(-) diff --git a/autoenv.zsh b/autoenv.zsh index 1211f9c..23866f3 100644 --- a/autoenv.zsh +++ b/autoenv.zsh @@ -195,11 +195,11 @@ _autoenv_source_dir=${0:A:h} _autoenv_source() { local env_file=$1 - _autoenv_event=$2 + autoenv_event=$2 local _autoenv_envfile_dir=${3:-${1:A:h}} - _autoenv_from_dir=$_autoenv_chpwd_prev_dir - _autoenv_to_dir=$PWD + autoenv_from_dir=$_autoenv_chpwd_prev_dir + autoenv_to_dir=$PWD # Source varstash library once. if [[ -z "$functions[(I)autostash]" ]]; then @@ -221,7 +221,7 @@ _autoenv_source() { # 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 + # unset autoenv_event autoenv_from_dir autoenv_to_dir } _autoenv_get_file_upwards() { diff --git a/tests/cwd.t b/tests/cwd.t index 32687c2..60a2d50 100644 --- a/tests/cwd.t +++ b/tests/cwd.t @@ -1,4 +1,4 @@ -Test $PWD, $_autoenv_from_dir and _autoenv_to_dir. +Test $PWD, $autoenv_event, $autoenv_from_dir and $autoenv_to_dir. $ source $TESTDIR/setup.sh @@ -7,8 +7,8 @@ Setup env actions / output. $ AUTOENV_LOOK_UPWARDS=1 $ mkdir -p sub/sub2 $ cd sub - $ 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 + $ echo 'echo ENTERED: PWD:${PWD:t} from:${autoenv_from_dir:t} to:${autoenv_to_dir:t} event:${autoenv_event}' > .env + $ echo 'echo LEFT: PWD:${PWD:t} from:${autoenv_from_dir:t} to:${autoenv_to_dir:t} event:${autoenv_event}' > .env.leave Manually create auth files. @@ -17,21 +17,21 @@ Manually create auth files. The actual tests. $ cd . - ENTERED: PWD:sub from:sub to:sub + ENTERED: PWD:sub from:sub to:sub event:enter $ cd .. - LEFT: PWD:sub from:sub to:cwd.t + LEFT: PWD:sub from:sub to:cwd.t event:leave $ cd sub/sub2 - ENTERED: PWD:sub from:cwd.t to:sub2 + ENTERED: PWD:sub from:cwd.t to:sub2 event:enter Check that symlinked dirs get handled correctly. $ cd ../.. - LEFT: PWD:sub from:sub2 to:cwd.t + LEFT: PWD:sub from:sub2 to:cwd.t event:leave $ ln -s sub sub_linked $ cd sub_linked - ENTERED: PWD:sub from:cwd.t to:sub_linked + ENTERED: PWD:sub from:cwd.t to:sub_linked event:enter $ cd sub2 - ENTERED: PWD:sub from:sub_linked to:sub2 + ENTERED: PWD:sub from:sub_linked to:sub2 event:enter $ cd . diff --git a/tests/recurse-upwards.t b/tests/recurse-upwards.t index f4c2780..aa36edd 100644 --- a/tests/recurse-upwards.t +++ b/tests/recurse-upwards.t @@ -8,8 +8,8 @@ Setup env actions / output. 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 + $ 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. @@ -18,8 +18,8 @@ Create env files in sub dir. $ cd 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 + $ 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. From 4ed8aa2be31ffb5ff1544a7ee943a94342eee4be Mon Sep 17 00:00:00 2001 From: Daniel Hahler Date: Tue, 2 Dec 2014 22:49:01 +0100 Subject: [PATCH 38/72] gitignore tests/*.err --- .gitignore | 1 + 1 file changed, 1 insertion(+) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1700a56 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +tests/*.err From 4cdad1d4d565157119d76093a9fe973c2e54af5a Mon Sep 17 00:00:00 2001 From: Daniel Hahler Date: Thu, 4 Dec 2014 07:11:52 +0100 Subject: [PATCH 39/72] Handle missing $1 in _autoenv_hash_pair --- autoenv.zsh | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/autoenv.zsh b/autoenv.zsh index 23866f3..c710389 100644 --- a/autoenv.zsh +++ b/autoenv.zsh @@ -122,12 +122,18 @@ _autoenv_debug() { zmodload -F zsh/stat b:zstat +# Generate hash pair for a given file ($1). +# A fixed hash value can be given as 2nd arg, but is used with tests only. _autoenv_hash_pair() { local env_file=${1:A} local env_shasum if [[ -n $2 ]]; then env_shasum=$2 else + if ! [[ -e $env_file ]]; then + echo "Missing file argument for _autoenv_hash_pair!" >&2 + return 1 + fi env_shasum=$(shasum $env_file | cut -d' ' -f1) fi echo "$env_file:$env_shasum:1" From 13bb443f48391539ae7a47a59468f476e815b000 Mon Sep 17 00:00:00 2001 From: Daniel Hahler Date: Thu, 4 Dec 2014 07:12:29 +0100 Subject: [PATCH 40/72] Fix _autoenv_deauthorize with regard to newline handling, add tests --- autoenv.zsh | 4 +-- tests/.zshenv | 2 ++ tests/_autoenv_utils.t | 58 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 62 insertions(+), 2 deletions(-) diff --git a/autoenv.zsh b/autoenv.zsh index c710389..14e8159 100644 --- a/autoenv.zsh +++ b/autoenv.zsh @@ -154,8 +154,8 @@ _autoenv_authorize() { _autoenv_deauthorize() { local env_file=$1 - if [[ -f $AUTOENV_ENV_FILENAME ]]; then - echo $(\grep -vF $env_file $AUTOENV_ENV_FILENAME) > $AUTOENV_ENV_FILENAME + if [[ -s $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 2311e2a..029e73d 100644 --- a/tests/.zshenv +++ b/tests/.zshenv @@ -4,3 +4,5 @@ AUTOENV_DEBUG=0 source "$TESTDIR/../autoenv.plugin.zsh" export AUTOENV_ENV_FILENAME="$PWD/.env_auth" + +echo -n > $AUTOENV_ENV_FILENAME diff --git a/tests/_autoenv_utils.t b/tests/_autoenv_utils.t index 79c4bf1..c8c4a8c 100644 --- a/tests/_autoenv_utils.t +++ b/tests/_autoenv_utils.t @@ -8,8 +8,66 @@ Non-existing entries are allowed and handled without error. $ 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) + + +Tests for _autoenv_authorize. {{{ + +Auth file is empty. + + $ cd ../.. + $ cat $AUTOENV_ENV_FILENAME + +Failed authorization should keep the auth file empty. + + $ _autoenv_authorize does-not-exist + Missing file argument for _autoenv_hash_pair! + [1] + $ cat $AUTOENV_ENV_FILENAME + +Now adding some auth pair. + + $ echo first > first + $ _autoenv_authorize first + $ cat $AUTOENV_ENV_FILENAME + /tmp/cramtests-*/_autoenv_utils.t/first:271ac93c44ac198d92e706c6d6f1d84aefcfa337:1 (glob) + +And a second one. + + $ echo second > second + $ _autoenv_authorize second + $ cat $AUTOENV_ENV_FILENAME + /tmp/cramtests-*/_autoenv_utils.t/first:271ac93c44ac198d92e706c6d6f1d84aefcfa337:1 (glob) + /tmp/cramtests-*/_autoenv_utils.t/second:7bee8f3b184e1e141ff76efe369c3b8bfc50e64c:1 (glob) + +And a third. + + $ echo third > third + $ _autoenv_authorize third + $ cat $AUTOENV_ENV_FILENAME + /tmp/cramtests-*/_autoenv_utils.t/first:271ac93c44ac198d92e706c6d6f1d84aefcfa337:1 (glob) + /tmp/cramtests-*/_autoenv_utils.t/second:7bee8f3b184e1e141ff76efe369c3b8bfc50e64c:1 (glob) + /tmp/cramtests-*/_autoenv_utils.t/third:ad180453bf8a374a15df3e90a78c180230146a7c:1 (glob) + +Re-add the second one, with the same hash. + + $ _autoenv_authorize second + $ cat $AUTOENV_ENV_FILENAME + /tmp/cramtests-*/_autoenv_utils.t/first:271ac93c44ac198d92e706c6d6f1d84aefcfa337:1 (glob) + /tmp/cramtests-*/_autoenv_utils.t/third:ad180453bf8a374a15df3e90a78c180230146a7c:1 (glob) + /tmp/cramtests-*/_autoenv_utils.t/second:7bee8f3b184e1e141ff76efe369c3b8bfc50e64c:1 (glob) + +Re-add the first one, with a new hash. + + $ echo one more line >> first + $ _autoenv_authorize first + $ cat $AUTOENV_ENV_FILENAME + /tmp/cramtests-*/_autoenv_utils.t/third:ad180453bf8a374a15df3e90a78c180230146a7c:1 (glob) + /tmp/cramtests-*/_autoenv_utils.t/second:7bee8f3b184e1e141ff76efe369c3b8bfc50e64c:1 (glob) + /tmp/cramtests-*/_autoenv_utils.t/first:65eb010197b73ddc109b7210080f97a87f53451e:1 (glob) +}}} From 57038effd17daea289fe9ea1ccaa0d81b6ad2838 Mon Sep 17 00:00:00 2001 From: Daniel Hahler Date: Thu, 4 Dec 2014 07:58:45 +0100 Subject: [PATCH 41/72] README: build status: use master branch, and .svg --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index c00f1a7..bf5e088 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ [![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/Tarrasch/zsh-autoenv/trend.png)](https://bitdeli.com/free "Bitdeli Badge") -[![Build Status](https://travis-ci.org/Tarrasch/zsh-autoenv.png)](https://travis-ci.org/Tarrasch/zsh-autoenv) +[![Build Status](https://travis-ci.org/Tarrasch/zsh-autoenv.svg?branch=master)](https://travis-ci.org/Tarrasch/zsh-autoenv) # Autoenv for zsh From 5655e26d6a80b372d2a7ef633f73d3500bbca9a8 Mon Sep 17 00:00:00 2001 From: Daniel Hahler Date: Thu, 4 Dec 2014 10:35:09 +0100 Subject: [PATCH 42/72] Encapsulate the file name in the hash pair for stricter matching Ref: https://github.com/Tarrasch/zsh-autoenv/pull/13#issuecomment-65559752 --- autoenv.zsh | 8 ++++---- tests/_autoenv_utils.t | 24 ++++++++++++------------ 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/autoenv.zsh b/autoenv.zsh index 14e8159..0cc0566 100644 --- a/autoenv.zsh +++ b/autoenv.zsh @@ -136,7 +136,7 @@ _autoenv_hash_pair() { fi env_shasum=$(shasum $env_file | cut -d' ' -f1) fi - echo "$env_file:$env_shasum:1" + echo ":${env_file}:${env_shasum}:1" } _autoenv_authorized_env_file() { @@ -147,15 +147,15 @@ _autoenv_authorized_env_file() { } _autoenv_authorize() { - local env_file=$1 + local env_file=${1:A} _autoenv_deauthorize $env_file _autoenv_hash_pair $env_file >> $AUTOENV_ENV_FILENAME } _autoenv_deauthorize() { - local env_file=$1 + local env_file=${1:A} if [[ -s $AUTOENV_ENV_FILENAME ]]; then - echo "$(\grep -vF $env_file $AUTOENV_ENV_FILENAME)" > $AUTOENV_ENV_FILENAME + echo "$(\grep -vF :${env_file}: $AUTOENV_ENV_FILENAME)" > $AUTOENV_ENV_FILENAME fi } diff --git a/tests/_autoenv_utils.t b/tests/_autoenv_utils.t index c8c4a8c..3da1fde 100644 --- a/tests/_autoenv_utils.t +++ b/tests/_autoenv_utils.t @@ -35,39 +35,39 @@ Now adding some auth pair. $ echo first > first $ _autoenv_authorize first $ cat $AUTOENV_ENV_FILENAME - /tmp/cramtests-*/_autoenv_utils.t/first:271ac93c44ac198d92e706c6d6f1d84aefcfa337:1 (glob) + :/tmp/cramtests-*/_autoenv_utils.t/first:271ac93c44ac198d92e706c6d6f1d84aefcfa337:1 (glob) And a second one. $ echo second > second $ _autoenv_authorize second $ cat $AUTOENV_ENV_FILENAME - /tmp/cramtests-*/_autoenv_utils.t/first:271ac93c44ac198d92e706c6d6f1d84aefcfa337:1 (glob) - /tmp/cramtests-*/_autoenv_utils.t/second:7bee8f3b184e1e141ff76efe369c3b8bfc50e64c:1 (glob) + :/tmp/cramtests-*/_autoenv_utils.t/first:271ac93c44ac198d92e706c6d6f1d84aefcfa337:1 (glob) + :/tmp/cramtests-*/_autoenv_utils.t/second:7bee8f3b184e1e141ff76efe369c3b8bfc50e64c:1 (glob) And a third. $ echo third > third $ _autoenv_authorize third $ cat $AUTOENV_ENV_FILENAME - /tmp/cramtests-*/_autoenv_utils.t/first:271ac93c44ac198d92e706c6d6f1d84aefcfa337:1 (glob) - /tmp/cramtests-*/_autoenv_utils.t/second:7bee8f3b184e1e141ff76efe369c3b8bfc50e64c:1 (glob) - /tmp/cramtests-*/_autoenv_utils.t/third:ad180453bf8a374a15df3e90a78c180230146a7c:1 (glob) + :/tmp/cramtests-*/_autoenv_utils.t/first:271ac93c44ac198d92e706c6d6f1d84aefcfa337:1 (glob) + :/tmp/cramtests-*/_autoenv_utils.t/second:7bee8f3b184e1e141ff76efe369c3b8bfc50e64c:1 (glob) + :/tmp/cramtests-*/_autoenv_utils.t/third:ad180453bf8a374a15df3e90a78c180230146a7c:1 (glob) Re-add the second one, with the same hash. $ _autoenv_authorize second $ cat $AUTOENV_ENV_FILENAME - /tmp/cramtests-*/_autoenv_utils.t/first:271ac93c44ac198d92e706c6d6f1d84aefcfa337:1 (glob) - /tmp/cramtests-*/_autoenv_utils.t/third:ad180453bf8a374a15df3e90a78c180230146a7c:1 (glob) - /tmp/cramtests-*/_autoenv_utils.t/second:7bee8f3b184e1e141ff76efe369c3b8bfc50e64c:1 (glob) + :/tmp/cramtests-*/_autoenv_utils.t/first:271ac93c44ac198d92e706c6d6f1d84aefcfa337:1 (glob) + :/tmp/cramtests-*/_autoenv_utils.t/third:ad180453bf8a374a15df3e90a78c180230146a7c:1 (glob) + :/tmp/cramtests-*/_autoenv_utils.t/second:7bee8f3b184e1e141ff76efe369c3b8bfc50e64c:1 (glob) Re-add the first one, with a new hash. $ echo one more line >> first $ _autoenv_authorize first $ cat $AUTOENV_ENV_FILENAME - /tmp/cramtests-*/_autoenv_utils.t/third:ad180453bf8a374a15df3e90a78c180230146a7c:1 (glob) - /tmp/cramtests-*/_autoenv_utils.t/second:7bee8f3b184e1e141ff76efe369c3b8bfc50e64c:1 (glob) - /tmp/cramtests-*/_autoenv_utils.t/first:65eb010197b73ddc109b7210080f97a87f53451e:1 (glob) + :/tmp/cramtests-*/_autoenv_utils.t/third:ad180453bf8a374a15df3e90a78c180230146a7c:1 (glob) + :/tmp/cramtests-*/_autoenv_utils.t/second:7bee8f3b184e1e141ff76efe369c3b8bfc50e64c:1 (glob) + :/tmp/cramtests-*/_autoenv_utils.t/first:65eb010197b73ddc109b7210080f97a87f53451e:1 (glob) }}} From 1bfed02bc2f1cb0bcca16b1ac7d7503c842b88c4 Mon Sep 17 00:00:00 2001 From: Daniel Hahler Date: Thu, 4 Dec 2014 10:39:46 +0100 Subject: [PATCH 43/72] Add doc for _autoenv_deauthorize --- autoenv.zsh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/autoenv.zsh b/autoenv.zsh index 0cc0566..b8a8f05 100644 --- a/autoenv.zsh +++ b/autoenv.zsh @@ -152,6 +152,9 @@ _autoenv_authorize() { _autoenv_hash_pair $env_file >> $AUTOENV_ENV_FILENAME } +# Deauthorize a given filename, by removing it from the auth file. +# This uses `test -s` to only handle non-empty files, and a subshell to +# allow for writing to the same file again. _autoenv_deauthorize() { local env_file=${1:A} if [[ -s $AUTOENV_ENV_FILENAME ]]; then From b478c5463f81797e09b4f923d6930b60b8f035d4 Mon Sep 17 00:00:00 2001 From: Daniel Hahler Date: Thu, 4 Dec 2014 05:36:12 +0100 Subject: [PATCH 44/72] Call `autounstash` automatically/always when leaving a directory --- autoenv.zsh | 4 +++ tests/varstash.t | 65 +++++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 65 insertions(+), 4 deletions(-) diff --git a/autoenv.zsh b/autoenv.zsh index 23866f3..f8ca079 100644 --- a/autoenv.zsh +++ b/autoenv.zsh @@ -266,6 +266,10 @@ _autoenv_chpwd_handler() { if _autoenv_check_authorized_env_file $env_file_leave; then _autoenv_source $env_file_leave leave $prev_dir fi + + # Unstash any autostash'd stuff. + varstash_dir=$prev_dir autounstash + _autoenv_stack_entered_remove $prev_file fi done diff --git a/tests/varstash.t b/tests/varstash.t index 7458044..30a45dd 100644 --- a/tests/varstash.t +++ b/tests/varstash.t @@ -6,7 +6,7 @@ Setup test environment. $ mkdir sub $ cd sub - $ echo 'echo ENTER; autostash FOO=baz' > $AUTOENV_FILE_ENTER + $ echo 'echo ENTER; autostash FOO=changed' > $AUTOENV_FILE_ENTER $ echo 'echo LEAVE; autounstash' > $AUTOENV_FILE_LEAVE Manually create auth file @@ -15,18 +15,75 @@ Manually create auth file Set environment variable. - $ FOO=bar + $ FOO=orig Activating the env stashes it and applies a new value. $ cd . ENTER $ echo $FOO - baz + changed Leaving the directory unstashes it. $ cd .. LEAVE $ echo $FOO - bar + orig + + +Test autounstashing when leaving a directory. {{{ + +Setup: + + $ cd sub + ENTER + $ echo 'echo ENTER; autostash VAR=changed' > $AUTOENV_FILE_ENTER + $ echo 'echo LEAVE; echo "no explicit call to autounstash"' > $AUTOENV_FILE_LEAVE + $ test_autoenv_auth_env_files + +$VAR is empty: + + $ echo VAR:$VAR + VAR: + +Set it: + + $ VAR=orig + $ cd .. + LEAVE + no explicit call to autounstash + +Leaving the directory keeps it intact - nothing had been stashed yet. + + $ echo $VAR + orig + +Enter the dir, trigger the autostashing. + + $ cd sub + ENTER + $ echo $VAR + changed + +Now leave again. + + $ cd .. + LEAVE + no explicit call to autounstash + $ echo $VAR + orig + + +Remove the leave file, auto-unstashing should still happen. + + $ rm sub/$AUTOENV_FILE_LEAVE + $ cd sub + ENTER + $ echo $VAR + changed + $ cd .. + $ echo $VAR + orig + +}}} From e567a4059230880d1f9359567a913dbbf8078fea Mon Sep 17 00:00:00 2001 From: Daniel Hahler Date: Mon, 8 Dec 2014 21:37:25 +0100 Subject: [PATCH 45/72] Fixes after using `setopt nounset` during tests Also add tests for unset variable with varstash. --- autoenv.zsh | 13 +++++-------- tests/autoenv.t | 8 ++++---- tests/setup.sh | 6 +++++- tests/varstash.t | 38 +++++++++++++++++++++----------------- 4 files changed, 35 insertions(+), 30 deletions(-) diff --git a/autoenv.zsh b/autoenv.zsh index f87f350..db77553 100644 --- a/autoenv.zsh +++ b/autoenv.zsh @@ -41,9 +41,8 @@ autoenv_source_parent() { # Internal functions. {{{ # Internal: stack of entered (and handled) directories. {{{ -_autoenv_stack_entered=() +typeset -a _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() { @@ -126,10 +125,8 @@ zmodload -F zsh/stat b:zstat # A fixed hash value can be given as 2nd arg, but is used with tests only. _autoenv_hash_pair() { local env_file=${1:A} - local env_shasum - if [[ -n $2 ]]; then - env_shasum=$2 - else + local env_shasum=${2:-} + if [[ -z $env_shasum ]]; then if ! [[ -e $env_file ]]; then echo "Missing file argument for _autoenv_hash_pair!" >&2 return 1 @@ -220,7 +217,7 @@ _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 "== SOURCE: ${bold_color:-}$env_file${reset_color:-}\n PWD: $PWD" (( _autoenv_debug_indent++ )) source $env_file (( _autoenv_debug_indent-- )) @@ -276,7 +273,7 @@ _autoenv_chpwd_handler() { _autoenv_source $env_file_leave leave $prev_dir fi - # Unstash any autostash'd stuff. + # Unstash any autostashed stuff. varstash_dir=$prev_dir autounstash _autoenv_stack_entered_remove $prev_file diff --git a/tests/autoenv.t b/tests/autoenv.t index 19d0592..701e3b4 100644 --- a/tests/autoenv.t +++ b/tests/autoenv.t @@ -12,7 +12,7 @@ Manually create auth file Now try to make it accept it - $ unset _autoenv_stack_entered + $ _autoenv_stack_entered=() $ rm $AUTOENV_ENV_FILENAME $ _autoenv_ask_for_yes() { echo "yes" } $ cd . @@ -33,11 +33,11 @@ The last "ENTERED" is because it executed the command. Now lets see that it actually checks the shasum value. - $ unset _autoenv_stack_entered + $ _autoenv_stack_entered=() $ cd . ENTERED - $ unset _autoenv_stack_entered + $ _autoenv_stack_entered=() $ rm $AUTOENV_ENV_FILENAME $ test_autoenv_add_to_env $PWD/.env mischief $ cd . @@ -56,7 +56,7 @@ Now lets see that it actually checks the shasum value. Now, will it take no for an answer? - $ unset _autoenv_stack_entered + $ _autoenv_stack_entered=() $ rm $AUTOENV_ENV_FILENAME $ _autoenv_ask_for_yes() { echo "no"; return 1 } $ cd . diff --git a/tests/setup.sh b/tests/setup.sh index 90bfc51..5c6ae9e 100644 --- a/tests/setup.sh +++ b/tests/setup.sh @@ -1,6 +1,10 @@ # Ensure we have our mocked out AUTOENV_ENV_FILENAME # (via .zshenv). +# Treat unset variables as errors. +# Not handled in varstash yet. +# setopt nounset + [[ $AUTOENV_ENV_FILENAME[0,4] == '/tmp' ]] || return 1 # Reset any authentication. @@ -8,7 +12,7 @@ echo -n > $AUTOENV_ENV_FILENAME # Add file $1 (with optional hash $2) to authentication file. test_autoenv_add_to_env() { - _autoenv_hash_pair $1 $2 >> $AUTOENV_ENV_FILENAME + _autoenv_hash_pair $1 ${2:-} >> $AUTOENV_ENV_FILENAME } # Add enter and leave env files to authentication file. diff --git a/tests/varstash.t b/tests/varstash.t index 30a45dd..cdb47a8 100644 --- a/tests/varstash.t +++ b/tests/varstash.t @@ -36,31 +36,23 @@ Test autounstashing when leaving a directory. {{{ Setup: + $ unset VAR $ cd sub ENTER $ echo 'echo ENTER; autostash VAR=changed' > $AUTOENV_FILE_ENTER $ echo 'echo LEAVE; echo "no explicit call to autounstash"' > $AUTOENV_FILE_LEAVE $ test_autoenv_auth_env_files -$VAR is empty: +$VAR is unset: - $ echo VAR:$VAR - VAR: + $ echo VAR_set:$+VAR + VAR_set:0 -Set it: +Trigger the autostashing in the enter file. - $ VAR=orig $ cd .. LEAVE no explicit call to autounstash - -Leaving the directory keeps it intact - nothing had been stashed yet. - - $ echo $VAR - orig - -Enter the dir, trigger the autostashing. - $ cd sub ENTER $ echo $VAR @@ -71,9 +63,8 @@ Now leave again. $ cd .. LEAVE no explicit call to autounstash - $ echo $VAR - orig - + $ echo VAR_set:$+VAR + VAR_set:0 Remove the leave file, auto-unstashing should still happen. @@ -83,7 +74,20 @@ Remove the leave file, auto-unstashing should still happen. $ echo $VAR changed $ cd .. + $ echo VAR_set:$+VAR + VAR_set:0 + +And once again where a value gets restored. + + $ VAR=orig_2 $ echo $VAR - orig + orig_2 + $ cd sub + ENTER + $ echo $VAR + changed + $ cd .. + $ echo $VAR + orig_2 }}} From 027e8fb5dedbd0143fb3dc5bff85d8aad02bb3f0 Mon Sep 17 00:00:00 2001 From: Srijan R Shetty Date: Mon, 8 Dec 2014 23:16:27 +0530 Subject: [PATCH 46/72] Create $AUTHENV_ENV_FILENAME if it does not exist --- autoenv.zsh | 1 + 1 file changed, 1 insertion(+) diff --git a/autoenv.zsh b/autoenv.zsh index db77553..8bc39bf 100644 --- a/autoenv.zsh +++ b/autoenv.zsh @@ -2,6 +2,7 @@ # https://github.com/joshuaclayton/dotfiles/blob/master/zsh_profile.d/autoenv.zsh export AUTOENV_ENV_FILENAME=$HOME/.env_auth +[ -e $AUTOENV_ENV_FILENAME ] || touch $AUTOENV_ENV_FILENAME # Name of file to look for when entering directories. : ${AUTOENV_FILE_ENTER:=.env} From 9c829733ad2cb61b5873c1f20abeffea6af6043f Mon Sep 17 00:00:00 2001 From: Daniel Hahler Date: Mon, 8 Dec 2014 22:12:30 +0100 Subject: [PATCH 47/72] tests: setup for multiple ZDOTDIRs, fix/add "setopt clobber" --- .travis.yml | 2 +- Makefile | 15 ++++++++++++--- autoenv.zsh | 4 ++-- tests/ZDOTDIR.clobber/.zshenv | 3 +++ tests/{ => ZDOTDIR}/.zshenv | 0 tests/autoenv.t | 2 +- tests/leave.t | 4 ++-- tests/recurse-upwards.t | 4 ++-- tests/setup.sh | 4 ++-- tests/varstash.t | 4 ++-- 10 files changed, 27 insertions(+), 15 deletions(-) create mode 100644 tests/ZDOTDIR.clobber/.zshenv rename tests/{ => ZDOTDIR}/.zshenv (100%) diff --git a/.travis.yml b/.travis.yml index 00828ba..715854b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,4 +4,4 @@ python: before_script: - "sudo apt-get install zsh" install: "sudo pip install cram" -script: "make test" +script: "make test_full" diff --git a/Makefile b/Makefile index 0ffe150..db303fa 100644 --- a/Makefile +++ b/Makefile @@ -1,10 +1,17 @@ -.PHONY: itest test +export ZDOTDIR=${PWD}/tests/ZDOTDIR test: - ZDOTDIR="${PWD}/tests" cram --shell=zsh -v tests + cram --shell=zsh -v tests itest: - ZDOTDIR="${PWD}/tests" cram -i --shell=zsh tests + cram -i --shell=zsh tests + +# Run tests with all ZDOTDIRs. +test_full: + for i in $(wildcard tests/ZDOTDIR*); do \ + echo "ZDOTDIR=$$i"; \ + ZDOTDIR=${PWD}/$$i cram --shell=zsh -v tests; \ + done # Define targets for test files, with relative and abolute path. # Use verbose output, which is useful with Vim's 'errorformat'. @@ -15,3 +22,5 @@ _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) + +.PHONY: itest test diff --git a/autoenv.zsh b/autoenv.zsh index 8bc39bf..e8d0b99 100644 --- a/autoenv.zsh +++ b/autoenv.zsh @@ -147,7 +147,7 @@ _autoenv_authorized_env_file() { _autoenv_authorize() { local env_file=${1:A} _autoenv_deauthorize $env_file - _autoenv_hash_pair $env_file >> $AUTOENV_ENV_FILENAME + _autoenv_hash_pair $env_file >>| $AUTOENV_ENV_FILENAME } # Deauthorize a given filename, by removing it from the auth file. @@ -156,7 +156,7 @@ _autoenv_authorize() { _autoenv_deauthorize() { local env_file=${1:A} if [[ -s $AUTOENV_ENV_FILENAME ]]; then - echo "$(\grep -vF :${env_file}: $AUTOENV_ENV_FILENAME)" > $AUTOENV_ENV_FILENAME + echo "$(\grep -vF :${env_file}: $AUTOENV_ENV_FILENAME)" >| $AUTOENV_ENV_FILENAME fi } diff --git a/tests/ZDOTDIR.clobber/.zshenv b/tests/ZDOTDIR.clobber/.zshenv new file mode 100644 index 0000000..62037dc --- /dev/null +++ b/tests/ZDOTDIR.clobber/.zshenv @@ -0,0 +1,3 @@ +source ${ZDOTDIR}/../ZDOTDIR/.zshenv + +setopt noclobber diff --git a/tests/.zshenv b/tests/ZDOTDIR/.zshenv similarity index 100% rename from tests/.zshenv rename to tests/ZDOTDIR/.zshenv diff --git a/tests/autoenv.t b/tests/autoenv.t index 701e3b4..aef6bb9 100644 --- a/tests/autoenv.t +++ b/tests/autoenv.t @@ -2,7 +2,7 @@ Lets set a simple .env action - $ echo 'echo ENTERED' >> .env + $ echo 'echo ENTERED' > .env Manually create auth file diff --git a/tests/leave.t b/tests/leave.t index 2e4e360..227da71 100644 --- a/tests/leave.t +++ b/tests/leave.t @@ -4,8 +4,8 @@ Lets set a simple .env action $ mkdir sub $ cd sub - $ echo 'echo ENTERED' >> .env - $ echo 'echo LEFT' >> .env.leave + $ echo 'echo ENTERED' > .env + $ echo 'echo LEFT' > .env.leave Change to the directory. diff --git a/tests/recurse-upwards.t b/tests/recurse-upwards.t index aa36edd..3e6067e 100644 --- a/tests/recurse-upwards.t +++ b/tests/recurse-upwards.t @@ -86,7 +86,7 @@ Prepend call to autoenv_source_parent to sub/.env file. Add sub/sub2/.env file. - $ echo -e "echo autoenv_source_parent_from_sub2:\nautoenv_source_parent\necho done_sub2\n" > sub2/.env + $ 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: @@ -109,7 +109,7 @@ Changing the root .env should trigger re-authentication via autoenv_source_paren First, let's answer "no". - $ echo "echo NEW" > .env + $ echo "echo NEW" >| .env $ _autoenv_ask_for_yes() { echo "no"; return 1 } $ cd sub autoenv_source_parent_from_sub: diff --git a/tests/setup.sh b/tests/setup.sh index 5c6ae9e..557b9e7 100644 --- a/tests/setup.sh +++ b/tests/setup.sh @@ -8,11 +8,11 @@ [[ $AUTOENV_ENV_FILENAME[0,4] == '/tmp' ]] || return 1 # Reset any authentication. -echo -n > $AUTOENV_ENV_FILENAME +echo -n >| $AUTOENV_ENV_FILENAME # Add file $1 (with optional hash $2) to authentication file. test_autoenv_add_to_env() { - _autoenv_hash_pair $1 ${2:-} >> $AUTOENV_ENV_FILENAME + _autoenv_hash_pair $1 ${2:-} >>| $AUTOENV_ENV_FILENAME } # Add enter and leave env files to authentication file. diff --git a/tests/varstash.t b/tests/varstash.t index cdb47a8..487230b 100644 --- a/tests/varstash.t +++ b/tests/varstash.t @@ -39,8 +39,8 @@ Setup: $ unset VAR $ cd sub ENTER - $ echo 'echo ENTER; autostash VAR=changed' > $AUTOENV_FILE_ENTER - $ echo 'echo LEAVE; echo "no explicit call to autounstash"' > $AUTOENV_FILE_LEAVE + $ echo 'echo ENTER; autostash VAR=changed' >| $AUTOENV_FILE_ENTER + $ echo 'echo LEAVE; echo "no explicit call to autounstash"' >| $AUTOENV_FILE_LEAVE $ test_autoenv_auth_env_files $VAR is unset: From 5a968c82995bd8e1af5efa0b5a3bbe69ed705b6d Mon Sep 17 00:00:00 2001 From: Daniel Hahler Date: Tue, 9 Dec 2014 23:10:54 +0100 Subject: [PATCH 48/72] minor: fix debug message ordering --- autoenv.zsh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/autoenv.zsh b/autoenv.zsh index e8d0b99..2428c92 100644 --- a/autoenv.zsh +++ b/autoenv.zsh @@ -49,11 +49,11 @@ typeset -A _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 + _autoenv_debug "[stack] adding: $env_file" 2 + # 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) From 53da60d3e3d30205a1de52cbe6bd92d0884cb9c2 Mon Sep 17 00:00:00 2001 From: Daniel Hahler Date: Tue, 9 Dec 2014 23:12:38 +0100 Subject: [PATCH 49/72] Init arrays (see #14) --- autoenv.zsh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/autoenv.zsh b/autoenv.zsh index 2428c92..8387558 100644 --- a/autoenv.zsh +++ b/autoenv.zsh @@ -43,7 +43,9 @@ autoenv_source_parent() { # Internal functions. {{{ # Internal: stack of entered (and handled) directories. {{{ typeset -a _autoenv_stack_entered +_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() { From 1219d83c51e36d31741f7cc634b56b66a75a64bf Mon Sep 17 00:00:00 2001 From: Daniel Hahler Date: Wed, 10 Dec 2014 00:09:04 +0100 Subject: [PATCH 50/72] Fix autoloading of colors; just once --- autoenv.zsh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/autoenv.zsh b/autoenv.zsh index 8387558..bfd9347 100644 --- a/autoenv.zsh +++ b/autoenv.zsh @@ -99,7 +99,7 @@ _autoenv_debug() { return fi # Load zsh color support. - if [[ -z $colors ]]; then + if [[ -z $color ]]; then autoload colors colors fi From 020a9152b74077475f5974362f1eb42813083657 Mon Sep 17 00:00:00 2001 From: Daniel Hahler Date: Thu, 11 Dec 2014 16:22:54 +0100 Subject: [PATCH 51/72] Fix being loaded from a function (antigen) Fixes https://github.com/Tarrasch/zsh-autoenv/issues/14 --- autoenv.zsh | 5 +++-- tests/ZDOTDIR.loadviafunction/.zshenv | 12 ++++++++++++ 2 files changed, 15 insertions(+), 2 deletions(-) create mode 100644 tests/ZDOTDIR.loadviafunction/.zshenv diff --git a/autoenv.zsh b/autoenv.zsh index bfd9347..14c4a7a 100644 --- a/autoenv.zsh +++ b/autoenv.zsh @@ -42,9 +42,10 @@ autoenv_source_parent() { # Internal functions. {{{ # Internal: stack of entered (and handled) directories. {{{ -typeset -a _autoenv_stack_entered +typeset -g -a _autoenv_stack_entered _autoenv_stack_entered=() -typeset -A _autoenv_stack_entered_mtime +# -g: make it global, this is required when used with antigen. +typeset -g -A _autoenv_stack_entered_mtime _autoenv_stack_entered_mtime=() # Add an entry to the stack, and remember its mtime. diff --git a/tests/ZDOTDIR.loadviafunction/.zshenv b/tests/ZDOTDIR.loadviafunction/.zshenv new file mode 100644 index 0000000..4e41fbc --- /dev/null +++ b/tests/ZDOTDIR.loadviafunction/.zshenv @@ -0,0 +1,12 @@ +test -f "$TESTDIR/.zcompdump" && rm "$TESTDIR/.zcompdump" + +AUTOENV_DEBUG=0 + +antigen-like-loader-function() { + source "$TESTDIR/../autoenv.plugin.zsh" +} +antigen-like-loader-function + +export AUTOENV_ENV_FILENAME="$PWD/.env_auth" + +echo -n > $AUTOENV_ENV_FILENAME From d136fd8731b415e884ed76ae5349da574e167afa Mon Sep 17 00:00:00 2001 From: Daniel Hahler Date: Thu, 11 Dec 2014 16:31:41 +0100 Subject: [PATCH 52/72] README: add section about manual installation --- README.md | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index bf5e088..9271fba 100644 --- a/README.md +++ b/README.md @@ -15,10 +15,17 @@ This is is a zsh optimized version of ## Installation -Using [antigen](https://github.com/zsh-users/antigen) +### Using [antigen](https://github.com/zsh-users/antigen) antigen-bundle Tarrasch/zsh-autoenv +### Manually + +Clone the repository and source it from your `~/.zshrc` file: + + git clone https://github.com/Tarrasch/zsh-autoenv ~/.dotfiles/lib/zsh-autoenv + echo 'source ~/.dotfiles/lib/zsh-autoenv/autoenv.zsh' >> ~/.zshrc + ## Credits The code was mostly copied from [Joshua Clayton](https://github.com/joshuaclayton) From f5077e320de2dbd783aefb8dbb4340c40fb15b32 Mon Sep 17 00:00:00 2001 From: Daniel Hahler Date: Thu, 18 Dec 2014 19:45:19 +0100 Subject: [PATCH 53/72] varstash: no need to use regex, avoids 'failed to load module: zsh/regex' error --- lib/varstash | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/varstash b/lib/varstash index 9844c32..320649c 100644 --- a/lib/varstash +++ b/lib/varstash @@ -231,7 +231,7 @@ function stash() { function autostash() { local run_from_autostash=1 while [[ -n $1 ]]; do - if [[ $1 == "alias" && $2 =~ "=" ]]; then + if [[ $1 == "alias" && $2 = *=* ]]; then shift local _stashing_alias_assign=1 fi From 936b5eaf7798740d0008a48949da2e02bc4e26d3 Mon Sep 17 00:00:00 2001 From: Daniel Hahler Date: Thu, 18 Dec 2014 19:45:48 +0100 Subject: [PATCH 54/72] Handle failure of loading zsh/stat --- autoenv.zsh | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/autoenv.zsh b/autoenv.zsh index 14c4a7a..e501f90 100644 --- a/autoenv.zsh +++ b/autoenv.zsh @@ -122,7 +122,14 @@ _autoenv_debug() { # }}} # Load zstat module, but only its builtin `zstat`. -zmodload -F zsh/stat b:zstat +if ! zmodload -F zsh/stat b:zstat 2>/dev/null; then + # If the module is not available, define a wrapper around `stat`, and use its + # terse output instead of format, which is not supported by busybox. + # Assume '+mtime' as $1. + zstat() { + stat -t $2 | cut -f13 -d ' ' + } +fi # Generate hash pair for a given file ($1). From 07abe9cea86cdaff41f75e6ef279a6260dcf2f17 Mon Sep 17 00:00:00 2001 From: Daniel Hahler Date: Thu, 18 Dec 2014 20:08:51 +0100 Subject: [PATCH 55/72] varstash: remove all usages of =~ --- lib/varstash | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/lib/varstash b/lib/varstash index 320649c..d5016c1 100644 --- a/lib/varstash +++ b/lib/varstash @@ -101,7 +101,7 @@ function stash() { fi while [[ -n $1 ]]; do - if [[ $1 == "alias" && $2 =~ "=" ]]; then + if [[ $1 == "alias" && $2 == *=* ]]; then shift local _stashing_alias_assign=1 continue @@ -179,13 +179,13 @@ function stash() { else local pattern="^declare" fi - if [[ $vartype =~ $pattern" -a" ]]; then + 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 + elif [[ $vartype == $pattern" -x"* ]]; then # variable is exported if [[ -z $already_stashed ]]; then eval "__varstash_export__$stash_name=\"\$$stash_which\"" @@ -310,7 +310,8 @@ function unstash() { 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 + # Using substitution to avoid using regex, which might fail to load on Zsh (minimal system). + if [[ ${unstash_which//[^a-zA-Z0-9_]/} == $unstash_which && $unstash_which != [0-9]* ]]; then unset -v $unstash_which fi fi From be306b1178907ee74d7b4e792ec467f91b0f54ee Mon Sep 17 00:00:00 2001 From: Daniel Hahler Date: Thu, 18 Dec 2014 20:36:54 +0100 Subject: [PATCH 56/72] varstash: fix pattern in stash --- lib/varstash | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/varstash b/lib/varstash index d5016c1..eae62b3 100644 --- a/lib/varstash +++ b/lib/varstash @@ -175,9 +175,9 @@ function stash() { local vartype="$(declare -p $stash_which 2>/dev/null)" if [[ -n $vartype ]]; then if [[ -n $ZSH_VERSION ]]; then - local pattern="^typeset" + local pattern="typeset" else - local pattern="^declare" + local pattern="declare" fi if [[ $vartype == $pattern" -a"* ]]; then # varible is an array From 06b96e78c3377a0d88925d88d5d097b8cb8ac5ab Mon Sep 17 00:00:00 2001 From: Daniel Hahler Date: Thu, 18 Dec 2014 20:52:36 +0100 Subject: [PATCH 57/72] test_full: output extra newline between suites/variants --- Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/Makefile b/Makefile index db303fa..5c50ef4 100644 --- a/Makefile +++ b/Makefile @@ -11,6 +11,7 @@ test_full: for i in $(wildcard tests/ZDOTDIR*); do \ echo "ZDOTDIR=$$i"; \ ZDOTDIR=${PWD}/$$i cram --shell=zsh -v tests; \ + echo; \ done # Define targets for test files, with relative and abolute path. From 7d970a03f714764f0e76b8ae60ff51777a45f479 Mon Sep 17 00:00:00 2001 From: Daniel Hahler Date: Thu, 18 Dec 2014 20:52:52 +0100 Subject: [PATCH 58/72] varstash: use '==' for consistency --- lib/varstash | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/varstash b/lib/varstash index eae62b3..17bcd62 100644 --- a/lib/varstash +++ b/lib/varstash @@ -231,7 +231,7 @@ function stash() { function autostash() { local run_from_autostash=1 while [[ -n $1 ]]; do - if [[ $1 == "alias" && $2 = *=* ]]; then + if [[ $1 == "alias" && $2 == *=* ]]; then shift local _stashing_alias_assign=1 fi From 685a3f16f5ccbee81be689fec5ab8ec85587d2a1 Mon Sep 17 00:00:00 2001 From: Daniel Hahler Date: Sat, 17 Jan 2015 16:38:40 +0100 Subject: [PATCH 59/72] Minor cleanup: centralize call to _autoenv_stack_entered_add --- autoenv.zsh | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/autoenv.zsh b/autoenv.zsh index e501f90..7d6e142 100644 --- a/autoenv.zsh +++ b/autoenv.zsh @@ -31,12 +31,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} - - _autoenv_stack_entered_add $parent_env_file - - _autoenv_source $parent_env_file enter $parent_env_dir + _autoenv_source $parent_env_file enter fi } @@ -235,6 +230,10 @@ _autoenv_source() { _autoenv_debug "== END SOURCE ==" builtin cd -q $new_dir + if [[ $autoenv_event == enter ]]; then + _autoenv_stack_entered_add $env_file + fi + # 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. @@ -313,8 +312,6 @@ _autoenv_chpwd_handler() { return fi - _autoenv_stack_entered_add $env_file - # Source the enter env file. _autoenv_debug "Sourcing from chpwd handler: $env_file" _autoenv_source $env_file enter From 1856e8936551701f08d29e1f0184977181e73517 Mon Sep 17 00:00:00 2001 From: Daniel Hahler Date: Sat, 17 Jan 2015 16:39:04 +0100 Subject: [PATCH 60/72] Set autoenv_env_file in _autoenv_source --- autoenv.zsh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/autoenv.zsh b/autoenv.zsh index 7d6e142..9f1780a 100644 --- a/autoenv.zsh +++ b/autoenv.zsh @@ -212,6 +212,7 @@ _autoenv_source() { autoenv_from_dir=$_autoenv_chpwd_prev_dir autoenv_to_dir=$PWD + autoenv_env_file=$env_file # Source varstash library once. if [[ -z "$functions[(I)autostash]" ]]; then @@ -237,7 +238,7 @@ _autoenv_source() { # 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 + # unset autoenv_event autoenv_from_dir autoenv_to_dir autoenv_env_file } _autoenv_get_file_upwards() { From 986a7609ff20ad7a482f744a83c2c4bdb1dcc224 Mon Sep 17 00:00:00 2001 From: Daniel Hahler Date: Sat, 17 Jan 2015 17:03:02 +0100 Subject: [PATCH 61/72] Do not `cd` in the `chpwd` hook This is not really necessary, except for the convenience of being in the .env file's directory during the hook. But it messes around with the "cd history", e.g. `cd -`! To reference the .env file or its directory, `$autoenv_env_file` and `${autoenv_env_file:h}` can be used instead. --- autoenv.zsh | 4 +--- tests/cwd.t | 16 ++++++++-------- tests/recurse-upwards.t | 22 +++++++++++----------- 3 files changed, 20 insertions(+), 22 deletions(-) diff --git a/autoenv.zsh b/autoenv.zsh index 9f1780a..561a336 100644 --- a/autoenv.zsh +++ b/autoenv.zsh @@ -26,7 +26,7 @@ export AUTOENV_ENV_FILENAME=$HOME/.env_auth # 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) + local parent_env_file=$(_autoenv_get_file_upwards ${autoenv_env_file:h}) if [[ -n $parent_env_file ]] \ && _autoenv_check_authorized_env_file $parent_env_file; then @@ -223,13 +223,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 if [[ $autoenv_event == enter ]]; then _autoenv_stack_entered_add $env_file diff --git a/tests/cwd.t b/tests/cwd.t index 60a2d50..ee586b4 100644 --- a/tests/cwd.t +++ b/tests/cwd.t @@ -7,8 +7,8 @@ Setup env actions / output. $ AUTOENV_LOOK_UPWARDS=1 $ mkdir -p sub/sub2 $ cd sub - $ echo 'echo ENTERED: PWD:${PWD:t} from:${autoenv_from_dir:t} to:${autoenv_to_dir:t} event:${autoenv_event}' > .env - $ echo 'echo LEFT: PWD:${PWD:t} from:${autoenv_from_dir:t} to:${autoenv_to_dir:t} event:${autoenv_event}' > .env.leave + $ echo 'echo ENTERED: PWD:${PWD:t} pwd:${${"$(pwd)"}:t} from:${autoenv_from_dir:t} to:${autoenv_to_dir:t} event:${autoenv_event}' > .env + $ echo 'echo LEFT: PWD:${PWD:t} pwd:${${"$(pwd)"}:t} from:${autoenv_from_dir:t} to:${autoenv_to_dir:t} event:${autoenv_event}' > .env.leave Manually create auth files. @@ -17,21 +17,21 @@ Manually create auth files. The actual tests. $ cd . - ENTERED: PWD:sub from:sub to:sub event:enter + ENTERED: PWD:sub pwd:sub from:sub to:sub event:enter $ cd .. - LEFT: PWD:sub from:sub to:cwd.t event:leave + LEFT: PWD:cwd.t pwd:cwd.t from:sub to:cwd.t event:leave $ cd sub/sub2 - ENTERED: PWD:sub from:cwd.t to:sub2 event:enter + ENTERED: PWD:sub2 pwd:sub2 from:cwd.t to:sub2 event:enter Check that symlinked dirs get handled correctly. $ cd ../.. - LEFT: PWD:sub from:sub2 to:cwd.t event:leave + LEFT: PWD:cwd.t pwd:cwd.t from:sub2 to:cwd.t event:leave $ ln -s sub sub_linked $ cd sub_linked - ENTERED: PWD:sub from:cwd.t to:sub_linked event:enter + ENTERED: PWD:sub_linked pwd:sub_linked from:cwd.t to:sub_linked event:enter $ cd sub2 - ENTERED: PWD:sub from:sub_linked to:sub2 event:enter + ENTERED: PWD:sub2 pwd:sub2 from:sub_linked to:sub2 event:enter $ cd . diff --git a/tests/recurse-upwards.t b/tests/recurse-upwards.t index 3e6067e..68f79be 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:recurse-upwards.t from:recurse-upwards.t to: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 @@ -28,10 +28,10 @@ The actual tests. ENTERED_sub: PWD:sub from:sub to:sub $ cd .. - LEFT_sub: PWD:sub from:sub to:recurse-upwards.t + LEFT_sub: PWD:recurse-upwards.t from:sub to:recurse-upwards.t $ cd sub/sub2 - ENTERED_sub: PWD:sub from:recurse-upwards.t to:sub2 + ENTERED_sub: PWD:sub2 from:recurse-upwards.t to:sub2 $ cd .. @@ -54,7 +54,7 @@ Add sub/sub2/.env file, with a call to autoenv_source_parent. $ test_autoenv_add_to_env sub2/.env $ cd sub2 autoenv_source_parent_from_sub2: - ENTERED_sub: PWD:sub from:sub to:sub2 + ENTERED_sub: PWD:sub2 from:sub to:sub2 ENTER2 done_sub2 @@ -64,7 +64,7 @@ Move sub/.env away, now the root .env file should get sourced. $ touch -t 201401010102 .env $ cd . autoenv_source_parent_from_sub2: - ENTERED_root: PWD:recurse-upwards.t from:sub2 to:sub2 + ENTERED_root: PWD:sub2 from:sub2 to:sub2 done_sub2 $ mv ../.env.out ../.env @@ -78,7 +78,7 @@ Prepend call to autoenv_source_parent to sub/.env file. $ cd . autoenv_source_parent_from_sub: - ENTERED_root: PWD:recurse-upwards.t from:sub to:sub + ENTERED_root: PWD:sub from:sub to:sub ENTERED_sub: PWD:sub from:sub to:sub ENTER2 done_sub @@ -91,8 +91,8 @@ Add sub/sub2/.env file. $ 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 + ENTERED_root: PWD:sub2 from:sub to:sub2 + ENTERED_sub: PWD:sub2 from:sub to:sub2 ENTER2 done_sub done_sub2 @@ -102,7 +102,7 @@ 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 + LEFT_sub: PWD:recurse-upwards.t from:sub2 to:recurse-upwards.t Changing the root .env should trigger re-authentication via autoenv_source_parent. @@ -155,13 +155,13 @@ Touching the .env file will now source the parent env file. $ cd .. - LEFT_sub: PWD:sub from:sub to:recurse-upwards.t + LEFT_sub: PWD:recurse-upwards.t 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 + ENTERED_sub: PWD:sub3 from:recurse-upwards.t to:sub3 ENTER2 done_sub done_sub2 From ae7c8ae73d25a13179b859d3eae0ac3bc0c156ef Mon Sep 17 00:00:00 2001 From: Daniel Hahler Date: Sat, 17 Jan 2015 20:43:59 +0100 Subject: [PATCH 62/72] Makefile: use CURDIR instead of PWD; used with 'make -C ..' --- Makefile | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Makefile b/Makefile index 5c50ef4..7b1b23f 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -export ZDOTDIR=${PWD}/tests/ZDOTDIR +export ZDOTDIR=${CURDIR}/tests/ZDOTDIR test: cram --shell=zsh -v tests @@ -10,7 +10,7 @@ itest: test_full: for i in $(wildcard tests/ZDOTDIR*); do \ echo "ZDOTDIR=$$i"; \ - ZDOTDIR=${PWD}/$$i cram --shell=zsh -v tests; \ + ZDOTDIR=${CURDIR}/$$i cram --shell=zsh -v tests; \ echo; \ done @@ -21,7 +21,7 @@ TESTS:=$(wildcard 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 $@ + ZDOTDIR="${CURDIR}/tests" cram --shell=zsh -v $@ .PHONY: $(_TESTS_REL_AND_ABS) .PHONY: itest test From 8208d1ce1f300a28f56c9225dbb44290b6d67882 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aur=C3=A9lien=20Scoubeau?= Date: Mon, 19 Jan 2015 15:25:42 +0100 Subject: [PATCH 63/72] Create init.zsh to make compatible with prezto --- init.zsh | 1 + 1 file changed, 1 insertion(+) create mode 100644 init.zsh diff --git a/init.zsh b/init.zsh new file mode 100644 index 0000000..b6aca49 --- /dev/null +++ b/init.zsh @@ -0,0 +1 @@ +. $(dirname $0)/autoenv.zsh From 392bca542c7f965f06b7471488e6784a14574a40 Mon Sep 17 00:00:00 2001 From: Daniel Hahler Date: Mon, 19 Jan 2015 18:54:41 +0100 Subject: [PATCH 64/72] make: fix calling tests files directly --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 7b1b23f..f59c91d 100644 --- a/Makefile +++ b/Makefile @@ -21,7 +21,7 @@ TESTS:=$(wildcard 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="${CURDIR}/tests" cram --shell=zsh -v $@ + cram --shell=zsh -v $@ .PHONY: $(_TESTS_REL_AND_ABS) .PHONY: itest test From 873b9f8062f093f84d2b64fe36552c9c1e855464 Mon Sep 17 00:00:00 2001 From: Daniel Hahler Date: Mon, 19 Jan 2015 18:57:47 +0100 Subject: [PATCH 65/72] Fix symlink handling, especially for symlinks not below "env_dir" --- autoenv.zsh | 19 ++++++++++++++++--- tests/cwd.t | 7 +++++-- tests/leave.t | 25 +++++++++++++++++++++++++ 3 files changed, 46 insertions(+), 5 deletions(-) diff --git a/autoenv.zsh b/autoenv.zsh index 561a336..c569ef8 100644 --- a/autoenv.zsh +++ b/autoenv.zsh @@ -74,11 +74,24 @@ _autoenv_stack_entered_remove() { } # Is the given entry already in the stack? +# This checks for the env_file ($1) as-is and with symlinks resolved. _autoenv_stack_entered_contains() { local env_file=$1 + local f i 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 + f=$env_file + else + for i in $_autoenv_stack_entered; do + if [[ ${i:A} == ${env_file:A} ]]; then + # Entry is in stack (compared with resolved symlinks). + f=$i + break + fi + done + fi + if [[ -n $f ]]; then + if [[ $_autoenv_stack_entered_mtime[$f] == $(_autoenv_get_file_mtime $f) ]]; then # Entry has the expected mtime. return fi @@ -275,8 +288,8 @@ _autoenv_chpwd_handler() { if [[ $AUTOENV_HANDLE_LEAVE == 1 ]] && (( $#_autoenv_stack_entered )); then local prev_file prev_dir for prev_file in ${_autoenv_stack_entered}; do - prev_dir=${prev_file:A:h} - if ! [[ ${PWD:A}/ == ${prev_dir}/* ]]; then + prev_dir=${prev_file: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 diff --git a/tests/cwd.t b/tests/cwd.t index ee586b4..e0ae132 100644 --- a/tests/cwd.t +++ b/tests/cwd.t @@ -33,5 +33,8 @@ Check that symlinked dirs get handled correctly. $ cd sub_linked ENTERED: PWD:sub_linked pwd:sub_linked from:cwd.t to:sub_linked event:enter $ cd sub2 - ENTERED: PWD:sub2 pwd:sub2 from:sub_linked to:sub2 event:enter - $ cd . + + $ cd ../.. + LEFT: PWD:cwd.t pwd:cwd.t from:sub2 to:cwd.t event:leave + $ cd sub_linked/sub2 + ENTERED: PWD:sub2 pwd:sub2 from:cwd.t to:sub2 event:enter diff --git a/tests/leave.t b/tests/leave.t index 227da71..fb7ee37 100644 --- a/tests/leave.t +++ b/tests/leave.t @@ -88,3 +88,28 @@ Test that .env is sourced only once with AUTOENV_HANDLE_LEAVE=0. ENTERED $ cd .. $ cd sub + + +Test that "leave" is not triggered when entering an outside dir via symlink. + + $ AUTOENV_HANDLE_LEAVE=1 + $ cd .. + LEFT + $ mkdir outside + $ cd outside + $ echo 'echo ENTERED outside: PWD:${PWD:t} pwd:${${"$(pwd)"}:t} from:${autoenv_from_dir:t} to:${autoenv_to_dir:t} event:${autoenv_event}' > .env + $ echo 'echo LEFT outside: PWD:${PWD:t} pwd:${${"$(pwd)"}:t} from:${autoenv_from_dir:t} to:${autoenv_to_dir:t} event:${autoenv_event}' > .env.leave + $ test_autoenv_auth_env_files + + $ cd .. + $ ln -s ../outside sub/symlink + $ cd sub + ENTERED + $ cd symlink + ENTERED outside: PWD:symlink pwd:symlink from:sub to:symlink event:enter + + $ cd ../.. + LEFT + LEFT outside: PWD:leave.t pwd:leave.t from:symlink to:leave.t event:leave + $ cd sub/symlink + ENTERED outside: PWD:symlink pwd:symlink from:leave.t to:symlink event:enter From 373e1b21fba4b469ed5c555f44df941da2c79cdd Mon Sep 17 00:00:00 2001 From: Daniel Hahler Date: Mon, 19 Jan 2015 19:01:20 +0100 Subject: [PATCH 66/72] Add support for $AUTOENV_DISABLED, which skips the chpwd hook --- autoenv.zsh | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/autoenv.zsh b/autoenv.zsh index 561a336..d4cd642 100644 --- a/autoenv.zsh +++ b/autoenv.zsh @@ -21,6 +21,9 @@ export AUTOENV_ENV_FILENAME=$HOME/.env_auth # Enable debugging. Multiple levels are supported (max 2). : ${AUTOENV_DEBUG:=0} +# (Temporarily) disable zsh-autoenv. This gets looked at in the chpwd handler. +: ${AUTOENV_DISABLED:=0} + # Public helper functions, which can be used from your .env files: # # Source the next .env file from parent directories. @@ -267,10 +270,16 @@ _autoenv_get_file_upwards() { _autoenv_chpwd_prev_dir=$PWD _autoenv_chpwd_handler() { - local env_file="$PWD/$AUTOENV_FILE_ENTER" - _autoenv_debug "Calling chpwd handler: PWD=$PWD" + if (( $AUTOENV_DISABLED )); then + _autoenv_debug "Disabled (AUTOENV_DISABLED)." + return + fi + + local env_file="$PWD/$AUTOENV_FILE_ENTER" + _autoenv_debug "env_file: $env_file" + # Handle leave event for previously sourced env files. if [[ $AUTOENV_HANDLE_LEAVE == 1 ]] && (( $#_autoenv_stack_entered )); then local prev_file prev_dir From 5cfc69ad47a4b9736f96bfdec9a46fe5a510f612 Mon Sep 17 00:00:00 2001 From: Daniel Hahler Date: Sun, 25 Jan 2015 19:16:30 +0100 Subject: [PATCH 67/72] Improve ZDOTDIR setting in Makefile --- Makefile | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index f59c91d..fc1e35d 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,8 @@ -export ZDOTDIR=${CURDIR}/tests/ZDOTDIR +# Default, can be overridden using "make test ZDOTDIR=...". +ZDOTDIR:=${CURDIR}/tests/ZDOTDIR + +# Export it, and make it absolute. +override export ZDOTDIR:=$(abspath $(ZDOTDIR)) test: cram --shell=zsh -v tests From 6fe08c3fdeec540d7f4dc126e6625e6ae3bbc213 Mon Sep 17 00:00:00 2001 From: Daniel Hahler Date: Sun, 25 Jan 2015 19:18:25 +0100 Subject: [PATCH 68/72] Improve zsh/zstat integration; also make it handle dirs --- autoenv.zsh | 34 +++++++++++++++++----------------- tests/_autoenv_stack.t | 4 +++- tests/_autoenv_utils.t | 14 ++++++++++++++ 3 files changed, 34 insertions(+), 18 deletions(-) diff --git a/autoenv.zsh b/autoenv.zsh index 24f4b04..3ec01e9 100644 --- a/autoenv.zsh +++ b/autoenv.zsh @@ -60,13 +60,23 @@ _autoenv_stack_entered_add() { _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 -} + +# zstat_mime helper, conditionally defined. +# Load zstat module, but only its builtin `zstat`. +if ! zmodload -F zsh/stat b:zstat 2>/dev/null; then + # If the module is not available, define a wrapper around `stat`, and use its + # terse output instead of format, which is not supported by busybox. + # Assume '+mtime' as $1. + _autoenv_get_file_mtime() { + setopt localoptions pipefail + stat -t $1 2>/dev/null | cut -f13 -d ' ' || echo 0 + } +else + _autoenv_get_file_mtime() { + zstat +mtime $1 2>/dev/null || echo 0 + } +fi + # Remove an entry from the stack. _autoenv_stack_entered_remove() { @@ -132,16 +142,6 @@ _autoenv_debug() { } # }}} -# Load zstat module, but only its builtin `zstat`. -if ! zmodload -F zsh/stat b:zstat 2>/dev/null; then - # If the module is not available, define a wrapper around `stat`, and use its - # terse output instead of format, which is not supported by busybox. - # Assume '+mtime' as $1. - zstat() { - stat -t $2 | cut -f13 -d ' ' - } -fi - # Generate hash pair for a given file ($1). # A fixed hash value can be given as 2nd arg, but is used with tests only. diff --git a/tests/_autoenv_stack.t b/tests/_autoenv_stack.t index 6f659c6..299d064 100644 --- a/tests/_autoenv_stack.t +++ b/tests/_autoenv_stack.t @@ -12,6 +12,8 @@ Add existing entries. $ mkdir -p sub/sub2 $ touch -t 201401010101 sub/file + $ touch -t 201401010102 sub + $ touch -t 201401010103 sub/sub2 $ _autoenv_stack_entered_add sub $ _autoenv_stack_entered_add sub/file $ _autoenv_stack_entered_add sub/sub2 @@ -26,7 +28,7 @@ Add existing entries. sub sub/file sub/sub2 non-existing $ echo $_autoenv_stack_entered_mtime - 0 1388538060 0 0 (glob) + 1388538180 1388538060 1388538120 0 Touch the file and re-add it. diff --git a/tests/_autoenv_utils.t b/tests/_autoenv_utils.t index 3da1fde..91fa1be 100644 --- a/tests/_autoenv_utils.t +++ b/tests/_autoenv_utils.t @@ -71,3 +71,17 @@ Re-add the first one, with a new hash. :/tmp/cramtests-*/_autoenv_utils.t/second:7bee8f3b184e1e141ff76efe369c3b8bfc50e64c:1 (glob) :/tmp/cramtests-*/_autoenv_utils.t/first:65eb010197b73ddc109b7210080f97a87f53451e:1 (glob) }}} + + +Explicit calls to _autoenv_get_file_mtime to test alternative implementation +of _autoenv_get_file_mtime (via ZDOTDIR.invalid-module_path/). + + $ _autoenv_get_file_mtime non-existing + 0 + $ touch -t 201401010101 file + $ _autoenv_get_file_mtime file + 1388538060 + $ mkdir dir + $ touch -t 201401010102 dir + $ _autoenv_get_file_mtime dir + 1388538120 From 5d65371786a1e97f73ba37bc2f6db29b31db9fab Mon Sep 17 00:00:00 2001 From: Daniel Hahler Date: Sun, 25 Jan 2015 19:19:11 +0100 Subject: [PATCH 69/72] Test env for invalid zsh module_path, where zsh/zstat fails --- tests/ZDOTDIR.invalid-module_path/.zshenv | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 tests/ZDOTDIR.invalid-module_path/.zshenv diff --git a/tests/ZDOTDIR.invalid-module_path/.zshenv b/tests/ZDOTDIR.invalid-module_path/.zshenv new file mode 100644 index 0000000..baa1de6 --- /dev/null +++ b/tests/ZDOTDIR.invalid-module_path/.zshenv @@ -0,0 +1,13 @@ +# Use invalid module path for zsh, to test alternative zstat implementation. + +# Pre-load zsh/parameter, where we do not have/need(?) an alternative +# implementation. +zmodload zsh/parameter + +module_path=(/dev/null) + +zstat() { + echo "Should not get called." +} + +source ${ZDOTDIR}/../ZDOTDIR/.zshenv From 5cb689875e3fc9e231663f2ecfc1d146c4451021 Mon Sep 17 00:00:00 2001 From: Daniel Hahler Date: Sun, 25 Jan 2015 19:48:25 +0100 Subject: [PATCH 70/72] tests: abort if setup fails! Otherwise the user's auth file might get removed. --- tests/_autoenv_stack.t | 2 +- tests/_autoenv_utils.t | 2 +- tests/autoenv.t | 2 +- tests/cwd.t | 2 +- tests/leave.t | 2 +- tests/recurse-upwards.t | 2 +- tests/varstash.t | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/tests/_autoenv_stack.t b/tests/_autoenv_stack.t index 6f659c6..de919a1 100644 --- a/tests/_autoenv_stack.t +++ b/tests/_autoenv_stack.t @@ -1,6 +1,6 @@ Tests for internal stack handling. - $ source $TESTDIR/setup.sh + $ source $TESTDIR/setup.sh || return 1 Non-existing entries are allowed and handled without error. diff --git a/tests/_autoenv_utils.t b/tests/_autoenv_utils.t index 3da1fde..8e47a15 100644 --- a/tests/_autoenv_utils.t +++ b/tests/_autoenv_utils.t @@ -1,6 +1,6 @@ Tests for internal util methods. - $ source $TESTDIR/setup.sh + $ source $TESTDIR/setup.sh || return 1 Non-existing entries are allowed and handled without error. diff --git a/tests/autoenv.t b/tests/autoenv.t index aef6bb9..7618385 100644 --- a/tests/autoenv.t +++ b/tests/autoenv.t @@ -1,4 +1,4 @@ - $ source $TESTDIR/setup.sh + $ source $TESTDIR/setup.sh || return 1 Lets set a simple .env action diff --git a/tests/cwd.t b/tests/cwd.t index e0ae132..9a0bd13 100644 --- a/tests/cwd.t +++ b/tests/cwd.t @@ -1,6 +1,6 @@ Test $PWD, $autoenv_event, $autoenv_from_dir and $autoenv_to_dir. - $ source $TESTDIR/setup.sh + $ source $TESTDIR/setup.sh || return 1 Setup env actions / output. diff --git a/tests/leave.t b/tests/leave.t index fb7ee37..ad70e2f 100644 --- a/tests/leave.t +++ b/tests/leave.t @@ -1,4 +1,4 @@ - $ source $TESTDIR/setup.sh + $ source $TESTDIR/setup.sh || return 1 Lets set a simple .env action diff --git a/tests/recurse-upwards.t b/tests/recurse-upwards.t index 68f79be..20a35d1 100644 --- a/tests/recurse-upwards.t +++ b/tests/recurse-upwards.t @@ -1,6 +1,6 @@ Test recursing into parent .env files. - $ source $TESTDIR/setup.sh + $ source $TESTDIR/setup.sh || return 1 Setup env actions / output. diff --git a/tests/varstash.t b/tests/varstash.t index 487230b..85d665f 100644 --- a/tests/varstash.t +++ b/tests/varstash.t @@ -1,6 +1,6 @@ Test varstash integration. - $ source $TESTDIR/setup.sh + $ source $TESTDIR/setup.sh || return 1 Setup test environment. From 88e602e3675353f14cd181497b180fa6f2b6c2b3 Mon Sep 17 00:00:00 2001 From: Daniel Hahler Date: Sun, 25 Jan 2015 19:50:27 +0100 Subject: [PATCH 71/72] tests: setup.sh: doc / more verbose --- tests/setup.sh | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/tests/setup.sh b/tests/setup.sh index 557b9e7..5dcb62b 100644 --- a/tests/setup.sh +++ b/tests/setup.sh @@ -1,3 +1,7 @@ +# Setup for tests. +# +# It returns 1 in case of errors, and no tests should be run then! +# # Ensure we have our mocked out AUTOENV_ENV_FILENAME # (via .zshenv). @@ -5,7 +9,10 @@ # Not handled in varstash yet. # setopt nounset -[[ $AUTOENV_ENV_FILENAME[0,4] == '/tmp' ]] || return 1 +if [[ $AUTOENV_ENV_FILENAME[0,4] != '/tmp' ]]; then + echo "AUTOENV_ENV_FILENAME is not in /tmp. Aborting." + return 1 +fi # Reset any authentication. echo -n >| $AUTOENV_ENV_FILENAME From c3c0cb96764211e7ee28f95fd7120fe14e858cc7 Mon Sep 17 00:00:00 2001 From: Daniel Hahler Date: Sun, 25 Jan 2015 23:51:41 +0100 Subject: [PATCH 72/72] Makefile: add clean target --- Makefile | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Makefile b/Makefile index f59c91d..0c7b2e9 100644 --- a/Makefile +++ b/Makefile @@ -25,3 +25,6 @@ $(_TESTS_REL_AND_ABS): .PHONY: $(_TESTS_REL_AND_ABS) .PHONY: itest test + +clean: + $(RM) tests/*.err