Skip to content

Commit

Permalink
ENH: Add direnv, asdf helper
Browse files Browse the repository at this point in the history
  • Loading branch information
HaoZeke committed Jan 23, 2022
1 parent 51f94f8 commit 522f3ba
Show file tree
Hide file tree
Showing 3 changed files with 229 additions and 0 deletions.
3 changes: 3 additions & 0 deletions dot_config/asdf/asdfrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# https://asdf-vm.com/manage/configuration.html
legacy_version_file = yes
always_keep_download = no
212 changes: 212 additions & 0 deletions dot_config/direnv/direnvrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,212 @@
########
# ASDF #
########

# Usage (lines other than the first are optional):
## use asdf
#
# This loads asdf and uses a cached setup which circumvents one reshim
#
# https://github.com/asdf-community/asdf-direnv
#

source "$(asdf direnv hook asdf)"

########
# Ruby #
########

# Usage (lines other than the first are optional):
## layout ruby
## use asdf
## PATH_add .direnv/bundler-bin
#
# This watches some files. Uses asdf for managing versions.
#
# https://github.com/direnv/direnv/wiki/Ruby
#

layout_ruby() {
# Direnv specials
watch_file Gemfile
watch_file .ruby_version
}

######
# Go #
######

# Usage: layout golang
#
# Sets up environment for a Go project using the alternative gb build tool. Also
# works with the official dep package.In addition to project executables on
# PATH, this includes an exclusive, project- local GOPATH which enables many
# tools like gocode and oracle to "just work".
#
# http://getgb.io/
# https://golang.github.io/dep/
#

layout_golang() {
export GOPATH="$PWD/vendor:$PWD"
PATH_add "$PWD/vendor/bin"
PATH_add bin
}

#######
# Nix #
#######

# From https://github.com/direnv/direnv/wiki/Nix and https://github.com/kalbasit/nur-packages/blob/master/pkgs/nixify/envrc

# Usage: use_nix [...]
#
# Load environment variables from `nix-shell`.
# If you have a `default.nix` or `shell.nix` one of these will be used and
# the derived environment will be stored at ./.direnv/env-<hash>
# and symlink to it will be created at ./.direnv/default.
# Dependencies are added to the GC roots, such that the environment remains persistent.
#
# The resulting environment is cached for better performance.
#
# To trigger switch to a different environment:
# `rm -f .direnv/default`
#
# To derive a new environment:
# `rm -rf .direnv/env-$(md5sum {shell,default}.nix 2> /dev/null | cut -c -32)`
#
# To remove cache:
# `rm -f .direnv/dump-*`
#
# To remove all environments:
# `rm -rf .direnv/env-*`
#
# To remove only old environments:
# `find .direnv -name 'env-*' -and -not -name `readlink .direnv/default` -exec rm -rf {} +`
#

set -eo pipefail

use_nix() {
# define all local variables
local shell f env_hash dir default wd drv dump path_backup
local files_to_watch=()

while getopts ":s:w:" opt; do
case "${opt}" in
s)
shell="${OPTARG}"
files_to_watch=("${files_to_watch[@]}" "${shell}")
;;
w)
files_to_watch=("${files_to_watch[@]}" "${OPTARG}")
;;
:)
>&2 echo "Invalid option: $OPTARG requires an argument"
;;
\?)
>&2 echo "Invalid option: $OPTARG"
exit 1
;;
esac
done
shift $((OPTIND -1))

if [[ -z "${shell}" ]]; then
>&2 echo "ERR: no shell was given"
exit 1
fi

for f in "${files_to_watch[@]}"; do
if ! [[ -f "${f}" ]]; then
>&2 echo "cannot watch file ${f} because it does not exist"
exit 1
fi
done

# compute the hash of all the files that makes up the development environment
env_hash="$(hashContents "${files_to_watch[@]}")"

dir="$(direnv_layout_dir)"
default="${dir}/default"
if [[ ! -L "${default}" ]] || [[ ! -d $(readlink "${default}") ]]; then
wd="${dir}/env-${env_hash}"
mkdir -p "${wd}"

drv="${wd}/env.drv"
if [[ ! -f "${drv}" ]]; then
log_status "use nix: deriving new environment"
IN_NIX_SHELL=1 nix-instantiate --add-root "${drv}" --indirect "${shell}" > /dev/null
nix-store -r $(nix-store --query --references "${drv}") --add-root "${wd}/dep" --indirect > /dev/null
fi

rm -f "${default}"
ln -s $(basename "${wd}") "${default}"
fi

drv=$(readlink "${default}/env.drv")
dump="${dir}/dump-$(hashFile ".envrc")-$(hashFile ${drv})"

if [[ ! -f "${dump}" ]] || [[ "${XDG_CONFIG_DIR}/direnv/direnvrc" -nt "${dump}" ]]; then
log_status "use nix: updating cache"

old=$(find "${dir}" -name 'dump-*')
nix-shell --pure "${drv}" --show-trace --run "$(join_args "$direnv" dump bash)" > "${dump}"
rm -f ${old}
fi

# evaluate the dump created by nix-shell earlier, but have to merge the PATH
# with the current PATH
# NOTE: we eval the dump here as opposed to direnv_load it because we don't
# want to persist environment variables coming from the shell at the time of
# the dump. See https://github.com/direnv/direnv/issues/405 for context.
path_backup="${PATH}"
eval $(cat "${dump}")
export PATH="${PATH}:${path_backup}"

for f in "${files_to_watch[@]}"; do
watch_file "${f}"
done
}

hashContents() {
if has md5sum; then
cat "${@}" | md5sum | cut -c -32
elif has md5; then
cat "${@}" | md5 -q
fi
}

hashFile() {
if has md5sum; then
md5sum "${@}" | cut -c -32
elif has md5; then
md5 -q "${@}"
fi
}

fail() {
log_error "${@}"
exit 1
}

validateVersion() {
local version="$("${direnv}" version)"
local major="$(echo "${version}" | cut -d. -f1)"
local minor="$(echo "${version}" | cut -d. -f2)"
local patch="$(echo "${version}" | cut -d. -f3)"

if [[ "${major}" -gt 2 ]]; then return 0; fi
if [[ "${major}" -eq 2 ]] && [[ "${minor}" -gt 18 ]]; then return 0; fi
if [[ "${major}" -eq 2 ]] && [[ "${minor}" -eq 18 ]] && [[ "${patch}" -ge 2 ]]; then return 0; fi
return 1
}

if ! validateVersion; then
echo "This .envrc requires direnv version 2.18.2 or above."
exit 1
fi

# Local Variables:
# mode: sh
# End:
14 changes: 14 additions & 0 deletions runnable/run_once_asdf_direnv.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#!/usr/bin/env bash
# Although I no longer recommend asdf, (shims are awful)
# This is the fastest way to get direnv up and running

if [[ ! -d ~/.asdf ]]; then
mkdir ~/.asdf
git clone https://github.com/asdf-vm/asdf.git ~/.asdf
fi

export ASDF_CONFIG_FILE="~/.config/asdf/asdfrc"

asdf plugin-add direnv
asdf install direnv latest
asdf global direnv latest

0 comments on commit 522f3ba

Please sign in to comment.