lib/gdk/diagnostic/tool_version_manager.rb (110 lines of code) (raw):
# frozen_string_literal: true
require 'json'
module GDK
module Diagnostic
# Notifies users about the supported tool version manager and suggests migrating from asdf to mise.
class ToolVersionManager < Base
TITLE = 'Tool Version Manager'
BROKEN_ASDF_VERSION_REGEX = /v0\.16\.\d+/
def correctable?
using_asdf? || (mise_update_command && mise_update_required?)
end
def correct!
migrate_to_mise! if using_asdf?
update_mise! if mise_update_command && mise_update_required?
end
def success?
!using_asdf? && !mise_update_required?
end
def detail(context = nil)
return if success?
messages = []
messages << <<~MESSAGE if broken_asdf_version?
ERROR: Your installed version of asdf (`#{current_asdf_version}`) has a bug that makes it incompatible with GDK.
Please downgrade to `v0.15.0` or switch to `mise`.
MESSAGE
if using_asdf?
messages << <<~MESSAGE
We're dropping support for asdf in GDK.
You can still use asdf if you need to, for example outside of GDK. But it's no longer supported in GDK and won't be maintained going forward.
Mise provides better supply chain security while running faster and avoiding the dependency installation problems that we had to manually fix with asdf.
MESSAGE
unless context == :update
messages << <<~MESSAGE
To migrate, run:
gdk update
MESSAGE
end
return messages.join("\n")
end
if mise_update_required?
messages << <<~MESSAGE
WARNING: Your installed version of mise (#{current_mise_version}) is out of date.
The latest available version is #{mise_latest_version}.
MESSAGE
if mise_update_command
messages << <<~MESSAGE
To update to the latest version, run:
`#{mise_update_command}`
MESSAGE
end
end
messages.join("\n")
end
private
def using_mise?
GDK.config.asdf.opt_out? && GDK.config.mise.enabled?
end
def using_asdf?
!GDK.config.asdf.opt_out?
end
def broken_asdf_version?
return false unless using_asdf?
BROKEN_ASDF_VERSION_REGEX.match?(current_asdf_version)
end
def current_asdf_version
@current_asdf_version ||= begin
GDK::Shellout.new('asdf version').readlines.first&.strip
rescue Errno::ENOENT
nil
end
end
def mise_version_output
@mise_version_output ||= begin
output = GDK::Shellout.new('mise version --json').execute(display_output: false).read_stdout
JSON.parse(output)
rescue Errno::ENOENT, JSON::ParserError
{}
end
end
def current_mise_version
mise_version_output['version']&.split&.first
end
def mise_latest_version
mise_version_output['latest']
end
def mise_update_command
if GDK::Machine.macos?
'brew update && brew upgrade mise'
elsif GDK::Machine.linux?
'apt update && apt upgrade mise'
end
end
def mise_update_required?
return false unless using_mise?
return false unless current_mise_version && mise_latest_version
begin
current_version = Gem::Version.new(current_mise_version)
latest_version = Gem::Version.new(mise_latest_version)
current_version < latest_version
rescue ArgumentError
false
end
end
def update_mise!
GDK::Shellout.new(mise_update_command).execute(display_output: false)
true
rescue StandardError => e
GDK::Output.warn("Failed to update mise: #{e.message}")
false
end
def migrate_to_mise!
GDK::Execute::Rake.new('mise:migrate').execute_in_gdk
end
end
end
end