From 06f9aa09302ef2d7789b2fb655571d596305ea0a Mon Sep 17 00:00:00 2001 From: Yosh Date: Wed, 4 Dec 2024 17:35:23 +0100 Subject: [PATCH] add author parsing --- crates/wasm-encoder/src/core/custom.rs | 2 +- crates/wasm-metadata/src/add_metadata.rs | 8 ++- crates/wasm-metadata/src/metadata.rs | 7 ++ .../src/oci_annotations/author.rs | 67 ++++++++++++------- crates/wasm-metadata/src/producers.rs | 2 +- crates/wasm-metadata/src/registry.rs | 2 +- crates/wasm-metadata/src/rewrite.rs | 13 +++- crates/wasm-metadata/tests/component.rs | 16 +++-- crates/wasm-metadata/tests/module.rs | 7 +- 9 files changed, 83 insertions(+), 41 deletions(-) diff --git a/crates/wasm-encoder/src/core/custom.rs b/crates/wasm-encoder/src/core/custom.rs index 870ee62617..1fbeb10223 100644 --- a/crates/wasm-encoder/src/core/custom.rs +++ b/crates/wasm-encoder/src/core/custom.rs @@ -3,7 +3,7 @@ use std::borrow::Cow; use crate::{encoding_size, Encode, Section, SectionId}; /// A custom section holding arbitrary data. -#[derive(Clone, Debug)] +#[derive(Clone, Debug, PartialEq)] pub struct CustomSection<'a> { /// The name of this custom section. pub name: Cow<'a, str>, diff --git a/crates/wasm-metadata/src/add_metadata.rs b/crates/wasm-metadata/src/add_metadata.rs index c2b997e44a..cb18569476 100644 --- a/crates/wasm-metadata/src/add_metadata.rs +++ b/crates/wasm-metadata/src/add_metadata.rs @@ -1,4 +1,4 @@ -use crate::{rewrite_wasm, Producers, RegistryMetadata}; +use crate::{rewrite_wasm, Author, Producers, RegistryMetadata}; use anyhow::Result; @@ -25,6 +25,11 @@ pub struct AddMetadata { #[cfg_attr(feature="clap", clap(long, value_parser = parse_key_value, value_name="NAME=VERSION"))] pub sdk: Vec<(String, String)>, + /// Contact details of the people or organization responsible, + /// encoded as a freeform string. + #[cfg_attr(feature = "clap", clap(long, value_name = "NAME"))] + pub author: Option, + /// Add an registry metadata to the registry-metadata section #[cfg_attr(feature="clap", clap(long, value_parser = parse_registry_metadata_value, value_name="PATH"))] pub registry_metadata: Option, @@ -54,6 +59,7 @@ impl AddMetadata { rewrite_wasm( &self.name, &Producers::from_meta(self), + &self.author, self.registry_metadata.as_ref(), input, ) diff --git a/crates/wasm-metadata/src/metadata.rs b/crates/wasm-metadata/src/metadata.rs index beba7f5fce..2277455a36 100644 --- a/crates/wasm-metadata/src/metadata.rs +++ b/crates/wasm-metadata/src/metadata.rs @@ -110,6 +110,13 @@ impl Metadata { .expect("non-empty metadata stack") .set_registry_metadata(registry); } + KnownCustom::Unknown if c.name() == "author" => { + let a = Author::parse_custom_section(&c)?; + match metadata.last_mut().expect("non-empty metadata stack") { + Metadata::Module { author, .. } => *author = Some(a), + Metadata::Component { author, .. } => *author = Some(a), + } + } _ => {} }, _ => {} diff --git a/crates/wasm-metadata/src/oci_annotations/author.rs b/crates/wasm-metadata/src/oci_annotations/author.rs index 675956842c..ae7948292c 100644 --- a/crates/wasm-metadata/src/oci_annotations/author.rs +++ b/crates/wasm-metadata/src/oci_annotations/author.rs @@ -1,34 +1,17 @@ use std::borrow::Cow; use std::fmt::{self, Display}; +use std::str::FromStr; -use anyhow::{ensure, Result}; +use anyhow::{ensure, Error, Result}; use serde::Serialize; -use wasm_encoder::{ComponentSection, CustomSection, Encode}; +use wasm_encoder::{ComponentSection, CustomSection, Encode, Section}; use wasmparser::CustomSectionReader; -/// Contact details of the people or organization responsible for the image +/// Contact details of the people or organization responsible, /// encoded as a freeform string. -#[derive(Debug)] +#[derive(Debug, Clone, PartialEq)] pub struct Author(CustomSection<'static>); -impl Serialize for Author { - fn serialize(&self, serializer: S) -> std::result::Result - where - S: serde::Serializer, - { - serializer.serialize_str(&self.to_string()) - } -} - -impl Display for Author { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - // NOTE: this will never panic since we always guarantee the data is - // encoded as utf8, even if we internally store it as [u8]. - let data = String::from_utf8(self.0.data.to_vec()).unwrap(); - write!(f, "{data}") - } -} - impl Author { /// Create a new instance of `Author`. pub fn new>>(s: S) -> Self { @@ -42,9 +25,9 @@ impl Author { } /// Parse an `author` custom section from a wasm binary. - pub fn parse_wasm(reader: CustomSectionReader<'_>) -> Result { + pub(crate) fn parse_custom_section(reader: &CustomSectionReader<'_>) -> Result { ensure!( - dbg!(reader.name()) == "author", + reader.name() == "author", "The `author` custom section should have a name of 'author'" ); let data = String::from_utf8(reader.data().to_owned())?; @@ -52,9 +35,41 @@ impl Author { } } +impl FromStr for Author { + type Err = Error; + + fn from_str(s: &str) -> Result { + Ok(Self::new(s.to_owned())) + } +} + +impl Serialize for Author { + fn serialize(&self, serializer: S) -> std::result::Result + where + S: serde::Serializer, + { + serializer.serialize_str(&self.to_string()) + } +} + +impl Display for Author { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + // NOTE: this will never panic since we always guarantee the data is + // encoded as utf8, even if we internally store it as [u8]. + let data = String::from_utf8(self.0.data.to_vec()).unwrap(); + write!(f, "{data}") + } +} + impl ComponentSection for Author { fn id(&self) -> u8 { - self.0.id() + ComponentSection::id(&self.0) + } +} + +impl Section for Author { + fn id(&self) -> u8 { + Section::id(&self.0) } } @@ -79,7 +94,7 @@ mod test { let mut parsed = false; for section in wasmparser::Parser::new(0).parse_all(&component) { if let Payload::CustomSection(reader) = section.unwrap() { - let author = Author::parse_wasm(reader).unwrap(); + let author = Author::parse_custom_section(&reader).unwrap(); assert_eq!(author.to_string(), "Nori Cat"); parsed = true; } diff --git a/crates/wasm-metadata/src/producers.rs b/crates/wasm-metadata/src/producers.rs index ccec57e4d6..4ddac5e312 100644 --- a/crates/wasm-metadata/src/producers.rs +++ b/crates/wasm-metadata/src/producers.rs @@ -148,7 +148,7 @@ impl Producers { /// Merge into an existing wasm module. Rewrites the module with this producers section /// merged into its existing one, or adds this producers section if none is present. pub fn add_to_wasm(&self, input: &[u8]) -> Result> { - rewrite_wasm(&None, self, None, input) + rewrite_wasm(&None, self, &None, None, input) } pub(crate) fn display(&self, f: &mut fmt::Formatter, indent: usize) -> fmt::Result { diff --git a/crates/wasm-metadata/src/registry.rs b/crates/wasm-metadata/src/registry.rs index fbdc30937e..e52a349bef 100644 --- a/crates/wasm-metadata/src/registry.rs +++ b/crates/wasm-metadata/src/registry.rs @@ -44,7 +44,7 @@ impl RegistryMetadata { /// Merge into an existing wasm module. Rewrites the module with this registry-metadata section /// overwriting its existing one, or adds this registry-metadata section if none is present. pub fn add_to_wasm(&self, input: &[u8]) -> Result> { - rewrite_wasm(&None, &Producers::empty(), Some(&self), input) + rewrite_wasm(&None, &Producers::empty(), &None, Some(&self), input) } /// Parse a Wasm binary and extract the `Registry` section, if there is any. diff --git a/crates/wasm-metadata/src/rewrite.rs b/crates/wasm-metadata/src/rewrite.rs index 77d351729e..b1e8aa1424 100644 --- a/crates/wasm-metadata/src/rewrite.rs +++ b/crates/wasm-metadata/src/rewrite.rs @@ -1,4 +1,4 @@ -use crate::{ComponentNames, ModuleNames, Producers, RegistryMetadata}; +use crate::{Author, ComponentNames, ModuleNames, Producers, RegistryMetadata}; use anyhow::Result; use std::borrow::Cow; use std::mem; @@ -9,6 +9,7 @@ use wasmparser::{KnownCustom, Parser, Payload::*}; pub(crate) fn rewrite_wasm( add_name: &Option, add_producers: &Producers, + add_author: &Option, add_registry_metadata: Option<&RegistryMetadata>, input: &[u8], ) -> Result> { @@ -90,6 +91,13 @@ pub(crate) fn rewrite_wasm( continue; } } + KnownCustom::Unknown if c.name() == "author" => { + if add_author.is_none() { + let author = Author::parse_custom_section(c)?; + author.append_to(&mut output); + continue; + } + } _ => {} } } @@ -119,6 +127,9 @@ pub(crate) fn rewrite_wasm( // Encode into output: producers.section().append_to(&mut output); } + if let Some(author) = add_author { + author.append_to(&mut output); + } if add_registry_metadata.is_some() { let registry_metadata = wasm_encoder::CustomSection { name: Cow::Borrowed("registry-metadata"), diff --git a/crates/wasm-metadata/tests/component.rs b/crates/wasm-metadata/tests/component.rs index 88be96f7dd..ae588d9b69 100644 --- a/crates/wasm-metadata/tests/component.rs +++ b/crates/wasm-metadata/tests/component.rs @@ -11,6 +11,7 @@ fn add_to_empty_component() { language: vec![("bar".to_owned(), "1.0".to_owned())], processed_by: vec![("baz".to_owned(), "1.0".to_owned())], sdk: vec![], + author: Some(Author::new("Chashu Cat")), registry_metadata: Some(RegistryMetadata { authors: Some(vec!["foo".to_owned()]), description: Some("foo bar baz".to_owned()), @@ -58,6 +59,8 @@ fn add_to_empty_component() { "1.0" ); + assert_eq!(author.unwrap(), Author::new("Chashu Cat")); + let registry_metadata = registry_metadata.unwrap(); assert!(registry_metadata.validate().is_ok()); @@ -99,10 +102,8 @@ fn add_to_empty_component() { vec!["Tools".to_owned()] ); - assert!(author.is_none()); - assert_eq!(range.start, 0); - assert_eq!(range.end, 435); + assert_eq!(range.end, 454); } _ => panic!("metadata should be component"), } @@ -117,6 +118,7 @@ fn add_to_nested_component() { language: vec![("bar".to_owned(), "1.0".to_owned())], processed_by: vec![("baz".to_owned(), "1.0".to_owned())], sdk: vec![], + author: Some(Author::new("Chashu Cat")), registry_metadata: Some(RegistryMetadata { authors: Some(vec!["Foo".to_owned()]), ..Default::default() @@ -177,16 +179,16 @@ fn add_to_nested_component() { "1.0" ); + assert_eq!(author, &Some(Author::new("Chashu Cat"))); + let registry_metadata = registry_metadata.as_ref().unwrap(); assert_eq!( registry_metadata.authors.as_ref().unwrap(), &["Foo".to_owned()] ); - assert!(author.is_none()); - - assert_eq!(range.start, 10); - assert_eq!(range.end, 123); + assert_eq!(range.start, 11); + assert_eq!(range.end, 143); } _ => panic!("child is a module"), } diff --git a/crates/wasm-metadata/tests/module.rs b/crates/wasm-metadata/tests/module.rs index e177c2c0f6..c59484a020 100644 --- a/crates/wasm-metadata/tests/module.rs +++ b/crates/wasm-metadata/tests/module.rs @@ -11,6 +11,7 @@ fn add_to_empty_module() { language: vec![("bar".to_owned(), "1.0".to_owned())], processed_by: vec![("baz".to_owned(), "1.0".to_owned())], sdk: vec![], + author: Some(Author::new("Chashu Cat")), registry_metadata: Some(RegistryMetadata { authors: Some(vec!["foo".to_owned()]), description: Some("foo bar baz".to_owned()), @@ -56,6 +57,8 @@ fn add_to_empty_module() { "1.0" ); + assert_eq!(author.unwrap(), Author::new("Chashu Cat")); + let registry_metadata = registry_metadata.unwrap(); assert!(registry_metadata.validate().is_ok()); @@ -97,10 +100,8 @@ fn add_to_empty_module() { vec!["Tools".to_owned()] ); - assert!(author.is_none()); - assert_eq!(range.start, 0); - assert_eq!(range.end, 425); + assert_eq!(range.end, 444); } _ => panic!("metadata should be module"), }