-
Notifications
You must be signed in to change notification settings - Fork 0
/
.direnvrc
151 lines (130 loc) · 3.93 KB
/
.direnvrc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
# 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=()
declare opt
declare OPTARG
declare OPTIND
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