Populate repo with initial version

master
0xee 2019-11-20 10:09:15 +01:00
parent 86140610dd
commit cd10903ba1
4 changed files with 184 additions and 0 deletions

View File

@ -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 <<EOF
# everything in here will be cached
use nix -p hello
EOF
# you can also have stuff outside the cached region
export PATH=/some/other/path:$PATH
If you now enter the directory, direnv will tell you that the environment
is not yet cached. We can fix that by running `direnv-cache reload`. This
will also tell direnv to reload. From now on, if you enter the directory,
direnv will load the cached environment.
Re-run `direnv-cache reload` whenever your `.envrc` or other dependencies change
to update the cache.
## How it works
Everything piped into the `cache` function is stored in a recipe file in
direnv-cache's cache directory when the `.envrc` is evaluated. Then, if the
environment cache exists, it is sourced.
When `direnv-cache reload` is called, it looks for a recipe file for the
current directory, and runs it. A diff of the environments before and after the
recipe is run is written to the directory-specific cache file.

3
default.nix Normal file
View File

@ -0,0 +1,3 @@
{ pkgs ? import <nixpkgs> {} }:
(pkgs.writers.writeBashBin "direnv-cache" ./direnv-cache).overrideAttrs
(o: { passthru = { direnvrc = ./direnvrc; }; })

106
direnv-cache Executable file
View File

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

17
direnvrc Normal file
View File

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