From 4676713bc6539f5bdf3a26cb21b6091ddf8b1451 Mon Sep 17 00:00:00 2001 From: Daniel Hahler Date: Sat, 15 Nov 2014 15:08:52 +0100 Subject: [PATCH] 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_stack_entered=() - _dotenv_read_answer +_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 [[ $answer == 'y' ]] - then - _dotenv_authorize $env_file - source $env_file + 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 -- 2.44.0