Prune Unused Versions
ctsstc opened this issue · 3 comments
Is your feature request related to a problem? Please describe.
Offer a way to prune old versions.
Describe the solution you'd like
A simple way may be to just offer mass uninstalling.
A more eloquent method would be to keep track of project locations. Then it could go see what current versions are being used by projects - assuming other branches may not be using something else -- this is a command you would not often run. Next it would remove all unused versions.
I would imagine ideally every time asdf recognizes a directory with versions it would update a dictionary of the path and the version in use.
Describe similar asdf features and why they are not sufficient
You can list versions and uninstall right now, but it could be tedious if you have many. It would also be nice to have asdf know which versions are in use so you could remove any guess work/heavy lifting/praying.
Describe workarounds you've considered
Uninstall everything and start fresh :P
Additional context
Nope.jpg
related #830
Describe workarounds you've considered
Uninstall everything and start fresh :P
Removing the plugin for a tool (asdf plugin remove <name>
) is a quick way to start fresh for a particular tool.
There are a couple issues with this. First is with the definition of "unused". asdf doesn't currently have any knowledge about what versions are used. Different users may have different definitions of what constitutes a "used" version. For example, here a couple different possible definitions that come to mind:
- Any version specified in a
.tool-versions
file - Any version specified in a
.tool-versions
file or any supported legacy version file format - Any version specified in an
ASDF_
shell version variable - Any combination of the above
That's quite a lot of possible places we'd need to check, and in the case of shell versions it is impossible (at least not without resorting to hacky methods of inspecting the environments of running processes) to know which ones are used.
Additionally, asdf would have to either be able to quickly determine this, or cache this and update it in the background in order to always have a clear picture of what versions are "used" and what versions are "unused". I think this out of scope for asdf and would add a lot of complexity to the tool without yielding a lot of benefit.
Also, this can be implemented outside of asdf core with a little bit of work. For example, I threw together the following code to demonstrate this is possible. I am going to add this code (in some form) to my asdf cookbook which I hope to release for free within the next year. This script finds all .tool-version
files in the users home directory and all sub-directories and prints all versions found via asdf list $tool_name
but not used any any of the .tool-version
files. It's a little slow but it demonstrates this is possible outside of asdf, provided you make some assumptions about what is "used" and what is "unused":
#!/usr/bin/env bash
# Unoffical Bash "strict mode"
# http://redsymbol.net/articles/unofficial-bash-strict-mode/
set -euo pipefail
#ORIGINAL_IFS=$IFS
IFS=$'\t\n' # Stricter IFS settings
# Function used to convert lines like this:
#
# ruby 2.0.0
# ruby 3.0.0
# elixir 1.10.0
#
# To lines like this:
#
# ruby 2.0.0 3.0.0
# elixir 1.10.0
join_multiple() {
local last
local n
while IFS=' ' read -r word definition
do
if [ "$last" = "$word" ]
then
printf " %s" "$definition"
else
if [ -n "$n" ]; then
echo
else
n=1
fi
printf "%s\\t%s" "$word" "$definition"
last="$word"
fi
done < "${1:-/dev/stdin}"
echo
}
# Find command often crashes due to permission issues
version_files="$(find "$HOME" -name .tool-versions || true)"
# Combine all .tool-version file contents into one variable
versions_in_use="$(
while read -r filename; do
cat "$filename";
done <<< "$version_files"
)"
# Loop over each line of the .tool-versions file
while read -r line; do
IFS=$' \t' read -r -a tool_and_versions <<< "$line"
# Split out the tool name and versions
tool_name="${tool_and_versions[0]}"
global_versions=("${tool_and_versions[@]:1}")
# Loop over each version of the tool name
for version in $(asdf list "$tool_name"); do
# Trim off leading/trailing tab/spaces
trimmed_version=$(echo "$version" | xargs)
# When version not in `global_versions` array from .tool-versions file
if [[ ! " ${global_versions[*]} " =~ ${trimmed_version} ]]; then
# Remove the version here if you want
echo "$tool_name version $trimmed_version not found in any .tool-versions"
fi
done
done < <(echo "$versions_in_use" | sort -k1 | sort -u | join_multiple)
I am going to close this issue because I do not think this is worth adding to asdf-core for the above reasons. Sorry for the late reply, I hope this all makes sense. Please do reply if you feel I've missed anything here.
my 2cents:
- read plugin names
- filter non-current version
- uninstall non-current version if any
declare -i checked=0 failed=0
while IFS= read -r name; do
(( checked+=1 ))
asdf list "$name" \
| sed -e '/^\s*\*/d' \
| xargs -rt -I@ -- asdf uninstall "$name" @ \
|| (( failed+=1 ))
done < <(awk '{print $1}' .tool-versions | sort -u)
echo "checked: ${checked}"
echo " failed: ${failed}"