Skip to content

Commit 2a8ebfa

Browse files
committed
Add a new asdf direnv install command
Before this diff, it was difficult to install tools that depend on other tools. For example, here's what happens if I try to install a version of poetry on my machine: $ asdf install poetry 1.5.1 No version is set for command python3 Consider adding one of the following versions in your config file at python 3.10.2 python 3.8.10 curl: (23) Failure writing output to destination Cleanup: Something went wrong! 48 /home/jeremy/.asdf/plugins/poetry/bin/install: POETRY_HOME=$install_path python3 - --version "$version" $flags This is because my system doesn't actually have a global `python` or `python3`. While I *could* install python with my system's package manager, I'd rather re-use my asdf-managed python if at all possible. Plus, poetry's installer doesn't even work with the 2 most popular ways of installing python systemwide on macOS (see [this poetry issue](python-poetry/install.python-poetry.org#24 (comment)) and [this homebrew issue](Homebrew/homebrew-core#138159)). I know this doesn't solve the general build-dependencies issue: asdf is not a full package manager and I doubt it ever will become one. I do think this fairly minor change is worth implementing though, as it will solve a pain point my team has started running into ever since [homebrew changed they way they build binaries and that broke poetry install](Homebrew/homebrew-core#138159). As a happy side effect, we can now run `direnv reload` for the user, which saves them a step whenever they need to install missing dependencies.
1 parent 04b8873 commit 2a8ebfa

File tree

4 files changed

+137
-8
lines changed

4 files changed

+137
-8
lines changed

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,16 @@ github compare-link with the previous one.
1111

1212
## [Unreleased](https://github.com/asdf-community/asdf-direnv/compare/v0.3.0..master)
1313

14+
- Add new `asdf direnv install` command to help when installing tools that depend on each other. #180
15+
1416
- Fix `find` warning. #178
17+
1518
- Add '--no-touch-rc-file' option to prevent rc file modification during updates. #176
19+
1620
- Alternatively, `export ASDF_DIRENV_NO_TOUCH_RC_FILE=1` to prevent rc file modification. #176
1721

1822
- Add support for resolving 'latest:X' in .tool-versions #136
23+
1924
- Add support for resolving 'latest' in .tool-versions #168
2025

2126
## [0.3.0](https://github.com/asdf-community/asdf-direnv/compare/v0.3.0) (2022-04-03)

lib/commands/command-install.bash

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
#!/usr/bin/env bash
2+
3+
# Exit on error, since this is an executable and not a sourced file.
4+
set -Eeuo pipefail
5+
6+
# shellcheck source=lib/install-lib.bash
7+
source "$(dirname "${BASH_SOURCE[0]}")/../install-lib.bash"
8+
install_command "$@"

lib/install-lib.bash

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
#!/usr/bin/env bash
2+
3+
# shellcheck source=lib/tools-environment-lib.bash
4+
source "$(dirname "${BASH_SOURCE[0]}")/tools-environment-lib.bash"
5+
6+
function print_usage() {
7+
echo "Usage: asdf direnv install"
8+
echo ""
9+
echo "Installs tools needed for the current directory. This is very similar"
10+
echo "to 'asdf install' except it installs the tools in the exact order specified"
11+
echo "in the '.tool-versions' file, and loads the environment of each tool in order."
12+
echo ""
13+
echo "This is useful when installing tools that depend on other tools, for"
14+
echo "example: the poetry plugin expects python to be available."
15+
echo ""
16+
echo "Note: this problem isn't entirely unique to asdf-direnv. asdf itself"
17+
echo "isn't a full-fledged package manager. It simply doesn't understand"
18+
echo "dependencies between plugins and therefore cannot do a dependency sort of"
19+
echo "tools. You'll need to manually sort the lines of your '.tool-versions' file"
20+
echo "for this to work as intended. See these discussions in core asdf for"
21+
echo "more information:"
22+
echo ""
23+
echo " - https://github.com/asdf-vm/asdf/issues/929"
24+
echo " - https://github.com/asdf-vm/asdf/issues/1127"
25+
echo " - https://github.com/asdf-vm/asdf/issues/196"
26+
}
27+
28+
function install_command() {
29+
while [[ $# -gt 0 ]]; do
30+
arg=$1
31+
shift
32+
case $arg in
33+
-h | --help)
34+
print_usage
35+
exit 1
36+
;;
37+
*)
38+
echo "Unknown option: $arg"
39+
exit 1
40+
;;
41+
esac
42+
done
43+
44+
install_tools
45+
}
46+
47+
_load_asdf_functions_installs() {
48+
# `install_tool_version` depends on `reshim_command` from reshim.bash.
49+
# See https://github.com/asdf-vm/asdf/blob/v0.12.0/lib/functions/installs.bash#L243
50+
_load_asdf_lib reshim_command commands/reshim.bash
51+
52+
_load_asdf_lib install_tool_version functions/installs.bash
53+
}
54+
55+
function maybe_install_tool_version() {
56+
_load_asdf_functions_installs
57+
58+
local install_path
59+
install_path=$(get_install_path "$plugin_name" "version" "$version")
60+
61+
if [ -d "$install_path" ]; then
62+
printf "%s %s is already installed\n" "$plugin_name" "$version"
63+
else
64+
65+
# NOTE: we temporarily loosen the rules while invoking
66+
# install_tool_version because it's from core asdf and it doesn't run
67+
# well under "strict mode" (asdf_run_hook invokes get_asdf_config_value
68+
# in a way such that if the config piece is missing, the program exits
69+
# immediately if `set -e` is enabled.
70+
(
71+
set +ue
72+
install_tool_version "$plugin_name" "$version"
73+
set -ue
74+
)
75+
fi
76+
}
77+
78+
function install_tools {
79+
local tools_file
80+
tools_file="$(_local_versions_file)"
81+
82+
while IFS=$'\n' read -r plugin_name; do
83+
while IFS=$'\n' read -r version_and_path; do
84+
local version _path
85+
IFS='|' read -r version _path <<<"$version_and_path"
86+
87+
# Install this tool version if not already installed.
88+
maybe_install_tool_version "$plugin_name" "$version"
89+
90+
# Load the tools environment so subsequent installs can use this tool.
91+
direnv_code=$(_plugin_env_bash "$plugin_name" "$version" ">>> UH OH <<<")
92+
eval "$direnv_code"
93+
done <<<"$(_plugin_versions_and_path "$plugin_name")"
94+
done <<<"$(_plugins_in_file "$tools_file")"
95+
96+
direnv reload
97+
}

lib/tools-environment-lib.bash

Lines changed: 27 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -213,22 +213,23 @@ _load_local_plugins_env() {
213213
fi
214214
}
215215

216-
# from asdf plugin_current_command
217-
_load_plugin_version_and_file() {
216+
function _plugin_versions_and_path() {
218217
local plugin_name=$1
219218
local versions_and_path
220-
# NOTE: temporary disable nounset since find_versions expects ASDF_DEFAULT_TOOL_VERSIONS_FILENAME to be set.
219+
# NOTE: temporarily disable nounset since find_versions expects
220+
# ASDF_DEFAULT_TOOL_VERSIONS_FILENAME to be set.
221221
versions_and_path="$(
222222
set +u
223223
find_versions "$plugin_name" "$(pwd)"
224224
set -u
225225
)"
226-
if test -z "$versions_and_path"; then
226+
if [ -z "$versions_and_path" ]; then
227227
return 0
228228
fi
229229

230230
local path
231231
path=$(cut -d '|' -f 2 <<<"$versions_and_path")
232+
232233
local versions=()
233234
while IFS=$' \t' read -r -a inline_versions; do
234235
for ((idx = ${#inline_versions[@]} - 1; idx >= 0; idx--)); do
@@ -237,12 +238,30 @@ _load_plugin_version_and_file() {
237238
done <<<"$(cut -d '|' -f 1 <<<"$versions_and_path" | uniq | _tail_r)"
238239

239240
for version in "${versions[@]}"; do
240-
echo log_status "using asdf ${plugin_name} ${version}"
241-
_plugin_env_bash "$plugin_name" "$version" "$plugin_name $version not installed. Run 'asdf install' and then 'direnv reload'."
241+
printf '%q|%q\n' "$version" "$path"
242242
done
243-
if [ -f "$path" ]; then
244-
printf 'watch_file %q\n' "$path"
243+
}
244+
245+
# from asdf plugin_current_command
246+
_load_plugin_version_and_file() {
247+
local plugin_name=$1
248+
249+
local plugin_versions_and_path
250+
plugin_versions_and_path="$(_plugin_versions_and_path "$plugin_name")"
251+
if [ -z "$plugin_versions_and_path" ]; then
252+
return 0
245253
fi
254+
255+
while IFS=$'\n' read -r version_and_path; do
256+
local version path
257+
IFS='|' read -r version path <<<"$version_and_path"
258+
259+
echo log_status "using asdf ${plugin_name} ${version}"
260+
_plugin_env_bash "$plugin_name" "$version" "$plugin_name $version not installed. Run 'asdf direnv install' to install."
261+
if [ -f "$path" ]; then
262+
printf 'watch_file %q\n' "$path"
263+
fi
264+
done <<<"$plugin_versions_and_path"
246265
}
247266

248267
_new_items() {

0 commit comments

Comments
 (0)