mirror of
https://github.com/fluencelabs/marine.git
synced 2025-06-25 20:51:35 +00:00
Support versioning in CLI (#67)
This commit is contained in:
59
crates/module-info-parser/src/custom_section_extractor.rs
Normal file
59
crates/module-info-parser/src/custom_section_extractor.rs
Normal file
@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright 2020 Fluence Labs Limited
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
use crate::ModuleInfoResult;
|
||||
use crate::ModuleInfoError;
|
||||
|
||||
use walrus::IdsToIndices;
|
||||
use walrus::Module;
|
||||
|
||||
use std::borrow::Cow;
|
||||
|
||||
pub(super) fn extract_custom_sections_by_name<'w>(
|
||||
wasm_module: &'w Module,
|
||||
section_name: &str,
|
||||
) -> ModuleInfoResult<Vec<Cow<'w, [u8]>>> {
|
||||
let default_ids = IdsToIndices::default();
|
||||
|
||||
let sections = wasm_module
|
||||
.customs
|
||||
.iter()
|
||||
.filter(|(_, section)| section.name() == section_name)
|
||||
.map(|s| s.1.data(&default_ids))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
Ok(sections)
|
||||
}
|
||||
|
||||
pub(super) fn try_as_one_section<'s>(
|
||||
mut sections: Vec<Cow<'s, [u8]>>,
|
||||
section_name: &'static str,
|
||||
) -> ModuleInfoResult<Cow<'s, [u8]>> {
|
||||
let sections_count = sections.len();
|
||||
|
||||
if sections_count > 1 {
|
||||
return Err(ModuleInfoError::MultipleCustomSections(
|
||||
section_name,
|
||||
sections_count,
|
||||
));
|
||||
}
|
||||
|
||||
if sections_count == 0 {
|
||||
return Err(ModuleInfoError::NoCustomSection(section_name));
|
||||
}
|
||||
|
||||
Ok(sections.remove(0))
|
||||
}
|
84
crates/module-info-parser/src/errors.rs
Normal file
84
crates/module-info-parser/src/errors.rs
Normal file
@ -0,0 +1,84 @@
|
||||
/*
|
||||
* Copyright 2020 Fluence Labs Limited
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
use semver::SemVerError;
|
||||
use thiserror::Error as ThisError;
|
||||
use std::str::Utf8Error;
|
||||
|
||||
#[derive(Debug, ThisError)]
|
||||
pub enum ModuleInfoError {
|
||||
/// Version section is absent.
|
||||
#[error("the module doesn't contain section with '{0}', probably it's compiled with an old sdk version")]
|
||||
NoCustomSection(&'static str),
|
||||
|
||||
/// Multiple sections with the same name.
|
||||
#[error("the module contains {1} sections with name '{0}' - it's corrupted")]
|
||||
MultipleCustomSections(&'static str, usize),
|
||||
|
||||
/// Errors related to corrupted version.
|
||||
#[error("{0}")]
|
||||
VersionError(#[from] SDKVersionError),
|
||||
|
||||
/// Errors related to corrupted manifest.
|
||||
#[error("{0}")]
|
||||
ManifestError(#[from] ManifestError),
|
||||
|
||||
/// An error occurred while parsing Wasm file.
|
||||
#[error("provided Wasm file is corrupted: {0}")]
|
||||
CorruptedWasmFile(anyhow::Error),
|
||||
}
|
||||
|
||||
#[derive(Debug, ThisError)]
|
||||
pub enum SDKVersionError {
|
||||
/// Version can't be parsed to Utf8 string.
|
||||
#[error("embedded to the Wasm file version isn't valid UTF8 string: '{0}'")]
|
||||
VersionNotValidUtf8(Utf8Error),
|
||||
|
||||
/// Version can't be parsed with semver.
|
||||
#[error("embedded to the Wasm file version is corrupted: '{0}'")]
|
||||
VersionCorrupted(#[from] SemVerError),
|
||||
}
|
||||
|
||||
#[derive(Debug, ThisError, PartialEq)]
|
||||
pub enum ManifestError {
|
||||
/// Manifest of a Wasm file doesn't have enough bytes to read size of a field from its prefix.
|
||||
#[error(
|
||||
"{0} can't be read: embedded manifest doesn't contain enough bytes to read field size from prefix"
|
||||
)]
|
||||
NotEnoughBytesForPrefix(&'static str),
|
||||
|
||||
/// Manifest of a Wasm file doesn't have enough bytes to read a field.
|
||||
#[error(
|
||||
"{0} can't be read: embedded manifest doesn't contain enough bytes to read field of size {1}"
|
||||
)]
|
||||
NotEnoughBytesForField(&'static str, usize),
|
||||
|
||||
/// Manifest of a Wasm file doesn't have enough bytes to read field.
|
||||
#[error("{0} is an invalid Utf8 string: {1}")]
|
||||
FieldNotValidUtf8(&'static str, Utf8Error),
|
||||
|
||||
/// Size inside prefix of a field is too big (it exceeds usize or overflows with prefix size).
|
||||
#[error("{0} has too big size: {1}")]
|
||||
TooBigFieldSize(&'static str, u64),
|
||||
|
||||
/// Version can't be parsed with semver.
|
||||
#[error("embedded to the Wasm file version is corrupted: '{0}'")]
|
||||
ModuleVersionCorrupted(#[from] SemVerError),
|
||||
|
||||
/// Manifest contains some trailing characters.
|
||||
#[error("embedded manifest is corrupted: there are some trailing characters")]
|
||||
ManifestRemainderNotEmpty,
|
||||
}
|
49
crates/module-info-parser/src/lib.rs
Normal file
49
crates/module-info-parser/src/lib.rs
Normal file
@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright 2020 Fluence Labs Limited
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
#![warn(rust_2018_idioms)]
|
||||
#![deny(
|
||||
dead_code,
|
||||
nonstandard_style,
|
||||
unused_imports,
|
||||
unused_mut,
|
||||
unused_variables,
|
||||
unused_unsafe,
|
||||
unreachable_patterns
|
||||
)]
|
||||
|
||||
mod custom_section_extractor;
|
||||
mod errors;
|
||||
mod manifest;
|
||||
mod manifest_extractor;
|
||||
mod version_extractor;
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
||||
pub use errors::ModuleInfoError;
|
||||
pub use errors::ManifestError;
|
||||
pub use errors::SDKVersionError;
|
||||
|
||||
pub use version_extractor::extract_sdk_version_by_path;
|
||||
pub use version_extractor::extract_sdk_version_by_module;
|
||||
|
||||
pub use manifest::ModuleManifest;
|
||||
pub use manifest_extractor::extract_manifest_by_path;
|
||||
pub use manifest_extractor::extract_version_by_module;
|
||||
|
||||
pub(crate) use custom_section_extractor::extract_custom_sections_by_name;
|
||||
pub(crate) use custom_section_extractor::try_as_one_section;
|
||||
|
||||
pub(crate) type ModuleInfoResult<T> = std::result::Result<T, ModuleInfoError>;
|
145
crates/module-info-parser/src/manifest.rs
Normal file
145
crates/module-info-parser/src/manifest.rs
Normal file
@ -0,0 +1,145 @@
|
||||
/*
|
||||
* Copyright 2020 Fluence Labs Limited
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/// Describes manifest of a Wasm module in the Fluence network.
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct ModuleManifest {
|
||||
pub authors: String,
|
||||
pub version: semver::Version,
|
||||
pub description: String,
|
||||
pub repository: String,
|
||||
}
|
||||
|
||||
use crate::ManifestError;
|
||||
|
||||
use std::convert::TryFrom;
|
||||
use std::str::FromStr;
|
||||
|
||||
type Result<T> = std::result::Result<T, ManifestError>;
|
||||
|
||||
impl TryFrom<&[u8]> for ModuleManifest {
|
||||
type Error = ManifestError;
|
||||
|
||||
#[rustfmt::skip]
|
||||
fn try_from(value: &[u8]) -> Result<Self> {
|
||||
let (authors, next_offset) = try_extract_field_as_string(value, 0, "authors")?;
|
||||
let (version, next_offset) = try_extract_field_as_version(value, next_offset, "version")?;
|
||||
let (description, next_offset) = try_extract_field_as_string(value, next_offset, "description")?;
|
||||
let (repository, next_offset) = try_extract_field_as_string(value, next_offset, "repository")?;
|
||||
|
||||
if next_offset != value.len() {
|
||||
return Err(ManifestError::ManifestRemainderNotEmpty)
|
||||
}
|
||||
|
||||
let manifest = ModuleManifest {
|
||||
authors,
|
||||
version,
|
||||
description,
|
||||
repository,
|
||||
};
|
||||
|
||||
Ok(manifest)
|
||||
}
|
||||
}
|
||||
|
||||
fn try_extract_field_as_string(
|
||||
raw_manifest: &[u8],
|
||||
offset: usize,
|
||||
field_name: &'static str,
|
||||
) -> Result<(String, usize)> {
|
||||
let raw_manifest = &raw_manifest[offset..];
|
||||
let (field_as_bytes, read_len) = try_extract_prefixed_field(raw_manifest, field_name)?;
|
||||
let field_as_string = try_to_str(field_as_bytes, field_name)?.to_string();
|
||||
|
||||
Ok((field_as_string, offset + read_len))
|
||||
}
|
||||
|
||||
fn try_extract_field_as_version(
|
||||
raw_manifest: &[u8],
|
||||
offset: usize,
|
||||
field_name: &'static str,
|
||||
) -> Result<(semver::Version, usize)> {
|
||||
let raw_manifest = &raw_manifest[offset..];
|
||||
let (field_as_bytes, read_len) = try_extract_prefixed_field(raw_manifest, field_name)?;
|
||||
let field_as_str = try_to_str(field_as_bytes, field_name)?;
|
||||
let version = semver::Version::from_str(field_as_str)?;
|
||||
|
||||
Ok((version, offset + read_len))
|
||||
}
|
||||
|
||||
const PREFIX_SIZE: usize = std::mem::size_of::<u64>();
|
||||
|
||||
fn try_extract_prefixed_field<'a>(
|
||||
array: &'a [u8],
|
||||
field_name: &'static str,
|
||||
) -> Result<(&'a [u8], usize)> {
|
||||
let field_len = try_extract_field_len(array, field_name)?;
|
||||
let field = try_extract_field(array, field_len, field_name)?;
|
||||
|
||||
let read_size = PREFIX_SIZE + field.len();
|
||||
Ok((field, read_size))
|
||||
}
|
||||
|
||||
fn try_extract_field_len(array: &[u8], field_name: &'static str) -> Result<usize> {
|
||||
if array.len() < PREFIX_SIZE {
|
||||
return Err(ManifestError::NotEnoughBytesForPrefix(field_name));
|
||||
}
|
||||
|
||||
let mut field_len = [0u8; PREFIX_SIZE];
|
||||
field_len.copy_from_slice(&array[0..PREFIX_SIZE]);
|
||||
|
||||
let field_len = u64::from_le_bytes(field_len);
|
||||
// TODO: Until we use Wasm32 and compiles our node to x86_64, converting to usize is sound
|
||||
if field_len.checked_add(PREFIX_SIZE as u64).is_none()
|
||||
|| usize::try_from(field_len + PREFIX_SIZE as u64).is_err()
|
||||
{
|
||||
return Err(ManifestError::TooBigFieldSize(field_name, field_len));
|
||||
}
|
||||
|
||||
// it's safe to convert it to usize because it's been checked
|
||||
Ok(field_len as usize)
|
||||
}
|
||||
|
||||
fn try_extract_field<'a>(
|
||||
array: &'a [u8],
|
||||
field_len: usize,
|
||||
field_name: &'static str,
|
||||
) -> Result<&'a [u8]> {
|
||||
if array.len() < PREFIX_SIZE + field_len {
|
||||
return Err(ManifestError::NotEnoughBytesForField(field_name, field_len));
|
||||
}
|
||||
|
||||
let field = &array[PREFIX_SIZE..PREFIX_SIZE + field_len];
|
||||
Ok(field)
|
||||
}
|
||||
|
||||
fn try_to_str<'v>(value: &'v [u8], field_name: &'static str) -> Result<&'v str> {
|
||||
match std::str::from_utf8(value) {
|
||||
Ok(s) => Ok(s),
|
||||
Err(e) => Err(ManifestError::FieldNotValidUtf8(field_name, e)),
|
||||
}
|
||||
}
|
||||
|
||||
use std::fmt;
|
||||
|
||||
impl fmt::Display for ModuleManifest {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
writeln!(f, "authors: {}", self.authors)?;
|
||||
writeln!(f, "version: {}", self.version)?;
|
||||
writeln!(f, "description: {}", self.description)?;
|
||||
write!(f, "repository: {}", self.repository)
|
||||
}
|
||||
}
|
55
crates/module-info-parser/src/manifest_extractor.rs
Normal file
55
crates/module-info-parser/src/manifest_extractor.rs
Normal file
@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Copyright 2020 Fluence Labs Limited
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
use crate::ModuleInfoResult;
|
||||
use crate::ModuleInfoError;
|
||||
use crate::extract_custom_sections_by_name;
|
||||
use crate::try_as_one_section;
|
||||
use crate::ModuleManifest;
|
||||
|
||||
use fluence_sdk_main::MANIFEST_SECTION_NAME;
|
||||
use walrus::ModuleConfig;
|
||||
use walrus::Module;
|
||||
|
||||
use std::borrow::Cow;
|
||||
use std::path::Path;
|
||||
use std::convert::TryInto;
|
||||
|
||||
pub fn extract_manifest_by_path(
|
||||
wasm_module_path: &Path,
|
||||
) -> ModuleInfoResult<Option<ModuleManifest>> {
|
||||
let module = ModuleConfig::new()
|
||||
.parse_file(wasm_module_path)
|
||||
.map_err(ModuleInfoError::CorruptedWasmFile)?;
|
||||
|
||||
extract_version_by_module(&module)
|
||||
}
|
||||
|
||||
pub fn extract_version_by_module(wasm_module: &Module) -> ModuleInfoResult<Option<ModuleManifest>> {
|
||||
let sections = extract_custom_sections_by_name(&wasm_module, MANIFEST_SECTION_NAME)?;
|
||||
if sections.is_empty() {
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
let section = try_as_one_section(sections, MANIFEST_SECTION_NAME)?;
|
||||
|
||||
let manifest = match section {
|
||||
Cow::Borrowed(bytes) => bytes.try_into(),
|
||||
Cow::Owned(vec) => vec.as_slice().try_into(),
|
||||
}?;
|
||||
|
||||
Ok(Some(manifest))
|
||||
}
|
154
crates/module-info-parser/src/tests.rs
Normal file
154
crates/module-info-parser/src/tests.rs
Normal file
@ -0,0 +1,154 @@
|
||||
/*
|
||||
* Copyright 2020 Fluence Labs Limited
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
use crate::ManifestError;
|
||||
use crate::ModuleManifest;
|
||||
|
||||
use std::convert::TryInto;
|
||||
use std::str::FromStr;
|
||||
|
||||
#[derive(Debug, Clone, Default, PartialEq, Eq)]
|
||||
struct ByteEncoder {
|
||||
buffer: Vec<u8>,
|
||||
}
|
||||
|
||||
impl ByteEncoder {
|
||||
pub fn new() -> Self {
|
||||
<_>::default()
|
||||
}
|
||||
|
||||
pub fn add_u64(&mut self, number: u64) {
|
||||
use std::io::Write;
|
||||
|
||||
let number_le_bytes = number.to_le_bytes();
|
||||
self.buffer
|
||||
.write(&number_le_bytes)
|
||||
.expect("writing to buffer should be successful");
|
||||
}
|
||||
|
||||
pub fn add_utf8_string(&mut self, str: &str) {
|
||||
use std::io::Write;
|
||||
|
||||
let str_as_bytes = str.as_bytes();
|
||||
self.buffer
|
||||
.write(&str_as_bytes)
|
||||
.expect("writing to buffer should be successful");
|
||||
}
|
||||
|
||||
pub fn add_utf8_field(&mut self, field: &str) {
|
||||
let field_len = field.as_bytes().len();
|
||||
|
||||
self.add_u64(field_len as u64);
|
||||
self.add_utf8_string(field);
|
||||
}
|
||||
|
||||
pub fn as_bytes(&self) -> &[u8] {
|
||||
&self.buffer
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn into_vec(self) -> Vec<u8> {
|
||||
self.buffer
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_reading_simple_config() {
|
||||
let authors = "authors".to_string();
|
||||
let version = semver::Version::from_str("0.1.0").unwrap();
|
||||
let description = "description".to_string();
|
||||
let repository = "repository".to_string();
|
||||
|
||||
let mut array = ByteEncoder::new();
|
||||
|
||||
array.add_utf8_field(&authors);
|
||||
array.add_utf8_field(&version.to_string());
|
||||
array.add_utf8_field(&description);
|
||||
array.add_utf8_field(&repository);
|
||||
|
||||
let actual: ModuleManifest = array
|
||||
.as_bytes()
|
||||
.try_into()
|
||||
.expect("module manifest should be deserialized correctly");
|
||||
|
||||
let expected = ModuleManifest {
|
||||
authors,
|
||||
version,
|
||||
description,
|
||||
repository,
|
||||
};
|
||||
|
||||
assert_eq!(actual, expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_too_big_field_len() {
|
||||
let mut array = ByteEncoder::new();
|
||||
|
||||
array.add_utf8_field("authors");
|
||||
let incorrect_size = u64::MAX;
|
||||
array.add_u64(incorrect_size);
|
||||
array.add_utf8_string("version");
|
||||
array.add_utf8_field("description");
|
||||
array.add_utf8_field("repository");
|
||||
|
||||
let actual: Result<ModuleManifest, _> = array.as_bytes().try_into();
|
||||
let expected = Err(ManifestError::TooBigFieldSize("version", incorrect_size));
|
||||
|
||||
assert_eq!(actual, expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_without_one_field() {
|
||||
let mut array = ByteEncoder::new();
|
||||
|
||||
array.add_utf8_field("authors");
|
||||
array.add_utf8_field("0.1.0");
|
||||
array.add_utf8_field("description");
|
||||
|
||||
let actual: Result<ModuleManifest, _> = array.as_bytes().try_into();
|
||||
let expected = Err(ManifestError::NotEnoughBytesForPrefix("repository"));
|
||||
|
||||
assert_eq!(actual, expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_with_empty_slice() {
|
||||
let actual: Result<ModuleManifest, _> = vec![].as_slice().try_into();
|
||||
let expected = Err(ManifestError::NotEnoughBytesForPrefix("authors"));
|
||||
|
||||
assert_eq!(actual, expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_not_enough_data_for_field() {
|
||||
let mut array = ByteEncoder::new();
|
||||
|
||||
array.add_utf8_field("authors");
|
||||
array.add_utf8_field("0.1.0");
|
||||
array.add_utf8_field("description");
|
||||
let too_big_size = 0xFF;
|
||||
array.add_u64(too_big_size);
|
||||
array.add_utf8_string("repository");
|
||||
|
||||
let actual: Result<ModuleManifest, _> = array.as_bytes().try_into();
|
||||
let expected = Err(ManifestError::NotEnoughBytesForField(
|
||||
"repository",
|
||||
too_big_size as usize,
|
||||
));
|
||||
|
||||
assert_eq!(actual, expected);
|
||||
}
|
64
crates/module-info-parser/src/version_extractor.rs
Normal file
64
crates/module-info-parser/src/version_extractor.rs
Normal file
@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Copyright 2020 Fluence Labs Limited
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
use crate::ModuleInfoResult;
|
||||
use crate::ModuleInfoError;
|
||||
use crate::SDKVersionError;
|
||||
use crate::extract_custom_sections_by_name;
|
||||
use crate::try_as_one_section;
|
||||
|
||||
use fluence_sdk_main::VERSION_SECTION_NAME;
|
||||
use walrus::ModuleConfig;
|
||||
use walrus::Module;
|
||||
|
||||
use std::borrow::Cow;
|
||||
use std::str::FromStr;
|
||||
use std::path::Path;
|
||||
|
||||
pub fn extract_sdk_version_by_path(
|
||||
wasm_module_path: &Path,
|
||||
) -> ModuleInfoResult<Option<semver::Version>> {
|
||||
let module = ModuleConfig::new()
|
||||
.parse_file(wasm_module_path)
|
||||
.map_err(ModuleInfoError::CorruptedWasmFile)?;
|
||||
|
||||
extract_sdk_version_by_module(&module)
|
||||
}
|
||||
|
||||
pub fn extract_sdk_version_by_module(
|
||||
wasm_module: &Module,
|
||||
) -> ModuleInfoResult<Option<semver::Version>> {
|
||||
let sections = extract_custom_sections_by_name(&wasm_module, VERSION_SECTION_NAME)?;
|
||||
|
||||
if sections.is_empty() {
|
||||
return Ok(None);
|
||||
}
|
||||
let section = try_as_one_section(sections, VERSION_SECTION_NAME)?;
|
||||
|
||||
let version = match section {
|
||||
Cow::Borrowed(bytes) => as_semver(bytes),
|
||||
Cow::Owned(vec) => as_semver(&vec),
|
||||
}?;
|
||||
|
||||
Ok(Some(version))
|
||||
}
|
||||
|
||||
fn as_semver(version_as_bytes: &[u8]) -> Result<semver::Version, crate::SDKVersionError> {
|
||||
match std::str::from_utf8(version_as_bytes) {
|
||||
Ok(str) => Ok(semver::Version::from_str(str)?),
|
||||
Err(e) => Err(SDKVersionError::VersionNotValidUtf8(e)),
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user