Skip to content
Closed
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
3,760 changes: 1,845 additions & 1,915 deletions Cargo.lock

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion src/dfx/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ actix-server = "0.6.1"
actix-web = "1.0.8"
atty = "0.2.13"
base64 = "0.11.0"
candid = "0.2.1"
candid = { git = "https://github.com/hansl/candid", branch = "rust-cdk" }
clap = "2.33.0"
console = "0.7.7"
crossbeam = "0.7.3"
Expand Down
5 changes: 2 additions & 3 deletions src/dfx/src/commands/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,7 @@ pub fn exec(env: &dyn Environment, args: &ArgMatches<'_>) -> DfxResult {
slog::info!(logger, "Building canisters...");

// TODO: remove the forcing of generating canister id once we have an update flow.
canister_pool
.build_or_fail(BuildConfig::from_config(config.get_config()).with_generate_id(true))?;
canister_pool.build_or_fail(BuildConfig::from_config(&config).with_generate_id(true))?;

// If there is not a package.json, we don't have a frontend and can quit early.
if !config.get_project_root().join("package.json").exists() || args.is_present("skip-frontend")
Expand Down Expand Up @@ -68,7 +67,7 @@ pub fn exec(env: &dyn Environment, args: &ArgMatches<'_>) -> DfxResult {

// Second build with assets.
slog::info!(logger, "Bundling assets with canisters...");
canister_pool.build_or_fail(BuildConfig::from_config(config.get_config()).with_assets(true))?;
canister_pool.build_or_fail(BuildConfig::from_config(&config).with_assets(true))?;

Ok(())
}
7 changes: 6 additions & 1 deletion src/dfx/src/commands/canister/call.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,12 @@ pub fn exec(env: &dyn Environment, args: &ArgMatches<'_>) -> DfxResult {
let arguments: Option<&str> = args.value_of("argument");
let arg_type: Option<&str> = args.value_of("type");

let idl_ast = load_idl_file(env, canister_info.get_output_idl_path());
let idl_ast = load_idl_file(
env,
&canister_info
.get_output_idl_path()
.expect("Could not find IDL file."),
);
let is_query = if args.is_present("async") {
false
} else {
Expand Down
4 changes: 3 additions & 1 deletion src/dfx/src/commands/canister/install.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,9 @@ async fn install_canister(
canister_id.to_text(),
);

let wasm_path = canister_info.get_output_wasm_path();
let wasm_path = canister_info
.get_output_wasm_path()
.expect("Cannot get WASM output path.");
let wasm = std::fs::read(wasm_path)?;

agent
Expand Down
17 changes: 11 additions & 6 deletions src/dfx/src/commands/language_service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -79,12 +79,17 @@ fn get_main_path(config: &ConfigInterface, args: &ArgMatches<'_>) -> Result<Stri
}
}?;

canister.main.ok_or_else(|| {
DfxError::InvalidData(format!(
"Canister {0} lacks a 'main' element in {1}",
canister_name, dfx_json
))
})
canister
.extras
.get("main")
.and_then(|v| v.as_str())
.ok_or_else(|| {
DfxError::InvalidData(format!(
"Canister {0} lacks a 'main' element in {1}",
canister_name, dfx_json
))
})
.map(|s| s.to_owned())
}

fn run_ide(
Expand Down
13 changes: 5 additions & 8 deletions src/dfx/src/config/dfinity.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,14 +43,15 @@ const EMPTY_CONFIG_DEFAULTS_START: ConfigDefaultsStart = ConfigDefaultsStart {
serve_root: None,
};

/// A Canister configuration in the dfx.json config file.
/// It only contains a type; everything else should be infered using the
/// CanisterInfo type.
#[derive(Clone, Debug, Default, Serialize, Deserialize)]
pub struct ConfigCanistersCanister {
pub main: Option<String>,
pub frontend: Option<Value>,
pub r#type: Option<String>,

#[serde(flatten)]
pub metadata: BTreeMap<String, Value>,
pub extras: BTreeMap<String, Value>,
}

#[derive(Clone, Debug, Default, Serialize, Deserialize)]
Expand Down Expand Up @@ -108,11 +109,7 @@ pub struct ConfigInterface {
pub defaults: Option<ConfigDefaults>,
}

impl ConfigCanistersCanister {
pub fn get_main(&self, default: &str) -> String {
self.main.to_owned().unwrap_or_else(|| default.to_string())
}
}
impl ConfigCanistersCanister {}

fn to_socket_addr(s: &str) -> DfxResult<SocketAddr> {
match s.to_socket_addrs() {
Expand Down
28 changes: 16 additions & 12 deletions src/dfx/src/lib/builders/mod.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
use crate::config::dfinity::{ConfigInterface, Profile};
use crate::config::dfinity::{Config, Profile};
use crate::lib::canister_info::CanisterInfo;
use crate::lib::environment::Environment;
use crate::lib::error::DfxResult;
use crate::lib::models::canister::CanisterPool;
use ic_agent::CanisterId;
use std::collections::BTreeMap;
use std::path::PathBuf;
use std::sync::Arc;

mod motoko;
mod rust;

#[derive(Debug)]
pub enum WasmBuildOutput {
Expand All @@ -31,8 +31,8 @@ pub struct BuildOutput {

/// A stateless canister builder. This is meant to not keep any state and be passed everything.
pub trait CanisterBuilder {
/// Returns the types of canister this builder can build.
fn supported_canister_types(&self) -> &[&str];
/// Returns true if this builder supports building the canister.
fn supports(&self, info: &CanisterInfo) -> bool;

/// Returns the dependencies of this canister, if any. This should not be a transitive
/// list.
Expand All @@ -59,16 +59,23 @@ pub struct BuildConfig {
profile: Profile,
assets: bool,
pub generate_id: bool,
metadata: BTreeMap<String, serde_json::Value>,

/// The root of all IDL files.
pub idl_root: PathBuf,
}

impl BuildConfig {
pub fn from_config(config: &ConfigInterface) -> Self {
pub fn from_config(config: &Config) -> Self {
let workspace_root = config.get_path().parent().unwrap();
let config = config.get_config();
let build_root =
workspace_root.join(config.get_defaults().get_build().get_output("build/"));

BuildConfig {
profile: config.profile.unwrap_or(Profile::Debug),
assets: false,
generate_id: false,
metadata: BTreeMap::new(),
idl_root: build_root.join("idl/"),
}
}

Expand All @@ -92,18 +99,15 @@ impl BuilderPool {
pub fn new(env: &dyn Environment) -> DfxResult<Self> {
let mut builders: Vec<Arc<dyn CanisterBuilder>> = Vec::new();
builders.push(Arc::new(motoko::MotokoBuilder::new(env)?));
builders.push(Arc::new(rust::RustBuilder::new(env)?));

Ok(Self { builders })
}

pub fn get(&self, info: &CanisterInfo) -> Option<Arc<dyn CanisterBuilder>> {
self.builders
.iter()
.find(|builder| {
builder
.supported_canister_types()
.contains(&info.get_type())
})
.find(|builder| builder.supports(&info))
.map(|x| Arc::clone(x))
}
}
51 changes: 29 additions & 22 deletions src/dfx/src/lib/builders/motoko.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use crate::config::dfinity::Profile;
use crate::lib::builders::{
BuildConfig, BuildOutput, CanisterBuilder, IdlBuildOutput, WasmBuildOutput,
};
use crate::lib::canister_info::motoko::MotokoCanisterInfo;
use crate::lib::canister_info::CanisterInfo;
use crate::lib::environment::Environment;
use crate::lib::error::{BuildErrorKind, DfxError, DfxResult};
Expand Down Expand Up @@ -37,6 +38,7 @@ impl CanisterBuilder for MotokoBuilder {
info: &CanisterInfo,
) -> DfxResult<Vec<CanisterId>> {
let mut result = BTreeSet::new();
let motoko_info = info.as_info::<MotokoCanisterInfo>()?;

fn find_deps_recursive(
cache: &dyn Cache,
Expand Down Expand Up @@ -70,7 +72,11 @@ impl CanisterBuilder for MotokoBuilder {

Ok(())
}
find_deps_recursive(self.cache.as_ref(), info.get_main_path(), &mut result)?;
find_deps_recursive(
self.cache.as_ref(),
motoko_info.get_main_path(),
&mut result,
)?;

Ok(result
.iter()
Expand All @@ -85,8 +91,8 @@ impl CanisterBuilder for MotokoBuilder {
.collect())
}

fn supported_canister_types(&self) -> &[&str] {
&["motoko"]
fn supports(&self, info: &CanisterInfo) -> bool {
info.get_type() == "motoko"
}

fn build(
Expand All @@ -95,29 +101,27 @@ impl CanisterBuilder for MotokoBuilder {
canister_info: &CanisterInfo,
config: &BuildConfig,
) -> DfxResult<BuildOutput> {
let motoko_info = canister_info.as_info::<MotokoCanisterInfo>()?;
let profile = config.profile;
let input_path = canister_info.get_main_path();
let output_wasm_path = canister_info.get_output_wasm_path();
let input_path = motoko_info.get_main_path();
let output_wasm_path = motoko_info.get_output_wasm_path();

let id_map = BTreeMap::from_iter(
pool.get_canister_list()
.iter()
.map(|c| (c.get_name().to_string(), c.canister_id().to_text())),
);

std::fs::create_dir_all(canister_info.get_output_root())?;
std::fs::create_dir_all(motoko_info.get_output_root())?;
let cache = &self.cache;
let idl_dir_path = canister_info.get_idl_dir_path();
let idl_dir_path = &config.idl_root;
std::fs::create_dir_all(&idl_dir_path)?;

let package_arguments =
package_arguments::load(cache.as_ref(), canister_info.get_packtool())?;
package_arguments::load(cache.as_ref(), motoko_info.get_packtool())?;

// Generate IDL
let output_idl_path = canister_info.get_output_idl_path();
let idl_file_path = canister_info
.get_idl_file_path()
.ok_or_else(|| DfxError::BuildError(BuildErrorKind::CouldNotReadCanisterId()))?;
let output_idl_path = motoko_info.get_output_idl_path();
let params = MotokoParams {
build_target: BuildTarget::IDL,
surpress_warning: false,
Expand All @@ -130,16 +134,15 @@ impl CanisterBuilder for MotokoBuilder {
idl_map: &id_map,
};
motoko_compile(cache.as_ref(), &params, &BTreeMap::new())?;
std::fs::copy(&output_idl_path, &idl_file_path)?;

// Generate JS code even if the canister doesn't have a frontend. It might still be
// used by another canister's frontend.
let output_did_js_path = canister_info.get_output_did_js_path();
let output_did_js_path = motoko_info.get_output_did_js_path();
let canister_id = canister_info
.get_canister_id()
.ok_or_else(|| DfxError::BuildError(BuildErrorKind::CouldNotReadCanisterId()))?;
build_did_js(cache.as_ref(), &output_idl_path, &output_did_js_path)?;
build_canister_js(&canister_id, &canister_info)?;
build_canister_js(&canister_id, &canister_info, &motoko_info)?;

let mut assets = AssetMap::new();

Expand All @@ -151,15 +154,15 @@ impl CanisterBuilder for MotokoBuilder {
assets.insert("candid.js".to_owned(), did_js_content);

// Add assets from the folder (the frontend dfx.json key).
if config.assets && canister_info.has_frontend() {
for dir_entry in std::fs::read_dir(canister_info.get_output_assets_root())? {
if config.assets && motoko_info.has_frontend() {
for dir_entry in std::fs::read_dir(motoko_info.get_output_assets_root())? {
if let Ok(e) = dir_entry {
let p = e.path();
let ext = p.extension().unwrap_or_else(|| std::ffi::OsStr::new(""));
if p.is_file() && ext != "map" {
let content = base64::encode(&std::fs::read(&p)?);
assets.insert(
p.strip_prefix(canister_info.get_output_assets_root())
p.strip_prefix(motoko_info.get_output_assets_root())
.expect("Cannot strip prefix.")
.to_str()
.expect("Could not get path.")
Expand Down Expand Up @@ -193,8 +196,8 @@ impl CanisterBuilder for MotokoBuilder {
canister_id: canister_info
.get_canister_id()
.expect("Could not find canister ID."),
wasm: WasmBuildOutput::File(canister_info.get_output_wasm_path().to_path_buf()),
idl: IdlBuildOutput::File(canister_info.get_output_idl_path().to_path_buf()),
wasm: WasmBuildOutput::File(motoko_info.get_output_wasm_path().to_path_buf()),
idl: IdlBuildOutput::File(motoko_info.get_output_idl_path().to_path_buf()),
})
}
}
Expand Down Expand Up @@ -414,8 +417,12 @@ fn decode_path_to_str(path: &Path) -> DfxResult<&str> {
})
}

fn build_canister_js(canister_id: &CanisterId, canister_info: &CanisterInfo) -> DfxResult {
let output_canister_js_path = canister_info.get_output_canister_js_path();
fn build_canister_js(
canister_id: &CanisterId,
canister_info: &CanisterInfo,
motoko_info: &MotokoCanisterInfo,
) -> DfxResult {
let output_canister_js_path = motoko_info.get_output_canister_js_path();

let mut language_bindings = assets::language_bindings()?;

Expand Down
Loading