diff --git a/.circleci/config.yml b/.circleci/config.yml index dc5afa57..4b1fe648 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -13,12 +13,12 @@ jobs: keys: - fce04-{{ checksum "Cargo.lock" }} - run: | - rustup toolchain install nightly-2020-12-15 - rustup default nightly-2020-12-15 - rustup override set nightly-2020-12-15 + rustup toolchain install nightly-2021-02-27 + rustup default nightly-2021-02-27 + rustup override set nightly-2021-02-27 - rustup component add rustfmt --toolchain nightly-2020-12-15 - rustup component add clippy --toolchain nightly-2020-12-15 + rustup component add rustfmt --toolchain nightly-2021-02-27 + rustup component add clippy --toolchain nightly-2021-02-27 rustup target add wasm32-wasi cargo install fcli diff --git a/Cargo.lock b/Cargo.lock index 2f3fd71b..e61a59e1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -69,7 +69,7 @@ dependencies = [ name = "arguments-passing-test" version = "0.1.0" dependencies = [ - "fluence 0.4.2", + "fluence 0.5.0", "safe-transmute", ] @@ -83,7 +83,7 @@ checksum = "a4c527152e37cf757a3f78aae5a06fbeefdb07ccc535c980a3208ee3060dd544" name = "arrays-passing-test" version = "0.1.0" dependencies = [ - "fluence 0.4.2", + "fluence 0.5.0", "safe-transmute", ] @@ -186,9 +186,9 @@ checksum = "63396b8a4b9de3f4fdfb320ab6080762242f66a8ef174c49d8e19b674db4cdbe" [[package]] name = "byteorder" -version = "1.4.2" +version = "1.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae44d1a3d5a19df61dd0c8beb138458ac2a53a7ac09eba97d55592540004306b" +checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" [[package]] name = "bytes" @@ -206,7 +206,7 @@ checksum = "b700ce4376041dcd0a327fd0097c41095743c4c8af8887265942faf1100bd040" name = "call_parameters" version = "0.1.0" dependencies = [ - "fluence 0.4.2", + "fluence 0.5.0", ] [[package]] @@ -421,7 +421,7 @@ dependencies = [ name = "curl_adapter" version = "0.1.0" dependencies = [ - "fluence 0.4.2", + "fluence 0.5.0", "log", ] @@ -626,7 +626,7 @@ name = "facade" version = "0.1.0" dependencies = [ "anyhow", - "fluence 0.4.2", + "fluence 0.5.0", "log", ] @@ -680,6 +680,18 @@ dependencies = [ "wasmer-wasi-fl", ] +[[package]] +name = "fce-module-manifest-parser" +version = "0.1.0" +dependencies = [ + "anyhow", + "fluence-sdk-main 0.5.0", + "semver 0.11.0", + "serde", + "thiserror", + "walrus", +] + [[package]] name = "fce-sqlite-connector" version = "0.2.0" @@ -698,7 +710,7 @@ name = "fce-wit-generator" version = "0.2.0" dependencies = [ "fce-wit-parser", - "fluence-sdk-wit 0.4.2", + "fluence-sdk-wit 0.5.0", "once_cell", "serde", "serde_json", @@ -721,6 +733,7 @@ dependencies = [ "anyhow", "fce-wit-interfaces", "serde", + "thiserror", "walrus", "wasmer-interface-types-fl", "wasmer-runtime-core-fl", @@ -728,11 +741,12 @@ dependencies = [ [[package]] name = "fcli" -version = "0.2.0" +version = "0.3.0" dependencies = [ "anyhow", "clap", "exitfailure", + "fce-module-manifest-parser", "fce-wit-generator", "fce-wit-parser", "serde", @@ -759,6 +773,16 @@ dependencies = [ "fluence-sdk-main 0.4.2", ] +[[package]] +name = "fluence" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "342831732a977f13220ecd6f25c7e6b6127af8d3794d42e3c880b05e457a0484" +dependencies = [ + "fluence-sdk-macro 0.5.0", + "fluence-sdk-main 0.5.0", +] + [[package]] name = "fluence-app-service" version = "0.5.2" @@ -781,7 +805,7 @@ dependencies = [ "env_logger 0.7.1", "fce", "fce-utils", - "fluence-sdk-main 0.4.2", + "fluence-sdk-main 0.5.0", "itertools", "log", "once_cell", @@ -828,6 +852,15 @@ dependencies = [ "fluence-sdk-wit 0.4.2", ] +[[package]] +name = "fluence-sdk-macro" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00c840552e5e58b62d4a272e3e4aabd548e1a4519df629a51d42157c7ecbe653" +dependencies = [ + "fluence-sdk-wit 0.5.0", +] + [[package]] name = "fluence-sdk-main" version = "0.2.18" @@ -850,6 +883,17 @@ dependencies = [ "serde", ] +[[package]] +name = "fluence-sdk-main" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f1d126f05a798c8f812fbe47a42145478ce8029e00411b04d1c5194ab368313" +dependencies = [ + "fluence-sdk-macro 0.5.0", + "log", + "serde", +] + [[package]] name = "fluence-sdk-wit" version = "0.2.18" @@ -878,6 +922,20 @@ dependencies = [ "uuid", ] +[[package]] +name = "fluence-sdk-wit" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ac71e8d48a8e2bdaccf59572dc7a8e8a1ad0de512fc452107756e37ac0bf752" +dependencies = [ + "proc-macro2", + "quote", + "serde", + "serde_json", + "syn", + "uuid", +] + [[package]] name = "fnv" version = "1.0.7" @@ -917,7 +975,7 @@ dependencies = [ "clap", "env_logger 0.7.1", "fluence-app-service", - "fluence-sdk-main 0.4.2", + "fluence-sdk-main 0.5.0", "itertools", "log", "rustop", @@ -979,7 +1037,7 @@ checksum = "1812c7ab8aedf8d6f2701a43e1243acdbcc2b36ab26e2ad421eb99ac963d96d1" dependencies = [ "futures-core", "futures-task", - "pin-project-lite 0.2.5", + "pin-project-lite 0.2.6", "pin-utils", ] @@ -1230,9 +1288,9 @@ dependencies = [ [[package]] name = "indexmap" -version = "1.6.1" +version = "1.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fb1fa934250de4de8aef298d81c729a7d33d8c239daa3a7575e6b92bfc7313b" +checksum = "824845a0bf897a9042383849b02c1bc219c2383772efcd5c6f9766fa4b81aef3" dependencies = [ "autocfg", "hashbrown", @@ -1243,7 +1301,7 @@ dependencies = [ name = "inner-records-test" version = "0.1.0" dependencies = [ - "fluence 0.4.2", + "fluence 0.5.0", "safe-transmute", ] @@ -1291,7 +1349,7 @@ dependencies = [ name = "ipfs-effector" version = "0.1.0" dependencies = [ - "fluence 0.4.2", + "fluence 0.5.0", "log", ] @@ -1299,7 +1357,7 @@ dependencies = [ name = "ipfs-pure" version = "0.1.0" dependencies = [ - "fluence 0.4.2", + "fluence 0.5.0", "log", ] @@ -1376,15 +1434,15 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.87" +version = "0.2.88" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "265d751d31d6780a3f956bb5b8022feba2d94eeee5a84ba64f4212eedca42213" +checksum = "03b07a082330a35e43f63177cc01689da34fbffa0105e1246cf0311472cac73a" [[package]] name = "local_storage" version = "0.1.0" dependencies = [ - "fluence 0.4.2", + "fluence 0.5.0", "log", ] @@ -1756,6 +1814,15 @@ version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" +[[package]] +name = "pest" +version = "2.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10f4872ae94d7b90ae48754df22fd42ad52ce740b8f370b03da4835417403e53" +dependencies = [ + "ucd-trie", +] + [[package]] name = "pin-project" version = "1.0.5" @@ -1784,9 +1851,9 @@ checksum = "257b64915a082f7811703966789728173279bdebb956b143dbcd23f6f970a777" [[package]] name = "pin-project-lite" -version = "0.2.5" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0cf491442e4b033ed1c722cb9f0df5fcfcf4de682466c46469c36bc47dc5548a" +checksum = "dc0e1f259c92177c30a4c9d177246edd0a3568b25756a977d0632cf8fa37e905" [[package]] name = "pin-utils" @@ -1933,7 +2000,7 @@ dependencies = [ name = "record-effector" version = "0.1.0" dependencies = [ - "fluence 0.4.2", + "fluence 0.5.0", "test-record", ] @@ -1941,7 +2008,7 @@ dependencies = [ name = "record-pure" version = "0.1.0" dependencies = [ - "fluence 0.4.2", + "fluence 0.5.0", "test-record", ] @@ -1983,21 +2050,20 @@ dependencies = [ [[package]] name = "regex" -version = "1.4.3" +version = "1.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9251239e129e16308e70d853559389de218ac275b515068abc96829d05b948a" +checksum = "54fd1046a3107eb58f42de31d656fee6853e5d276c455fd943742dce89fc3dd3" dependencies = [ "aho-corasick", "memchr", "regex-syntax", - "thread_local", ] [[package]] name = "regex-syntax" -version = "0.6.22" +version = "0.6.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5eb417147ba9860a96cfe72a0b93bf88fee1744b5636ec99ab20c1aa9376581" +checksum = "24d5f089152e60f62d28b835fbff2cd2e8dc0baf1ac13343bef92ab7eed84548" [[package]] name = "remove_dir_all" @@ -2031,7 +2097,7 @@ dependencies = [ "mime_guess", "native-tls", "percent-encoding", - "pin-project-lite 0.2.5", + "pin-project-lite 0.2.6", "serde", "serde_urlencoded", "tokio", @@ -2067,7 +2133,7 @@ version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" dependencies = [ - "semver", + "semver 0.9.0", ] [[package]] @@ -2136,9 +2202,9 @@ checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" [[package]] name = "security-framework" -version = "2.1.1" +version = "2.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dfd318104249865096c8da1dfabf09ddbb6d0330ea176812a62ec75e40c4166" +checksum = "d493c5f39e02dfb062cd8f33301f90f9b13b650e8c1b1d0fd75c19dd64bff69d" dependencies = [ "bitflags", "core-foundation", @@ -2163,7 +2229,16 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" dependencies = [ - "semver-parser", + "semver-parser 0.7.0", +] + +[[package]] +name = "semver" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f301af10236f6df4160f7c3f04eec6dbc70ace82d23326abad5edee88801c6b6" +dependencies = [ + "semver-parser 0.10.2", ] [[package]] @@ -2172,6 +2247,15 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" +[[package]] +name = "semver-parser" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0bef5b7f9e0df16536d3961cfb6e84331c065b4066afb39768d0e319411f7" +dependencies = [ + "pest", +] + [[package]] name = "serde" version = "1.0.118" @@ -2314,9 +2398,9 @@ checksum = "1e81da0851ada1f3e9d4312c704aa4f8806f0f9d69faaf8df2f3464b4a9437c2" [[package]] name = "syn" -version = "1.0.60" +version = "1.0.63" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c700597eca8a5a762beb35753ef6b94df201c81cca676604f547495a0d7f0081" +checksum = "8fd9bc7ccc2688b3344c2f48b9b546648b25ce0b20fc717ee7fa7981a8ca9717" dependencies = [ "proc-macro2", "quote", @@ -2379,7 +2463,7 @@ dependencies = [ name = "test-record" version = "0.1.0" dependencies = [ - "fluence 0.4.2", + "fluence 0.5.0", ] [[package]] @@ -2530,7 +2614,7 @@ checksum = "01ebdc2bb4498ab1ab5f5b73c5803825e60199229ccba0698170e3be0e7f959f" dependencies = [ "cfg-if 1.0.0", "log", - "pin-project-lite 0.2.5", + "pin-project-lite 0.2.6", "tracing-core", ] @@ -2603,6 +2687,12 @@ dependencies = [ "syn", ] +[[package]] +name = "ucd-trie" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56dee185309b50d1f11bfedef0fe6d036842e3fb77413abef29f8f8d1c5d4c1c" + [[package]] name = "unicase" version = "2.6.0" @@ -2716,23 +2806,23 @@ dependencies = [ [[package]] name = "walrus" -version = "0.17.0" +version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f970863270179a4e0ca2bfb470931f883f7535ae8b9dac4271761fa1b77e253d" +checksum = "4d470d0583e65f4cab21a1ff3c1ba3dd23ae49e68f516f0afceaeb001b32af39" dependencies = [ "anyhow", "id-arena", "leb128", "log", "walrus-macro", - "wasmparser 0.55.0", + "wasmparser 0.59.0", ] [[package]] name = "walrus-macro" -version = "0.17.0" +version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80927fca8665132b48c7714bcec983d6e761c60b3a9877c6cd7df86417b13573" +checksum = "d7c2bb690b44cb1b0fdcc54d4998d21f8bdaf706b93775425e440b174f39ad16" dependencies = [ "heck", "proc-macro2", @@ -2834,7 +2924,7 @@ checksum = "7d6f8ec44822dd71f5f221a5847fb34acd9060535c1211b70a05844c0f6383b1" name = "wasm-greeting" version = "0.1.0" dependencies = [ - "fluence 0.4.2", + "fluence 0.5.0", ] [[package]] @@ -2842,7 +2932,7 @@ name = "wasm-sqlite-test" version = "0.1.0" dependencies = [ "fce-sqlite-connector", - "fluence 0.4.2", + "fluence 0.5.0", ] [[package]] @@ -3025,9 +3115,9 @@ checksum = "aeb1956b19469d1c5e63e459d29e7b5aa0f558d9f16fcef09736f8a265e6c10a" [[package]] name = "wasmparser" -version = "0.55.0" +version = "0.59.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af931e2e1960c53f4a28b063fec4cacd036f35acbec8ff3a4739125b17382a87" +checksum = "a950e6a618f62147fd514ff445b2a0b53120d382751960797f85f058c7eda9b9" [[package]] name = "wast" diff --git a/Cargo.toml b/Cargo.toml index f704bf5b..b206722f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,7 @@ [workspace] members = [ "aquamarine-vm", + "crates/module-info-parser", "crates/utils", "crates/wit-generator", "crates/wit-interfaces", diff --git a/crates/module-info-parser/Cargo.toml b/crates/module-info-parser/Cargo.toml new file mode 100644 index 00000000..d2bd7681 --- /dev/null +++ b/crates/module-info-parser/Cargo.toml @@ -0,0 +1,21 @@ +[package] +name = "fce-module-manifest-parser" +description = "Fluence FCE Wasm module manifest parser" +version = "0.1.0" +authors = ["Fluence Labs"] +license = "Apache-2.0" +edition = "2018" + +[lib] +name = "fce_module_manifest_parser" +path = "src/lib.rs" + +[dependencies] +fluence-sdk-main = "0.5.0" + +anyhow = "1.0.31" +walrus = "0.18.0" +semver = "0.11.0" + +serde = "=1.0.118" +thiserror = "1.0.24" diff --git a/crates/module-info-parser/src/custom_section_extractor.rs b/crates/module-info-parser/src/custom_section_extractor.rs new file mode 100644 index 00000000..272139ed --- /dev/null +++ b/crates/module-info-parser/src/custom_section_extractor.rs @@ -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>> { + 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::>(); + + Ok(sections) +} + +pub(super) fn try_as_one_section<'s>( + mut sections: Vec>, + section_name: &'static str, +) -> ModuleInfoResult> { + 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)) +} diff --git a/crates/module-info-parser/src/errors.rs b/crates/module-info-parser/src/errors.rs new file mode 100644 index 00000000..dda79e1b --- /dev/null +++ b/crates/module-info-parser/src/errors.rs @@ -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, +} diff --git a/crates/module-info-parser/src/lib.rs b/crates/module-info-parser/src/lib.rs new file mode 100644 index 00000000..06b07ff5 --- /dev/null +++ b/crates/module-info-parser/src/lib.rs @@ -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 = std::result::Result; diff --git a/crates/module-info-parser/src/manifest.rs b/crates/module-info-parser/src/manifest.rs new file mode 100644 index 00000000..c8df9824 --- /dev/null +++ b/crates/module-info-parser/src/manifest.rs @@ -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 = std::result::Result; + +impl TryFrom<&[u8]> for ModuleManifest { + type Error = ManifestError; + + #[rustfmt::skip] + fn try_from(value: &[u8]) -> Result { + 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::(); + +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 { + 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) + } +} diff --git a/crates/module-info-parser/src/manifest_extractor.rs b/crates/module-info-parser/src/manifest_extractor.rs new file mode 100644 index 00000000..312a3938 --- /dev/null +++ b/crates/module-info-parser/src/manifest_extractor.rs @@ -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> { + 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> { + 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)) +} diff --git a/crates/module-info-parser/src/tests.rs b/crates/module-info-parser/src/tests.rs new file mode 100644 index 00000000..946e9417 --- /dev/null +++ b/crates/module-info-parser/src/tests.rs @@ -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, +} + +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 { + 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 = 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 = array.as_bytes().try_into(); + let expected = Err(ManifestError::NotEnoughBytesForPrefix("repository")); + + assert_eq!(actual, expected); +} + +#[test] +fn test_with_empty_slice() { + let actual: Result = 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 = array.as_bytes().try_into(); + let expected = Err(ManifestError::NotEnoughBytesForField( + "repository", + too_big_size as usize, + )); + + assert_eq!(actual, expected); +} diff --git a/crates/module-info-parser/src/version_extractor.rs b/crates/module-info-parser/src/version_extractor.rs new file mode 100644 index 00000000..32c67aed --- /dev/null +++ b/crates/module-info-parser/src/version_extractor.rs @@ -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> { + 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> { + 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 { + match std::str::from_utf8(version_as_bytes) { + Ok(str) => Ok(semver::Version::from_str(str)?), + Err(e) => Err(SDKVersionError::VersionNotValidUtf8(e)), + } +} diff --git a/crates/wit-generator/Cargo.toml b/crates/wit-generator/Cargo.toml index bf62133a..48c6004c 100644 --- a/crates/wit-generator/Cargo.toml +++ b/crates/wit-generator/Cargo.toml @@ -12,9 +12,9 @@ path = "src/lib.rs" [dependencies] fce-wit-parser = { path = "../wit-parser", version = "0.2.0"} -fluence-sdk-wit = "=0.4.2" +fluence-sdk-wit = "=0.5.0" -walrus = "0.17.0" +walrus = "0.18.0" wasmer-wit = { package = "wasmer-interface-types-fl", version = "=0.17.24" } once_cell = "1.4.0" serde = { version = "=1.0.118", features = ["derive"] } diff --git a/crates/wit-parser/Cargo.toml b/crates/wit-parser/Cargo.toml index c1f6fc69..b4bee0e2 100644 --- a/crates/wit-parser/Cargo.toml +++ b/crates/wit-parser/Cargo.toml @@ -14,8 +14,9 @@ path = "src/lib.rs" fce-wit-interfaces = { path = "../wit-interfaces", version = "0.1.29" } anyhow = "1.0.31" -walrus = "0.17.0" +walrus = "0.18.0" wasmer-core = { package = "wasmer-runtime-core-fl", version = "0.17.0"} wasmer-wit = { package = "wasmer-interface-types-fl", version = "=0.17.24" } serde = "=1.0.118" +thiserror = "1.0.24" diff --git a/crates/wit-parser/src/custom.rs b/crates/wit-parser/src/custom.rs index 8d318725..854459cf 100644 --- a/crates/wit-parser/src/custom.rs +++ b/crates/wit-parser/src/custom.rs @@ -14,17 +14,19 @@ * limitations under the License. */ -use std::borrow::Cow; -use walrus::{CustomSection, IdsToIndices}; +use walrus::CustomSection; +use walrus::IdsToIndices; -pub const WIT_SECTION_NAME: &str = "interface-types"; +use std::borrow::Cow; + +pub const IT_SECTION_NAME: &str = "interface-types"; #[derive(Debug, Clone)] -pub(super) struct WITCustom(pub Vec); +pub(super) struct ITCustomSection(pub Vec); -impl CustomSection for WITCustom { +impl CustomSection for ITCustomSection { fn name(&self) -> &str { - WIT_SECTION_NAME + IT_SECTION_NAME } fn data(&self, _ids_to_indices: &IdsToIndices) -> Cow<'_, [u8]> { diff --git a/crates/wit-parser/src/deleter.rs b/crates/wit-parser/src/deleter.rs index b252db4f..060f46e1 100644 --- a/crates/wit-parser/src/deleter.rs +++ b/crates/wit-parser/src/deleter.rs @@ -15,7 +15,7 @@ */ use super::errors::WITParserError; -use super::custom::WIT_SECTION_NAME; +use super::custom::IT_SECTION_NAME; use walrus::ModuleConfig; @@ -45,7 +45,7 @@ pub fn delete_wit_section(mut wasm_module: walrus::Module) -> walrus::Module { .customs .iter() .filter_map(|(id, section)| { - if section.name() == WIT_SECTION_NAME { + if section.name() == IT_SECTION_NAME { Some(id) } else { None diff --git a/crates/wit-parser/src/embedder.rs b/crates/wit-parser/src/embedder.rs index c00003cf..ee48a447 100644 --- a/crates/wit-parser/src/embedder.rs +++ b/crates/wit-parser/src/embedder.rs @@ -14,8 +14,9 @@ * limitations under the License. */ -use super::custom::WITCustom; +use super::custom::ITCustomSection; use super::errors::WITParserError; +use crate::Result; use walrus::ModuleConfig; use wasmer_wit::{ @@ -27,11 +28,7 @@ use wasmer_wit::ToBytes; use std::path::PathBuf; /// Embed provided WIT to a Wasm file by path. -pub fn embed_text_wit( - in_wasm_path: PathBuf, - out_wasm_path: PathBuf, - wit: &str, -) -> Result<(), WITParserError> { +pub fn embed_text_wit(in_wasm_path: PathBuf, out_wasm_path: PathBuf, wit: &str) -> Result<()> { let module = ModuleConfig::new() .parse_file(&in_wasm_path) .map_err(WITParserError::CorruptedWasmFile)?; @@ -53,7 +50,7 @@ pub fn embed_wit(mut wasm_module: walrus::Module, interfaces: &Interfaces<'_>) - // TODO: think about possible errors here interfaces.to_bytes(&mut bytes).unwrap(); - let custom = WITCustom(bytes); + let custom = ITCustomSection(bytes); wasm_module.customs.add(custom); wasm_module diff --git a/crates/wit-parser/src/errors.rs b/crates/wit-parser/src/errors.rs index dbe158f6..df246e25 100644 --- a/crates/wit-parser/src/errors.rs +++ b/crates/wit-parser/src/errors.rs @@ -15,77 +15,57 @@ */ use wasmer_wit::decoders::wat::Error as WATError; -use std::io::Error as StdIOError; -use std::error::Error; +use thiserror::Error as ThisError; -#[derive(Debug)] +use std::io::Error as IOError; + +#[derive(Debug, ThisError)] pub enum WITParserError { /// WIT section is absent. - NoWITSection, + #[error("the module doesn't contain IT section")] + NoITSection, /// Multiple WIT sections. - MultipleWITSections, + #[error("the module contains multiple IT sections that is unsupported")] + MultipleITSections, /// WIT section remainder isn't empty. - WITRemainderNotEmpty, + #[error("IT section is corrupted: IT section remainder isn't empty")] + ITRemainderNotEmpty, /// An error occurred while parsing WIT section. - CorruptedWITSection, + #[error("IT section is corrupted")] + CorruptedITSection, - // An error related to incorrect wit section. - IncorrectWIT(String), + /// An error related to incorrect data of wit section. + #[error("{0}")] + IncorrectITFormat(String), /// An error occurred while parsing file in Wat format. - CorruptedWATFile(WATError), + #[error("provided file with IT definitions is corrupted: {0}")] + CorruptedITFile(WATError), - /// An error occurred while parsing Wasm file + /// An error occurred while parsing Wasm file. + #[error("provided Wasm file is corrupted: {0}")] CorruptedWasmFile(anyhow::Error), /// An error occurred while manipulating with converting ast to bytes. - AstToBytesError(StdIOError), + #[error("Convertation Wast to AST failed with: {0}")] + AstToBytesError(IOError), - // Wasm emittig file error. + /// Wasm emitting file error. + #[error("Emitting resulted Wasm file failed with: {0}")] WasmEmitError(anyhow::Error), } -impl Error for WITParserError {} - -impl std::fmt::Display for WITParserError { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> { - match self { - WITParserError::NoWITSection => write!(f, "Loaded module doesn't contain WIT section"), - WITParserError::MultipleWITSections => write!( - f, - "Loaded module contains multiple WIT sections that is unsupported now" - ), - WITParserError::WITRemainderNotEmpty => write!( - f, - "WIT section remainder isn't empty - WIT section possibly corrupted" - ), - WITParserError::IncorrectWIT(err_msg) => write!(f, "{}", err_msg), - WITParserError::CorruptedWITSection => write!(f, "WIT section is corrupted"), - WITParserError::CorruptedWATFile(err) => { - write!(f, "an error occurred while parsing wat file: {}", err) - } - WITParserError::CorruptedWasmFile(err) => { - write!(f, "Failed to parse the Wasm module: {}", err) - } - WITParserError::AstToBytesError(err) => { - write!(f, "Wasm AST converting to bytes failed with: {}", err) - } - WITParserError::WasmEmitError(err) => write!(f, "Failed to emit Wasm file: {}", err), - } - } -} - impl From for WITParserError { fn from(err: WATError) -> Self { - WITParserError::CorruptedWATFile(err) + WITParserError::CorruptedITFile(err) } } -impl From for WITParserError { - fn from(err: StdIOError) -> Self { +impl From for WITParserError { + fn from(err: IOError) -> Self { WITParserError::AstToBytesError(err) } } diff --git a/crates/wit-parser/src/extractor.rs b/crates/wit-parser/src/extractor.rs index 64ab4724..74269701 100644 --- a/crates/wit-parser/src/extractor.rs +++ b/crates/wit-parser/src/extractor.rs @@ -26,8 +26,8 @@ use std::path::Path; pub fn module_interface(module_path: &Path) -> Result { use fce_wit_interfaces::FCEWITInterfaces; - let wit_section_bytes = extract_wit_section_bytes(module_path)?; - let wit = extract_wit_with_fn(&wit_section_bytes)?; + let wit_section_bytes = extract_custom_section(module_path)?; + let wit = extract_wit_from_bytes(&wit_section_bytes)?; let fce_interface = FCEWITInterfaces::new(wit); get_interface(&fce_interface) diff --git a/crates/wit-parser/src/extractor/functions.rs b/crates/wit-parser/src/extractor/functions.rs index be154948..76644d8c 100644 --- a/crates/wit-parser/src/extractor/functions.rs +++ b/crates/wit-parser/src/extractor/functions.rs @@ -88,7 +88,7 @@ fn get_exports(wit: &FCEWITInterfaces<'_>) -> Result> }; Ok(signature) } - _ => Err(WITParserError::IncorrectWIT(format!( + _ => Err(WITParserError::IncorrectITFormat(format!( "type with idx = {} isn't a function type", adapter_function_type ))), diff --git a/crates/wit-parser/src/extractor/wit.rs b/crates/wit-parser/src/extractor/wit.rs index ccca43bc..9eabaec8 100644 --- a/crates/wit-parser/src/extractor/wit.rs +++ b/crates/wit-parser/src/extractor/wit.rs @@ -14,8 +14,9 @@ * limitations under the License. */ -use crate::custom::WIT_SECTION_NAME; +use crate::custom::IT_SECTION_NAME; use crate::errors::WITParserError; +use crate::Result; use walrus::{IdsToIndices, ModuleConfig}; use wasmer_wit::ast::Interfaces; @@ -24,36 +25,34 @@ use wasmer_core::Module as WasmerModule; use std::path::Path; /// Extracts WIT section of provided Wasm binary and converts it to a string. -pub fn extract_text_wit(wasm_file_path: &Path) -> Result { - let wit_section_bytes = extract_wit_section_bytes(&wasm_file_path)?; - let wit = extract_wit_with_fn(&wit_section_bytes)?; +pub fn extract_text_wit(wasm_file_path: &Path) -> Result { + let wit_section_bytes = extract_custom_section(&wasm_file_path)?; + let wit = extract_wit_from_bytes(&wit_section_bytes)?; Ok((&wit).to_string()) } /// Extracts WIT section of provided Wasm binary and converts it to a FCEWITInterfaces. -pub fn extract_wit(wasmer_module: &WasmerModule) -> Result, WITParserError> { +pub fn extract_wit(wasmer_module: &WasmerModule) -> Result> { let wit_sections = wasmer_module - .custom_sections(WIT_SECTION_NAME) - .ok_or(WITParserError::NoWITSection)?; + .custom_sections(IT_SECTION_NAME) + .ok_or(WITParserError::NoITSection)?; if wit_sections.len() > 1 { - return Err(WITParserError::MultipleWITSections); + return Err(WITParserError::MultipleITSections); } - extract_wit_with_fn(&wit_sections[0]) + extract_wit_from_bytes(&wit_sections[0]) } -pub(crate) fn extract_wit_with_fn( - wit_section_bytes: &[u8], -) -> Result, WITParserError> { - match wasmer_wit::decoders::binary::parse::<()>(&wit_section_bytes) { +pub(crate) fn extract_wit_from_bytes(wit_section_bytes: &[u8]) -> Result> { + match wasmer_wit::decoders::binary::parse::<()>(wit_section_bytes) { Ok((remainder, wit)) if remainder.is_empty() => Ok(wit), - Ok(_) => Err(WITParserError::WITRemainderNotEmpty), - Err(_) => Err(WITParserError::CorruptedWITSection), + Ok(_) => Err(WITParserError::ITRemainderNotEmpty), + Err(_) => Err(WITParserError::CorruptedITSection), } } -pub(crate) fn extract_wit_section_bytes(wasm_file_path: &Path) -> Result, WITParserError> { +pub(crate) fn extract_custom_section(wasm_file_path: &Path) -> Result> { let module = ModuleConfig::new() .parse_file(wasm_file_path) .map_err(WITParserError::CorruptedWasmFile)?; @@ -61,14 +60,14 @@ pub(crate) fn extract_wit_section_bytes(wasm_file_path: &Path) -> Result let sections = module .customs .iter() - .filter(|(_, section)| section.name() == WIT_SECTION_NAME) + .filter(|(_, section)| section.name() == IT_SECTION_NAME) .collect::>(); if sections.is_empty() { - return Err(WITParserError::NoWITSection); + return Err(WITParserError::NoITSection); } if sections.len() > 1 { - return Err(WITParserError::MultipleWITSections); + return Err(WITParserError::MultipleITSections); } let default_ids = IdsToIndices::default(); diff --git a/examples/call_parameters/Cargo.toml b/examples/call_parameters/Cargo.toml index cfe2047c..e8a115fd 100644 --- a/examples/call_parameters/Cargo.toml +++ b/examples/call_parameters/Cargo.toml @@ -10,4 +10,4 @@ name = "call_parameters" path = "src/main.rs" [dependencies] -fluence = "=0.4.2" +fluence = "=0.5.0" diff --git a/examples/call_parameters/artifacts/call_parameters.wasm b/examples/call_parameters/artifacts/call_parameters.wasm index 22c28f2d..e7c48982 100755 Binary files a/examples/call_parameters/artifacts/call_parameters.wasm and b/examples/call_parameters/artifacts/call_parameters.wasm differ diff --git a/examples/greeting/Cargo.toml b/examples/greeting/Cargo.toml index c49273de..5159f292 100644 --- a/examples/greeting/Cargo.toml +++ b/examples/greeting/Cargo.toml @@ -2,6 +2,8 @@ name = "wasm-greeting" version = "0.1.0" authors = ["Fluence Labs"] +description = "The greeting module for the Fluence network" +repository = "https://github.com/fluencelabs/fce/tree/master/examples/greeting" edition = "2018" publish = false @@ -10,4 +12,4 @@ name = "greeting" path = "src/main.rs" [dependencies] -fluence = "=0.4.2" +fluence = "0.5.0" diff --git a/examples/greeting/artifacts/greeting.wasm b/examples/greeting/artifacts/greeting.wasm index 511bbf2b..dd26f263 100755 Binary files a/examples/greeting/artifacts/greeting.wasm and b/examples/greeting/artifacts/greeting.wasm differ diff --git a/examples/greeting/src/main.rs b/examples/greeting/src/main.rs index dcf27182..bfee80eb 100644 --- a/examples/greeting/src/main.rs +++ b/examples/greeting/src/main.rs @@ -15,6 +15,9 @@ */ use fluence::fce; +use fluence::module_manifest; + +module_manifest!(); pub fn main() {} diff --git a/examples/ipfs-node/artifacts/ipfs_effector.wasm b/examples/ipfs-node/artifacts/ipfs_effector.wasm index 89842bd3..730598bd 100755 Binary files a/examples/ipfs-node/artifacts/ipfs_effector.wasm and b/examples/ipfs-node/artifacts/ipfs_effector.wasm differ diff --git a/examples/ipfs-node/artifacts/ipfs_pure.wasm b/examples/ipfs-node/artifacts/ipfs_pure.wasm index aa83539d..6dccb063 100755 Binary files a/examples/ipfs-node/artifacts/ipfs_pure.wasm and b/examples/ipfs-node/artifacts/ipfs_pure.wasm differ diff --git a/examples/ipfs-node/effector/Cargo.toml b/examples/ipfs-node/effector/Cargo.toml index 5a2f6072..0ce45df1 100644 --- a/examples/ipfs-node/effector/Cargo.toml +++ b/examples/ipfs-node/effector/Cargo.toml @@ -10,5 +10,5 @@ name = "ipfs_effector" path = "src/main.rs" [dependencies] -fluence = { version = "=0.4.2", features = ["logger"] } +fluence = { version = "=0.5.0", features = ["logger"] } log = "0.4.14" diff --git a/examples/ipfs-node/effector/src/main.rs b/examples/ipfs-node/effector/src/main.rs index e3163fdd..dcea1e46 100644 --- a/examples/ipfs-node/effector/src/main.rs +++ b/examples/ipfs-node/effector/src/main.rs @@ -21,6 +21,7 @@ mod path; use crate::path::to_full_path; use fluence::fce; +use fluence::module_manifest; use fluence::WasmLoggerBuilder; use fluence::MountedBinaryResult; @@ -28,6 +29,8 @@ const RESULT_FILE_PATH: &str = "/tmp/ipfs_rpc_file"; const IPFS_ADDR_ENV_NAME: &str = "IPFS_ADDR"; const TIMEOUT_ENV_NAME: &str = "timeout"; +module_manifest!(); + pub fn main() { WasmLoggerBuilder::new() .with_log_level(log::LevelFilter::Info) diff --git a/examples/ipfs-node/pure/Cargo.toml b/examples/ipfs-node/pure/Cargo.toml index 0bf3f6b2..4712c7ce 100644 --- a/examples/ipfs-node/pure/Cargo.toml +++ b/examples/ipfs-node/pure/Cargo.toml @@ -10,5 +10,5 @@ name = "ipfs_pure" path = "src/main.rs" [dependencies] -fluence = { version = "=0.4.2", features = ["logger"] } +fluence = { version = "=0.5.0", features = ["logger"] } log = "0.4.14" diff --git a/examples/ipfs-node/pure/src/main.rs b/examples/ipfs-node/pure/src/main.rs index 8454a6ec..98c0c683 100644 --- a/examples/ipfs-node/pure/src/main.rs +++ b/examples/ipfs-node/pure/src/main.rs @@ -17,6 +17,7 @@ #![allow(improper_ctypes)] use fluence::fce; +use fluence::module_manifest; use fluence::WasmLoggerBuilder; use std::fs; @@ -24,6 +25,8 @@ use std::path::PathBuf; const RPC_TMP_FILEPATH: &str = "/tmp/ipfs_rpc_file"; +module_manifest!(); + pub fn main() { WasmLoggerBuilder::new() .with_log_level(log::LevelFilter::Info) diff --git a/examples/records/artifacts/records_effector.wasm b/examples/records/artifacts/records_effector.wasm index 928c3b40..a6091425 100755 Binary files a/examples/records/artifacts/records_effector.wasm and b/examples/records/artifacts/records_effector.wasm differ diff --git a/examples/records/artifacts/records_pure.wasm b/examples/records/artifacts/records_pure.wasm index 68f23595..3d4579cd 100755 Binary files a/examples/records/artifacts/records_pure.wasm and b/examples/records/artifacts/records_pure.wasm differ diff --git a/examples/records/effector/Cargo.toml b/examples/records/effector/Cargo.toml index 4ca8967b..2ee8518d 100644 --- a/examples/records/effector/Cargo.toml +++ b/examples/records/effector/Cargo.toml @@ -10,5 +10,5 @@ name = "records_effector" path = "src/main.rs" [dependencies] -fluence = { version = "=0.4.2", features = ["logger"]} +fluence = { version = "=0.5.0", features = ["logger"]} test-record = { path = "../test-record" } diff --git a/examples/records/effector/src/main.rs b/examples/records/effector/src/main.rs index 9ff05b32..9973b2c8 100644 --- a/examples/records/effector/src/main.rs +++ b/examples/records/effector/src/main.rs @@ -15,8 +15,12 @@ */ use fluence::fce; +use fluence::module_manifest; + use test_record::TestRecord; +module_manifest!(); + pub fn main() {} #[fce] diff --git a/examples/records/pure/Cargo.toml b/examples/records/pure/Cargo.toml index d0eecf3f..07e3fdc6 100644 --- a/examples/records/pure/Cargo.toml +++ b/examples/records/pure/Cargo.toml @@ -10,5 +10,5 @@ name = "records_pure" path = "src/main.rs" [dependencies] -fluence = { version = "=0.4.2", features = ["logger"]} +fluence = { version = "=0.5.0", features = ["logger"]} test-record = { path = "../test-record" } diff --git a/examples/records/pure/src/main.rs b/examples/records/pure/src/main.rs index e9c0daad..2e1f3b67 100644 --- a/examples/records/pure/src/main.rs +++ b/examples/records/pure/src/main.rs @@ -17,8 +17,12 @@ #![allow(improper_ctypes)] use fluence::fce; +use fluence::module_manifest; + use test_record::TestRecord; +module_manifest!(); + pub fn main() {} #[fce] diff --git a/examples/records/test-record/Cargo.toml b/examples/records/test-record/Cargo.toml index d26348da..b7979b7f 100644 --- a/examples/records/test-record/Cargo.toml +++ b/examples/records/test-record/Cargo.toml @@ -10,4 +10,4 @@ name = "test_record" path = "src/test_record.rs" [dependencies] -fluence = "=0.4.2" +fluence = "=0.5.0" diff --git a/examples/sqlite/Cargo.toml b/examples/sqlite/Cargo.toml index 99ff645b..615db8cd 100644 --- a/examples/sqlite/Cargo.toml +++ b/examples/sqlite/Cargo.toml @@ -10,5 +10,5 @@ name = "sqlite_test" path = "src/main.rs" [dependencies] -fluence = "0.4.2" +fluence = "0.5.0" fce-sqlite-connector = "0.2.0" diff --git a/examples/sqlite/src/main.rs b/examples/sqlite/src/main.rs index eae11e65..2e137825 100644 --- a/examples/sqlite/src/main.rs +++ b/examples/sqlite/src/main.rs @@ -15,9 +15,13 @@ */ use fluence::fce; +use fluence::module_manifest; + use fce_sqlite_connector; use fce_sqlite_connector::State; +module_manifest!(); + pub fn main() {} #[fce] diff --git a/examples/url-downloader/artifacts/curl_adapter.wasm b/examples/url-downloader/artifacts/curl_adapter.wasm index 32da82ca..13c1e113 100755 Binary files a/examples/url-downloader/artifacts/curl_adapter.wasm and b/examples/url-downloader/artifacts/curl_adapter.wasm differ diff --git a/examples/url-downloader/artifacts/facade.wasm b/examples/url-downloader/artifacts/facade.wasm index 681e63af..bf18123c 100755 Binary files a/examples/url-downloader/artifacts/facade.wasm and b/examples/url-downloader/artifacts/facade.wasm differ diff --git a/examples/url-downloader/artifacts/local_storage.wasm b/examples/url-downloader/artifacts/local_storage.wasm index ca946751..fd8aaa0b 100755 Binary files a/examples/url-downloader/artifacts/local_storage.wasm and b/examples/url-downloader/artifacts/local_storage.wasm differ diff --git a/examples/url-downloader/curl_adapter/Cargo.toml b/examples/url-downloader/curl_adapter/Cargo.toml index c029a8f8..5080e66a 100644 --- a/examples/url-downloader/curl_adapter/Cargo.toml +++ b/examples/url-downloader/curl_adapter/Cargo.toml @@ -10,5 +10,5 @@ path = "src/main.rs" name = "curl_adapter" [dependencies] -fluence = { version = "=0.4.2", features = ["logger"] } +fluence = { version = "=0.5.0", features = ["logger"] } log = "0.4.8" diff --git a/examples/url-downloader/curl_adapter/src/main.rs b/examples/url-downloader/curl_adapter/src/main.rs index 66df238d..c3e6acc5 100644 --- a/examples/url-downloader/curl_adapter/src/main.rs +++ b/examples/url-downloader/curl_adapter/src/main.rs @@ -17,10 +17,13 @@ #![allow(improper_ctypes)] use fluence::fce; +use fluence::module_manifest; use fluence::WasmLoggerBuilder; use fluence::MountedBinaryResult; +module_manifest!(); + /// Log level can be changed by `RUST_LOG` env as well. pub fn main() { WasmLoggerBuilder::new().build().unwrap(); diff --git a/examples/url-downloader/facade/Cargo.toml b/examples/url-downloader/facade/Cargo.toml index 6a0123e2..d40090f7 100644 --- a/examples/url-downloader/facade/Cargo.toml +++ b/examples/url-downloader/facade/Cargo.toml @@ -10,6 +10,6 @@ name = "facade" path = "src/main.rs" [dependencies] -fluence = { version = "=0.4.2", features = ["logger"]} +fluence = { version = "=0.5.0", features = ["logger"]} anyhow = "1.0.31" log = "0.4.8" diff --git a/examples/url-downloader/facade/src/main.rs b/examples/url-downloader/facade/src/main.rs index 3b2fedc6..8ff919b8 100644 --- a/examples/url-downloader/facade/src/main.rs +++ b/examples/url-downloader/facade/src/main.rs @@ -16,8 +16,11 @@ #![allow(improper_ctypes)] use fluence::fce; +use fluence::module_manifest; use fluence::WasmLoggerBuilder; +module_manifest!(); + pub fn main() { WasmLoggerBuilder::new().build().unwrap(); } diff --git a/examples/url-downloader/local_storage/Cargo.toml b/examples/url-downloader/local_storage/Cargo.toml index 1120da76..c89e8b4b 100644 --- a/examples/url-downloader/local_storage/Cargo.toml +++ b/examples/url-downloader/local_storage/Cargo.toml @@ -10,5 +10,5 @@ name = "local_storage" path = "src/main.rs" [dependencies] -fluence = { version = "=0.4.2", features = ["logger"]} +fluence = { version = "=0.5.0", features = ["logger"]} log = "0.4.8" diff --git a/examples/url-downloader/local_storage/src/main.rs b/examples/url-downloader/local_storage/src/main.rs index 015ddc9c..8f6dabb0 100644 --- a/examples/url-downloader/local_storage/src/main.rs +++ b/examples/url-downloader/local_storage/src/main.rs @@ -14,11 +14,15 @@ * limitations under the License. */ -use std::fs; use fluence::fce; +use fluence::module_manifest; use fluence::WasmLoggerBuilder; + +use std::fs; use std::path::PathBuf; +module_manifest!(); + const SITES_DIR: &str = "/sites/"; /// Log level can be changed by `RUST_LOG` env as well. diff --git a/fluence-faas/Cargo.toml b/fluence-faas/Cargo.toml index 7221e0b7..7f6feb9a 100644 --- a/fluence-faas/Cargo.toml +++ b/fluence-faas/Cargo.toml @@ -9,7 +9,7 @@ edition = "2018" [dependencies] fce = { path = "../engine", version = "0.3.0" } fce-utils = { path = "../crates/utils", version = "0.1.29" } -fluence-sdk-main = { version = "0.4.2", features = ["logger"] } +fluence-sdk-main = { version = "0.5.0", features = ["logger"] } wasmer-runtime = { package = "wasmer-runtime-fl", version = "0.17.0" } # dynamicfunc-fat-closures allows using state inside DynamicFunc diff --git a/fluence-faas/tests/wasm_tests/arguments_passing/Cargo.toml b/fluence-faas/tests/wasm_tests/arguments_passing/Cargo.toml index 0dac9b76..f81c1937 100644 --- a/fluence-faas/tests/wasm_tests/arguments_passing/Cargo.toml +++ b/fluence-faas/tests/wasm_tests/arguments_passing/Cargo.toml @@ -14,5 +14,5 @@ name = "arguments_passing_effector" path = "src/effector.rs" [dependencies] -fluence = "=0.4.2" +fluence = "=0.5.0" safe-transmute = "0.11.0" diff --git a/fluence-faas/tests/wasm_tests/arrays_passing/Cargo.toml b/fluence-faas/tests/wasm_tests/arrays_passing/Cargo.toml index ad5fb1dc..55361fb6 100644 --- a/fluence-faas/tests/wasm_tests/arrays_passing/Cargo.toml +++ b/fluence-faas/tests/wasm_tests/arrays_passing/Cargo.toml @@ -14,5 +14,5 @@ name = "arrays_passing_effector" path = "src/effector.rs" [dependencies] -fluence = "=0.4.2" +fluence = "=0.5.0" safe-transmute = "0.11.0" diff --git a/fluence-faas/tests/wasm_tests/inner_records/Cargo.toml b/fluence-faas/tests/wasm_tests/inner_records/Cargo.toml index aac0cf5d..7f75653b 100644 --- a/fluence-faas/tests/wasm_tests/inner_records/Cargo.toml +++ b/fluence-faas/tests/wasm_tests/inner_records/Cargo.toml @@ -10,5 +10,5 @@ name = "inner_records_pure" path = "src/pure.rs" [dependencies] -fluence = "=0.4.2" +fluence = "=0.5.0" safe-transmute = "0.11.0" diff --git a/tools/cli/Cargo.toml b/tools/cli/Cargo.toml index 176d2708..0d36d6f9 100644 --- a/tools/cli/Cargo.toml +++ b/tools/cli/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "fcli" description = "Fluence FCE command line tool" -version = "0.2.0" +version = "0.3.0" authors = ["Fluence Labs"] repository = "https://github.com/fluencelabs/fce/tools/cli" license = "Apache-2.0" @@ -14,6 +14,7 @@ path = "src/main.rs" [dependencies] fce-wit-generator = { path = "../../crates/wit-generator", version = "0.2.0" } fce-wit-parser = { path = "../../crates/wit-parser", version = "0.2.0" } +fce-module-manifest-parser = { path = "../../crates/module-info-parser", version = "0.1.0" } anyhow = "1.0.31" clap = "2.33.1" diff --git a/tools/cli/src/args.rs b/tools/cli/src/args.rs index a2df7583..8f3fd930 100644 --- a/tools/cli/src/args.rs +++ b/tools/cli/src/args.rs @@ -34,7 +34,7 @@ pub fn build<'a, 'b>() -> App<'a, 'b> { pub fn embed_wit<'a, 'b>() -> App<'a, 'b> { SubCommand::with_name("embed") - .about("Embed IT to a provided Wasm file") + .about("Embed IT to the provided Wasm file") .args(&[ Arg::with_name(IN_WASM_PATH) .required(true) @@ -54,8 +54,19 @@ pub fn embed_wit<'a, 'b>() -> App<'a, 'b> { } pub fn show_wit<'a, 'b>() -> App<'a, 'b> { - SubCommand::with_name("show") - .about("Show IT of provided Wasm file") + SubCommand::with_name("it") + .about("Show IT of the provided Wasm file") + .setting(clap::AppSettings::ArgRequiredElseHelp) + .args(&[Arg::with_name(IN_WASM_PATH) + .required(true) + .takes_value(true) + .short("i") + .help("path to the Wasm file")]) +} + +pub fn show_manifest<'a, 'b>() -> App<'a, 'b> { + SubCommand::with_name("info") + .about("Show manifest and sdk version of the provided Wasm file") .setting(clap::AppSettings::ArgRequiredElseHelp) .args(&[Arg::with_name(IN_WASM_PATH) .required(true) diff --git a/tools/cli/src/build.rs b/tools/cli/src/build.rs index 393bb506..e102e822 100644 --- a/tools/cli/src/build.rs +++ b/tools/cli/src/build.rs @@ -14,7 +14,7 @@ * limitations under the License. */ -use crate::Result; +use crate::CLIResult; use crate::errors::CLIError; use std::process::Command; @@ -28,7 +28,7 @@ enum DiagnosticMessage { RunWithArgs, } -pub(crate) fn build(trailing_args: Vec<&str>) -> Result<()> { +pub(crate) fn build(trailing_args: Vec<&str>) -> CLIResult<()> { use std::io::Read; let mut cargo = Command::new("cargo"); diff --git a/tools/cli/src/main.rs b/tools/cli/src/main.rs index af1e3fa8..cfaeda05 100644 --- a/tools/cli/src/main.rs +++ b/tools/cli/src/main.rs @@ -29,73 +29,103 @@ mod args; mod build; mod errors; -pub(crate) type Result = std::result::Result; +pub(crate) type CLIResult = std::result::Result; -pub fn main() -> std::result::Result<(), anyhow::Error> { +pub fn main() -> Result<(), anyhow::Error> { let app = clap::App::new(args::DESCRIPTION) .version(args::VERSION) .author(args::AUTHORS) .setting(clap::AppSettings::ArgRequiredElseHelp) .subcommand(args::build()) .subcommand(args::embed_wit()) + .subcommand(args::show_manifest()) .subcommand(args::show_wit()) .subcommand(args::repl()); let arg_matches = app.get_matches(); match arg_matches.subcommand() { - ("build", Some(args)) => { - let trailing_args: Vec<&str> = args.values_of("optional").unwrap_or_default().collect(); - - crate::build::build(trailing_args)?; - - Ok(()) - } - ("embed", Some(arg)) => { - let in_wasm_path = arg.value_of(args::IN_WASM_PATH).unwrap(); - let wit_path = arg.value_of(args::WIT_PATH).unwrap(); - let out_wasm_path = match arg.value_of(args::OUT_WASM_PATH) { - Some(path) => path, - None => in_wasm_path, - }; - - let wit = String::from_utf8(std::fs::read(wit_path)?).unwrap(); - - fce_wit_parser::embed_text_wit( - std::path::PathBuf::from(in_wasm_path), - std::path::PathBuf::from(out_wasm_path), - &wit, - )?; - - Ok(()) - } - ("show", Some(arg)) => { - let wasm_path = arg.value_of(args::IN_WASM_PATH).unwrap(); - let wasm_path = std::path::Path::new(wasm_path); - - let result = fce_wit_parser::extract_text_wit(&wasm_path)?; - println!("{}", result); - - Ok(()) - } - ("repl", Some(args)) => { - use std::process::Command; - // use UNIX-specific API for replacing process image - use std::os::unix::process::CommandExt; - - let trailing_args: Vec<&str> = args.values_of("optional").unwrap_or_default().collect(); - - let mut repl = Command::new("fce-repl"); - repl.args(trailing_args); - let error = repl.exec(); - if error.kind() == std::io::ErrorKind::NotFound { - println!("fce-repl not found, run `cargo +nightly install frepl` to install it"); - } else { - // this branch should be executed if exec was successful, so just else if fine here - println!("error occurred: {:?}", error); - } - - Ok(()) - } - c => Err(crate::errors::CLIError::NoSuchCommand(c.0.to_string()).into()), + ("build", Some(args)) => build(args), + ("embed", Some(args)) => embed(args), + ("it", Some(args)) => it(args), + ("info", Some(args)) => info(args), + ("repl", Some(args)) => repl(args), + (c, _) => Err(crate::errors::CLIError::NoSuchCommand(c.to_string()).into()), } } + +fn build(args: &clap::ArgMatches<'_>) -> Result<(), anyhow::Error> { + let trailing_args: Vec<&str> = args.values_of("optional").unwrap_or_default().collect(); + + crate::build::build(trailing_args)?; + + Ok(()) +} + +fn embed(args: &clap::ArgMatches<'_>) -> Result<(), anyhow::Error> { + let in_wasm_path = args.value_of(args::IN_WASM_PATH).unwrap(); + let wit_path = args.value_of(args::WIT_PATH).unwrap(); + let out_wasm_path = match args.value_of(args::OUT_WASM_PATH) { + Some(path) => path, + None => in_wasm_path, + }; + + let wit = String::from_utf8(std::fs::read(wit_path)?).unwrap(); + + fce_wit_parser::embed_text_wit( + std::path::PathBuf::from(in_wasm_path), + std::path::PathBuf::from(out_wasm_path), + &wit, + )?; + + Ok(()) +} + +fn it(args: &clap::ArgMatches<'_>) -> Result<(), anyhow::Error> { + let wasm_path = args.value_of(args::IN_WASM_PATH).unwrap(); + let wasm_path = std::path::Path::new(wasm_path); + + let it = fce_wit_parser::extract_text_wit(&wasm_path)?; + println!("{}", it); + + Ok(()) +} + +fn info(args: &clap::ArgMatches<'_>) -> Result<(), anyhow::Error> { + let wasm_path = args.value_of(args::IN_WASM_PATH).unwrap(); + let wasm_path = std::path::Path::new(wasm_path); + + let sdk_version = fce_module_manifest_parser::extract_sdk_version_by_path(&wasm_path)?; + let module_manifest = fce_module_manifest_parser::extract_manifest_by_path(&wasm_path)?; + + match sdk_version { + Some(sdk_version) => println!("sdk version: {}", sdk_version), + None => println!("module doesn't contain sdk version"), + } + + match module_manifest { + Some(manifest) => println!("{}", manifest), + None => println!("module doesn't contain module manifest"), + } + + Ok(()) +} + +fn repl(args: &clap::ArgMatches<'_>) -> Result<(), anyhow::Error> { + use std::process::Command; + // use UNIX-specific API for replacing process image + use std::os::unix::process::CommandExt; + + let trailing_args: Vec<&str> = args.values_of("optional").unwrap_or_default().collect(); + + let mut repl = Command::new("fce-repl"); + repl.args(trailing_args); + let error = repl.exec(); + if error.kind() == std::io::ErrorKind::NotFound { + println!("fce-repl not found, run `cargo +nightly install frepl` to install it"); + } else { + // this branch should be executed if exec was successful, so just else if fine here + println!("error occurred: {:?}", error); + } + + Ok(()) +} diff --git a/tools/repl/Cargo.toml b/tools/repl/Cargo.toml index c61838f6..6048db45 100644 --- a/tools/repl/Cargo.toml +++ b/tools/repl/Cargo.toml @@ -13,7 +13,7 @@ path = "src/main.rs" [dependencies] fluence-app-service = { path = "../../fluence-app-service", version = "0.5.2", features = ["raw-module-api"] } -fluence-sdk-main = { version = "0.4.2", features = ["logger"] } +fluence-sdk-main = { version = "0.5.0", features = ["logger"] } anyhow = "1.0.31" clap = "2.33.1"