Skip to content

Commit

Permalink
feat: vfox backend (jdx#2187)
Browse files Browse the repository at this point in the history
  • Loading branch information
jdx authored and triarius committed Sep 18, 2024
1 parent 2de3ad1 commit 2f3f194
Show file tree
Hide file tree
Showing 29 changed files with 1,256 additions and 171 deletions.
886 changes: 846 additions & 40 deletions Cargo.lock

Large diffs are not rendered by default.

4 changes: 3 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@ toml_edit = { version = "0.22.12", features = ["parse"] }
url = "2.5.0"
usage-lib = { version = "0.3", features = ["clap"] }
versions = { version = "6.2.0", features = ["serde"] }
vfox = "0.1"
walkdir = "2.5.0"
which = "6.0.1"
xx = { version = "1.0.0", features = ["glob"] }
Expand All @@ -130,6 +131,7 @@ nix = {version="0.29", features=["signal", "user"]}

[build-dependencies]
built = { version = "0.7", features = ["chrono", "git2"] }
cfg_aliases = "0.2"

[dev-dependencies]
assert_cmd = "2.0.14"
Expand Down Expand Up @@ -160,4 +162,4 @@ pkg-url = "{ repo }/releases/download/v{ version }/mise-v{version}-linux-x64{ ar
pkg-url = "{ repo }/releases/download/v{ version }/mise-v{version}-linux-armv7{ archive-suffix }"

[package.metadata.cargo-machete]
ignored = ["built", "openssl"]
ignored = ["built", "openssl", "cfg_aliases"]
8 changes: 8 additions & 0 deletions build.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
fn main() {
cfg_aliases::cfg_aliases! {
linux: { target_os = "linux" },
macos: { target_os = "macos" },
windows: { target_os = "windows" },

vfox: { any(feature = "vfox", target_os = "windows") },
asdf: { any(feature = "asdf", not(target_os = "windows")) },
}
built::write_built_file().expect("Failed to acquire build-time information");
}
101 changes: 4 additions & 97 deletions src/backend/asdf.rs
Original file line number Diff line number Diff line change
@@ -1,16 +1,17 @@
use std::collections::{BTreeMap, HashMap};
use std::collections::BTreeMap;
use std::fmt::{Debug, Formatter};
use std::fs;
use std::hash::{Hash, Hasher};
use std::path::{Path, PathBuf};
use std::sync::{Arc, RwLock};
use std::sync::Arc;

use color_eyre::eyre::{eyre, Result, WrapErr};
use console::style;
use itertools::Itertools;
use rayon::prelude::*;
use url::Url;

use crate::backend::external_plugin_cache::ExternalPluginCache;
use crate::backend::{ABackend, Backend, BackendList};
use crate::cache::CacheManager;
use crate::cli::args::BackendArg;
Expand All @@ -25,7 +26,6 @@ use crate::plugins::asdf_plugin::AsdfPlugin;
use crate::plugins::mise_plugin_toml::MisePluginToml;
use crate::plugins::Script::{Download, ExecEnv, Install, ParseLegacyFile};
use crate::plugins::{Plugin, PluginType, Script, ScriptManager};
use crate::tera::{get_tera, BASE_CONTEXT};
use crate::toolset::{ToolRequest, ToolVersion, Toolset};
use crate::ui::progress_report::SingleReport;
use crate::{dirs, env, file, http};
Expand Down Expand Up @@ -91,6 +91,7 @@ impl AsdfBackend {
pub fn list() -> Result<BackendList> {
Ok(file::dir_subdirs(&dirs::PLUGINS)?
.into_par_iter()
.filter(|name| !dirs::PLUGINS.join(name).join("metadata.lua").exists())
.map(|name| Arc::new(Self::from_arg(name.into())) as ABackend)
.collect())
}
Expand Down Expand Up @@ -458,100 +459,6 @@ impl Debug for AsdfBackend {
}
}

#[derive(Debug, Default)]
pub struct ExternalPluginCache {
list_bin_paths: RwLock<HashMap<ToolRequest, CacheManager<Vec<String>>>>,
exec_env: RwLock<HashMap<ToolRequest, CacheManager<BTreeMap<String, String>>>>,
}

impl ExternalPluginCache {
pub fn list_bin_paths<F>(
&self,
plugin: &AsdfBackend,
tv: &ToolVersion,
fetch: F,
) -> eyre::Result<Vec<String>>
where
F: FnOnce() -> eyre::Result<Vec<String>>,
{
let mut w = self.list_bin_paths.write().unwrap();
let cm = w.entry(tv.request.clone()).or_insert_with(|| {
let list_bin_paths_filename = match &plugin.toml.list_bin_paths.cache_key {
Some(key) => {
let config = Config::get();
let key = render_cache_key(&config, tv, key);
let filename = format!("{}-$KEY.msgpack.z", key);
tv.cache_path().join("list_bin_paths").join(filename)
}
None => tv.cache_path().join("list_bin_paths-$KEY.msgpack.z"),
};
CacheManager::new(list_bin_paths_filename)
.with_fresh_file(dirs::DATA.to_path_buf())
.with_fresh_file(plugin.plugin_path.clone())
.with_fresh_file(tv.install_path())
});
cm.get_or_try_init(fetch).cloned()
}

pub fn exec_env<F>(
&self,
config: &Config,
plugin: &AsdfBackend,
tv: &ToolVersion,
fetch: F,
) -> eyre::Result<BTreeMap<String, String>>
where
F: FnOnce() -> eyre::Result<BTreeMap<String, String>>,
{
let mut w = self.exec_env.write().unwrap();
let cm = w.entry(tv.request.clone()).or_insert_with(|| {
let exec_env_filename = match &plugin.toml.exec_env.cache_key {
Some(key) => {
let key = render_cache_key(config, tv, key);
let filename = format!("{}-$KEY.msgpack.z", key);
tv.cache_path().join("exec_env").join(filename)
}
None => tv.cache_path().join("exec_env-$KEY.msgpack.z"),
};
CacheManager::new(exec_env_filename)
.with_fresh_file(dirs::DATA.to_path_buf())
.with_fresh_file(plugin.plugin_path.clone())
.with_fresh_file(tv.install_path())
});
cm.get_or_try_init(fetch).cloned()
}
}

fn render_cache_key(config: &Config, tv: &ToolVersion, cache_key: &[String]) -> String {
let elements = cache_key
.iter()
.map(|tmpl| {
let s = parse_template(config, tv, tmpl).unwrap();
let s = s.trim().to_string();
trace!("cache key element: {} -> {}", tmpl.trim(), s);
let mut s = hash_to_str(&s);
s.truncate(10);
s
})
.collect::<Vec<String>>();
elements.join("-")
}

fn parse_template(config: &Config, tv: &ToolVersion, tmpl: &str) -> eyre::Result<String> {
let mut ctx = BASE_CONTEXT.clone();
ctx.insert("project_root", &config.project_root);
ctx.insert("opts", &tv.request.options());
get_tera(
config
.project_root
.as_ref()
.or(env::current_dir().as_ref().ok())
.map(|p| p.as_path()),
)
.render_str(tmpl, &ctx)
.wrap_err_with(|| eyre!("failed to parse template: {tmpl}"))
}

fn normalize_remote(remote: &str) -> eyre::Result<String> {
let url = Url::parse(remote)?;
let host = url.host_str().unwrap();
Expand Down
105 changes: 105 additions & 0 deletions src/backend/external_plugin_cache.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
use crate::backend::asdf::AsdfBackend;
use crate::cache::CacheManager;
use crate::config::Config;
use crate::dirs;
use crate::hash::hash_to_str;
use crate::tera::{get_tera, BASE_CONTEXT};
use crate::toolset::{ToolRequest, ToolVersion};
use eyre::{eyre, WrapErr};
use std::collections::{BTreeMap, HashMap};
use std::env;
use std::sync::RwLock;

#[derive(Debug, Default)]
pub struct ExternalPluginCache {
list_bin_paths: RwLock<HashMap<ToolRequest, CacheManager<Vec<String>>>>,
exec_env: RwLock<HashMap<ToolRequest, CacheManager<BTreeMap<String, String>>>>,
}

impl ExternalPluginCache {
pub fn list_bin_paths<F>(
&self,
plugin: &AsdfBackend,
tv: &ToolVersion,
fetch: F,
) -> eyre::Result<Vec<String>>
where
F: FnOnce() -> eyre::Result<Vec<String>>,
{
let mut w = self.list_bin_paths.write().unwrap();
let cm = w.entry(tv.request.clone()).or_insert_with(|| {
let list_bin_paths_filename = match &plugin.toml.list_bin_paths.cache_key {
Some(key) => {
let config = Config::get();
let key = render_cache_key(&config, tv, key);
let filename = format!("{}-$KEY.msgpack.z", key);
tv.cache_path().join("list_bin_paths").join(filename)
}
None => tv.cache_path().join("list_bin_paths-$KEY.msgpack.z"),
};
CacheManager::new(list_bin_paths_filename)
.with_fresh_file(dirs::DATA.to_path_buf())
.with_fresh_file(plugin.plugin_path.clone())
.with_fresh_file(tv.install_path())
});
cm.get_or_try_init(fetch).cloned()
}

pub fn exec_env<F>(
&self,
config: &Config,
plugin: &AsdfBackend,
tv: &ToolVersion,
fetch: F,
) -> eyre::Result<BTreeMap<String, String>>
where
F: FnOnce() -> eyre::Result<BTreeMap<String, String>>,
{
let mut w = self.exec_env.write().unwrap();
let cm = w.entry(tv.request.clone()).or_insert_with(|| {
let exec_env_filename = match &plugin.toml.exec_env.cache_key {
Some(key) => {
let key = render_cache_key(config, tv, key);
let filename = format!("{}-$KEY.msgpack.z", key);
tv.cache_path().join("exec_env").join(filename)
}
None => tv.cache_path().join("exec_env-$KEY.msgpack.z"),
};
CacheManager::new(exec_env_filename)
.with_fresh_file(dirs::DATA.to_path_buf())
.with_fresh_file(plugin.plugin_path.clone())
.with_fresh_file(tv.install_path())
});
cm.get_or_try_init(fetch).cloned()
}
}

fn render_cache_key(config: &Config, tv: &ToolVersion, cache_key: &[String]) -> String {
let elements = cache_key
.iter()
.map(|tmpl| {
let s = parse_template(config, tv, tmpl).unwrap();
let s = s.trim().to_string();
trace!("cache key element: {} -> {}", tmpl.trim(), s);
let mut s = hash_to_str(&s);
s.truncate(10);
s
})
.collect::<Vec<String>>();
elements.join("-")
}

fn parse_template(config: &Config, tv: &ToolVersion, tmpl: &str) -> eyre::Result<String> {
let mut ctx = BASE_CONTEXT.clone();
ctx.insert("project_root", &config.project_root);
ctx.insert("opts", &tv.request.options());
get_tera(
config
.project_root
.as_ref()
.or(env::current_dir().as_ref().ok())
.map(|p| p.as_path()),
)
.render_str(tmpl, &ctx)
.wrap_err_with(|| eyre!("failed to parse template: {tmpl}"))
}
18 changes: 15 additions & 3 deletions src/backend/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,13 @@ use self::backend_meta::BackendMeta;
pub mod asdf;
pub mod backend_meta;
pub mod cargo;
mod external_plugin_cache;
pub mod go;
pub mod npm;
pub mod pipx;
pub mod spm;
pub mod ubi;
pub mod vfox;

pub type ABackend = Arc<dyn Backend>;
pub type BackendMap = BTreeMap<String, ABackend>;
Expand Down Expand Up @@ -63,6 +65,7 @@ pub enum BackendType {
Pipx,
Spm,
Ubi,
Vfox,
}

impl Display for BackendType {
Expand All @@ -77,10 +80,18 @@ fn load_tools() -> BackendMap {
if let Some(backends) = TOOLS.lock().unwrap().as_ref() {
return backends.clone();
}
let mut tools = CORE_PLUGINS.clone();
tools.extend(asdf::AsdfBackend::list().expect("failed to list plugins"));
tools.extend(list_installed_backends().expect("failed to list backends"));
let mut tools = CORE_PLUGINS
.iter()
.map(|(_, p)| p.clone())
.collect::<Vec<ABackend>>();
let settings = Settings::get();
if settings.asdf {
tools.extend(asdf::AsdfBackend::list().expect("failed to list asdf plugins"));
}
if settings.vfox {
tools.extend(vfox::VfoxBackend::list().expect("failed to list vfox plugins"));
}
tools.extend(list_installed_backends().expect("failed to list backends"));
tools.retain(|plugin| !settings.disable_tools.contains(plugin.id()));
let tools: BackendMap = tools
.into_iter()
Expand Down Expand Up @@ -130,6 +141,7 @@ pub fn arg_to_backend(ba: BackendArg) -> ABackend {
BackendType::Pipx => Arc::new(pipx::PIPXBackend::from_arg(ba)),
BackendType::Spm => Arc::new(spm::SPMBackend::from_arg(ba)),
BackendType::Ubi => Arc::new(ubi::UbiBackend::from_arg(ba)),
BackendType::Vfox => Arc::new(vfox::VfoxBackend::from_arg(ba)),
}
}

Expand Down
Loading

0 comments on commit 2f3f194

Please sign in to comment.