Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
4 changes: 2 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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" }
Expand Down Expand Up @@ -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 }
Expand Down
13 changes: 9 additions & 4 deletions crates/wasm-compose/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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'] }
Expand All @@ -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']
68 changes: 42 additions & 26 deletions crates/wasm-compose/src/config.rs
Original file line number Diff line number Diff line change
@@ -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,
Expand All @@ -26,16 +25,20 @@ 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,

/// 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<String>,
}

Expand All @@ -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.
///
Expand All @@ -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<String, InstantiationArg>,
}

/// 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<PathBuf>,

/// 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<PathBuf>,

/// 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<String, Dependency>,

/// The explicit instantiations of the composed component.
#[serde(default)]
#[cfg_attr(feature = "serde", serde(default))]
pub instantiations: IndexMap<String, Instantiation>,
}

impl Config {
/// Reads a composition configuration from the given path.
#[cfg(feature = "yaml")]
pub fn from_file(path: impl Into<PathBuf>) -> Result<Self> {
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)
Expand All @@ -141,6 +156,7 @@ impl Config {
}
}

#[cfg(feature = "serde")]
mod de {
use indexmap::IndexMap;
use serde::{
Expand Down
Loading