From 438d81e965c97413ee005d0e6493fe89b8040ddb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1vid=20Istv=C3=A1n=20B=C3=ADr=C3=B3?= Date: Thu, 14 Nov 2024 13:54:34 +0100 Subject: [PATCH] transitive resolve for package deps --- wasm-rpc-stubgen/src/commands/declarative.rs | 33 +++++---- wasm-rpc-stubgen/src/model/wasm_rpc.rs | 7 ++ wasm-rpc-stubgen/src/wit_resolve.rs | 74 ++++++++++++++++++++ 3 files changed, 102 insertions(+), 12 deletions(-) diff --git a/wasm-rpc-stubgen/src/commands/declarative.rs b/wasm-rpc-stubgen/src/commands/declarative.rs index 4f9426d7..a3ad5de8 100644 --- a/wasm-rpc-stubgen/src/commands/declarative.rs +++ b/wasm-rpc-stubgen/src/commands/declarative.rs @@ -16,12 +16,13 @@ use crate::wit_generate::{ add_stub_as_dependency_to_wit_dir, extract_main_interface_as_wit_dep, AddStubAsDepConfig, UpdateCargoToml, }; -use crate::wit_resolve::{parse_wit_deps_dir, ResolvedWitApplication}; +use crate::wit_resolve::{ResolvedWitApplication, WitDepsResolver}; use crate::{commands, naming, WasmRpcOverride}; use anyhow::{anyhow, Context, Error}; use colored::Colorize; use glob::glob; use itertools::Itertools; +use std::cell::OnceCell; use std::cmp::Ordering; use std::path::{Path, PathBuf}; use std::process::Command; @@ -43,6 +44,7 @@ struct ApplicationContext { config: Config, application: Application, wit: ResolvedWitApplication, + wit_deps: OnceCell>, } impl ApplicationContext { @@ -54,6 +56,7 @@ impl ApplicationContext { config, application, wit, + wit_deps: OnceCell::new(), }) }), ) @@ -67,6 +70,17 @@ impl ApplicationContext { }), ) } + + fn wit_deps(&self) -> anyhow::Result<&WitDepsResolver> { + match self + .wit_deps + .get_or_init(|| WitDepsResolver::new(self.application.wit_deps())) + .as_ref() + { + Ok(wit_deps) => Ok(wit_deps), + Err(err) => Err(anyhow!("Failed to init wit dependency resolver? {}", err)), + } + } } pub fn init(component_name: ComponentName) -> anyhow::Result<()> { @@ -655,16 +669,14 @@ fn create_base_output_wit( ctx.wit.missing_generic_input_package_deps(component_name)?; if !missing_package_deps.is_empty() { - log_action("Adding", "common package deps"); + log_action("Adding", "package deps"); let _indent = LogIndent::new(); - // TODO: transitive deps? - // TODO: use wit dep from app manifest - // TODO: extract dep management, with preferring higher versions + let wit_deps = ctx.wit_deps()?; - let wit_deps = parse_wit_deps_dir(Path::new("wit-deps"))?; + let all_package_deps = wit_deps.package_names_with_deps(&missing_package_deps)?; - for package_name in missing_package_deps { + for package_name in all_package_deps { log_action( "Adding", format!( @@ -672,11 +684,8 @@ fn create_base_output_wit( package_name.to_string().log_color_highlight() ), ); - let dep = wit_deps - .iter() - .find(|package| package.main.name == package_name) - .ok_or_else(|| anyhow!("Package dependency {} not found", package_name))?; - for source in dep.source_map.source_files() { + + for source in wit_deps.package_sources(&package_name)? { let source = PathExtra::new(source); let parent = PathExtra::new( source diff --git a/wasm-rpc-stubgen/src/model/wasm_rpc.rs b/wasm-rpc-stubgen/src/model/wasm_rpc.rs index 05453a6c..2e7a5b52 100644 --- a/wasm-rpc-stubgen/src/model/wasm_rpc.rs +++ b/wasm-rpc-stubgen/src/model/wasm_rpc.rs @@ -584,6 +584,13 @@ impl Application { ) } + pub fn wit_deps(&self) -> Vec { + self.common_wasm_build + .as_ref() + .map(|wasm_build| wasm_build._wit_deps.clone()) + .unwrap_or_default() + } + pub fn all_wasm_rpc_dependencies(&self) -> BTreeSet { self.wasm_components_by_name .iter() diff --git a/wasm-rpc-stubgen/src/wit_resolve.rs b/wasm-rpc-stubgen/src/wit_resolve.rs index 60f59fd0..1f78cd7d 100644 --- a/wasm-rpc-stubgen/src/wit_resolve.rs +++ b/wasm-rpc-stubgen/src/wit_resolve.rs @@ -516,3 +516,77 @@ pub fn parse_wit_deps_dir(path: &Path) -> Result, Er }) .collect::, _>>() } + +pub struct WitDepsResolver { + sources: Vec, + packages: HashMap>, +} + +impl WitDepsResolver { + pub fn new(sources: Vec) -> anyhow::Result { + let mut packages = HashMap::>::new(); + + for source in &sources { + packages.insert( + source.clone(), + parse_wit_deps_dir(source)? + .into_iter() + .map(|package| (package.main.name.clone(), package)) + .collect(), + ); + } + + Ok(Self { sources, packages }) + } + + pub fn package(&self, package_name: &PackageName) -> anyhow::Result<&UnresolvedPackageGroup> { + for source in &self.sources { + if let Some(package) = self.packages.get(source).unwrap().get(package_name) { + return Ok(package); + } + } + bail!( + "Package {} not found, sources searched: {}", + package_name, + self.sources + .iter() + .map(|s| s.display().to_string()) + .join(", ") + ) + } + + pub fn package_sources( + &self, + package_name: &PackageName, + ) -> anyhow::Result> { + self.package(package_name) + .map(|package| package.source_map.source_files()) + } + + pub fn package_names_with_deps( + &self, + package_names: &[PackageName], + ) -> anyhow::Result> { + fn visit( + resolver: &WitDepsResolver, + all_package_names: &mut HashSet, + package_name: &PackageName, + ) -> anyhow::Result<()> { + if !all_package_names.contains(package_name) { + let package = resolver.package(package_name)?; + all_package_names.insert(package_name.clone()); + for package_name in package.main.foreign_deps.keys() { + visit(resolver, all_package_names, package_name)?; + } + } + + Ok(()) + } + + let mut all_package_names = HashSet::::new(); + for package_name in package_names { + visit(self, &mut all_package_names, package_name)?; + } + Ok(all_package_names) + } +}