From 73acc145e5480beb2d2b0df72a12fb9ef7b21b80 Mon Sep 17 00:00:00 2001 From: Bailey Hayes Date: Fri, 31 Jul 2026 10:15:22 -0400 Subject: [PATCH] refactor: extract filesystem-free core into crates/core Pulls the parts of componentize-go that are pure byte transformations: WIT resolution, Go bindings generation, WIT metadata embedding, and component encoding into a new `componentize-go-core` crate. `src/utils.rs` and `src/cmd_bindings.rs` become thin filesystem wrappers over it. WIT inputs reach the core as `(path, contents)` pairs, so `utils::parse_wit` now reads the filesystem into `WitSource`s and delegates. Resolution uses `Resolve::push_groups` rather than `push_path`: a `SourceMap` holds exactly one package, so dependency packages are parsed separately and topologically sorted against the root. Two things move as a consequence: - The preview1 adapter is sourced from wasmtime's `wasi-preview1-component-adapter-provider` crate instead of the 52 KB binary checked in at `src/wasi_snapshot_preview1.reactor.wasm`, so updating it is a version bump. The committed copy was provider 46 while `tests/` had already moved to wasmtime 47, so this also corrects that drift. - `gofmt` moves out of bindings generation and into the native driver, applied to the emitted files. Generation no longer shells out, which is what will let the core compile without a process API. `examples/wasip2` output has an identical import/export surface and identical size before and after; the remaining byte differences are internal to the newer adapter. Also refreshes three checked-in fixture bindings whose `wit-bindgen` version stamp was left stale by the bump in #69. --- Cargo.lock | 50 ++- Cargo.toml | 11 +- crates/core/Cargo.toml | 23 ++ crates/core/src/lib.rs | 348 ++++++++++++++++++ src/cmd_bindings.rs | 84 +++-- src/utils.rs | 174 ++++----- src/wasi_snapshot_preview1.reactor.wasm | Bin 52675 -> 0 bytes .../foo_baz_store/wit_bindings.go | 2 +- .../named-implements/primary/wit_bindings.go | 2 +- .../secondary/wit_bindings.go | 2 +- 10 files changed, 550 insertions(+), 146 deletions(-) create mode 100644 crates/core/Cargo.toml create mode 100644 crates/core/src/lib.rs delete mode 100644 src/wasi_snapshot_preview1.reactor.wasm diff --git a/Cargo.lock b/Cargo.lock index 1804202..6e7e749 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -342,6 +342,7 @@ dependencies = [ "anyhow", "bzip2", "clap", + "componentize-go-core", "dirs", "regex", "reqwest", @@ -349,6 +350,16 @@ dependencies = [ "tar", "toml 1.1.2+spec-1.1.0", "which", + "wit-parser 0.254.0", +] + +[[package]] +name = "componentize-go-core" +version = "0.4.1" +dependencies = [ + "anyhow", + "wasi-preview1-component-adapter-provider", + "wat", "wit-bindgen-go", "wit-component", "wit-parser 0.254.0", @@ -2580,6 +2591,12 @@ version = "0.11.1+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" +[[package]] +name = "wasi-preview1-component-adapter-provider" +version = "47.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffea5cc4926d42465ede05953cff22ad074e281709fc274033e7a09ff323c0f8" + [[package]] name = "wasip2" version = "1.0.2+wasi-0.2.9" @@ -2681,6 +2698,16 @@ dependencies = [ "wasmparser 0.254.0", ] +[[package]] +name = "wasm-encoder" +version = "0.255.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b524283fb5df62eec102ed0574838961bdd7ba5ac9c50d38e2756c51c971a42" +dependencies = [ + "leb128fmt", + "wasmparser 0.255.0", +] + [[package]] name = "wasm-metadata" version = "0.254.0" @@ -2718,6 +2745,17 @@ dependencies = [ "semver", ] +[[package]] +name = "wasmparser" +version = "0.255.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8e329ef4b5d46e73b91d3ac6924417cad55a8cbbf869c199283383427c3320b" +dependencies = [ + "bitflags", + "indexmap", + "semver", +] + [[package]] name = "wasmprinter" version = "0.252.0" @@ -3019,24 +3057,24 @@ dependencies = [ [[package]] name = "wast" -version = "252.0.0" +version = "255.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "942a3449d6a593fccc111a6241c8df52bda168af30e40bf9580d4394d7374c65" +checksum = "55ffec530f199bd3d553ac442c13dd108353cad533cad8514bc41e1f1f0fe686" dependencies = [ "bumpalo", "leb128fmt", "memchr", "unicode-width", - "wasm-encoder 0.252.0", + "wasm-encoder 0.255.0", ] [[package]] name = "wat" -version = "1.252.0" +version = "1.255.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c72a4ba7088f7bac94cf516e49882bdf97068904a563768cf249efc839ec42cb" +checksum = "dda82c82e1486c7eed42a0465e544d80fff37abc3b39482e0d34dbaabe2fe5b1" dependencies = [ - "wast 252.0.0", + "wast 255.0.0", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 8b794c0..4672b51 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,14 +9,18 @@ name = "componentize_go" crate-type = ["cdylib", "rlib"] [workspace] -members = ["./tests"] +members = ["./tests", "crates/core"] [workspace.dependencies] anyhow = "1.0.103" bzip2 = "0.6.1" +componentize-go-core = { path = "crates/core" } once_cell = "1.21.3" reqwest = { version = "0.13.4", features = ["blocking"] } tar = "0.4.46" +wit-bindgen-go = { git = "https://github.com/bytecodealliance/wit-bindgen", rev = "d3ebba0957500bf3edb200a89e70555545d92f6c" } +wit-component = "0.254.0" +wit-parser = "0.254.0" [workspace.package] version = "0.4.1" @@ -40,14 +44,13 @@ allow_attributes_without_reason = 'warn' [dependencies] anyhow = { workspace = true } bzip2 = { workspace = true } +componentize-go-core = { workspace = true } reqwest = { workspace = true } tar = { workspace = true } clap = { version = "4.6.1", features = ["derive"] } regex = "1.12.4" serde = { version = "1.0.228", features = ["derive"] } toml = "1.1.0" -wit-bindgen-go = { git = "https://github.com/bytecodealliance/wit-bindgen", rev = "d3ebba0957500bf3edb200a89e70555545d92f6c" } -wit-component = "0.254.0" -wit-parser = "0.254.0" +wit-parser = { workspace = true } which = "8.0.4" dirs = "6.0.0" diff --git a/crates/core/Cargo.toml b/crates/core/Cargo.toml new file mode 100644 index 0000000..590594a --- /dev/null +++ b/crates/core/Cargo.toml @@ -0,0 +1,23 @@ +[package] +name = "componentize-go-core" +description = """ +The filesystem- and subprocess-free core of componentize-go: WIT resolution, Go +bindings generation, WIT metadata embedding, and component encoding. Everything +here is a pure byte transform, so it compiles to wasm as well as to native. +""" +version = { workspace = true } +edition = { workspace = true } + +[lints] +workspace = true + +[dependencies] +anyhow = { workspace = true } +# Versioned in lockstep with wasmtime; keep aligned with the wasmtime used in +# `tests/`. The adapter this replaces was checked in at 46 while wasmtime had +# already moved to 47, so sourcing it here also corrects that drift. +wasi-preview1-component-adapter-provider = "47" +wat = "1.253.0" +wit-bindgen-go = { workspace = true } +wit-component = { workspace = true } +wit-parser = { workspace = true } diff --git a/crates/core/src/lib.rs b/crates/core/src/lib.rs new file mode 100644 index 0000000..9379060 --- /dev/null +++ b/crates/core/src/lib.rs @@ -0,0 +1,348 @@ +//! The filesystem- and subprocess-free core of componentize-go. +//! +//! Every operation here is a pure byte transform: WIT sources in, generated Go +//! or encoded wasm out. Nothing in this crate touches the filesystem, spawns a +//! process, or talks to the network, which is what lets it compile to +//! `wasm32-unknown-unknown` and run as a component with zero WASI imports. +//! +//! The native driver wraps these functions with filesystem I/O; the component +//! wrapper in `crates/component` exposes them over WIT. Both go through this +//! one implementation so the two paths cannot drift. + +use anyhow::{Context, Result, anyhow, bail}; +use wit_parser::{ + CloneMaps, Package, PackageId, PackageName, Resolve, Stability, UnresolvedPackageGroup, World, + WorldId, +}; + +pub use wit_bindgen_go::remote_pkg_version; +pub use wit_parser; + +/// The `wasi_snapshot_preview1` reactor adapter. +/// +/// Sourced from wasmtime's `wasi-preview1-component-adapter-provider` crate +/// rather than checked in, so updating it is a version bump. That crate is +/// versioned in lockstep with wasmtime, so keep it aligned with the wasmtime +/// used in `tests/`. +pub use wasi_preview1_component_adapter_provider::WASI_SNAPSHOT_PREVIEW1_REACTOR_ADAPTER as WASIP1_SNAPSHOT_ADAPT; + +/// A single file, identified by a path relative to the root of its +/// [`WitSource`] (for inputs) or to the output directory (for generated code). +#[derive(Clone, Debug)] +pub struct File { + pub path: String, + pub contents: Vec, +} + +/// One WIT input, corresponding to a single `-d`/`--wit-path` argument. +/// +/// Paths are relative to the root of that argument, and their structure carries +/// the same meaning the filesystem layout does for `wit-parser`'s `push_path`: +/// +/// * `*.wit` at the root — parsed together as this source's package. +/// * `deps//*.wit` — a dependency package. +/// * `deps/.wit` — a single-file dependency package. +/// * `deps/.{wasm,wat}` — a wasm-encoded dependency package. +/// +/// A source whose root holds a single `.wasm`/`.wat` and no `.wit` is itself a +/// wasm-encoded package. +#[derive(Clone, Debug, Default)] +pub struct WitSource { + /// Where this source came from — the `--wit-path` argument, natively. Used + /// only so that errors name the offending input, which matters when several + /// sources are in play and `componentize-go.toml` discovery can add more. + pub name: String, + pub files: Vec, +} + +impl WitSource { + pub fn new(name: impl Into, files: Vec) -> Self { + Self { + name: name.into(), + files, + } + } +} + +/// Options for Go bindings generation. +/// +/// Deliberately has no `format` field: `gofmt` is a subprocess and so is +/// unavailable in wasm. Formatting is the caller's job, applied to the returned +/// files, which keeps the two drivers producing identical bytes here. +#[derive(Clone, Debug, Default)] +pub struct BindingsOptions { + pub generate_stubs: bool, + pub pkg_name: Option, + pub export_pkg_name: Option, + pub include_versions: bool, +} + +fn is_wasm_encoded(path: &str) -> bool { + path.ends_with(".wasm") || path.ends_with(".wat") +} + +fn decode_package(resolve: &mut Resolve, name: &str, bytes: &[u8]) -> Result { + // `.wat` needs converting to binary first; `wit-component` only decodes wasm. + let owned; + let bytes = if name.ends_with(".wat") { + owned = wat::parse_bytes(bytes) + .with_context(|| format!("failed to parse `{name}` as WAT"))? + .into_owned(); + &owned + } else { + bytes + }; + + let decoded = wit_component::decode(bytes) + .with_context(|| format!("failed to decode `{name}` as a WIT package"))?; + let pkg = decoded.package(); + let remap = resolve.merge(decoded.resolve().clone())?; + Ok(remap.packages[pkg.index()]) +} + +/// Split a source's files into its main package and its `deps/` entries, then +/// push all of them into `resolve`, returning the id of the main package. +fn push_source(resolve: &mut Resolve, source: &WitSource) -> Result { + let mut root_wit: Vec<&File> = Vec::new(); + let mut root_encoded: Vec<&File> = Vec::new(); + // dep name -> files, preserving the `deps//...` grouping. + let mut dep_dirs: std::collections::BTreeMap> = Default::default(); + let mut dep_files: Vec<&File> = Vec::new(); + + for file in &source.files { + let path = file.path.replace('\\', "/"); + let rest = path.strip_prefix("deps/"); + match rest { + None => { + if path.contains('/') { + // Not at the root and not under `deps/`; wit-parser ignores + // these, so do the same rather than guessing. + continue; + } + if is_wasm_encoded(&path) { + root_encoded.push(file); + } else if path.ends_with(".wit") { + root_wit.push(file); + } + } + Some(rest) => match rest.split_once('/') { + // `deps//...` — a directory package. + Some((name, _)) => dep_dirs.entry(name.to_string()).or_default().push(file), + // `deps/.{wit,wasm,wat}` — a single-file package. + None => dep_files.push(file), + }, + } + } + + // Wasm-encoded packages must land first: text packages may reference them, + // and `push_groups` only resolves against what is already in `resolve`. + for file in dep_files.iter().filter(|f| is_wasm_encoded(&f.path)) { + decode_package(resolve, &file.path, &file.contents)?; + } + for files in dep_dirs.values() { + for file in files.iter().filter(|f| is_wasm_encoded(&f.path)) { + decode_package(resolve, &file.path, &file.contents)?; + } + } + + if root_wit.is_empty() { + // A source that is itself a wasm-encoded package. + return match root_encoded.as_slice() { + [file] => decode_package(resolve, &file.path, &file.contents), + [] => bail!("no WIT files found in source"), + _ => bail!("source root contains multiple wasm-encoded packages"), + }; + } + + let main = parse_group(&root_wit)?; + let mut deps = Vec::new(); + for files in dep_dirs.values() { + let text: Vec<&File> = files + .iter() + .copied() + .filter(|f| f.path.ends_with(".wit")) + .collect(); + if !text.is_empty() { + deps.push(parse_group(&text)?); + } + } + for file in dep_files.iter().filter(|f| f.path.ends_with(".wit")) { + deps.push(parse_group(&[file])?); + } + + // `push_groups` topologically sorts main against its dependencies, which is + // why the deps cannot simply be pushed one at a time. + Ok(resolve.push_groups(main, deps)?) +} + +fn parse_group(files: &[&File]) -> Result { + let mut map = wit_parser::SourceMap::default(); + for file in files { + let text = std::str::from_utf8(&file.contents) + .with_context(|| format!("`{}` is not valid UTF-8", file.path))?; + map.push(std::path::Path::new(&file.path), text); + } + map.parse().map_err(|(_, e)| e.into()) +} + +/// Resolve WIT sources into a [`Resolve`] and the world to target. +/// +/// Mirrors the CLI's semantics: each source is resolved independently and then +/// merged, so the same package appearing in several sources is consolidated +/// rather than duplicated. Naming more than one world merges them into a +/// synthetic `componentize-go:union/union` world. +pub fn resolve_wit( + sources: &[WitSource], + worlds: &[String], + features: &[String], + all_features: bool, +) -> Result<(Resolve, WorldId)> { + if sources.is_empty() { + bail!("no WIT sources provided"); + } + + let mut resolve = Resolve { + all_features, + ..Default::default() + }; + for features in features { + for feature in features + .split(',') + .flat_map(|s| s.split_whitespace()) + .filter(|f| !f.is_empty()) + { + resolve.features.insert(feature.to_string()); + } + } + + let packages = sources + .iter() + .map(|source| { + // Resolve into a scratch `Resolve` and merge, which consolidates a + // package referenced by more than one source. + let mut tmp = Resolve { + all_features, + features: resolve.features.clone(), + ..Default::default() + }; + let pkg = push_source(&mut tmp, source) + .with_context(|| format!("failed to parse WIT for path [{}]", source.name))?; + let consolidated = resolve.merge(tmp)?; + Ok(consolidated.packages[pkg.index()]) + }) + .collect::>>()?; + + let worlds = worlds + .iter() + .map(|world| { + packages + .iter() + .find_map(|&pkg| resolve.select_world(&[pkg], Some(world)).ok()) + .ok_or_else(|| { + anyhow!("no world named `{world}` found in any of the loaded WIT packages") + }) + }) + .collect::>>()?; + + let world = match &worlds[..] { + [] => packages + .iter() + .find_map(|&pkg| resolve.select_world(&[pkg], None).ok()) + .ok_or_else(|| anyhow!("no default world found in any of the loaded WIT packages"))?, + &[world] => world, + worlds => { + let union_package = resolve.packages.alloc(Package { + name: PackageName { + namespace: "componentize-go".into(), + name: "union".into(), + version: None, + }, + docs: Default::default(), + interfaces: Default::default(), + worlds: Default::default(), + }); + + let union_world = resolve.worlds.alloc(World { + name: "union".into(), + imports: Default::default(), + exports: Default::default(), + package: Some(union_package), + docs: Default::default(), + stability: Stability::Unknown, + includes: Default::default(), + span: Default::default(), + }); + + resolve.packages[union_package] + .worlds + .insert("union".into(), union_world); + + for &world in worlds { + resolve.merge_worlds(world, union_world, &mut CloneMaps::default())?; + } + + union_world + } + }; + + Ok((resolve, world)) +} + +/// Generate Go bindings for `world`, returning the files to write. +pub fn generate_bindings( + resolve: &mut Resolve, + world: WorldId, + opts: &BindingsOptions, +) -> Result> { + let mut files = Default::default(); + + wit_bindgen_go::Opts { + generate_stubs: opts.generate_stubs, + // Always off: `gofmt` is a subprocess. Callers format the result. + format: wit_bindgen_go::Format::False, + pkg_name: opts.pkg_name.clone(), + export_pkg_name: opts.export_pkg_name.clone(), + include_versions: opts.include_versions, + ..Default::default() + } + .build() + .generate(resolve, world, &mut files)?; + + Ok(files + .iter() + .map(|(path, contents)| File { + path: path.to_string(), + contents: contents.to_vec(), + }) + .collect()) +} + +/// Embed the component-type custom section describing `world` into `module`. +pub fn embed_wit(module: &[u8], resolve: &Resolve, world: WorldId) -> Result> { + let mut wasm = module.to_vec(); + wit_component::embed_component_metadata( + &mut wasm, + resolve, + world, + wit_component::StringEncoding::UTF8, + )?; + Ok(wasm) +} + +/// Encode a core module into a component. +/// +/// `adapter` overrides the bundled `wasi_snapshot_preview1` reactor adapter, +/// which is used when `None`. +pub fn module_to_component(module: &[u8], adapter: Option<&[u8]>) -> Result> { + let mut encoder = wit_component::ComponentEncoder::default() + .validate(true) + .module(module)? + .adapter( + wasi_preview1_component_adapter_provider::WASI_SNAPSHOT_PREVIEW1_ADAPTER_NAME, + adapter.unwrap_or(WASIP1_SNAPSHOT_ADAPT), + )?; + + encoder + .encode() + .context("failed to encode component from module") +} diff --git a/src/cmd_bindings.rs b/src/cmd_bindings.rs index 5a5560b..8f4fa0f 100644 --- a/src/cmd_bindings.rs +++ b/src/cmd_bindings.rs @@ -1,8 +1,38 @@ use crate::utils::make_path_absolute; -use anyhow::Result; -use std::path::{Path, PathBuf}; +use anyhow::{Context, Result}; +use componentize_go_core::BindingsOptions; +use std::{ + path::{Path, PathBuf}, + process::{Command, Stdio}, +}; use wit_parser::{Resolve, WorldId}; +/// Format Go source with `gofmt`, if it is on `PATH`. +/// +/// Generation itself happens in `componentize-go-core`, which cannot spawn a +/// process, so formatting is applied here to the emitted bytes instead. That +/// keeps the native and component code paths producing identical output. +fn gofmt(path: &Path) -> Result<()> { + let file = std::fs::File::open(path)?; + let output = match Command::new("gofmt") + .stdin(Stdio::from(file)) + .stderr(Stdio::inherit()) + .output() + { + Ok(output) => output, + // Not installed: generated code is still valid, just unformatted. + Err(e) if e.kind() == std::io::ErrorKind::NotFound => return Ok(()), + Err(e) => return Err(e).context("failed to run `gofmt`"), + }; + + if output.status.success() { + std::fs::write(path, output.stdout) + .with_context(|| format!("failed to write '{}'", path.display()))?; + } + + Ok(()) +} + #[allow(clippy::too_many_arguments)] pub fn generate_bindings( resolve: &mut Resolve, @@ -14,47 +44,43 @@ pub fn generate_bindings( export_pkg_name: Option, include_versions: bool, ) -> Result<()> { - let mut files = Default::default(); - - let format = if should_format { - wit_bindgen_go::Format::True - } else { - wit_bindgen_go::Format::False - }; - // If the user wants to create a package rather than a standalone binary, provide them with the // go.bytecodealliance.org/pkg version that needs to be placed in their go.mod file - let mut message: Option = None; - if pkg_name.is_some() { - message = Some(format!( + let message = pkg_name.as_ref().map(|_| { + format!( "Success! Please add the following line to your 'go.mod' file:\n\nrequire {}", - wit_bindgen_go::remote_pkg_version() - )); - } + componentize_go_core::remote_pkg_version() + ) + }); - wit_bindgen_go::Opts { - generate_stubs, - format, - pkg_name, - export_pkg_name, - include_versions, - ..Default::default() - } - .build() - .generate(resolve, world, &mut files)?; + let files = componentize_go_core::generate_bindings( + resolve, + world, + &BindingsOptions { + generate_stubs, + pkg_name, + export_pkg_name, + include_versions, + }, + )?; let output_path = match output { Some(p) => make_path_absolute(p)?, None => PathBuf::from("."), }; - for (name, contents) in files.iter() { - let file_path = output_path.join(name); + for file in &files { + let file_path = output_path.join(&file.path); if let Some(parent) = file_path.parent() { std::fs::create_dir_all(parent)?; } - std::fs::write(&file_path, contents)?; + std::fs::write(&file_path, &file.contents) + .with_context(|| format!("failed to write '{}'", file_path.display()))?; + + if should_format && file.path.ends_with(".go") { + gofmt(&file_path)?; + } } if let Some(msg) = message { diff --git a/src/utils.rs b/src/utils.rs index ec1d5d4..022785b 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -1,5 +1,6 @@ use anyhow::{Context, Result, anyhow, bail}; use bzip2::read::BzDecoder; +use componentize_go_core::{File as CoreFile, WitSource}; use serde::Deserialize; use std::{ collections::BTreeSet, @@ -11,8 +12,7 @@ use std::{ }; use tar::Archive; use wit_parser::{ - CloneMaps, Function, Interface, Package, PackageName, Resolve, Stability, Type, TypeDef, - TypeDefKind, World, WorldId, WorldItem, + Function, Interface, Resolve, Type, TypeDef, TypeDefKind, World, WorldId, WorldItem, }; pub fn dummy_wit() -> (Resolve, WorldId) { @@ -30,9 +30,62 @@ pub fn dummy_wit() -> (Resolve, WorldId) { (resolve, world) } -// In the rare case the snapshot needs to be updated, the latest version -// can be found here: https://github.com/bytecodealliance/wasmtime/releases -const WASIP1_SNAPSHOT_ADAPT: &[u8] = include_bytes!("wasi_snapshot_preview1.reactor.wasm"); +/// Read one `--wit-path` argument off the filesystem into a [`WitSource`]. +/// +/// Mirrors the layout `wit-parser`'s `push_path` expects: `*.wit` at the root of +/// a directory form its package, and a `deps` subdirectory holds dependency +/// packages as directories, single `.wit` files, or `.wasm`/`.wat` encoded +/// packages. A path to a single file becomes a one-file source. +fn read_wit_source(path: &Path) -> Result { + let mut files = Vec::new(); + + if path.is_file() { + files.push(CoreFile { + path: path + .file_name() + .map(|n| n.to_string_lossy().into_owned()) + .unwrap_or_else(|| path.display().to_string()), + contents: fs::read(path) + .with_context(|| format!("failed to read '{}'", path.display()))?, + }); + return Ok(WitSource::new(path.display().to_string(), files)); + } + + let read_into = |dir: &Path, prefix: &str, files: &mut Vec| -> Result<()> { + for entry in fs::read_dir(dir) + .with_context(|| format!("failed to read directory '{}'", dir.display()))? + { + let entry = entry?; + if !entry.file_type()?.is_file() { + continue; + } + let name = entry.file_name().to_string_lossy().into_owned(); + files.push(CoreFile { + path: format!("{prefix}{name}"), + contents: fs::read(entry.path()) + .with_context(|| format!("failed to read '{}'", entry.path().display()))?, + }); + } + Ok(()) + }; + + read_into(path, "", &mut files)?; + + let deps = path.join("deps"); + if deps.is_dir() { + read_into(&deps, "deps/", &mut files)?; + for entry in fs::read_dir(&deps)? { + let entry = entry?; + if !entry.file_type()?.is_dir() { + continue; + } + let name = entry.file_name().to_string_lossy().into_owned(); + read_into(&entry.path(), &format!("deps/{name}/"), &mut files)?; + } + } + + Ok(WitSource::new(path.display().to_string(), files)) +} pub fn parse_wit( paths: &[impl AsRef], @@ -51,89 +104,12 @@ pub fn parse_wit( } debug_assert!(!paths.is_empty(), "The paths should not be empty"); - let mut resolve = Resolve { - all_features, - ..Default::default() - }; - for features in features { - for feature in features - .split(',') - .flat_map(|s| s.split_whitespace()) - .filter(|f| !f.is_empty()) - { - resolve.features.insert(feature.to_string()); - } - } - - let packages = paths + let sources = paths .iter() - .map(|path| { - // Consolidates if the same package is referenced in multiple worlds - let mut tmp = Resolve { - all_features, - features: resolve.features.clone(), - ..Default::default() - }; - let (pkg, _files) = tmp.push_path(path)?; - let consolidated = resolve.merge(tmp)?; - Ok(consolidated.packages[pkg.index()]) - }) - .collect::>>()?; - - let worlds = worlds - .iter() - .map(|world| { - packages - .iter() - .find_map(|&pkg| resolve.select_world(&[pkg], Some(world)).ok()) - .ok_or_else(|| { - anyhow!("no world named `{world}` found in any of the loaded WIT packages") - }) - }) + .map(|path| read_wit_source(path.as_ref())) .collect::>>()?; - let world = match &worlds[..] { - [] => packages - .iter() - .find_map(|&pkg| resolve.select_world(&[pkg], None).ok()) - .ok_or_else(|| anyhow!("no default world found in any of the loaded WIT packages"))?, - &[world] => world, - worlds => { - let union_package = resolve.packages.alloc(Package { - name: PackageName { - namespace: "componentize-go".into(), - name: "union".into(), - version: None, - }, - docs: Default::default(), - interfaces: Default::default(), - worlds: Default::default(), - }); - - let union_world = resolve.worlds.alloc(World { - name: "union".into(), - imports: Default::default(), - exports: Default::default(), - package: Some(union_package), - docs: Default::default(), - stability: Stability::Unknown, - includes: Default::default(), - span: Default::default(), - }); - - resolve.packages[union_package] - .worlds - .insert("union".into(), union_world); - - for &world in worlds { - resolve.merge_worlds(world, union_world, &mut CloneMaps::default())?; - } - - union_world - } - }; - - Ok((resolve, world)) + componentize_go_core::resolve_wit(&sources, worlds, features, all_features) } /// Unless `ignore_toml_files` is `true`, use `go list` to search the current @@ -198,13 +174,8 @@ pub fn make_path_absolute(p: &Path) -> Result { } pub fn embed_wit(wasm_file: &Path, resolve: &Resolve, world: WorldId) -> Result<()> { - let mut wasm = fs::read(wasm_file)?; - wit_component::embed_component_metadata( - &mut wasm, - resolve, - world, - wit_component::StringEncoding::UTF8, - )?; + let wasm = fs::read(wasm_file)?; + let wasm = componentize_go_core::embed_wit(&wasm, resolve, world)?; fs::write(wasm_file, wasm).context(format!("failed to write '{}'", wasm_file.display()))?; Ok(()) } @@ -213,19 +184,14 @@ pub fn embed_wit(wasm_file: &Path, resolve: &Resolve, world: WorldId) -> Result< pub fn module_to_component(wasm_file: &Path, adapt_file: Option<&Path>) -> Result<()> { let wasm: Vec = fs::read(wasm_file)?; - let mut encoder = wit_component::ComponentEncoder::default().validate(true); - encoder = encoder.module(&wasm)?; - let adapt_bytes = if let Some(adapt) = adapt_file { - fs::read(adapt) - .with_context(|| format!("failed to read adapt file '{}'", adapt.display()))? - } else { - WASIP1_SNAPSHOT_ADAPT.to_vec() - }; - encoder = encoder.adapter("wasi_snapshot_preview1", &adapt_bytes)?; + let adapt_bytes = adapt_file + .map(|adapt| { + fs::read(adapt) + .with_context(|| format!("failed to read adapt file '{}'", adapt.display())) + }) + .transpose()?; - let bytes = encoder - .encode() - .context("failed to encode component from module")?; + let bytes = componentize_go_core::module_to_component(&wasm, adapt_bytes.as_deref())?; fs::write(wasm_file, bytes).context(format!("failed to write `{}`", wasm_file.display()))?; diff --git a/src/wasi_snapshot_preview1.reactor.wasm b/src/wasi_snapshot_preview1.reactor.wasm deleted file mode 100644 index 0207d751145dc169ff47ff89cde8d0ac25bb0f1e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 52675 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 diff --git a/tests/fixtures/named-implements/foo_baz_store/wit_bindings.go b/tests/fixtures/named-implements/foo_baz_store/wit_bindings.go index ac31a35..7d01c89 100644 --- a/tests/fixtures/named-implements/foo_baz_store/wit_bindings.go +++ b/tests/fixtures/named-implements/foo_baz_store/wit_bindings.go @@ -1,4 +1,4 @@ -// Generated by `wit-bindgen` 0.59.0. DO NOT EDIT! +// Generated by `wit-bindgen` 0.60.0. DO NOT EDIT! // // This code was generated from the following packages: // foo:baz@0.1.0 diff --git a/tests/fixtures/named-implements/primary/wit_bindings.go b/tests/fixtures/named-implements/primary/wit_bindings.go index e162485..8c3116c 100644 --- a/tests/fixtures/named-implements/primary/wit_bindings.go +++ b/tests/fixtures/named-implements/primary/wit_bindings.go @@ -1,4 +1,4 @@ -// Generated by `wit-bindgen` 0.59.0. DO NOT EDIT! +// Generated by `wit-bindgen` 0.60.0. DO NOT EDIT! // // This code was generated from the following packages: // foo:baz@0.1.0 diff --git a/tests/fixtures/named-implements/secondary/wit_bindings.go b/tests/fixtures/named-implements/secondary/wit_bindings.go index 83af910..f07b6de 100644 --- a/tests/fixtures/named-implements/secondary/wit_bindings.go +++ b/tests/fixtures/named-implements/secondary/wit_bindings.go @@ -1,4 +1,4 @@ -// Generated by `wit-bindgen` 0.59.0. DO NOT EDIT! +// Generated by `wit-bindgen` 0.60.0. DO NOT EDIT! // // This code was generated from the following packages: // foo:baz@0.1.0