Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
99 changes: 57 additions & 42 deletions dfx/src/commands/build.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use crate::config::dfinity::Profile;
use crate::config::dfinity::{Config, Profile};
use crate::lib::canister_info::CanisterInfo;
use crate::lib::env::{BinaryResolverEnv, ProjectConfigEnv};
use crate::lib::error::{BuildErrorKind, DfxError, DfxResult};
use crate::lib::message::UserMessage;
Expand All @@ -15,9 +16,9 @@ pub fn construct() -> App<'static, 'static> {
/// Compile a motoko file.
fn motoko_compile<T: BinaryResolverEnv>(
env: &T,
profile: Option<Profile>,
input_path: &Path,
output_path: &Path,
profile: Option<Profile>,
) -> DfxResult {
// Invoke the compiler in debug (development) or release mode, based on the current profile:
let arg_profile = match profile {
Expand Down Expand Up @@ -101,36 +102,53 @@ fn build_user_lib<T: BinaryResolverEnv>(
}
}

fn build_file<T>(
env: &T,
profile: Option<Profile>,
input_path: &Path,
output_path: &Path,
) -> DfxResult
fn build_file<T>(env: &T, config: &Config, name: &str) -> DfxResult
where
T: BinaryResolverEnv,
{
let output_wasm_path = output_path.with_extension("wasm");
let canister_info = CanisterInfo::load(config, name)?;
let config = config.get_config();
let profile = config.profile.clone();
let input_path = canister_info.get_main_path();

let output_wasm_path = canister_info.get_output_wasm_path();
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)
.map_err(|e| DfxError::BuildError(BuildErrorKind::WatCompileError(e)))?;

std::fs::create_dir_all(canister_info.get_output_root())?;
std::fs::write(&output_wasm_path, wasm)?;

// Write the CID.
std::fs::write(
canister_info.get_canister_id_path(),
canister_info.generate_canister_id()?.into_blob().0,
)
.map_err(DfxError::from)?;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍


Ok(())
}

Some("mo") => {
let output_idl_path = output_path.with_extension("did");
let output_js_path = output_path.with_extension("js");
let output_idl_path = canister_info.get_output_idl_path();
let output_js_path = canister_info.get_output_js_path();

motoko_compile(env, &input_path, &output_wasm_path, profile)?;
std::fs::create_dir_all(canister_info.get_output_root())?;

motoko_compile(env, profile, &input_path, &output_wasm_path)?;
didl_compile(env, &input_path, &output_idl_path)?;
build_user_lib(env, &output_idl_path, &output_js_path)?;

// Write the CID.
std::fs::write(
canister_info.get_canister_id_path(),
canister_info.generate_canister_id()?.into_blob().0,
)
.map_err(DfxError::from)?;

Ok(())
}
Some(ext) => Err(DfxError::BuildError(BuildErrorKind::InvalidExtension(
Expand All @@ -153,34 +171,10 @@ where
.get_config()
.ok_or(DfxError::CommandMustBeRunInAProject)?;

// get_path() returns the full path of the config file. We need to get the dirname.
let project_root = config.get_path().parent().unwrap();

let build_root = project_root.join(
config
.get_config()
.get_defaults()
.get_build()
.get_output("build/"),
);

if let Some(canisters) = &config.get_config().canisters {
for (k, v) in canisters {
for k in canisters.keys() {
println!("Building {}...", k);
if let Some(path) = &v.main {
let path = Path::new(&path);
let input_as_path = project_root.join(path);
let path = path.strip_prefix("src/").unwrap_or(&path);
let output_path = build_root.join(path).with_extension("wasm");
std::fs::create_dir_all(output_path.parent().unwrap())?;

build_file(
env,
config.config.profile.clone(),
&input_as_path,
&output_path,
)?;
}
build_file(env, &config, &k)?;
}
}

Expand Down Expand Up @@ -234,13 +228,17 @@ mod tests {
out_file: &out_file,
};

build_file(
motoko_compile(
&env,
None,
Path::new("/in/file.mo"),
Path::new("/out/file.wasm"),
)
.expect("Function failed.");
didl_compile(&env, Path::new("/in/file.mo"), Path::new("/out/file.did"))
.expect("Function failed");
build_user_lib(&env, Path::new("/out/file.did"), Path::new("/out/file.js"))
.expect("Function failed");

out_file.flush().expect("Could not flush.");

Expand Down Expand Up @@ -280,14 +278,31 @@ mod tests {
let temp_dir = tempfile::tempdir().unwrap();
let temp_path = temp_dir.into_path();
let input_path = temp_path.join("input.wat");
let output_path = temp_path.join("output.wasm");
let output_path = temp_path.join("out/name/input.wasm");

assert!(!output_path.exists());

std::fs::write(input_path.as_path(), wat).expect("Could not create input.");
build_file(&env, None, input_path.as_path(), output_path.as_path())
.expect("Function failed.");
let config = Config::from_str_and_path(
temp_path.join("dfx.json"),
r#"
{
"canisters": {
"name": {
"main": "input.wat"
}
},
"defaults": {
"build": {
"output": "out/"
}
}
}
"#,
)
.unwrap();

build_file(&env, &config, "name").expect("Function failed - build_file");
assert!(output_path.exists());
}
}
34 changes: 19 additions & 15 deletions dfx/src/commands/canister/call.rs
Original file line number Diff line number Diff line change
@@ -1,23 +1,22 @@
use crate::lib::api_client::{call, request_status, QueryResponseReply, ReadResponse};
use crate::lib::env::ClientEnv;
use crate::lib::canister_info::CanisterInfo;
use crate::lib::env::{ClientEnv, ProjectConfigEnv};
use crate::lib::error::{DfxError, DfxResult};
use crate::lib::message::UserMessage;
use crate::util::clap::validators;
use crate::util::print_idl_blob;
use clap::{App, Arg, ArgMatches, SubCommand};
use ic_http_agent::{Blob, CanisterId};
use ic_http_agent::Blob;
use serde_idl::{Encode, IDLArgs};
use tokio::runtime::Runtime;

pub fn construct() -> App<'static, 'static> {
SubCommand::with_name("call")
.about(UserMessage::CallCanister.to_str())
.arg(
Arg::with_name("deployment_id")
Arg::with_name("canister_name")
.takes_value(true)
.help(UserMessage::DeploymentId.to_str())
.required(true)
.validator(validators::is_canister_id),
.help(UserMessage::CanisterName.to_str())
.required(true),
)
.arg(
Arg::with_name("method_name")
Expand Down Expand Up @@ -47,14 +46,18 @@ pub fn construct() -> App<'static, 'static> {

pub fn exec<T>(env: &T, args: &ArgMatches<'_>) -> DfxResult
where
T: ClientEnv,
T: ClientEnv + ProjectConfigEnv,
{
// Read the config.
let canister_id = args
.value_of("deployment_id")
.unwrap()
.parse::<CanisterId>()
.map_err(|e| DfxError::InvalidArgument(format!("Invalid deployment ID: {}", e)))?;
let config = env
.get_config()
.ok_or(DfxError::CommandMustBeRunInAProject)?;

let canister_name = args.value_of("canister_name").unwrap();
let canister_info = CanisterInfo::load(config, canister_name)?;
let canister_id = canister_info.get_canister_id().ok_or_else(|| {
DfxError::CannotFindBuildOutputForCanister(canister_info.get_name().to_owned())
})?;

let method_name = args.value_of("method_name").unwrap();
let arguments: Option<&str> = args.value_of("argument");
let arg_type: Option<&str> = args.value_of("type");
Expand Down Expand Up @@ -91,14 +94,15 @@ where
let request_id = runtime.block_on(call_future)?;

if args.is_present("async") {
eprint!("Request ID: ");
println!("0x{}", String::from(request_id));
Ok(())
} else {
let request_status = request_status(env.get_client(), request_id);
let mut runtime = Runtime::new().expect("Unable to create a runtime");
match runtime.block_on(request_status) {
Ok(ReadResponse::Pending) => {
eprintln!("Pending");
eprint!("Request ID: ");
println!("0x{}", String::from(request_id));
Ok(())
}
Expand Down
Loading