@@ -9,16 +9,21 @@ use spin_manifest::{
99 schema:: v2:: { AppManifest , ComponentDependency } ,
1010} ;
1111use spin_serde:: { DependencyName , DependencyPackageName , KebabId } ;
12- use std:: { collections:: HashMap , path:: { Path , PathBuf } } ;
12+ use std:: {
13+ collections:: HashMap ,
14+ path:: { Path , PathBuf } ,
15+ } ;
1316use tokio:: fs;
1417use url:: Url ;
1518use wasm_pkg_client:: { PackageRef , Registry } ;
1619use wit_parser:: { PackageId , Resolve } ;
1720
1821use crate :: common:: {
19- constants:: SPIN_WIT_DIRECTORY , interact:: { select_multiple_prompt, select_prompt} , manifest:: { edit_component_deps_in_manifest, get_component_ids} , paths:: fs_safe_segment, wit:: {
20- get_exported_interfaces, parse_component_bytes, resolve_to_wit,
21- }
22+ constants:: SPIN_WIT_DIRECTORY ,
23+ interact:: { select_multiple_prompt, select_prompt} ,
24+ manifest:: { edit_component_deps_in_manifest, get_component_ids} ,
25+ paths:: fs_safe_segment,
26+ wit:: { get_exported_interfaces, parse_component_bytes, resolve_to_wit} ,
2227} ;
2328
2429mod http;
@@ -94,7 +99,8 @@ impl ComponentSource {
9499
95100impl AddCommand {
96101 pub async fn run ( & self ) -> Result < ( ) > {
97- let ( manifest_file, distance) = spin_common:: paths:: find_manifest_file_path ( self . manifest_path . as_ref ( ) ) ?;
102+ let ( manifest_file, distance) =
103+ spin_common:: paths:: find_manifest_file_path ( self . manifest_path . as_ref ( ) ) ?;
98104 if distance > 0 {
99105 anyhow:: bail!(
100106 "No spin.toml in current directory - did you mean '-f {}'?" ,
@@ -131,48 +137,78 @@ impl AddCommand {
131137 // };
132138 // }
133139
134- let target_component_id = KebabId :: try_from ( selected_component. clone ( ) ) . map_err ( |e| anyhow ! ( "{e}" ) ) ?;
135- let target_component = manifest. components . get ( & target_component_id) . ok_or_else ( || anyhow ! ( "component does not exist" ) ) ?;
140+ let target_component_id =
141+ KebabId :: try_from ( selected_component. clone ( ) ) . map_err ( |e| anyhow ! ( "{e}" ) ) ?;
142+ let target_component = manifest
143+ . components
144+ . get ( & target_component_id)
145+ . ok_or_else ( || anyhow ! ( "component does not exist" ) ) ?;
146+
147+ let root_dir = manifest_file
148+ . parent ( )
149+ . ok_or_else ( || anyhow ! ( "Manifest cannot be the root directory" ) ) ?;
136150
137- let root_dir = manifest_file. parent ( ) . ok_or_else ( || anyhow ! ( "Manifest cannot be the root directory" ) ) ?;
138-
139151 // gen bindings
140152 for package in selected_interface_map. keys ( ) {
141153 // if id != main {
142154 // continue; // TODO: yes, this is a silly way to just do main
143155 // }
144- let id = resolve. packages . iter ( ) . find ( |( _, p) | & p. name == package) . unwrap ( ) . 0 ;
156+ let id = resolve
157+ . packages
158+ . iter ( )
159+ . find ( |( _, p) | & p. name == package)
160+ . unwrap ( )
161+ . 0 ;
145162
146163 let fs_name = fs_safe_segment ( package. name . to_string ( ) ) ;
147164
148- let dep_dir = PathBuf :: from ( SPIN_WIT_DIRECTORY ) . join ( "deps" ) . join ( & fs_name) ;
165+ let dep_dir = PathBuf :: from ( SPIN_WIT_DIRECTORY )
166+ . join ( "deps" )
167+ . join ( & fs_name) ;
149168 std:: fs:: create_dir_all ( & dep_dir) ?;
150169
151- let output_wit_file = format ! ( "{ns}-{name}.wit" , ns = package. namespace, name = package. name) ;
170+ let output_wit_file = format ! (
171+ "{ns}-{name}.wit" ,
172+ ns = package. namespace,
173+ name = package. name
174+ ) ;
152175 let output_wit_path = dep_dir. join ( output_wit_file) ;
153-
154- let output_wit_text = resolve_to_wit ( & resolve, id) . context ( "failed to resolve to wit" ) ?;
155176
156- fs:: write ( & output_wit_path, output_wit_text) . await . context ( "failed to write wit" ) ?;
177+ let output_wit_text =
178+ resolve_to_wit ( & resolve, id) . context ( "failed to resolve to wit" ) ?;
179+
180+ fs:: write ( & output_wit_path, output_wit_text)
181+ . await
182+ . context ( "failed to write wit" ) ?;
157183
158184 // I _think_ we have to generate bindings for *all* the interfaces
159185 // because of the possibility of dependencies
160- let interfaces = resolve. packages . iter ( ) . flat_map ( |( _, p) |
161- p. interfaces . keys ( ) . map ( |itf_name| qualified_itf_name ( & p. name , itf_name) )
162- ) . collect :: < Vec < _ > > ( ) ;
186+ let interfaces = resolve
187+ . packages
188+ . iter ( )
189+ . flat_map ( |( _, p) | {
190+ p. interfaces
191+ . keys ( )
192+ . map ( |itf_name| qualified_itf_name ( & p. name , itf_name) )
193+ } )
194+ . collect :: < Vec < _ > > ( ) ;
163195
164196 let target = BindOMatic {
165197 // manifest: &manifest,
166198 root_dir,
167199 target_component,
168- package_name : & package,
200+ package_name : package,
169201 interfaces : & interfaces,
170- rel_wit_path : & output_wit_path
202+ rel_wit_path : & output_wit_path,
171203 } ;
172204 try_generate_bindings ( & target) . await ?;
173205 }
174206
175- let selected_interfaces = selected_interface_map. values ( ) . flatten ( ) . cloned ( ) . collect :: < Vec < _ > > ( ) ;
207+ let selected_interfaces = selected_interface_map
208+ . values ( )
209+ . flatten ( )
210+ . cloned ( )
211+ . collect :: < Vec < _ > > ( ) ;
176212 self . update_manifest (
177213 source,
178214 & manifest_file,
@@ -199,10 +235,10 @@ impl AddCommand {
199235
200236 fn target_component ( & self , manifest : & AppManifest ) -> anyhow:: Result < String > {
201237 if let Some ( id) = & self . add_to_component {
202- return Ok ( id. to_owned ( ) )
238+ return Ok ( id. to_owned ( ) ) ;
203239 }
204240
205- let component_ids = get_component_ids ( & manifest) ;
241+ let component_ids = get_component_ids ( manifest) ;
206242 let selected_component_index = select_prompt (
207243 "Select a component to add the dependency to" ,
208244 & component_ids,
@@ -214,7 +250,11 @@ impl AddCommand {
214250 }
215251
216252 /// Prompts the user to select an interface to import.
217- fn select_interfaces ( & self , resolve : & mut Resolve , main : PackageId ) -> Result < HashMap < wit_parser:: PackageName , Vec < String > > > {
253+ fn select_interfaces (
254+ & self ,
255+ resolve : & mut Resolve ,
256+ main : PackageId ,
257+ ) -> Result < HashMap < wit_parser:: PackageName , Vec < String > > > {
218258 let world_id = resolve. select_world ( main, None ) ?;
219259 let exported_interfaces = get_exported_interfaces ( resolve, world_id) ;
220260
@@ -319,8 +359,12 @@ impl AddCommand {
319359 ) ;
320360 }
321361
322- let doc =
323- edit_component_deps_in_manifest ( manifest_file, selected_component, & component. dependencies ) . await ?;
362+ let doc = edit_component_deps_in_manifest (
363+ manifest_file,
364+ selected_component,
365+ & component. dependencies ,
366+ )
367+ . await ?;
324368
325369 fs:: write ( manifest_file, doc) . await ?;
326370
@@ -364,20 +408,28 @@ struct BindOMatic<'a> {
364408
365409enum Language {
366410 Rust ,
367- #[ allow( dead_code) ] // for now
368- TypeScript { package_json : PathBuf } ,
411+ #[ allow( dead_code) ] // for now
412+ TypeScript {
413+ package_json : PathBuf ,
414+ } ,
369415}
370416
371- impl < ' a > BindOMatic < ' a > {
417+ impl BindOMatic < ' _ > {
372418 fn try_infer_language ( & self ) -> anyhow:: Result < Language > {
373- let workdir = self . target_component . build . as_ref ( ) . and_then ( |b| b. workdir . as_ref ( ) ) ;
419+ let workdir = self
420+ . target_component
421+ . build
422+ . as_ref ( )
423+ . and_then ( |b| b. workdir . as_ref ( ) ) ;
374424 let build_dir = match workdir {
375425 None => self . root_dir . to_owned ( ) ,
376426 Some ( d) => self . root_dir . join ( d) ,
377427 } ;
378428
379429 if !build_dir. is_dir ( ) {
380- bail ! ( "unable to establish build directory for component (thought it was {build_dir:?})" ) ;
430+ bail ! (
431+ "unable to establish build directory for component (thought it was {build_dir:?})"
432+ ) ;
381433 }
382434
383435 let cargo_toml = build_dir. join ( "Cargo.toml" ) ;
@@ -396,39 +448,63 @@ impl<'a> BindOMatic<'a> {
396448
397449async fn try_generate_bindings < ' a > ( target : & ' a BindOMatic < ' a > ) -> anyhow:: Result < ( ) > {
398450 match target. try_infer_language ( ) ? {
399- Language :: Rust => generate_rust_bindings ( target. root_dir , target. package_name , target. interfaces , target. rel_wit_path ) . await ,
451+ Language :: Rust => {
452+ generate_rust_bindings (
453+ target. root_dir ,
454+ target. package_name ,
455+ target. interfaces ,
456+ target. rel_wit_path ,
457+ )
458+ . await
459+ }
400460 Language :: TypeScript { package_json : _ } => todo ! ( ) ,
401461 }
402462}
403463
404- async fn generate_rust_bindings ( root_dir : & Path , package_name : & wit_parser:: PackageName , interfaces : & [ String ] , rel_wit_path : & Path ) -> anyhow:: Result < ( ) > {
464+ async fn generate_rust_bindings (
465+ root_dir : & Path ,
466+ package_name : & wit_parser:: PackageName ,
467+ interfaces : & [ String ] ,
468+ rel_wit_path : & Path ,
469+ ) -> anyhow:: Result < ( ) > {
405470 // now set up the bindings
406471 let deps_rs_dir = root_dir. join ( "src/deps" ) ;
407472 fs:: create_dir_all ( & deps_rs_dir) . await ?;
408473 let dep_module_name = crate :: language:: rust:: identifier_safe ( package_name) ;
409474
410475 // step 1: create a module with the generate! macro
411- let imps = interfaces. iter ( )
476+ let imps = interfaces
477+ . iter ( )
412478 . filter ( |itf| !crate :: language:: rust:: is_stdlib_known ( itf) )
413- . map ( |i| format ! ( r#" import {i};"# ) ) . collect :: < Vec < _ > > ( ) ;
479+ . map ( |i| format ! ( r#" import {i};"# ) )
480+ . collect :: < Vec < _ > > ( ) ;
414481 let imps = imps. join ( "\n " ) ;
415- let gens = interfaces. iter ( )
482+ let gens = interfaces
483+ . iter ( )
416484 . filter ( |itf| !crate :: language:: rust:: is_stdlib_known ( itf) )
417- . map ( |i| if crate :: language:: rust:: is_sdk_known ( i) {
485+ . map ( |i| {
486+ if crate :: language:: rust:: is_sdk_known ( i) {
418487 let ( qname, _) = i. split_once ( "@" ) . unwrap ( ) ; // foo:bar/baz
419- let rust_qname = qname. replace ( ":" , "::" ) . replace ( "/" , "::" ) . replace ( "-" , "_" ) ;
420- let sdk_form = format ! ( "spin_sdk::wit::{rust_qname}" ) ; // TODO: this doesn't allow for when multiple versions are present! when that happens, but ONLY when that happens, bindgen version-mangles the name
488+ let rust_qname = qname
489+ . replace ( ":" , "::" )
490+ . replace ( "/" , "::" )
491+ . replace ( "-" , "_" ) ;
492+ let sdk_form = format ! ( "spin_sdk::wit::{rust_qname}" ) ; // TODO: this doesn't allow for when multiple versions are present! when that happens, but ONLY when that happens, bindgen version-mangles the name
421493 format ! ( r#" "{i}": {sdk_form},"# )
422494 } else {
423495 format ! ( r#" "{i}": generate,"# )
424496 }
425- ) . collect :: < Vec < _ > > ( ) ;
497+ } )
498+ . collect :: < Vec < _ > > ( ) ;
426499 let gens = gens. join ( "\n " ) ;
427500 let gen_name = format ! ( "{}-{}" , package_name. namespace, package_name. name) ;
428501
429502 let binding_file = deps_rs_dir. join ( format ! ( "{dep_module_name}.rs" ) ) ;
430503 let gen_macro = include_str ! ( "gen.txt" )
431- . replace ( "{!dep_path!}" , format ! ( "{}" , rel_wit_path. display( ) ) . as_str ( ) )
504+ . replace (
505+ "{!dep_path!}" ,
506+ format ! ( "{}" , rel_wit_path. display( ) ) . as_str ( ) ,
507+ )
432508 . replace ( "{!imps!}" , & imps)
433509 . replace ( "{!gens!}" , & gens)
434510 . replace ( "{!gen_name!}" , & gen_name) ;
@@ -447,11 +523,7 @@ async fn generate_rust_bindings(root_dir: &Path, package_name: &wit_parser::Pack
447523 if existing. contains ( & dep_module_decl) {
448524 // nothing to do. No I am not going to worry about if it is commented out, who do you think I am rust-analyzer
449525 } else {
450- let separator = if existing. ends_with ( '\n' ) {
451- ""
452- } else {
453- ""
454- } ;
526+ let separator = "" ;
455527 let new_mod_rs = format ! ( "{existing}{separator}pub {dep_module_decl}\n " ) ;
456528 fs:: write ( mod_rs_file, new_mod_rs) . await ?;
457529 }
0 commit comments