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");
}