Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: install dependencies in .tool-versions order #1723

Open
wants to merge 19 commits into
base: master
Choose a base branch
from
Open
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
198 changes: 184 additions & 14 deletions lib/functions/installs.bash
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,9 @@ install_local_tool_versions() {
local tool_versions_path
tool_versions_path=$(find_tool_versions)

local ordered_install
ordered_install=$1

chrisjpalmer marked this conversation as resolved.
Show resolved Hide resolved
# Locate all the plugins installed in the system
local plugins_installed
if find "$plugins_path" -mindepth 1 -type d &>/dev/null; then
Expand All @@ -102,6 +105,7 @@ install_local_tool_versions() {
fi

# Locate all the plugins defined in the versions file.
# This just checks the current directory
local tools_file
if [ -f "$tool_versions_path" ]; then
tools_file=$(strip_tool_version_comments "$tool_versions_path" | cut -d ' ' -f 1)
Expand All @@ -117,30 +121,146 @@ install_local_tool_versions() {
exit 1
fi

local tools_installed
if [ -n "$plugins_installed" ]; then
for plugin_name in $plugins_installed; do
local plugin_version_and_path
plugin_version_and_path="$(find_versions "$plugin_name" "$search_path")"

if [ -n "$plugin_version_and_path" ]; then
local plugin_version
some_tools_installed='yes'
plugin_versions=$(cut -d '|' -f 1 <<<"$plugin_version_and_path")
for plugin_version in $plugin_versions; do
install_tool_version "$plugin_name" "$plugin_version"
done
fi
done
plugins_installed=$(printf "%s" "$plugins_installed" | tr "\n" " " | awk '{$1=$1};1')
display_debug "install_local_tool_versions: plugins_installed='$plugins_installed'"
tools_installed=$(install_directory_tools_recursive "$search_path" "$plugins_installed")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the $() on lines 122 and 124 should be quoted.

fi

if [ -z "$some_tools_installed" ]; then
if [ -z "$tools_installed" ]; then
printf "Either specify a tool & version in the command\n"
printf "OR add .tool-versions file in this directory\n"
printf "or in a parent directory\n"
exit 1
fi
}

install_directory_tools_recursive() {
local search_path=$1
local plugins_installed=$2
local tools_installed=""

display_debug "install_directory_tools_recursive '$search_path': entered with plugins_installed='$plugins_installed'"

while [ "$search_path" != "/" ]; do
# install tools from files in current directory
display_debug "--------------------------------------------------------------------------------------------------------------"
tools_installed=$(install_directory_tools "$search_path" "$plugins_installed" "$tools_installed")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

quote this one too I think.

display_debug "install_directory_tools_recursive '$search_path': install_directory_tools returned tools_installed='$tools_installed'"

# terminate if all tools are installed
if [[ -n $(stringlist_same_length "$plugins_installed" "$tools_installed") ]]; then
chrisjpalmer marked this conversation as resolved.
Show resolved Hide resolved
display_debug "install_directory_tools_recursive '$search_path': exiting as tools_installed has same length as plugins_installed: tools_installed='$tools_installed', plugins_installed='$plugins_installed'"
printf "%s\n" "$tools_installed"
return 0
fi

# go up a directory
search_path=$(dirname "$search_path")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This one as well. paths can contain spaces but they should be treated like a single string.

done

printf "%s\n" "$tools_installed"
}

install_directory_tools() {
local search_path=$1
local plugins_installed=$2
local tools_installed=$3
display_debug "install_directory_tools '$search_path': starting install. tools_installed='$tools_installed'"

# install tools from .tool-versions
# install order is the order listed in .tool-versions
local tool_versions
file_name=$(asdf_tool_versions_filename)
if ! [[ -f "$search_path/$file_name" ]]; then
display_debug "install_directory_tools '$search_path': exiting early... $file_name file not found"
printf "%s\n" "$tools_installed"
return 0
fi

tool_versions=$(strip_tool_version_comments "$search_path/$file_name" | awk '{$1=$1};1')
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably want this $() to be quoted right?

Copy link
Author

@chrisjpalmer chrisjpalmer Mar 18, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not sure to be honest. I noticed that most of the assignments in the installs.bash file do not put quotes around the $(). When I ran the linter, the linter pulled up times where I had passed a $() to a bash function if I didn't wrap it in quotes. It would give the following warning: SC2046 (warning): Quote this to prevent word splitting.. This makes me think that variable assignment is okay but potentially passing as arguments without wrapping in quotes is the one that isn't right. Not sure though, no expert on bash myself.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Typically if the value produced by the expression contains spaces and you want it to stay as a string you should quote - string_with_spaces="$(echo "string with spaces")". I think that is the case here, but I may be wrong. Generally, quoting is safer in Bash (unless you are dealing with an array, in which case it won't work).

if [[ -z $tool_versions ]]; then
display_debug "install_directory_tools '$search_path': exiting early... no tools found in directory"
printf "%s\n" "$tools_installed"
return 0
fi
while IFS=' ' read -r tool_version; do
display_debug "install_directory_tools '$search_path': found '$tool_version'"

# read one version from the file
IFS=' ' read -ra parts <<< "$tool_version"
local plugin_name
plugin_name=${parts[0]}
local plugin_version
plugin_version=${parts[1]}

# skip if plugin is installed already
if [[ -n $(stringlist_contains "$tools_installed" "$plugin_name") ]]; then
display_debug "install_directory_tools '$search_path': '$plugin_name' is already installed... skipping"
continue
fi

# install the version
display_none $(install_tool_version "$plugin_name" "$plugin_version")
tools_installed=$(echo "$tools_installed $plugin_name" | awk '{$1=$1};1')

display_debug "install_directory_tools '$search_path': installed '$plugin_name':'$plugin_version' new state of tools_installed='$tools_installed'"
done <<< $tool_versions

# TODO when should we resolve tool version from the environment ?
chrisjpalmer marked this conversation as resolved.
Show resolved Hide resolved

# install tools from legacy version files
# install order is plugin order which is alphabetical
local legacy_config
legacy_config=$(get_asdf_config_value "legacy_version_file")
if [ "$legacy_config" = "yes" ]; then
display_debug "install_directory_tools '$search_path': resolving legacy files"
local plugin_name
for plugin_name in $plugins_installed; do
# skip if plugin is installed already
if [[ -n $(stringlist_contains "$tool_versions" "$plugin_name") ]]; then
display_debug "install_directory_tools '$search_path': legacy_install $plugin_name: skipping as tool was already installed"
continue
fi

# extract plugin legacy information
local plugin_path
plugin_path=$(get_plugin_path "$plugin_name")
local legacy_list_filenames_script
legacy_list_filenames_script="${plugin_path}/bin/list-legacy-filenames"

# skip if no legacy_list_filenames_script available
if ! [[ -f "$legacy_list_filenames_script" ]]; then
display_debug "install_directory_tools '$search_path': legacy_install $plugin_name: skipping as legacy files are not supported"
continue
fi

# extract plugin legacy filenames
local legacy_filenames=""
legacy_filenames=$("$legacy_list_filenames_script")

# lookup plugin version in current dir
local plugin_version
plugin_version=$(get_legacy_version_in_dir "$plugin_name" "$search_path" "$legacy_filenames")

# skip if version cannot be found
if [ -z "$plugin_version" ]; then
display_debug "install_directory_tools '$search_path': legacy_install $plugin_name: skipping as version cannot be found"
continue
fi

display_debug "install_directory_tools '$search_path': legacy_install $plugin_name: plugin_version='$plugin_version'"
display_none $(install_tool_version "$plugin_name" "$plugin_version")

tools_installed=$(echo "$tools_installed $plugin_name" | awk '{$1=$1};1')
display_debug "install_directory_tools '$search_path': legacy_install $plugin_name: installed '$plugin_version' new state of tools_installed='$tools_installed'"
done
fi

printf "%s\n" "$tools_installed"
}

install_tool_version() {
local plugin_name=$1
local full_version=$2
Expand Down Expand Up @@ -253,3 +373,53 @@ install_tool_version() {
fi
fi
}

get_legacy_version_in_dir() {
local plugin_name=$1
local search_path=$2
local legacy_filenames=$3

local asdf_version
for filename in $legacy_filenames; do
local legacy_version
legacy_version=$(parse_legacy_version_file "$search_path/$filename" "$plugin_name")

if [ -n "$legacy_version" ]; then
printf "%s\n" "$legacy_version"
return 0
fi
done
}


stringlist_same_length() {
IFS=' ' read -r -a array1 <<< "$1"
IFS=' ' read -r -a array2 <<< "$2"
if [[ ${#array1[@]} -eq ${#array2[@]} ]]; then
printf "true\n"
return 0
fi
}

stringlist_contains() {
local list=$1
local search=$2
local array
IFS=' ' read -r -a array <<< "$list"
for item in "${array[@]}"; do
if [ $item = $search ]; then
printf "true\n"
return 0
fi
done
}

display_debug() {
if [[ $DEBUG = "true" ]]; then
printf "debug: %s\n" "$1" >&2
fi
}

display_none() {
printf ""
}