diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index f1ea4da175..276391fb7a 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -324,6 +324,9 @@ jobs: - run: cargo check --no-default-features -p wasm-wave --features std - run: cargo check --no-default-features -p wasm-wave --features wit - run: cargo check --no-default-features -p wasm-wave --features std,wit + - run: cargo check --no-default-features -p wasm-compose + - run: cargo check --no-default-features -p wasm-compose --features serde + - run: cargo check --no-default-features -p wasm-compose --features yaml - run: | if cargo tree -p wasm-smith --no-default-features -e no-dev | grep wasmparser; then echo wasm-smith without default features should not depend on wasmparser diff --git a/Cargo.toml b/Cargo.toml index 818faa29ab..a1f6bd6d4c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -143,7 +143,7 @@ thiserror = { version = "2.0.12", default-features = false } tempfile = "3.2.0" wit-bindgen = { git = 'https://github.com/bytecodealliance/wit-bindgen', default-features = false } -wasm-compose = { version = "0.246.0", path = "crates/wasm-compose" } +wasm-compose = { version = "0.246.0", path = "crates/wasm-compose", default-features = false } wasm-encoder = { version = "0.246.0", path = "crates/wasm-encoder", default-features = false } wasm-metadata = { version = "0.246.0", path = "crates/wasm-metadata", default-features = false } wasm-mutate = { version = "0.246.0", path = "crates/wasm-mutate" } @@ -197,7 +197,7 @@ regex = { version = "1.6.0", optional = true } wasm-encoder = { workspace = true, features = ["std"], optional = true } # Dependencies of `compose` -wasm-compose = { workspace = true, optional = true } +wasm-compose = { workspace = true, optional = true, features = ['default'] } # Dependencies of `demangle` cpp_demangle = { version = "0.4.0", optional = true } diff --git a/crates/wasm-compose/Cargo.toml b/crates/wasm-compose/Cargo.toml index d3dc0851b5..f3b59fbfbe 100644 --- a/crates/wasm-compose/Cargo.toml +++ b/crates/wasm-compose/Cargo.toml @@ -17,12 +17,12 @@ workspace = true [dependencies] anyhow = { workspace = true } heck = "0.5.0" -indexmap = { workspace = true, features = ["std", "serde"] } +indexmap = { workspace = true, features = ["std"] } log = { workspace = true } petgraph = "0.6.2" -serde = { workspace = true } -serde_derive = { workspace = true } -serde_yaml2 = "0.1.3" +serde = { workspace = true, optional = true, features = ['std'] } +serde_derive = { workspace = true, optional = true } +serde_yaml2 = { version = "0.1.3", optional = true } smallvec = "1.10.0" wasm-encoder = { workspace = true, features = ['std', 'wasmparser', 'component-model'] } wasmparser = { workspace = true, features = ['std', 'validate', 'component-model', 'features'] } @@ -33,3 +33,8 @@ glob = "0.3.0" pretty_assertions = "1.2.1" wasmprinter = { workspace = true, features = ['component-model'] } wit-component = { workspace = true } + +[features] +default = ['yaml', 'serde'] +yaml = ['dep:serde_yaml2', 'serde'] +serde = ['dep:serde', 'dep:serde_derive', 'indexmap/serde'] diff --git a/crates/wasm-compose/src/config.rs b/crates/wasm-compose/src/config.rs index 827724e5ac..93106c9c95 100644 --- a/crates/wasm-compose/src/config.rs +++ b/crates/wasm-compose/src/config.rs @@ -1,17 +1,16 @@ //! Module for composition configuration. -use anyhow::{Context, Result}; +use anyhow::Result; use indexmap::IndexMap; -use serde_derive::Deserialize; -use std::{ - fs, - path::{Path, PathBuf}, - str::FromStr, -}; +use std::{path::PathBuf, str::FromStr}; /// An explicit transitive dependency of a composed component. -#[derive(Debug, Clone, Deserialize, Default)] -#[serde(rename_all = "kebab-case", deny_unknown_fields)] +#[derive(Debug, Clone, Default)] +#[cfg_attr(feature = "serde", derive(serde_derive::Deserialize))] +#[cfg_attr( + feature = "serde", + serde(rename_all = "kebab-case", deny_unknown_fields) +)] pub struct Dependency { /// The path to the dependency's component file. pub path: PathBuf, @@ -26,8 +25,12 @@ impl FromStr for Dependency { } /// An argument of an instantiation. -#[derive(Debug, Clone, Deserialize, Default)] -#[serde(rename_all = "kebab-case", deny_unknown_fields)] +#[derive(Debug, Clone, Default)] +#[cfg_attr(feature = "serde", derive(serde_derive::Deserialize))] +#[cfg_attr( + feature = "serde", + serde(rename_all = "kebab-case", deny_unknown_fields) +)] pub struct InstantiationArg { /// The name of the instance passed as the argument. pub instance: String, @@ -35,7 +38,7 @@ pub struct InstantiationArg { /// The name of the instance export to use as the argument. /// /// If `None`, the instance itself will be used as the argument. - #[serde(default)] + #[cfg_attr(feature = "serde", serde(default))] pub export: Option, } @@ -51,8 +54,12 @@ impl FromStr for InstantiationArg { } /// An instantiation of a component. -#[derive(Debug, Clone, Deserialize, Default)] -#[serde(rename_all = "kebab-case", deny_unknown_fields)] +#[derive(Debug, Clone, Default)] +#[cfg_attr(feature = "serde", derive(serde_derive::Deserialize))] +#[cfg_attr( + feature = "serde", + serde(rename_all = "kebab-case", deny_unknown_fields) +)] pub struct Instantiation { /// The name of the dependency being instantiated. /// @@ -63,65 +70,73 @@ pub struct Instantiation { /// /// Maps the argument name to the name of the instance to pass as /// the argument. - #[serde(default, deserialize_with = "de::index_map")] + #[cfg_attr(feature = "serde", serde(default, deserialize_with = "de::index_map"))] pub arguments: IndexMap, } /// The configuration for composing a WebAssembly component. -#[derive(Default, Debug, Clone, Deserialize)] -#[serde(rename_all = "kebab-case", deny_unknown_fields)] +#[derive(Default, Debug, Clone)] +#[cfg_attr(feature = "serde", derive(serde_derive::Deserialize))] +#[cfg_attr( + feature = "serde", + serde(rename_all = "kebab-case", deny_unknown_fields) +)] pub struct Config { /// The path of the configuration file's directory. /// /// All paths are relative to this directory. - #[serde(skip)] + #[cfg_attr(feature = "serde", serde(skip))] pub dir: PathBuf, /// Components whose exports define import dependencies to fulfill from. - #[serde(default)] + #[cfg_attr(feature = "serde", serde(default))] pub definitions: Vec, /// The paths to search when automatically resolving dependencies. /// /// The config directory is always searched first. - #[serde(default)] + #[cfg_attr(feature = "serde", serde(default))] pub search_paths: Vec, /// Whether or not to skip validation of the output component. - #[serde(default)] + #[cfg_attr(feature = "serde", serde(default))] pub skip_validation: bool, /// Whether or not to import components in the composed component. /// /// By default, components are defined rather than imported in /// the composed component. - #[serde(default)] + #[cfg_attr(feature = "serde", serde(default))] pub import_components: bool, /// Whether or not to disallow instance imports in the output component. /// /// Enabling this option will cause an error if a dependency cannot be /// located. - #[serde(default)] + #[cfg_attr(feature = "serde", serde(default))] pub disallow_imports: bool, /// The explicit, transitive dependencies of the root component. - #[serde(default, deserialize_with = "de::index_map")] + #[cfg_attr(feature = "serde", serde(default, deserialize_with = "de::index_map"))] pub dependencies: IndexMap, /// The explicit instantiations of the composed component. - #[serde(default)] + #[cfg_attr(feature = "serde", serde(default))] pub instantiations: IndexMap, } impl Config { /// Reads a composition configuration from the given path. + #[cfg(feature = "yaml")] pub fn from_file(path: impl Into) -> Result { + use anyhow::Context; + use std::path::Path; + let path = path.into(); log::info!("reading configuration file `{}`", path.display()); - let config = fs::read_to_string(&path) + let config = std::fs::read_to_string(&path) .with_context(|| format!("failed to read configuration file `{}`", path.display()))?; let mut config: Config = serde_yaml2::from_str(&config) @@ -141,6 +156,7 @@ impl Config { } } +#[cfg(feature = "serde")] mod de { use indexmap::IndexMap; use serde::{