From 6dbbc41415ed59a331c6e85141ec815ad73f3ce6 Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Sat, 16 Mar 2024 18:21:20 -0500 Subject: [PATCH] feat: very basic dependency support --- scripts/pre-release-hook.sh | 2 +- scripts/update-shorthand-repo.sh | 36 ++++++++++++++++---------------- src/forge/cargo.rs | 5 +++++ src/forge/go.rs | 5 +++++ src/forge/mod.rs | 5 +++++ src/forge/npm.rs | 5 +++++ src/plugins/external_plugin.rs | 10 +++++++++ src/toolset/mod.rs | 16 ++++++++++++++ 8 files changed, 65 insertions(+), 19 deletions(-) diff --git a/scripts/pre-release-hook.sh b/scripts/pre-release-hook.sh index 746c3f8085..001d6f3685 100755 --- a/scripts/pre-release-hook.sh +++ b/scripts/pre-release-hook.sh @@ -2,7 +2,7 @@ set -euxo pipefail if [[ "${NO_UPDATE:-}" == "1" ]]; then - echo "NO_UPDATE is set, skipping update" + echo "NO_UPDATE is set, skipping update" # else # cargo update && git add Cargo.lock fi diff --git a/scripts/update-shorthand-repo.sh b/scripts/update-shorthand-repo.sh index cbd19a7960..19909587f8 100755 --- a/scripts/update-shorthand-repo.sh +++ b/scripts/update-shorthand-repo.sh @@ -36,23 +36,23 @@ pub static DEFAULT_SHORTHANDS: Lazy> = EOF count=0 for plugin in $asdf_plugins; do - file="asdf-plugins/plugins/$plugin" - repository=$(grep -e '^repository = ' "$file") - repository="${repository/#repository = /}" - printf "\033[2K[%03d/%d] %s\r" $((++count)) "$num_plugins" "$repository" - if [[ $repository == "https://github.com/mise-plugins/"* ]]; then - trusted+=("$plugin") - elif grep -qe '^first-party = true' "$file"; then - trusted+=("$plugin") - fi - # if [[ $repository == "https://github.com/"* ]]; then - # owner=${repository#*github.com/} - # owner=${owner%/*} - # repo=${repository#*github.com/*/} - # repo=${repo%.git} - # stars["$owner/$repo"]="$plugin" - # fi - echo " (\"$plugin\", \"$repository\")," >>src/default_shorthands.rs + file="asdf-plugins/plugins/$plugin" + repository=$(grep -e '^repository = ' "$file") + repository="${repository/#repository = /}" + printf "\033[2K[%03d/%d] %s\r" $((++count)) "$num_plugins" "$repository" + if [[ $repository == "https://github.com/mise-plugins/"* ]]; then + trusted+=("$plugin") + elif grep -qe '^first-party = true' "$file"; then + trusted+=("$plugin") + fi + # if [[ $repository == "https://github.com/"* ]]; then + # owner=${repository#*github.com/} + # owner=${owner%/*} + # repo=${repository#*github.com/*/} + # repo=${repo%.git} + # stars["$owner/$repo"]="$plugin" + # fi + echo " (\"$plugin\", \"$repository\")," >>src/default_shorthands.rs done echo "]));" >>src/default_shorthands.rs @@ -63,7 +63,7 @@ pub static TRUSTED_SHORTHANDS: Lazy> = Lazy::new(|| HashSet::from([ EOF for plugin in "${trusted[@]}"; do - echo " \"$plugin\"," >>src/default_shorthands.rs + echo " \"$plugin\"," >>src/default_shorthands.rs done echo "]));" >>src/default_shorthands.rs diff --git a/src/forge/cargo.rs b/src/forge/cargo.rs index 6e1721e815..76d9275d5f 100644 --- a/src/forge/cargo.rs +++ b/src/forge/cargo.rs @@ -11,6 +11,7 @@ use crate::file; use crate::forge::{Forge, ForgeType}; use crate::http::HTTP_FETCH; use crate::install_context::InstallContext; +use crate::toolset::ToolVersion; #[derive(Debug)] pub struct CargoForge { @@ -27,6 +28,10 @@ impl Forge for CargoForge { &self.fa } + fn get_dependencies(&self, _tv: &ToolVersion) -> eyre::Result> { + Ok(vec!["cargo".into(), "rust".into()]) + } + fn list_remote_versions(&self) -> eyre::Result> { self.remote_version_cache .get_or_try_init(|| { diff --git a/src/forge/go.rs b/src/forge/go.rs index a12d24ad90..43014d8783 100644 --- a/src/forge/go.rs +++ b/src/forge/go.rs @@ -7,6 +7,7 @@ use crate::config::{Config, Settings}; use crate::forge::{Forge, ForgeType}; use crate::install_context::InstallContext; +use crate::toolset::ToolVersion; #[derive(Debug)] pub struct GoForge { @@ -23,6 +24,10 @@ impl Forge for GoForge { &self.fa } + fn get_dependencies(&self, _tv: &ToolVersion) -> eyre::Result> { + Ok(vec!["go".into()]) + } + fn list_remote_versions(&self) -> eyre::Result> { self.remote_version_cache .get_or_try_init(|| { diff --git a/src/forge/mod.rs b/src/forge/mod.rs index 4459869f51..a20eb43d02 100644 --- a/src/forge/mod.rs +++ b/src/forge/mod.rs @@ -99,6 +99,11 @@ pub trait Forge: Debug + Send + Sync { fn get_plugin_type(&self) -> PluginType { PluginType::Core } + /// If any of these tools are installing in parallel, we should wait for them to finish + /// before installing this tool. + fn get_dependencies(&self, _tv: &ToolVersion) -> eyre::Result> { + Ok(vec![]) + } fn list_remote_versions(&self) -> eyre::Result>; fn latest_stable_version(&self) -> eyre::Result> { self.latest_version(Some("latest".into())) diff --git a/src/forge/npm.rs b/src/forge/npm.rs index 39be0138ef..f4236a141c 100644 --- a/src/forge/npm.rs +++ b/src/forge/npm.rs @@ -7,6 +7,7 @@ use crate::config::{Config, Settings}; use crate::forge::{Forge, ForgeType}; use crate::install_context::InstallContext; +use crate::toolset::ToolVersion; use serde_json::Value; #[derive(Debug)] @@ -25,6 +26,10 @@ impl Forge for NPMForge { &self.fa } + fn get_dependencies(&self, _tv: &ToolVersion) -> eyre::Result> { + Ok(vec!["node".into()]) + } + fn list_remote_versions(&self) -> eyre::Result> { self.remote_version_cache .get_or_try_init(|| { diff --git a/src/plugins/external_plugin.rs b/src/plugins/external_plugin.rs index 0cb83a699f..c017dd8b6d 100644 --- a/src/plugins/external_plugin.rs +++ b/src/plugins/external_plugin.rs @@ -444,6 +444,16 @@ impl Forge for ExternalPlugin { fn get_plugin_type(&self) -> PluginType { PluginType::External } + + fn get_dependencies(&self, tv: &ToolVersion) -> Result> { + let out = match tv.forge.name.as_str() { + "poetry" | "pipenv" => vec!["python"], + "elixir" => vec!["erlang"], + _ => vec![], + }; + Ok(out.into_iter().map(|s| s.into()).collect()) + } + fn list_remote_versions(&self) -> Result> { self.remote_version_cache .get_or_try_init(|| self.fetch_remote_versions()) diff --git a/src/toolset/mod.rs b/src/toolset/mod.rs index b5ffd1e490..936fc97069 100644 --- a/src/toolset/mod.rs +++ b/src/toolset/mod.rs @@ -3,6 +3,8 @@ use std::fmt::{Display, Formatter}; use std::path::PathBuf; use std::sync::{Arc, Mutex}; use std::thread; +use std::thread::sleep; +use std::time::Duration; use console::truncate_str; use eyre::Result; @@ -154,15 +156,28 @@ impl Toolset { true => 1, false => opts.jobs.unwrap_or(settings.jobs), }; + let installing: HashSet = HashSet::new(); + let installing = Arc::new(Mutex::new(installing)); thread::scope(|s| { (0..jobs) .map(|_| { let queue = queue.clone(); + let installing = installing.clone(); let ts = &*self; s.spawn(move || { let next_job = || queue.lock().unwrap().pop(); while let Some((t, versions)) = next_job() { + installing.lock().unwrap().insert(t.id().into()); for tv in versions { + for dep in t.get_dependencies(&tv)? { + while installing.lock().unwrap().contains(dep.as_str()) { + trace!( + "{tv} waiting for dependency {} to finish installing", + dep + ); + sleep(Duration::from_millis(100)); + } + } let tv = tv.request.resolve( t.as_ref(), tv.opts.clone(), @@ -177,6 +192,7 @@ impl Toolset { }; t.install_version(ctx)?; } + installing.lock().unwrap().remove(t.id()); } Ok(()) })