From 4390ecdf77f581ac499488e339022e88f5767491 Mon Sep 17 00:00:00 2001 From: Max Fierke Date: Sun, 28 Jan 2024 20:59:42 -0600 Subject: [PATCH 1/4] Install mise directly, prior to Homebrew --- src/mstrap/platform.cr | 5 ++ src/mstrap/runtime_manager.cr | 1 + src/mstrap/runtime_managers/asdf.cr | 13 ++++ src/mstrap/runtime_managers/mise.cr | 11 ++++ src/mstrap/steps/dependencies_step.cr | 21 ++++++- src/mstrap/supports/mise_installer.cr | 88 +++++++++++++++++++++++++++ src/mstrap/templates/Brewfile.ecr | 2 - src/mstrap/templates/env.sh.ecr | 17 +----- 8 files changed, 137 insertions(+), 21 deletions(-) create mode 100644 src/mstrap/supports/mise_installer.cr diff --git a/src/mstrap/platform.cr b/src/mstrap/platform.cr index 0d207d6..93325ba 100644 --- a/src/mstrap/platform.cr +++ b/src/mstrap/platform.cr @@ -13,6 +13,11 @@ module MStrap ENV["MSTRAP_IGNORE_GIT"]? != "true" && (`command -v git` && $?.success?) end + # Indicates whether the host platform has GPG installed + def self.has_gpg? + !!(`command -v gpg` && $?.success?) + end + # Installs a list of packages using the platform's package manager def self.install_packages!(packages : Array(String)) platform.install_packages!(packages) diff --git a/src/mstrap/runtime_manager.cr b/src/mstrap/runtime_manager.cr index 4924673..8414e67 100644 --- a/src/mstrap/runtime_manager.cr +++ b/src/mstrap/runtime_manager.cr @@ -25,6 +25,7 @@ module MStrap abstract def runtime_exec(language_name : String, command : String, args : Array(String)? = nil, runtime_version : String? = nil) abstract def set_version(language_name : String, version : String?) : Bool abstract def set_global_version(language_name : String, version : String) : Bool + abstract def shell_activation(shell_name : String) : String macro finished # :nodoc: diff --git a/src/mstrap/runtime_managers/asdf.cr b/src/mstrap/runtime_managers/asdf.cr index 3675904..aa6eb31 100644 --- a/src/mstrap/runtime_managers/asdf.cr +++ b/src/mstrap/runtime_managers/asdf.cr @@ -83,6 +83,19 @@ module MStrap cmd "asdf global #{plugin_name(language_name)} #{version}", quiet: true end + def shell_activation(shell_name : String) : String + <<-SHELL + # Activate asdf for language runtime version management + if [ -d "$(brew --prefix asdf)" ]; then + source "$(brew --prefix asdf)/libexec/asdf.sh" + + if [ ! -f "$HOME/.asdfrc" ]; then + echo "legacy_version_file = yes\n" > "$HOME/.asdfrc" + fi + fi + SHELL + end + private def version_env_var(language_name) : String if asdf_plugin_name = plugin_name(language_name) "ASDF_#{asdf_plugin_name.upcase}_VERSION" diff --git a/src/mstrap/runtime_managers/mise.cr b/src/mstrap/runtime_managers/mise.cr index a94f5f2..e8c75eb 100644 --- a/src/mstrap/runtime_managers/mise.cr +++ b/src/mstrap/runtime_managers/mise.cr @@ -70,6 +70,17 @@ module MStrap def set_global_version(language_name, version : String) : Bool cmd "mise use -g #{plugin_name(language_name)}@#{version}", quiet: true end + + def shell_activation(shell_name : String) : String + <<-SHELL + # Activate mise for language runtime version management + if [ -x "#{MStrap::MiseInstaller::MISE_INSTALL_PATH}" ]; then + export MISE_ASDF_COMPAT=1 + eval "$(#{MStrap::MiseInstaller::MISE_INSTALL_PATH} activate #{shell_name})" + eval "$(#{MStrap::MiseInstaller::MISE_INSTALL_PATH} hook-env)" + fi + SHELL + end end end end diff --git a/src/mstrap/steps/dependencies_step.cr b/src/mstrap/steps/dependencies_step.cr index 8304d52..7993345 100644 --- a/src/mstrap/steps/dependencies_step.cr +++ b/src/mstrap/steps/dependencies_step.cr @@ -4,7 +4,7 @@ module MStrap # and installs software from any available `Brewfile`s. class DependenciesStep < Step def self.description - "Basic machine bootstrapping with strap.sh, hub, and brew bundle." + "Basic machine bootstrapping with strap.sh, brew bundle, and other dependencies" end def self.requires_mstrap? @@ -16,6 +16,7 @@ module MStrap end def bootstrap + install_mise if runtime_manager.name == "mise" set_strap_env! strap_sh load_profile! @@ -31,7 +32,7 @@ module MStrap private def strap_sh logn "==> Running strap.sh" unless cmd "bash #{MStrap::Paths::STRAP_SH_PATH} #{MStrap.debug? ? "--debug" : ""}" - logc "Uhh oh, something went wrong in strap.sh-land. Check above or in #{MStrap::Paths::LOG_FILE}." + logc "Uhh oh, something went wrong in strap.sh-land." end success "Finished running strap.sh" set_brew_env_if_not_set @@ -46,13 +47,27 @@ module MStrap if File.exists?(brewfile_path) log "--> Installing dependencies from Brewfile from profile '#{profile_config.name})': " unless cmd "brew bundle --file=#{brewfile_path} #{MStrap.debug? ? "--verbose" : ""}" - logc "Uhh oh, something went wrong in homebrewland. Check above or in #{MStrap::Paths::LOG_FILE}." + logc "Uhh oh, something went wrong in homebrewland." end success "OK" end end end + def install_mise + mise_installer = MiseInstaller.new + + log "==> Checking for mise: " + if mise_installer.installed? && !options.force? + success "OK" + else + logn "Not installed".colorize(:yellow) + log "--> Installing mise for language runtime version management: " + mise_installer.install! + success "OK" + end + end + private def load_profile! log "--> Reloading profile: " config.reload! diff --git a/src/mstrap/supports/mise_installer.cr b/src/mstrap/supports/mise_installer.cr new file mode 100644 index 0000000..c5fe450 --- /dev/null +++ b/src/mstrap/supports/mise_installer.cr @@ -0,0 +1,88 @@ +module MStrap + # Manages the install of mise for managing language runtimes + # + # NOTE: See `MStrap::RuntimeManagers::Mise` for how mise is integrated + class MiseInstaller + include DSL + + # :nodoc: + MISE_INSTALL_SH_PATH = File.join(MStrap::Paths::RC_DIR, "vendor", "mise_install.sh") + + # :nodoc: + MISE_INSTALL_SH_URL = "https://mise.jdx.dev/install.sh" + + # :nodoc: + MISE_INSTALL_SH_SIG_KEY_ID = "0x24853EC9F655CE80B48E6C3A8B81C9D17413A06D" + + # :nodoc: + MISE_INSTALL_SH_SIG_PATH = "#{MISE_INSTALL_SH_PATH}.sig" + + # :nodoc: + MISE_INSTALL_SH_SIG_URL = "https://mise.jdx.dev/install.sh.sig" + + # :nodoc: + MISE_BIN_DIR_PATH = File.join(MStrap::Paths::RC_DIR, "vendor", "mise", "bin") + + # :nodoc: + MISE_INSTALL_PATH = File.join(MISE_BIN_DIR_PATH, "mise") + + def initialize(@verify_installer : Bool? = nil) + end + + def install! + FileUtils.mkdir_p(MISE_BIN_DIR_PATH) + + fetch_installer! + + mise_env = { + "MISE_INSTALL_PATH" => MISE_INSTALL_PATH, + } + + if MStrap.debug? + mise_env["MISE_DEBUG"] = "1" + else + mise_env["MISE_QUIET"] = "1" + end + + cmd mise_env, "sh", [MISE_INSTALL_SH_PATH] + + # "Activate" it + path = ENV["PATH"] + ENV["PATH"] = "#{MISE_BIN_DIR_PATH}:#{path}" + end + + def installed? + File.exists?(MISE_INSTALL_PATH) + end + + private def fetch_installer! + if verify_installer? + HTTP::Client.get(MISE_INSTALL_SH_SIG_URL, tls: MStrap.tls_client) do |response| + File.write(MISE_INSTALL_SH_SIG_PATH, response.body_io.gets_to_end) + end + + unless fetch_installer_public_key && decrypt_installer + logc "Unable to verify mise installer. Signature does not appear to be valid." + end + else + logw "Skipping validation of the mise installer (likely because gpg is not installed or was not found)" + logw "mise will still be downloaded over HTTPS, but we cannot fully validate the authenticity of the installer" + HTTP::Client.get(MISE_INSTALL_SH_URL, tls: MStrap.tls_client) do |response| + File.write(MISE_INSTALL_SH_PATH, response.body_io.gets_to_end) + end + end + end + + private def fetch_installer_public_key + cmd "gpg", ["--keyserver", "hkps://keyserver.ubuntu.com", "--recv-keys", MISE_INSTALL_SH_SIG_KEY_ID], quiet: true + end + + private def decrypt_installer + cmd "gpg", ["-o", MISE_INSTALL_SH_PATH, "--yes", "--decrypt", MISE_INSTALL_SH_SIG_PATH], quiet: true + end + + private def verify_installer? + @verify_installer ||= MStrap::Platform.has_gpg? + end + end +end diff --git a/src/mstrap/templates/Brewfile.ecr b/src/mstrap/templates/Brewfile.ecr index ee883f0..bd52e8d 100644 --- a/src/mstrap/templates/Brewfile.ecr +++ b/src/mstrap/templates/Brewfile.ecr @@ -11,8 +11,6 @@ brew 'zlib' # Language runtime managers <% if runtime_manager.name == "asdf" %> brew 'asdf' -<% elsif runtime_manager.name == "mise" %> -brew 'mise' <% end %> if /darwin/ =~ RUBY_PLATFORM diff --git a/src/mstrap/templates/env.sh.ecr b/src/mstrap/templates/env.sh.ecr index 89faf3c..2235c06 100644 --- a/src/mstrap/templates/env.sh.ecr +++ b/src/mstrap/templates/env.sh.ecr @@ -10,19 +10,4 @@ export MSTRAP_RC_DIR="<%= MStrap::Paths::RC_DIR %>" test -d <%= MStrap::Paths::HOMEBREW_PREFIX %> && eval $(<%= MStrap::Paths::HOMEBREW_PREFIX %>/bin/brew shellenv) <% end -%> -<% if runtime_manager.name == "asdf" %> -# Activate asdf for language runtime version management -if [ -d "$(brew --prefix asdf)" ]; then - source "$(brew --prefix asdf)/libexec/asdf.sh" - - if [ ! -f "$HOME/.asdfrc" ]; then - echo "legacy_version_file = yes\n" > "$HOME/.asdfrc" - fi -fi -<% elsif runtime_manager.name == "mise" %> -# Activate mise for language runtime version management -if command -v mise 2>&1 > /dev/null; then - export MISE_ASDF_COMPAT=1 - eval "$(mise activate <%= shell_name %>)" -fi -<% end %> +<%= runtime_manager.shell_activation(shell_name) %> From a4c32a016c11129a4fbc744de9ee6e33938022cb Mon Sep 17 00:00:00 2001 From: Max Fierke Date: Sun, 28 Jan 2024 21:00:28 -0600 Subject: [PATCH 2/4] Add runtime manager to `mstrap debug` --- src/mstrap/steps/debug_step.cr | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/mstrap/steps/debug_step.cr b/src/mstrap/steps/debug_step.cr index 5794a3e..91fc95f 100644 --- a/src/mstrap/steps/debug_step.cr +++ b/src/mstrap/steps/debug_step.cr @@ -19,6 +19,8 @@ module MStrap puts "mstrap v#{MStrap::VERSION}" puts "Loaded Config:" puts " #{options.config_path}" + puts "Default runtime manager:" + puts " #{runtime_manager.name}" puts "Known Profiles:" config.known_profile_configs.each do |profile| puts " #{profile.name}" From 009962023235051a12b297ede807c282374fb0d0 Mon Sep 17 00:00:00 2001 From: Max Fierke Date: Sun, 28 Jan 2024 21:30:42 -0600 Subject: [PATCH 3/4] Only consider mise installed if callable by mstrap --- src/mstrap/supports/mise_installer.cr | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mstrap/supports/mise_installer.cr b/src/mstrap/supports/mise_installer.cr index c5fe450..770c051 100644 --- a/src/mstrap/supports/mise_installer.cr +++ b/src/mstrap/supports/mise_installer.cr @@ -52,7 +52,7 @@ module MStrap end def installed? - File.exists?(MISE_INSTALL_PATH) + File.exists?(MISE_INSTALL_PATH) && (`command -v mise` && $?.success?) end private def fetch_installer! From 49184e8cbbd8bf463fc57351d6dc7554ba80be81 Mon Sep 17 00:00:00 2001 From: Max Fierke Date: Sun, 28 Jan 2024 21:37:15 -0600 Subject: [PATCH 4/4] Add this PR to changelog --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2e488d8..e53d58d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,7 +8,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added -- Support for using [mise](https://mise.jdx.dev) to manage language runtime versions (#50). `config.hcl` can be configured as such to enable it: +- Support for using [mise](https://mise.jdx.dev) to manage language runtime versions (#50, #53). `config.hcl` can be configured as such to enable it: ``` version = "1.1"