diff --git a/crates/wasm-pkg-client/src/decoded_component.rs b/crates/wasm-pkg-client/src/decoded_component.rs index 2142e12..a9d1c75 100644 --- a/crates/wasm-pkg-client/src/decoded_component.rs +++ b/crates/wasm-pkg-client/src/decoded_component.rs @@ -16,11 +16,18 @@ pub struct DecodedComponent { } impl DecodedComponent { + /// Decode a publishing source. `package_override`, when supplied, is the + /// authoritative `(package, version)`; otherwise the identity is extracted + /// from the binary. pub async fn from_publishing_source( data: PublishingSource, + package_override: Option<(PackageRef, Version)>, ) -> Result<(PublishingSource, DecodedComponent), Error> { let (reader, decoded_wasm) = decode(SyncIoBridge::new(data)).await?; - let (package_ref, version) = extract_package_version(&decoded_wasm)?; + let (package_ref, version) = match package_override { + Some(id) => id, + None => extract_package_version(&decoded_wasm)?, + }; let mut data = reader.into_inner(); data.rewind().await?; @@ -35,20 +42,6 @@ impl DecodedComponent { )) } - /// Like [`Self::from_publishing_source`] but overrides the derived - /// `(package, version)` identity with `package_override` when supplied. - pub async fn from_publishing_source_with_package( - data: PublishingSource, - package_override: Option<(PackageRef, Version)>, - ) -> Result<(PublishingSource, DecodedComponent), Error> { - let (data, mut decoded) = Self::from_publishing_source(data).await?; - if let Some((p, v)) = package_override { - decoded.package_ref = p; - decoded.version = v; - } - Ok((data, decoded)) - } - /// Construct from a registry content stream. Callers already know the /// `(package, version)` identity from the registry listing they followed /// to get here, so we take it as input rather than re-deriving it from diff --git a/crates/wasm-pkg-client/src/lib.rs b/crates/wasm-pkg-client/src/lib.rs index 5808600..9ef1913 100644 --- a/crates/wasm-pkg-client/src/lib.rs +++ b/crates/wasm-pkg-client/src/lib.rs @@ -176,7 +176,7 @@ impl Client { // construct verifiable publishing source let (data, candidate) = - DecodedComponent::from_publishing_source_with_package(data, pkg_authority).await?; + DecodedComponent::from_publishing_source(data, pkg_authority).await?; let (package, version) = ( candidate.package().to_owned(), diff --git a/crates/wasm-pkg-client/tests/publish_package_override.rs b/crates/wasm-pkg-client/tests/publish_package_override.rs new file mode 100644 index 0000000..4d7000e --- /dev/null +++ b/crates/wasm-pkg-client/tests/publish_package_override.rs @@ -0,0 +1,75 @@ +use std::{io::Cursor, path::Path}; +use tempfile::TempDir; +use wasm_pkg_client::{Client, Config, PublishOpts}; + +const WIT: &str = r#" +package example:embedded@0.1.0; + +world the-world { + export base: func() -> u32; +} +"#; + +fn make_client(root: &Path) -> Client { + let toml = format!( + r#" +default_registry = "local" + +[registry."local"] +type = "local" + +[registry."local".local] +root = '{}' +"#, + root.display(), + ); + let config = Config::from_toml(&toml).expect("local-backend config should parse"); + Client::new(config) +} + +fn component_bytes() -> Vec { + let mut resolve = wit_parser::Resolve::new(); + let pkg = resolve + .push_str("test.wit", WIT) + .expect("test WIT should parse"); + let world = resolve + .select_world(&[pkg], None) + .expect("test WIT should have exactly one world"); + let mut module = + wit_component::dummy_module(&resolve, world, wit_parser::ManglingAndAbi::Standard32); + wit_component::embed_component_metadata( + &mut module, + &resolve, + world, + wit_component::StringEncoding::UTF8, + ) + .expect("component metadata should embed"); + wit_component::ComponentEncoder::default() + .module(&module) + .expect("dummy module should be accepted") + .validate(true) + .encode() + .expect("dummy module should encode as a component") +} + +#[tokio::test] +async fn override_supplies_identity_for_component() { + let tmp = TempDir::new().unwrap(); + let client = make_client(tmp.path()); + + let opts = PublishOpts { + package: Some(("example:app".parse().unwrap(), "1.0.0".parse().unwrap())), + ..Default::default() + }; + let (package, version) = client + .publish_release_data(Box::pin(Cursor::new(component_bytes())), opts) + .await + .expect("publishing a component with an explicit identity should succeed"); + + assert_eq!(package, "example:app".parse().unwrap()); + assert_eq!(version, "1.0.0".parse().unwrap()); + client + .get_release(&package, &version) + .await + .expect("published release should be retrievable at the supplied coordinate"); +}