From cd10903ba197ff4244765f85b56291f0bc390817 Mon Sep 17 00:00:00 2001 From: 0xee Date: Wed, 20 Nov 2019 10:09:15 +0100 Subject: [PATCH] Populate repo with initial version --- README.md | 58 ++++++++++++++++++++++++++++ default.nix | 3 ++ direnv-cache | 106 +++++++++++++++++++++++++++++++++++++++++++++++++++ direnvrc | 17 +++++++++ 4 files changed, 184 insertions(+) create mode 100644 default.nix create mode 100755 direnv-cache create mode 100644 direnvrc diff --git a/README.md b/README.md index 7836037..4e1fd07 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,60 @@ # direnv-cache +## Setup + +direnv-cache consists of two components: the direnv-cache script and an +extension to direnv's stdlib. + +To set up direnv-cache, make direnv read the provided direnvrc, eg. via + + cp direnvrc ~/.config/direnv/direnvrc + +and install direnv-cache somewhere in your PATH. + +If you use home-manager, you can add the following to your configuration + + ... + let + direnv-cache = pkgs.callPackage ./path/to/this/repo {}; + in + ... + + home.packages = [ ... direnv-cache ... ]; + programs.direnv = { + enable = true; + enableBashIntegration = true; + stdlib = builtins.readFile direnv-cache.direnvrc; + }; + ... + +## Usage + +The following assumes a working direnv setup. + +Use the cache function in your `.envrc` files, eg. + + cache < {} }: +(pkgs.writers.writeBashBin "direnv-cache" ./direnv-cache).overrideAttrs + (o: { passthru = { direnvrc = ./direnvrc; }; }) diff --git a/direnv-cache b/direnv-cache new file mode 100755 index 0000000..4dc30fd --- /dev/null +++ b/direnv-cache @@ -0,0 +1,106 @@ +#!/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 read -r -d '' line; do + name=$(tr -d '\0' <<<"$line" | head -n1 | cut -f1 -d'=') + if ! getByName "$name" "$new" >/dev/null; then + echo "export -n '${name}'" + fi + done <"$old" + + while read -rd $'\0' line; do + name=$(tr -d '\0' <<<"$line" | head -n1 | cut -f1 -d'=') + 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 + 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 ' -')" +} + +cmd="$1" + +if ! [[ -e .envrc ]]; then + echo "Error, no .envrc found in current directory" + exit 1 +fi + +cacheFile=$(getCacheFilePath) + +case $cmd in + reload|r) + echo "Re-creating cache" + mkdir -p "$(dirname ${cacheFile})" + dumpEnv > "${cacheFile}.pre" + source <(direnv stdlib) + if [[ .envrc -nt ${cacheFile}.recipe ]]; then + direnv exec . true > /dev/null + fi + 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 + ;; + *) + usage + exit 1 +esac diff --git a/direnvrc b/direnvrc new file mode 100644 index 0000000..11972dd --- /dev/null +++ b/direnvrc @@ -0,0 +1,17 @@ +# -*- mode: sh -*- + +cache() { + + local cacheDir="${XDG_CACHE_HOME:-$HOME/.cache}/direnv-cache" + mkdir -p "$cacheDir" + local cacheFile + cacheFile="${cacheDir}/$(pwd | sha1sum | tr -d ' -')" + cat - > "${cacheFile}.recipe" + if [[ -e "$cacheFile" ]]; then + echo "Using cached environment from $cacheFile" + . $cacheFile + else + echo "Environment not cached" + fi +} +