131 lines
3.4 KiB
Bash
Executable File
131 lines
3.4 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
|
|
set -eo pipefail
|
|
|
|
# Dumps all environment variables sorted alphabetically. Uses zero byte as a
|
|
# delimiter since bash variables can not contain '\0'.
|
|
dumpEnv() {
|
|
env -0 | sort -z
|
|
}
|
|
|
|
# Retrieves the value of variable name passed as $1 in dumped environment
|
|
# passed as $2 (see dumpEnv)
|
|
getByName() {
|
|
local name="$1"
|
|
local envFile="$2"
|
|
grep -z "^${name}=" $envFile | cut -z -f2- -d '=' | tr -d '\0'
|
|
}
|
|
|
|
# Produces a diff of two given environment dumps, suitable for consumption by
|
|
# bash. Given environment dumps A and B (both generated by dumpEnv),
|
|
#
|
|
# source A; source <(diffEnvs A B)
|
|
#
|
|
# shall be equivalent to
|
|
#
|
|
# source B
|
|
#
|
|
diffEnvs() {
|
|
local name
|
|
local old="$1"
|
|
local new="$2"
|
|
|
|
while IFS= read -r -d '' line; do
|
|
name=$(tr -d '\0' <<<"$line" | head -n1 | cut -f1 -d'=')
|
|
if ! [[ "$name" = DIRENV_* ]]; then
|
|
if ! getByName "$name" "$new" >/dev/null; then
|
|
echo "export -n '${name}'"
|
|
fi
|
|
fi
|
|
done <"$old"
|
|
|
|
while IFS= read -rd $'\0' line; do
|
|
name=$(tr -d '\0' <<<"$line" | head -n1 | cut -f1 -d'=')
|
|
if ! [[ "$name" = DIRENV_* ]]; then
|
|
if getByName "$name" "$old" >/dev/null; then
|
|
# found in old env, check if values match
|
|
if ! grep -z "^${line}\$" "$old" >/dev/null; then
|
|
# variable has changed
|
|
echo "export ${line@Q}"
|
|
fi
|
|
else
|
|
# variable is new
|
|
echo "export ${line@Q}"
|
|
fi
|
|
fi
|
|
done <"$new"
|
|
}
|
|
|
|
usage() {
|
|
echo "${BASH_SOURCE[0]} COMMAND"
|
|
echo
|
|
echo "Commands:"
|
|
echo -e "\tstatus,s: Show cache status"
|
|
echo -e "\treload,r: Recreate cache from .envrc"
|
|
echo -e "\tclear,c: Remove cache file for current directory"
|
|
}
|
|
|
|
getCacheFilePath() {
|
|
local cacheDir="${XDG_CACHE_HOME:-$HOME/.cache}/direnv-cache"
|
|
echo "${cacheDir}/$(pwd | sha1sum | tr -d ' -')"
|
|
}
|
|
|
|
switchToDirenvDir() {
|
|
# Find directory that contains the current .envrc. Allows direnv-cache to
|
|
# be called from subdirectories.
|
|
wd="$(pwd)"
|
|
|
|
if [[ -n $DIRENV_DIR ]]; then
|
|
wd="${DIRENV_DIR#-}"
|
|
fi
|
|
|
|
cd "$wd"
|
|
}
|
|
|
|
cmd="$1"
|
|
|
|
switchToDirenvDir
|
|
|
|
if ! [[ -e ".envrc" ]]; then
|
|
echo "Error, no .envrc found in current directory"
|
|
exit 1
|
|
fi
|
|
|
|
cacheFile=$(getCacheFilePath)
|
|
|
|
case $cmd in
|
|
reload|r)
|
|
if [[ -n $DIRENV_DIR ]]; then
|
|
# run self in clean environment (i.e. outside of the current direnv
|
|
# environment)
|
|
echo "Switching to clean environment"
|
|
exec direnv exec /proc "${BASH_SOURCE[0]}" "$@"
|
|
fi
|
|
echo "Re-creating cache"
|
|
mkdir -p "$(dirname ${cacheFile})"
|
|
dumpEnv > "${cacheFile}.pre"
|
|
source <(direnv stdlib)
|
|
echo "Re-creating recipe"
|
|
direnv exec . true > /dev/null
|
|
source "${cacheFile}.recipe"
|
|
dumpEnv > "${cacheFile}.post"
|
|
diffEnvs "${cacheFile}.pre" "${cacheFile}.post" > "$cacheFile"
|
|
rm "${cacheFile}.pre" "${cacheFile}.post"
|
|
echo "Environment cached in $cacheFile, telling direnv to reload"
|
|
direnv reload
|
|
;;
|
|
status|s)
|
|
shift
|
|
ls "$cacheFile" "$@"
|
|
;;
|
|
clear|c)
|
|
if [[ -e "$cacheFile" ]]; then
|
|
rm "$cacheFile"
|
|
fi
|
|
direnv reload
|
|
;;
|
|
*)
|
|
usage
|
|
exit 1
|
|
esac
|