1
0
mirror of https://github.com/Tarrasch/zsh-autoenv.git synced 2024-11-22 07:20:59 +02:00

Merge pull request #8 from blueyed/next

Next: varstash integration, tests refactoring, s/dotenv/autoenv/ and some more
This commit is contained in:
Daniel Hahler 2014-11-27 15:52:17 +01:00
commit c2a3009d4a
12 changed files with 933 additions and 134 deletions

View File

@ -1,7 +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)
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)

View File

@ -1,68 +1,177 @@
# 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}
: ${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}
# Enable debugging. Multiple levels are supported (max 2).
: ${AUTOENV_DEBUG:=0}
# Internal: stack of entered (and handled) directories.
_dotenv_stack_entered=()
# 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
_autoenv_debug "Calling autoenv_source_parent: parent_env_file:$parent_env_file"
_dotenv_hash_pair() {
local env_file=$1
env_shasum=$(shasum $env_file | cut -d' ' -f1)
echo "$env_file:$env_shasum"
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
}
_dotenv_authorized_env_file() {
# Internal functions. {{{
# 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
local pair=$(_dotenv_hash_pair $env_file)
test -f $ENV_AUTHORIZATION_FILE \
&& \grep -qF $pair $ENV_AUTHORIZATION_FILE
_autoenv_debug "[stack] adding: $env_file" 2
# Remove any existing entry.
_autoenv_stack_entered_remove $env_file
# 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)
}
_dotenv_authorize() {
local env_file=$1
_dotenv_deauthorize $env_file
_dotenv_hash_pair $env_file >> $ENV_AUTHORIZATION_FILE
_autoenv_get_file_mtime() {
if [[ -f $1 ]]; then
zstat +mtime $1
else
echo 0
fi
}
_dotenv_deauthorize() {
# Remove an entry from the stack.
_autoenv_stack_entered_remove() {
local env_file=$1
if [[ -f $ENV_AUTHORIZATION_FILE ]]; then
echo $(\grep -vF $env_file $ENV_AUTHORIZATION_FILE) > $ENV_AUTHORIZATION_FILE
_autoenv_debug "[stack] removing: $env_file" 2
_autoenv_stack_entered[$_autoenv_stack_entered[(i)$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
}
# }}}
# 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
_autoenv_hash_pair() {
local env_file=${1:A}
local env_shasum
if [[ -n $2 ]]; then
env_shasum=$2
else
env_shasum=$(shasum $env_file | cut -d' ' -f1)
fi
echo "$env_file:$env_shasum:1"
}
_autoenv_authorized_env_file() {
local env_file=$1
local pair=$(_autoenv_hash_pair $env_file)
test -f $AUTOENV_ENV_FILENAME \
&& \grep -qF $pair $AUTOENV_ENV_FILENAME
}
_autoenv_authorize() {
local env_file=$1
_autoenv_deauthorize $env_file
_autoenv_hash_pair $env_file >> $AUTOENV_ENV_FILENAME
}
_autoenv_deauthorize() {
local env_file=$1
if [[ -f $AUTOENV_ENV_FILENAME ]]; then
echo $(\grep -vF $env_file $AUTOENV_ENV_FILENAME) > $AUTOENV_ENV_FILENAME
fi
}
# This function can be mocked in tests
_dotenv_read_answer() {
_autoenv_ask_for_yes() {
local answer
read -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).
_dotenv_check_authorized_env_file() {
_autoenv_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"
if ! _autoenv_authorized_env_file $1; then
echo "Attempting to load unauthorized env file!"
command ls -l $1
echo ""
echo "**********************************************"
echo ""
@ -70,78 +179,133 @@ _dotenv_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=$(_dotenv_read_answer)
echo
if [[ $answer != 'y' ]]; then
if ! _autoenv_ask_for_yes; then
return 1
fi
_dotenv_authorize $1
_autoenv_authorize $1
fi
return 0
}
_dotenv_source() {
# Get directory of this file (absolute, with resolved symlinks).
_autoenv_source_dir=${0:A:h}
_autoenv_source() {
local env_file=$1
_dotenv_event=$2
_dotenv_cwd=$PWD
_autoenv_event=$2
local _autoenv_envfile_dir=${3:-${1:A:h}}
builtin cd -q ${env_file:h}
_autoenv_from_dir=$_autoenv_chpwd_prev_dir
_autoenv_to_dir=$PWD
# Source varstash library once.
if [[ -z "$functions[(I)autostash]" ]]; then
source $_autoenv_source_dir/lib/varstash
# 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 $_autoenv_envfile_dir
_autoenv_debug "== SOURCE: ${bold_color}$env_file${reset_color}\n PWD: $PWD"
(( _autoenv_debug_indent++ ))
source $env_file
builtin cd -q $_dotenv_cwd
(( _autoenv_debug_indent-- ))
_autoenv_debug "== END SOURCE =="
builtin cd -q $new_dir
unset _dotenv_event _dotenv_cwd
# 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
}
_dotenv_chpwd_handler() {
local env_file="$PWD/$DOTENV_FILE_ENTER"
_autoenv_get_file_upwards() {
local look_from=${1:-$PWD}
local look_for=${2:-$AUTOENV_FILE_ENTER}
# 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
}
_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 [[ $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
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/$DOTENV_FILE_LEAVE
if _dotenv_check_authorized_env_file $env_file_leave; then
_dotenv_source $env_file_leave leave
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_remove $prev_file
fi
done
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))
if (( $#m )); then
env_file=${${m[1]}:A}
else
if ! [[ -f $env_file ]] && [[ $AUTOENV_LOOK_UPWARDS == 1 ]]; then
env_file=$(_autoenv_get_file_upwards $PWD)
if [[ -z $env_file ]]; then
_autoenv_chpwd_prev_dir=$PWD
return
fi
fi
if ! _dotenv_check_authorized_env_file $env_file; then
# 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
# 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
if ! _autoenv_check_authorized_env_file $env_file; then
_autoenv_chpwd_prev_dir=$PWD
return
fi
_dotenv_stack_entered+=(${env_file_dir})
_autoenv_stack_entered_add $env_file
_dotenv_source $env_file enter
# 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 _dotenv_chpwd_handler
add-zsh-hook chpwd _autoenv_chpwd_handler
# Look in current directory already.
_dotenv_chpwd_handler
_autoenv_chpwd_handler

343
lib/varstash Normal file
View File

@ -0,0 +1,343 @@
################################################################################
# Stash/unstash support for per-directory variables
#
# Adopted for zsh-autoenv.
#
# Copyright (c) 2009,2012 Dave Olszewski <cxreg@pobox.com>
# 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 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.
#
################################################################################
# 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
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() {
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() {
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}"
}
# vim: filetype=sh autoindent expandtab shiftwidth=4 softtabstop=4

View File

@ -1,4 +1,6 @@
test -f "$TESTDIR/.zcompdump" && rm "$TESTDIR/.zcompdump"
AUTOENV_DEBUG=0
source "$TESTDIR/../autoenv.plugin.zsh"
export ENV_AUTHORIZATION_FILE="$PWD/.env_auth"
export AUTOENV_ENV_FILENAME="$PWD/.env_auth"

58
tests/_autoenv_stack.t Normal file
View File

@ -0,0 +1,58 @@
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]
Test removing.
$ _autoenv_stack_entered_remove sub
$ echo ${_autoenv_stack_entered}
sub/sub2 non-existing sub/file

15
tests/_autoenv_utils.t Normal file
View File

@ -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)

View File

@ -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
@ -8,17 +6,18 @@ Lets set a simple .env action
Manually create auth file
$ echo "$PWD/.env:$(echo echo ENTERED | shasum)" > $ENV_AUTHORIZATION_FILE
$ test_autoenv_add_to_env $PWD/.env
$ cd .
ENTERED
Now try to make it accept it
$ unset _dotenv_stack_entered
$ rm $ENV_AUTHORIZATION_FILE
$ _dotenv_read_answer() { echo 'y' }
$ unset _autoenv_stack_entered
$ rm $AUTOENV_ENV_FILENAME
$ _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)
**********************************************
@ -26,26 +25,24 @@ 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.
Now lets see that it actually checks the shasum value.
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
$ rm $ENV_AUTHORIZATION_FILE
$ echo "$PWD/.env:$(echo mischief | shasum)" > $ENV_AUTHORIZATION_FILE
$ unset _autoenv_stack_entered
$ 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)
**********************************************
@ -53,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 _dotenv_stack_entered
$ rm $ENV_AUTHORIZATION_FILE
$ _dotenv_read_answer() { echo 'n' }
$ unset _autoenv_stack_entered
$ rm $AUTOENV_ENV_FILENAME
$ _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)
**********************************************
@ -74,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)
**********************************************
@ -91,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

View File

@ -1,29 +1,26 @@
Test $PWD and $_dotenv_cwd.
Test $PWD, $_autoenv_from_dir and _autoenv_to_dir.
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.
$ DOTENV_LOOK_UPWARDS=1
$ AUTOENV_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:${_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.
$ 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
$ test_autoenv_auth_env_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:sub from:cwd.t to:sub2

View File

@ -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
@ -12,9 +9,10 @@ Lets set a simple .env action
Change to the directory.
$ _dotenv_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)
**********************************************
@ -22,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".
$ _dotenv_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)
**********************************************
@ -38,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
$ _dotenv_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)
**********************************************
@ -53,13 +53,13 @@ Leave the directory and answer "no".
**********************************************
Would you like to authorize it? [y/N]
Would you like to authorize it? (type 'yes') yes
LEFT
Now check with subdirs, looking upwards.
$ DOTENV_LOOK_UPWARDS=1
$ AUTOENV_LOOK_UPWARDS=1
$ mkdir sub/child
$ cd sub/child
ENTERED
@ -71,7 +71,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
@ -80,10 +80,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 ..

167
tests/recurse-upwards.t Normal file
View File

@ -0,0 +1,167 @@
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: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
$ 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:sub 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 "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 ..
$ 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
$ 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.
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
Changing the root .env should trigger re-authentication via autoenv_source_parent.
First, let's answer "no".
$ echo "echo NEW" > .env
$ _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)
**********************************************
echo NEW
**********************************************
Would you like to authorize it? (type 'yes') no
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_ask_for_yes() { echo "yes"; return 0 }
$ 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? (type 'yes') yes
NEW
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

18
tests/setup.sh Normal file
View File

@ -0,0 +1,18 @@
# Ensure we have our mocked out AUTOENV_ENV_FILENAME
# (via .zshenv).
[[ $AUTOENV_ENV_FILENAME[0,4] == '/tmp' ]] || return 1
# Reset any authentication.
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
}
# Add enter and leave env files to authentication file.
test_autoenv_auth_env_files() {
test_autoenv_add_to_env $PWD/$AUTOENV_FILE_ENTER
test_autoenv_add_to_env $PWD/$AUTOENV_FILE_LEAVE
}

32
tests/varstash.t Normal file
View File

@ -0,0 +1,32 @@
Test varstash integration.
$ source $TESTDIR/setup.sh
Setup test environment.
$ mkdir sub
$ cd sub
$ echo 'echo ENTER; autostash FOO=baz' > $AUTOENV_FILE_ENTER
$ echo 'echo LEAVE; autounstash' > $AUTOENV_FILE_LEAVE
Manually create auth file
$ test_autoenv_auth_env_files
Set environment variable.
$ FOO=bar
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