From e183b42ba37f3cfbbd6e465db1f44e1e60a68b85 Mon Sep 17 00:00:00 2001 From: jdx <216188+jdx@users.noreply.github.com> Date: Mon, 16 Dec 2024 15:38:44 -0600 Subject: [PATCH] feat: elixir core tool --- docs/core-tools.md | 5 +- docs/lang/elixir.md | 9 ++ docs/registry.md | 2 +- e2e/{plugins => }/core/test_bun | 0 e2e/{plugins => }/core/test_deno | 0 e2e/core/test_erlang_slow | 6 + e2e/{plugins => }/core/test_go | 0 e2e/{plugins => }/core/test_gopath | 0 e2e/{plugins => }/core/test_java | 0 e2e/{plugins => }/core/test_java_corretto | 0 e2e/{plugins => }/core/test_node | 0 e2e/{plugins => }/core/test_poetry_slow | 0 .../core/test_python_compile_slow | 0 .../core/test_python_precompiled | 0 e2e/{plugins => }/core/test_python_uv_venv | 0 e2e/{plugins => }/core/test_python_venv | 0 e2e/{plugins => }/core/test_ruby_build_slow | 0 e2e/{plugins => }/core/test_ruby_from_gemfile | 0 e2e/{plugins => }/core/test_ruby_install_slow | 0 e2e/{plugins => }/core/test_ruby_ls_remote | 0 e2e/{plugins => }/core/test_rust | 0 e2e/{plugins => }/core/test_swift_slow | 0 e2e/{plugins => }/core/test_system_node | 0 e2e/{plugins => }/core/test_zigmod | 0 e2e/plugins/core/test_erlang_slow | 3 - registry.toml | 2 +- src/plugins/core/elixir.rs | 115 ++++++++++++++++++ src/plugins/core/mod.rs | 4 + src/plugins/core/zig.rs | 6 +- src/shorthands.rs | 5 +- 30 files changed, 144 insertions(+), 13 deletions(-) create mode 100644 docs/lang/elixir.md rename e2e/{plugins => }/core/test_bun (100%) rename e2e/{plugins => }/core/test_deno (100%) create mode 100644 e2e/core/test_erlang_slow rename e2e/{plugins => }/core/test_go (100%) rename e2e/{plugins => }/core/test_gopath (100%) rename e2e/{plugins => }/core/test_java (100%) rename e2e/{plugins => }/core/test_java_corretto (100%) rename e2e/{plugins => }/core/test_node (100%) rename e2e/{plugins => }/core/test_poetry_slow (100%) rename e2e/{plugins => }/core/test_python_compile_slow (100%) rename e2e/{plugins => }/core/test_python_precompiled (100%) rename e2e/{plugins => }/core/test_python_uv_venv (100%) rename e2e/{plugins => }/core/test_python_venv (100%) rename e2e/{plugins => }/core/test_ruby_build_slow (100%) rename e2e/{plugins => }/core/test_ruby_from_gemfile (100%) rename e2e/{plugins => }/core/test_ruby_install_slow (100%) rename e2e/{plugins => }/core/test_ruby_ls_remote (100%) rename e2e/{plugins => }/core/test_rust (100%) rename e2e/{plugins => }/core/test_swift_slow (100%) rename e2e/{plugins => }/core/test_system_node (100%) rename e2e/{plugins => }/core/test_zigmod (100%) delete mode 100644 e2e/plugins/core/test_erlang_slow create mode 100644 src/plugins/core/elixir.rs diff --git a/docs/core-tools.md b/docs/core-tools.md index cd23d6b4c5..c7a4ca8a81 100644 --- a/docs/core-tools.md +++ b/docs/core-tools.md @@ -3,12 +3,13 @@ `mise` comes with some plugins built into the CLI written in Rust. These are new and will improve over time. -They can be easily overridden by installing a plugin with the same name, e.g.: `mise plugin install python https://github.com/asdf-community/asdf-python`. +They can be easily overridden by installing an asdf/vfox plugin with the same name, e.g.: `mise plugin install python https://github.com/asdf-community/asdf-python`. -You can see the core plugins with `mise plugin ls --core`. +You can see the core plugins with `mise registry -b core`. - [Bun](/lang/bun) - [Deno](/lang/deno) +- [Elixir](/lang/elixir) - [Erlang](/lang/erlang) - [Go](/lang/go) - [Java](/lang/java) diff --git a/docs/lang/elixir.md b/docs/lang/elixir.md new file mode 100644 index 0000000000..76002aa944 --- /dev/null +++ b/docs/lang/elixir.md @@ -0,0 +1,9 @@ +# Elixir + +## Usage + +Use the latest stable version of elixir: + +```sh +mise use -g erlang elixir +``` diff --git a/docs/registry.md b/docs/registry.md index 1832d695d3..5d1853af4f 100644 --- a/docs/registry.md +++ b/docs/registry.md @@ -222,7 +222,7 @@ You can also specify the full name for a tool using `mise use aqua:1password/cli | ejson | [aqua:Shopify/ejson](https://github.com/Shopify/ejson) [asdf:cipherstash/asdf-ejson](https://github.com/cipherstash/asdf-ejson) | | eksctl | [aqua:eksctl-io/eksctl](https://github.com/eksctl-io/eksctl) [asdf:elementalvoid/asdf-eksctl](https://github.com/elementalvoid/asdf-eksctl) | | elasticsearch | [asdf:asdf-community/asdf-elasticsearch](https://github.com/asdf-community/asdf-elasticsearch) | -| elixir | [asdf:mise-plugins/mise-elixir](https://github.com/mise-plugins/mise-elixir) [vfox:version-fox/vfox-elixir](https://github.com/version-fox/vfox-elixir) | +| elixir | [core:elixir](https://mise.jdx.dev/lang/elixir.html) | | elixir-ls | [asdf:juantascon/asdf-elixir-ls](https://github.com/juantascon/asdf-elixir-ls) | | elm | [ubi:elm/compiler](https://github.com/elm/compiler) [asdf:asdf-community/asdf-elm](https://github.com/asdf-community/asdf-elm) | | emsdk | [asdf:RobLoach/asdf-emsdk](https://github.com/RobLoach/asdf-emsdk) | diff --git a/e2e/plugins/core/test_bun b/e2e/core/test_bun similarity index 100% rename from e2e/plugins/core/test_bun rename to e2e/core/test_bun diff --git a/e2e/plugins/core/test_deno b/e2e/core/test_deno similarity index 100% rename from e2e/plugins/core/test_deno rename to e2e/core/test_deno diff --git a/e2e/core/test_erlang_slow b/e2e/core/test_erlang_slow new file mode 100644 index 0000000000..d1d3b7e8c7 --- /dev/null +++ b/e2e/core/test_erlang_slow @@ -0,0 +1,6 @@ +#!/usr/bin/env bash + +assert "mise use erlang@27.2" +assert_contains "mise x -- erl -eval 'erlang:display(erlang:system_info(otp_release)), halt().' -noshell" "27" +assert_contains "mise x elixir@1.17.3 -- elixir --version 2>&1" "Elixir 1.17.3" +assert_contains "mise x elixir@1.17.3 -- mix --version 2>&1" "Mix 1.17.3" diff --git a/e2e/plugins/core/test_go b/e2e/core/test_go similarity index 100% rename from e2e/plugins/core/test_go rename to e2e/core/test_go diff --git a/e2e/plugins/core/test_gopath b/e2e/core/test_gopath similarity index 100% rename from e2e/plugins/core/test_gopath rename to e2e/core/test_gopath diff --git a/e2e/plugins/core/test_java b/e2e/core/test_java similarity index 100% rename from e2e/plugins/core/test_java rename to e2e/core/test_java diff --git a/e2e/plugins/core/test_java_corretto b/e2e/core/test_java_corretto similarity index 100% rename from e2e/plugins/core/test_java_corretto rename to e2e/core/test_java_corretto diff --git a/e2e/plugins/core/test_node b/e2e/core/test_node similarity index 100% rename from e2e/plugins/core/test_node rename to e2e/core/test_node diff --git a/e2e/plugins/core/test_poetry_slow b/e2e/core/test_poetry_slow similarity index 100% rename from e2e/plugins/core/test_poetry_slow rename to e2e/core/test_poetry_slow diff --git a/e2e/plugins/core/test_python_compile_slow b/e2e/core/test_python_compile_slow similarity index 100% rename from e2e/plugins/core/test_python_compile_slow rename to e2e/core/test_python_compile_slow diff --git a/e2e/plugins/core/test_python_precompiled b/e2e/core/test_python_precompiled similarity index 100% rename from e2e/plugins/core/test_python_precompiled rename to e2e/core/test_python_precompiled diff --git a/e2e/plugins/core/test_python_uv_venv b/e2e/core/test_python_uv_venv similarity index 100% rename from e2e/plugins/core/test_python_uv_venv rename to e2e/core/test_python_uv_venv diff --git a/e2e/plugins/core/test_python_venv b/e2e/core/test_python_venv similarity index 100% rename from e2e/plugins/core/test_python_venv rename to e2e/core/test_python_venv diff --git a/e2e/plugins/core/test_ruby_build_slow b/e2e/core/test_ruby_build_slow similarity index 100% rename from e2e/plugins/core/test_ruby_build_slow rename to e2e/core/test_ruby_build_slow diff --git a/e2e/plugins/core/test_ruby_from_gemfile b/e2e/core/test_ruby_from_gemfile similarity index 100% rename from e2e/plugins/core/test_ruby_from_gemfile rename to e2e/core/test_ruby_from_gemfile diff --git a/e2e/plugins/core/test_ruby_install_slow b/e2e/core/test_ruby_install_slow similarity index 100% rename from e2e/plugins/core/test_ruby_install_slow rename to e2e/core/test_ruby_install_slow diff --git a/e2e/plugins/core/test_ruby_ls_remote b/e2e/core/test_ruby_ls_remote similarity index 100% rename from e2e/plugins/core/test_ruby_ls_remote rename to e2e/core/test_ruby_ls_remote diff --git a/e2e/plugins/core/test_rust b/e2e/core/test_rust similarity index 100% rename from e2e/plugins/core/test_rust rename to e2e/core/test_rust diff --git a/e2e/plugins/core/test_swift_slow b/e2e/core/test_swift_slow similarity index 100% rename from e2e/plugins/core/test_swift_slow rename to e2e/core/test_swift_slow diff --git a/e2e/plugins/core/test_system_node b/e2e/core/test_system_node similarity index 100% rename from e2e/plugins/core/test_system_node rename to e2e/core/test_system_node diff --git a/e2e/plugins/core/test_zigmod b/e2e/core/test_zigmod similarity index 100% rename from e2e/plugins/core/test_zigmod rename to e2e/core/test_zigmod diff --git a/e2e/plugins/core/test_erlang_slow b/e2e/plugins/core/test_erlang_slow deleted file mode 100644 index 96f60df2aa..0000000000 --- a/e2e/plugins/core/test_erlang_slow +++ /dev/null @@ -1,3 +0,0 @@ -#!/usr/bin/env bash - -assert_contains "mise x erlang@24.3.4.9 -- erl -eval 'erlang:display(erlang:system_info(otp_release)), halt().' -noshell" "24" diff --git a/registry.toml b/registry.toml index 2ae2d81d33..b7e166b853 100644 --- a/registry.toml +++ b/registry.toml @@ -315,7 +315,7 @@ editorconfig-checker.test = ["ec --version", "v{{version}}"] ejson.backends = ["aqua:Shopify/ejson", "asdf:cipherstash/asdf-ejson"] eksctl.backends = ["aqua:eksctl-io/eksctl", "asdf:elementalvoid/asdf-eksctl"] elasticsearch.backends = ["asdf:asdf-community/asdf-elasticsearch"] -elixir.backends = ["asdf:mise-plugins/mise-elixir", "vfox:version-fox/vfox-elixir"] +elixir.backends = ["core:elixir"] elixir.depends = ["erlang"] elixir-ls.backends = ["asdf:juantascon/asdf-elixir-ls"] elm.backends = ["ubi:elm/compiler[exe=elm]", "asdf:asdf-community/asdf-elm"] diff --git a/src/plugins/core/elixir.rs b/src/plugins/core/elixir.rs new file mode 100644 index 0000000000..a0259f466d --- /dev/null +++ b/src/plugins/core/elixir.rs @@ -0,0 +1,115 @@ +use std::path::{Path, PathBuf}; + +use crate::backend::Backend; +use crate::cli::args::BackendArg; +use crate::cmd::CmdLineRunner; +use crate::http::{HTTP, HTTP_FETCH}; +use crate::install_context::InstallContext; +use crate::plugins::VERSION_REGEX; +use crate::toolset::ToolVersion; +use crate::ui::progress_report::SingleReport; +use crate::{file, plugins}; +use eyre::Result; +use itertools::Itertools; +use versions::Versioning; +use xx::regex; + +#[derive(Debug)] +pub struct ElixirPlugin { + ba: BackendArg, +} + +impl ElixirPlugin { + pub fn new() -> Self { + Self { + ba: plugins::core::new_backend_arg("elixir"), + } + } + + fn elixir_bin(&self, tv: &ToolVersion) -> PathBuf { + tv.install_path().join("bin").join("elixir") + } + + fn test_elixir(&self, ctx: &InstallContext, tv: &ToolVersion) -> Result<()> { + ctx.pr.set_message("elixir --version".into()); + CmdLineRunner::new(self.elixir_bin(tv)) + .with_pr(ctx.pr.as_ref()) + .envs(self.dependency_env()?) + .arg("--version") + .execute() + } + + fn download(&self, tv: &ToolVersion, pr: &dyn SingleReport) -> Result { + let version = &tv.version; + let url = format!("https://builds.hex.pm/builds/elixir/v{version}.zip"); + + let filename = url.split('/').last().unwrap(); + let tarball_path = tv.download_path().join(filename); + + pr.set_message(format!("download {filename}")); + if !tarball_path.exists() { + HTTP.download_file(&url, &tarball_path, Some(pr))?; + } + + Ok(tarball_path) + } + + fn install(&self, ctx: &InstallContext, tv: &ToolVersion, tarball_path: &Path) -> Result<()> { + let filename = tarball_path.file_name().unwrap().to_string_lossy(); + ctx.pr.set_message(format!("extract {filename}")); + file::remove_all(tv.install_path())?; + file::unzip(tarball_path, &tv.install_path())?; + + Ok(()) + } + + fn verify(&self, ctx: &InstallContext, tv: &ToolVersion) -> Result<()> { + self.test_elixir(ctx, tv) + } +} + +impl Backend for ElixirPlugin { + fn ba(&self) -> &BackendArg { + &self.ba + } + + fn _list_remote_versions(&self) -> Result> { + let versions: Vec = HTTP_FETCH + .get_text("https://builds.hex.pm/builds/elixir/builds.txt")? + .lines() + .unique() + .filter_map(|s| s.split_once(' ').map(|(v, _)| v.trim_start_matches('v'))) + .filter(|s| regex!(r"^[0-9]+\.[0-9]+\.[0-9]").is_match(s)) + .sorted_by_cached_key(|s| { + ( + Versioning::new(s.split_once('-').map(|(v, _)| v).unwrap_or(s)), + !VERSION_REGEX.is_match(s), + s.contains("-otp-"), + Versioning::new(s), + s.to_string(), + ) + }) + .map(|s| s.to_string()) + .collect(); + Ok(versions) + } + + fn get_dependencies(&self) -> Result> { + Ok(vec!["erlang"]) + } + + fn install_version_(&self, ctx: &InstallContext, mut tv: ToolVersion) -> Result { + let tarball_path = self.download(&tv, ctx.pr.as_ref())?; + self.verify_checksum(ctx, &mut tv, &tarball_path)?; + self.install(ctx, &tv, &tarball_path)?; + self.verify(ctx, &tv)?; + Ok(tv) + } + + fn list_bin_paths(&self, tv: &ToolVersion) -> Result> { + Ok(["bin", ".mix/escripts"] + .iter() + .map(|p| tv.install_path().join(p)) + .collect()) + } +} diff --git a/src/plugins/core/mod.rs b/src/plugins/core/mod.rs index 6f2d0dc555..2a2114e13a 100644 --- a/src/plugins/core/mod.rs +++ b/src/plugins/core/mod.rs @@ -12,6 +12,7 @@ use crate::env; use crate::env::PATH_KEY; use crate::plugins::core::bun::BunPlugin; use crate::plugins::core::deno::DenoPlugin; +use crate::plugins::core::elixir::ElixirPlugin; #[cfg(unix)] use crate::plugins::core::erlang::ErlangPlugin; use crate::plugins::core::go::GoPlugin; @@ -27,6 +28,7 @@ use crate::toolset::ToolVersion; mod bun; mod deno; +mod elixir; #[cfg(unix)] mod erlang; mod go; @@ -45,6 +47,7 @@ pub static CORE_PLUGINS: Lazy = Lazy::new(|| { let plugins: Vec> = vec![ Arc::new(BunPlugin::new()), Arc::new(DenoPlugin::new()), + Arc::new(ElixirPlugin::new()), Arc::new(ErlangPlugin::new()), Arc::new(GoPlugin::new()), Arc::new(JavaPlugin::new()), @@ -60,6 +63,7 @@ pub static CORE_PLUGINS: Lazy = Lazy::new(|| { Arc::new(BunPlugin::new()), Arc::new(DenoPlugin::new()), // Arc::new(ErlangPlugin::new()), + // Arc::new(ElixirPlugin::new()), Arc::new(GoPlugin::new()), Arc::new(JavaPlugin::new()), Arc::new(NodePlugin::new()), diff --git a/src/plugins/core/zig.rs b/src/plugins/core/zig.rs index 038408eece..ea4f3c0e29 100644 --- a/src/plugins/core/zig.rs +++ b/src/plugins/core/zig.rs @@ -136,11 +136,7 @@ impl Backend for ZigPlugin { } #[requires(matches!(tv.request, ToolRequest::Version { .. } | ToolRequest::Prefix { .. } | ToolRequest::Ref { .. }), "unsupported tool version request type")] - fn install_version_( - &self, - ctx: &InstallContext, - mut tv: ToolVersion, - ) -> eyre::Result { + fn install_version_(&self, ctx: &InstallContext, mut tv: ToolVersion) -> Result { let tarball_path = self.download(&tv, ctx.pr.as_ref())?; self.verify_checksum(ctx, &mut tv, &tarball_path)?; self.install(ctx, &tv, &tarball_path)?; diff --git a/src/shorthands.rs b/src/shorthands.rs index 1fe843bb4b..2eb9af945f 100644 --- a/src/shorthands.rs +++ b/src/shorthands.rs @@ -76,7 +76,10 @@ mod tests { let mut settings = Settings::get().deref().clone(); settings.shorthands_file = Some("../fixtures/shorthands.toml".into()); let shorthands = get_shorthands(&settings); - assert_str_eq!(shorthands["elixir"][0], "asdf:mise-plugins/mise-elixir"); + assert_str_eq!( + shorthands["ephemeral-postgres"][0], + "asdf:smashedtoatoms/asdf-ephemeral-postgres" + ); assert_str_eq!(shorthands["node"][0], "https://node"); assert_str_eq!(shorthands["xxxxxx"][0], "https://xxxxxx"); }