Skip to content

Commit

Permalink
fix: trim "v" prefix for ubi backend tools (#2765)
Browse files Browse the repository at this point in the history
  • Loading branch information
jdx authored Oct 16, 2024
1 parent c412b32 commit 4d02763
Show file tree
Hide file tree
Showing 19 changed files with 331 additions and 389 deletions.
67 changes: 3 additions & 64 deletions src/backend/asdf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,28 +7,24 @@ 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, CacheManagerBuilder};
use crate::cli::args::BackendArg;
use crate::config::{Config, Settings, SETTINGS};
use crate::config::{Config, SETTINGS};
use crate::env_diff::{EnvDiff, EnvDiffOperation};
use crate::git::Git;
use crate::hash::hash_to_str;
use crate::http::HTTP_FETCH;
use crate::install_context::InstallContext;
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::registry::REGISTRY;
use crate::toolset::{ToolRequest, ToolVersion, Toolset};
use crate::ui::progress_report::SingleReport;
use crate::{dirs, env, file, http, registry};
use crate::{dirs, env, file};

/// This represents a plugin installed to ~/.local/share/mise/plugins
pub struct AsdfBackend {
Expand Down Expand Up @@ -101,56 +97,6 @@ impl AsdfBackend {
.collect())
}

fn fetch_versions(&self) -> Result<Option<Vec<String>>> {
let settings = Settings::get();
if !settings.use_versions_host {
return Ok(None);
}
// ensure that we're using a default shorthand plugin
let git = Git::new(&self.plugin_path);
let normalized_remote = normalize_remote(&git.get_remote_url().unwrap_or_default())
.unwrap_or("INVALID_URL".into());
let shorthand_remote = REGISTRY
.get(self.name.as_str())
.map(|s| registry::full_to_url(s))
.unwrap_or_default();
if normalized_remote != normalize_remote(&shorthand_remote).unwrap_or_default() {
return Ok(None);
}
let settings = Settings::get();
let raw_versions = match settings.paranoid {
true => HTTP_FETCH.get_text(format!("https://mise-versions.jdx.dev/{}", self.name)),
false => HTTP_FETCH.get_text(format!("http://mise-versions.jdx.dev/{}", self.name)),
};
let versions =
// using http is not a security concern and enabling tls makes mise significantly slower
match raw_versions {
Err(err) if http::error_code(&err) == Some(404) => return Ok(None),
res => res?,
};
let versions = versions
.lines()
.map(|v| v.trim().to_string())
.filter(|v| !v.is_empty())
.collect_vec();
match versions.is_empty() {
true => Ok(None),
false => Ok(Some(versions)),
}
}

