diff --git a/CHANGELOG.md b/CHANGELOG.md index 839f97d87c6..821237be1c2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ #### 🚀 Updates +- Added caching around `bun bun.lockb` commands, instead of running them for every task. - Updated environment variable substitution to support different outputs when a variable is missing, based on a trailing flag syntax. - `$FOO` or `${FOO}` - If variable is missing, keeps the original syntax (current default). diff --git a/Cargo.lock b/Cargo.lock index 8b6360e372a..b438774020d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3185,6 +3185,7 @@ dependencies = [ "moon_utils", "proto_core", "rustc-hash 2.0.0", + "scc", "starbase_utils", "tracing", ] @@ -3588,6 +3589,7 @@ dependencies = [ "moon_utils", "proto_core", "rustc-hash 2.0.0", + "scc", "starbase_styles", "starbase_utils", "tracing", diff --git a/legacy/bun/lang/src/bun_lockb.rs b/legacy/bun/lang/src/bun_lockb.rs index b3bdf6c2e1b..b647902a375 100644 --- a/legacy/bun/lang/src/bun_lockb.rs +++ b/legacy/bun/lang/src/bun_lockb.rs @@ -2,11 +2,12 @@ use cached::proc_macro::cached; use miette::IntoDiagnostic; use moon_lang::LockfileDependencyVersions; use rustc_hash::FxHashMap; +use std::sync::Arc; use yarn_lock_parser::{parse_str, Entry}; #[cached(result)] pub fn load_lockfile_dependencies( - lockfile_text: String, + lockfile_text: Arc, ) -> miette::Result { let mut deps: LockfileDependencyVersions = FxHashMap::default(); diff --git a/legacy/bun/tool/Cargo.toml b/legacy/bun/tool/Cargo.toml index e027f00af8e..77b894a37fa 100644 --- a/legacy/bun/tool/Cargo.toml +++ b/legacy/bun/tool/Cargo.toml @@ -16,6 +16,7 @@ moon_utils = { path = "../../core/utils" } miette = { workspace = true } proto_core = { workspace = true } rustc-hash = { workspace = true } +scc = { workspace = true } starbase_utils = { workspace = true } tracing = { workspace = true } diff --git a/legacy/bun/tool/src/bun_tool.rs b/legacy/bun/tool/src/bun_tool.rs index 28b9ba1f1d7..63341a9bb8b 100644 --- a/legacy/bun/tool/src/bun_tool.rs +++ b/legacy/bun/tool/src/bun_tool.rs @@ -12,6 +12,7 @@ use moon_utils::get_workspace_root; use proto_core::flow::install::InstallOptions; use proto_core::{Id, ProtoEnvironment, Tool as ProtoTool, UnresolvedVersionSpec}; use rustc_hash::FxHashMap; +use scc::hash_cache::Entry; use starbase_utils::fs; use std::env; use std::path::{Path, PathBuf}; @@ -34,6 +35,8 @@ pub struct BunTool { console: Arc, + lockfile_cache: scc::HashCache>, + proto_env: Arc, } @@ -50,6 +53,7 @@ impl BunTool { global: false, tool: load_tool_plugin(&Id::raw("bun"), &proto, config.plugin.as_ref().unwrap()) .await?, + lockfile_cache: scc::HashCache::default(), proto_env: proto, }; @@ -62,6 +66,37 @@ impl BunTool { Ok(bun) } + + // Bun lockfiles are binary, so we need to convert them to text first + // using Bun itself! + async fn load_lockfile(&self, cwd: &Path) -> miette::Result> { + let key = cwd.to_path_buf(); + + let cache = match self.lockfile_cache.entry_async(key).await { + Entry::Occupied(o) => o.get().clone(), + Entry::Vacant(v) => { + let yarn_lock = cwd.join("yarn.lock"); + + let content = if yarn_lock.exists() { + Arc::new(fs::read_file(yarn_lock)?) + } else { + let mut cmd = self.create_command(&())?; + cmd.arg("bun.lockb"); + cmd.cwd(cwd); + + let output = cmd.create_async().exec_capture_output().await?; + + Arc::new(output_to_string(&output.stdout)) + }; + + v.put_entry(content.clone()); + + content + } + }; + + Ok(cache) + } } #[async_trait] @@ -189,17 +224,9 @@ impl DependencyManager<()> for BunTool { return Ok(FxHashMap::default()); }; - // Bun lockfiles are binary, so we need to convert them to text first - // using Bun itself! - let mut cmd = self.create_command(&())?; - cmd.arg("bun.lockb"); - cmd.cwd(lockfile_path.parent().unwrap()); - - let output = cmd.create_async().exec_capture_output().await?; - - Ok(load_lockfile_dependencies(output_to_string( - &output.stdout, - ))?) + Ok(load_lockfile_dependencies( + self.load_lockfile(lockfile_path.parent().unwrap()).await?, + )?) } #[instrument(skip_all)] diff --git a/legacy/node/tool/Cargo.toml b/legacy/node/tool/Cargo.toml index 3e0faa28a41..869e5161562 100644 --- a/legacy/node/tool/Cargo.toml +++ b/legacy/node/tool/Cargo.toml @@ -16,6 +16,7 @@ moon_utils = { path = "../../core/utils" } miette = { workspace = true } proto_core = { workspace = true } rustc-hash = { workspace = true } +scc = { workspace = true } starbase_styles = { workspace = true } starbase_utils = { workspace = true } tracing = { workspace = true } diff --git a/legacy/node/tool/src/bun_tool.rs b/legacy/node/tool/src/bun_tool.rs index 1d2702d88b3..6a2dfbad264 100644 --- a/legacy/node/tool/src/bun_tool.rs +++ b/legacy/node/tool/src/bun_tool.rs @@ -13,9 +13,10 @@ use moon_utils::get_workspace_root; use proto_core::flow::install::InstallOptions; use proto_core::{Id, ProtoEnvironment, Tool as ProtoTool, UnresolvedVersionSpec}; use rustc_hash::FxHashMap; +use scc::hash_cache::Entry; use starbase_utils::fs; use std::env; -use std::path::Path; +use std::path::{Path, PathBuf}; use std::sync::Arc; use tracing::instrument; @@ -28,6 +29,8 @@ pub struct BunTool { console: Arc, + lockfile_cache: scc::HashCache>, + proto_env: Arc, } @@ -45,6 +48,7 @@ impl BunTool { .await?, config, proto_env, + lockfile_cache: scc::HashCache::default(), console, }) } @@ -67,6 +71,37 @@ impl BunTool { Ok(cmd) } + + // Bun lockfiles are binary, so we need to convert them to text first + // using Bun itself! + async fn load_lockfile(&self, cwd: &Path) -> miette::Result> { + let key = cwd.to_path_buf(); + + let cache = match self.lockfile_cache.entry_async(key).await { + Entry::Occupied(o) => o.get().clone(), + Entry::Vacant(v) => { + let yarn_lock = cwd.join("yarn.lock"); + + let content = if yarn_lock.exists() { + Arc::new(fs::read_file(yarn_lock)?) + } else { + let mut cmd = self.internal_create_command()?; + cmd.arg("bun.lockb"); + cmd.cwd(cwd); + + let output = cmd.create_async().exec_capture_output().await?; + + Arc::new(output_to_string(&output.stdout)) + }; + + v.put_entry(content.clone()); + + content + } + }; + + Ok(cache) + } } #[async_trait] @@ -196,17 +231,9 @@ impl DependencyManager for BunTool { return Ok(FxHashMap::default()); }; - // Bun lockfiles are binary, so we need to convert them to text first - // using Bun itself! - let mut cmd = self.internal_create_command()?; - cmd.arg("bun.lockb"); - cmd.cwd(lockfile_path.parent().unwrap()); - - let output = cmd.create_async().exec_capture_output().await?; - - Ok(bun::load_lockfile_dependencies(output_to_string( - &output.stdout, - ))?) + Ok(bun::load_lockfile_dependencies( + self.load_lockfile(lockfile_path.parent().unwrap()).await?, + )?) } #[instrument(skip_all)]