From 191051b64415cdb2cb28d7d995acc69615e64efc Mon Sep 17 00:00:00 2001 From: Aaron Turner Date: Wed, 1 Sep 2021 10:25:36 -0700 Subject: [PATCH] Docs: Created the Wasmtime Markdown Parser Example (#3193) * Finished the Markdown Parser Example for Wasmtime * Made requested changes * Tiny change to explanation of `--dir` CLI arg * Add `bash` annotations to shell script code blocks * Trying to fix the markdown example bug * Figured out rustdoc, and what needed to be done * Made requested changes Co-authored-by: Till Schneidereit --- .github/workflows/main.yml | 3 +- Cargo.toml | 5 +- docs/examples-markdown.md | 58 ++++++++++++++++++- docs/rust_wasi_markdown_parser/Cargo.toml | 10 ++++ .../example_markdown.md | 3 + docs/rust_wasi_markdown_parser/src/main.rs | 46 +++++++++++++++ 6 files changed, 122 insertions(+), 3 deletions(-) create mode 100644 docs/rust_wasi_markdown_parser/Cargo.toml create mode 100644 docs/rust_wasi_markdown_parser/example_markdown.md create mode 100644 docs/rust_wasi_markdown_parser/src/main.rs diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 8a2e2b5d38..fe1957cdd4 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -80,7 +80,8 @@ jobs: cargo install --root ${{ runner.tool_cache }}/mdbook --version ${{ env.CARGO_MDBOOK_VERSION }} mdbook - run: (cd docs && mdbook build) - run: cargo build -p wasmtime-wasi --features wasmtime/wat,wasmtime/cranelift - - run: (cd docs && mdbook test -L ../target/debug/deps) + - run: (cd docs/rust_wasi_markdown_parser && cargo build) + - run: (cd docs && mdbook test -L ../target/debug/deps,./rust_wasi_markdown_parser/target/debug/deps) # Build Rust API documentation - run: | diff --git a/Cargo.toml b/Cargo.toml index 2aaf5485f3..23eef96cd6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -79,7 +79,10 @@ members = [ "examples/tokio/wasm", "fuzz", ] -exclude = ['crates/wasi-common/WASI/tools/witx-cli'] +exclude = [ + 'crates/wasi-common/WASI/tools/witx-cli', + 'docs/rust_wasi_markdown_parser' + ] [features] default = ["jitdump", "wasmtime/wat", "wasmtime/parallel-compilation", "wasi-nn"] diff --git a/docs/examples-markdown.md b/docs/examples-markdown.md index 76c8e56d7f..fad4730f1a 100644 --- a/docs/examples-markdown.md +++ b/docs/examples-markdown.md @@ -1,3 +1,59 @@ # Markdown Parser -... more coming soon +The following steps describe an implementation of a WASI markdown parser, in Rust, using [pulldown-cmark](https://github.com/raphlinus/pulldown-cmark). + +First, we will generate a new executable with cargo: + +```bash +cargo new --bin rust_wasi_markdown_parser +cd rust_wasi_markdown_parser +``` + +Then, we will open the `src/main.rs` and enter the following contents. Please see the comments to understand what our program will be doing. + +## `src/main.rs` + +```rust,should_panic +{{#include ./rust_wasi_markdown_parser/src/main.rs}} +``` + +Next, we will want to add WASI as a target that we can compile to. We will ask the rustup tool to install support for WASI. Then, we will compile our program to WASI. To do this we will run: + +```bash +rustup target add wasm32-wasi +cargo build --target wasm32-wasi +``` + +Our wasm file should be compiled to `target/wasm32-wasi/debug/rust_wasi_markdown_parser.wasm`. It is worth noting that even though the WASI APIs are not being used directly, when we compile our program to target WASI, the rust APIs and standard library will be using these WASI APIs under the hood for us! Now that we have our program compiled to target WASI, let's run our program! + +To do this, we can use the Wasmtime CLI. However, there is one thing to note about Wasmtime, WASI, and the capability based security model. We need to give our program explicit access to read files on our device. Wasm modules that implement WASI will not have this capability unless we give them the capability. + +To grant the capability to read in a directory using the Wasmtime CLI, we need to use the --dir flag. --dir will instruct wasmtime to make the passed directory available to access files from. (You can also `--mapdir GUEST_DIRECTORY::HOST_DIRECTORY` to make it available under a different path inside the content.) For example: + +```bash +wasmtime --dir . my-wasi-program.wasm +``` + +For this example, we will be passing a markdown file to our program called: `example-markdown.md`, that will exist in whatever our current directory (`./`) is. Our markdown file, `example-markdown.md`, will contain: + +```md +# Hello! + +I am example markdown for this demo! +``` + +So, **to run our compiled WASI program, we will run**: + +```bash +wasmtime --dir . target/wasm32-wasi/debug/rust_wasi_markdown_parser.wasm -- ./example_markdown.md +``` + +Which should look like the following: + +```html +

Hello!

+

I am example markdown for this demo!

+``` + +Hooray! We were able to write a Wasm Module, that uses WASI to read a markdown file, parse the markdown, and write the output to stdout! Continue reading to see more examples of using Wasmtime to execute Wasm Modules, from the CLI or even embedded in your application! + diff --git a/docs/rust_wasi_markdown_parser/Cargo.toml b/docs/rust_wasi_markdown_parser/Cargo.toml new file mode 100644 index 0000000000..d86767178d --- /dev/null +++ b/docs/rust_wasi_markdown_parser/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "rust_wasi_markdown_parser" +version = "0.1.0" +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +pulldown-cmark = "0.1.2" +structopt = "0.3.22" diff --git a/docs/rust_wasi_markdown_parser/example_markdown.md b/docs/rust_wasi_markdown_parser/example_markdown.md new file mode 100644 index 0000000000..c43cf286e0 --- /dev/null +++ b/docs/rust_wasi_markdown_parser/example_markdown.md @@ -0,0 +1,3 @@ +# Hello! + +I am example markdown for this demo! diff --git a/docs/rust_wasi_markdown_parser/src/main.rs b/docs/rust_wasi_markdown_parser/src/main.rs new file mode 100644 index 0000000000..b588b6ad40 --- /dev/null +++ b/docs/rust_wasi_markdown_parser/src/main.rs @@ -0,0 +1,46 @@ +// Import our CLI parsing libraries (And PathBuf for reading paths) +extern crate structopt; + +use structopt::StructOpt; +use std::path::PathBuf; + +// Import our markdown parser library, crate +extern crate pulldown_cmark; + +use pulldown_cmark::{html, Parser}; + +// Import from the standard library, to allow reading from the file system +use std::fs; + +// Define our CLI options using structopt +#[derive(StructOpt)] +#[structopt(name = "rust_wasi_markdown_parser", about = "Markdown to HTML renderer CLI, written with Rust & WASI")] +pub struct Options { + /// The markdown file to render + #[structopt(parse(from_os_str))] + filename: PathBuf, +} + +// Our entrypoint into our WASI module +fn main() { + + // Get the passed CLI options + let options = Options::from_args(); + + // Read the markdown file into a string + let contents = fs::read_to_string(options.filename) + .expect("Something went wrong reading the file"); + + // Run our parsing function to get back an HTML string + let result = render_markdown(contents); + + // Print out the resulting HTML to standard out + println!("{}", result); +} + +pub fn render_markdown(markdown: String) -> String { + let mut html_buf = String::new(); + let parser = Parser::new(&markdown[..]); + html::push_html(&mut html_buf, parser); + html_buf +}