fn fetch_remote_versions(&self) -> Result<Vec<String>> {
match self.fetch_versions() {
Ok(Some(versions)) => return Ok(versions),
Err(err) => warn!(
"Failed to fetch remote versions for plugin {}: {}",
style(&self.name).blue().for_stderr(),
err
),
_ => {}
};
self.plugin.fetch_remote_versions()
}
fn fetch_cached_legacy_file(&self, legacy_file: &Path) -> Result<Option<String>> {
let fp = self.legacy_cache_file_path(legacy_file);
if !fp.exists() || fp.metadata()?.modified()? < legacy_file.metadata()?.modified()? {
Expand Down Expand Up @@ -310,7 +256,7 @@ impl Backend for AsdfBackend {

fn _list_remote_versions(&self) -> Result<Vec<String>> {
self.remote_version_cache
.get_or_try_init(|| self.fetch_remote_versions())
.get_or_try_init(|| self.plugin.fetch_remote_versions())
.wrap_err_with(|| {
eyre!(
"Failed listing remote versions for plugin {}",
Expand Down Expand Up @@ -470,13 +416,6 @@ impl Debug for AsdfBackend {
}
}

fn normalize_remote(remote: &str) -> eyre::Result<String> {
let url = Url::parse(remote)?;
let host = url.host_str().unwrap();
let path = url.path().trim_end_matches(".git");
Ok(format!("{host}{path}"))
}

#[cfg(test)]
mod tests {
use test_log::test;
Expand Down
75 changes: 59 additions & 16 deletions src/backend/mod.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use std::collections::{BTreeMap, HashSet};
use std::collections::{BTreeMap, HashMap, HashSet};
use std::fmt::{Debug, Display, Formatter};
use std::fs::File;
use std::hash::Hash;
Expand All @@ -9,12 +9,14 @@ use console::style;
use contracts::requires;
use eyre::{bail, eyre, WrapErr};
use itertools::Itertools;
use once_cell::sync::Lazy;
use rayon::prelude::*;
use regex::Regex;
use strum::IntoEnumIterator;
use versions::Versioning;

use self::backend_meta::BackendMeta;
use crate::cache::{CacheManager, CacheManagerBuilder};
use crate::cli::args::{BackendArg, ToolVersionType};
use crate::cmd::CmdLineRunner;
use crate::config::{Config, CONFIG, SETTINGS};
Expand All @@ -25,7 +27,7 @@ use crate::plugins::{Plugin, PluginType, VERSION_REGEX};
use crate::runtime_symlinks::is_runtime_symlink;
use crate::toolset::{is_outdated_version, ToolRequest, ToolVersion, Toolset};
use crate::ui::progress_report::SingleReport;
use crate::{dirs, env, file, lock_file};
use crate::{dirs, env, file, lock_file, versions_host};

pub mod asdf;
pub mod backend_meta;
Expand All @@ -41,6 +43,7 @@ pub mod vfox;
pub type ABackend = Arc<dyn Backend>;
pub type BackendMap = BTreeMap<String, ABackend>;
pub type BackendList = Vec<ABackend>;
pub type VersionCacheManager = CacheManager<Vec<String>>;

#[derive(
Debug,
Expand Down Expand Up @@ -196,24 +199,40 @@ pub trait Backend: Debug + Send + Sync {
}
Ok(deps)
}

fn list_remote_versions(&self) -> eyre::Result<Vec<String>> {
self.ensure_dependencies_installed()?;
trace!("Listing remote versions for {}", self.fa().to_string());
let versions = self
._list_remote_versions()?
.into_iter()
.filter(|v| match v.parse::<ToolVersionType>() {
Ok(ToolVersionType::Version(_)) => true,
_ => {
warn!("Invalid version: {}@{v}", self.id());
false
self.get_remote_version_cache()
.get_or_try_init(|| {
trace!("Listing remote versions for {}", self.fa().to_string());
match versions_host::list_versions(self.fa()) {
Ok(Some(versions)) => return Ok(versions),
Ok(None) => {}
Err(e) => {
debug!("Error getting versions from versions host: {:#}", e);
}
};
trace!(
"Calling backend to list remote versions for {}",
self.fa().to_string()
);
let versions = self
._list_remote_versions()?
.into_iter()
.filter(|v| match v.parse::<ToolVersionType>() {
Ok(ToolVersionType::Version(_)) => true,
_ => {
warn!("Invalid version: {}@{v}", self.id());
false
}
})
.collect_vec();
if versions.is_empty() {
warn!("No versions found for {}", self.id());
}
Ok(versions)
})
.collect_vec();
if versions.is_empty() {
warn!("No versions found for {}", self.id());
}
Ok(versions)
.cloned()
}
fn _list_remote_versions(&self) -> eyre::Result<Vec<String>>;
fn latest_stable_version(&self) -> eyre::Result<Option<String>> {
Expand Down Expand Up @@ -556,6 +575,30 @@ pub trait Backend: Debug + Send + Sync {
.collect();
Ok(versions)
}

fn get_remote_version_cache(&self) -> Arc<VersionCacheManager> {
static REMOTE_VERSION_CACHE: Lazy<Mutex<HashMap<String, Arc<VersionCacheManager>>>> =
Lazy::new(|| Mutex::new(HashMap::new()));

REMOTE_VERSION_CACHE
.lock()
.unwrap()
.entry(self.fa().full.to_string())
.or_insert_with(|| {
let mut cm = CacheManagerBuilder::new(
self.fa().cache_path.join("remote_versions.msgpack.z"),
)
.with_fresh_duration(SETTINGS.fetch_remote_versions_cache());
if let Some(plugin_path) = self.plugin().map(|p| p.path()) {
cm = cm
.with_fresh_file(plugin_path.clone())
.with_fresh_file(plugin_path.join("bin/list-all"))
}

Arc::new(cm.build())
})
.clone()
}
}

fn find_match_in_list(list: &[String], query: &str) -> Option<String> {
Expand Down
11 changes: 8 additions & 3 deletions src/backend/ubi.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
use std::fmt::Debug;

use eyre::eyre;
use ubi::UbiBuilder;

use crate::backend::{Backend, BackendType};
use crate::cache::{CacheManager, CacheManagerBuilder};
use crate::cli::args::BackendArg;
Expand All @@ -11,6 +8,9 @@ use crate::env::GITHUB_TOKEN;
use crate::install_context::InstallContext;
use crate::toolset::ToolRequest;
use crate::{github, http};
use eyre::eyre;
use ubi::UbiBuilder;
use xx::regex;

#[derive(Debug)]
pub struct UbiBackend {
Expand Down Expand Up @@ -41,6 +41,11 @@ impl Backend for UbiBackend {
Ok(github::list_releases(self.name())?
.into_iter()
.map(|r| r.tag_name)
// trim 'v' prefixes if they exist
.map(|t| match regex!(r"^v[0-9]").is_match(&t) {
true => t[1..].to_string(),
false => t,
})
.rev()
.collect())
})
Expand Down
1 change: 1 addition & 0 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ pub(crate) mod timeout;
mod toml;
mod toolset;
mod ui;
mod versions_host;

pub use crate::exit::exit;

Expand Down
4 changes: 4 additions & 0 deletions src/plugins/asdf_plugin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,10 @@ impl Plugin for AsdfPlugin {
&self.name
}

fn path(&self) -> PathBuf {
self.plugin_path.clone()
}

fn get_plugin_type(&self) -> PluginType {
PluginType::Asdf
}
Expand Down
32 changes: 10 additions & 22 deletions src/plugins/core/bun.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,24 +28,6 @@ impl BunPlugin {
Self { core }
}

fn fetch_remote_versions(&self) -> Result<Vec<String>> {
match self.core.fetch_remote_versions_from_mise() {
Ok(Some(versions)) => return Ok(versions),
Ok(None) => {}
Err(e) => warn!("failed to fetch remote versions: {}", e),
}
let releases: Vec<GithubRelease> =
HTTP_FETCH.json("https://api.github.com/repos/oven-sh/bun/releases?per_page=100")?;
let versions = releases
.into_iter()
.map(|r| r.tag_name)
.filter_map(|v| v.strip_prefix("bun-v").map(|v| v.to_string()))
.unique()
.sorted_by_cached_key(|s| (Versioning::new(s), s.to_string()))
.collect();
Ok(versions)
}

fn bun_bin(&self, tv: &ToolVersion) -> PathBuf {
tv.install_path().join("bin/bun")
}
Expand Down Expand Up @@ -103,10 +85,16 @@ impl Backend for BunPlugin {
}

fn _list_remote_versions(&self) -> Result<Vec<String>> {
self.core
.remote_version_cache
.get_or_try_init(|| self.fetch_remote_versions())
.cloned()
let releases: Vec<GithubRelease> =
HTTP_FETCH.json("https://api.github.com/repos/oven-sh/bun/releases?per_page=100")?;
let versions = releases
.into_iter()
.map(|r| r.tag_name)
.filter_map(|v| v.strip_prefix("bun-v").map(|v| v.to_string()))
.unique()
.sorted_by_cached_key(|s| (Versioning::new(s), s.to_string()))
.collect();
Ok(versions)
}

fn legacy_filenames(&self) -> Result<Vec<String>> {
Expand Down
32 changes: 10 additions & 22 deletions src/plugins/core/deno.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,24 +30,6 @@ impl DenoPlugin {
Self { core }
}

fn fetch_remote_versions(&self) -> Result<Vec<String>> {
match self.core.fetch_remote_versions_from_mise() {
Ok(Some(versions)) => return Ok(versions),
Ok(None) => {}
Err(e) => warn!("failed to fetch remote versions: {}", e),
}
let versions: DenoVersions = HTTP_FETCH.json("https://deno.com/versions.json")?;
let versions = versions
.cli
.into_iter()
.filter(|v| v.starts_with('v'))
.map(|v| v.trim_start_matches('v').to_string())
.unique()
.sorted_by_cached_key(|s| (Versioning::new(s), s.to_string()))
.collect();
Ok(versions)
}

fn deno_bin(&self, tv: &ToolVersion) -> PathBuf {
tv.install_path().join(if cfg!(target_os = "windows") {
"bin/deno.exe"
Expand Down Expand Up @@ -111,10 +93,16 @@ impl Backend for DenoPlugin {
}

fn _list_remote_versions(&self) -> Result<Vec<String>> {
self.core
.remote_version_cache
.get_or_try_init(|| self.fetch_remote_versions())
.cloned()
let versions: DenoVersions = HTTP_FETCH.json("https://deno.com/versions.json")?;
let versions = versions
.cli
.into_iter()
.filter(|v| v.starts_with('v'))
.map(|v| v.trim_start_matches('v').to_string())
.unique()
.sorted_by_cached_key(|s| (Versioning::new(s), s.to_string()))
.collect();
Ok(versions)
}

fn legacy_filenames(&self) -> Result<Vec<String>> {
Expand Down
Loading

0 comments on commit 4d02763

Please sign in to comment.