Skip to content

Commit

Permalink
feat: allow building of wat files
Browse files Browse the repository at this point in the history
It only outputs the WASM. We would need a way to generate IDL from
WAT which is probably out of scope. This allows to create low level
canisters for testing though so there is still value in this PR.
  • Loading branch information
Hans Larsen authored and hansl committed Sep 13, 2019
1 parent 57c9be3 commit 60e495e
Show file tree
Hide file tree
Showing 4 changed files with 134 additions and 28 deletions.
49 changes: 44 additions & 5 deletions dfx/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions dfx/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ serde_repr = "0.1.5"
serde_json = "1.0.40"
tar = "0.4.26"
tokio = "0.1"
wabt = "0.9.2"

[dev-dependencies]
env_logger = "0.6"
Expand Down
99 changes: 76 additions & 23 deletions dfx/src/commands/build.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
use crate::config::dfinity::ConfigCanistersCanister;
use crate::lib::env::{BinaryResolverEnv, ProjectConfigEnv};
use crate::lib::error::DfxResult;
use crate::lib::error::{BuildErrorKind, DfxError, DfxResult};
use clap::{App, Arg, ArgMatches, SubCommand};
use std::ffi::OsStr;
use std::path::Path;

pub fn construct() -> App<'static, 'static> {
Expand All @@ -15,26 +16,48 @@ where
T: BinaryResolverEnv,
{
let output_wasm_path = output_path.with_extension("wasm");
let output_idl_path = output_path.with_extension("did");
let output_js_path = output_path.with_extension("js");

env.get_binary_command("asc")?
.arg(input_path)
.arg("-o")
.arg(&output_wasm_path)
.output()?;
env.get_binary_command("asc")?
.arg("--idl")
.arg(input_path)
.arg("-o")
.arg(&output_idl_path)
.output()?;
env.get_binary_command("didc")?
.arg("--js")
.arg(&output_idl_path)
.arg("-o")
.arg(output_js_path)
.output()?;

match input_path.extension().and_then(OsStr::to_str) {
// TODO(SDK-441): Revisit supporting compilation from WAT files.
Some("wat") => {
let wat = std::fs::read(input_path)?;
let wasm = wabt::wat2wasm(wat)?;

std::fs::write(&output_wasm_path, wasm)?;

Ok(())
}
Some("as") => {
let output_idl_path = output_path.with_extension("did");
let output_js_path = output_path.with_extension("js");

env.get_binary_command("asc")?
.arg(&input_path)
.arg("-o")
.arg(&output_wasm_path)
.output()?;
env.get_binary_command("asc")?
.arg("--idl")
.arg(&input_path)
.arg("-o")
.arg(&output_idl_path)
.output()?;
env.get_binary_command("didc")?
.arg("--js")
.arg(&output_idl_path)
.arg("-o")
.arg(&output_js_path)
.output()?;

Ok(())
}
Some(ext) => Err(DfxError::BuildError(BuildErrorKind::InvalidExtension(
ext.to_owned(),
))),
None => Err(DfxError::BuildError(BuildErrorKind::InvalidExtension(
"".to_owned(),
))),
}?;

Ok(())
}
Expand Down Expand Up @@ -126,8 +149,7 @@ mod tests {

let mut s = String::new();
fs::File::open(temp_path)
.expect("Could not open temp file.")
.read_to_string(&mut s)
.and_then(|mut f| f.read_to_string(&mut s))
.expect("Could not read temp file.");

assert_eq!(
Expand All @@ -138,4 +160,35 @@ mod tests {
.replace(" ", "")
);
}

#[test]
/// Runs "echo" instead of the compiler to make sure the binaries are called in order
/// with the good arguments.
fn build_file_wat() -> () {
// Create a binary cache environment that just returns "echo", so we can test the STDOUT.
struct TestEnv {}

impl BinaryResolverEnv for TestEnv {
fn get_binary_command_path(&self, _binary_name: &str) -> io::Result<PathBuf> {
panic!("get_binary_command_path should not be called.")
}
fn get_binary_command(&self, _binary_name: &str) -> io::Result<process::Command> {
panic!("get_binary_command should not be called.")
}
}

let env = TestEnv {};
let wat = r#"(module )"#;

let temp_path = temp_dir();
let input_path = temp_path.join("input.wat");
let output_path = temp_path.join("output.wasm");

assert!(!output_path.exists());

std::fs::write(input_path.as_path(), wat).expect("Could not create input.");
build_file(&env, input_path.as_path(), output_path.as_path()).expect("Function failed.");

assert!(output_path.exists());
}
}
13 changes: 13 additions & 0 deletions dfx/src/lib/error.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,22 @@
use crate::lib::api_client::RejectCode;

#[derive(Debug)]
pub enum BuildErrorKind {
InvalidExtension(String),
}

// TODO: refactor this enum into a *Kind enum and a struct DfxError.
#[derive(Debug)]
pub enum DfxError {
BuildError(BuildErrorKind),
Clap(clap::Error),
IO(std::io::Error),
ParseInt(std::num::ParseIntError),
Reqwest(reqwest::Error),
SerdeCbor(serde_cbor::error::Error),
SerdeJson(serde_json::error::Error),
Url(reqwest::UrlError),
WabtError(wabt::Error),

/// An unknown command was used. The argument is the command itself.
UnknownCommand(String),
Expand Down Expand Up @@ -62,3 +69,9 @@ impl From<std::num::ParseIntError> for DfxError {
DfxError::ParseInt(err)
}
}

impl From<wabt::Error> for DfxError {
fn from(err: wabt::Error) -> DfxError {
DfxError::WabtError(err)
}
}

0 comments on commit 60e495e

Please sign in to comment.