Skip to content

Commit 4ea44e7

Browse files
author
Hans
authored
Merge pull request #36 from dfinity-lab/hansl/canister-install
New Feature: dfx canister install
2 parents 2927bb2 + d616773 commit 4ea44e7

File tree

13 files changed

+334
-53
lines changed

13 files changed

+334
-53
lines changed

dfx/Cargo.lock

+1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dfx/Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -32,3 +32,4 @@ wabt = "0.9.2"
3232
[dev-dependencies]
3333
env_logger = "0.6"
3434
mockito = "0.20.0"
35+
tempfile = "3.1.0"

dfx/shell.nix

+3
Original file line numberDiff line numberDiff line change
@@ -7,5 +7,8 @@ pkgs.mkCiShell {
77
inputsFrom = [
88
dfx
99
];
10+
shellHook = ''
11+
export DFX_TIMESTAMP_DEBUG_MODE_ONLY=$(date +%s)
12+
'';
1013
DFX_ASSETS = dfx.DFX_ASSETS;
1114
}

dfx/src/commands/build.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,8 @@ mod tests {
180180
let env = TestEnv {};
181181
let wat = r#"(module )"#;
182182

183-
let temp_path = temp_dir();
183+
let temp_dir = tempfile::tempdir().unwrap();
184+
let temp_path = temp_dir.into_path();
184185
let input_path = temp_path.join("input.wat");
185186
let output_path = temp_path.join("output.wasm");
186187

dfx/src/commands/call.rs

+5-5
Original file line numberDiff line numberDiff line change
@@ -39,21 +39,21 @@ where
3939
},
4040
)
4141
.and_then(|r| match r {
42-
Response::Accepted => {
43-
println!("Accepted");
42+
ReadResponse::Pending => {
43+
println!("Pending");
4444
ok(())
4545
}
46-
Response::Replied {
46+
ReadResponse::Replied {
4747
reply: QueryResponseReply { arg: Blob(blob) },
4848
} => {
4949
println!("{}", String::from_utf8_lossy(&blob));
5050
ok(())
5151
}
52-
Response::Rejected {
52+
ReadResponse::Rejected {
5353
reject_code,
5454
reject_message,
5555
} => err(DfxError::ClientError(reject_code, reject_message)),
56-
Response::Unknown => err(DfxError::Unknown("Unknown response".to_owned())),
56+
ReadResponse::Unknown => err(DfxError::Unknown("Unknown response".to_owned())),
5757
});
5858

5959
let mut runtime = Runtime::new().expect("Unable to create a runtime");

dfx/src/commands/canister/install.rs

+52
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
use crate::lib::api_client::{install_code, Blob};
2+
use crate::lib::env::{ClientEnv, ProjectConfigEnv};
3+
use crate::lib::error::DfxResult;
4+
use clap::{App, Arg, ArgMatches, SubCommand};
5+
use std::path::PathBuf;
6+
use tokio::runtime::Runtime;
7+
8+
fn is_number(v: String) -> Result<(), String> {
9+
v.parse::<u64>()
10+
.map_err(|_| String::from("The value must be a number."))
11+
.map(|_| ())
12+
}
13+
14+
pub fn construct() -> App<'static, 'static> {
15+
SubCommand::with_name("install")
16+
.about("Install a canister.")
17+
.arg(
18+
Arg::with_name("canister")
19+
.takes_value(true)
20+
.help("The canister ID (a number).")
21+
.required(true)
22+
.validator(is_number),
23+
)
24+
.arg(
25+
Arg::with_name("wasm")
26+
.help("The wasm file to use.")
27+
.required(true),
28+
)
29+
}
30+
31+
pub fn exec<T>(env: &T, args: &ArgMatches<'_>) -> DfxResult
32+
where
33+
T: ClientEnv + ProjectConfigEnv,
34+
{
35+
// Read the config.
36+
let config = env.get_config().unwrap();
37+
let project_root = config.get_path().parent().unwrap();
38+
39+
let canister_id = args.value_of("canister").unwrap().parse::<u64>()?;
40+
let wasm_path = args.value_of("wasm").unwrap();
41+
let wasm_path = PathBuf::from(project_root).join(wasm_path);
42+
43+
let wasm = std::fs::read(wasm_path)?;
44+
let client = env.get_client();
45+
46+
let install = install_code(client, canister_id, Blob(wasm), None);
47+
48+
let mut runtime = Runtime::new().expect("Unable to create a runtime");
49+
runtime.block_on(install)?;
50+
51+
Ok(())
52+
}

dfx/src/commands/canister/mod.rs

+48
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
use crate::commands::CliCommand;
2+
use crate::lib::env::{ClientEnv, ProjectConfigEnv};
3+
use crate::lib::error::{DfxError, DfxResult};
4+
use clap::{App, ArgMatches, SubCommand};
5+
6+
mod install;
7+
8+
fn builtins<T>() -> Vec<CliCommand<T>>
9+
where
10+
T: ClientEnv + ProjectConfigEnv,
11+
{
12+
vec![CliCommand::new(install::construct(), install::exec)]
13+
}
14+
15+
pub fn construct<T>() -> App<'static, 'static>
16+
where
17+
T: ClientEnv + ProjectConfigEnv,
18+
{
19+
SubCommand::with_name("canister")
20+
.about("Manage canisters from a network.")
21+
.subcommands(
22+
builtins::<T>()
23+
.into_iter()
24+
.map(|x| x.get_subcommand().clone()),
25+
)
26+
}
27+
28+
pub fn exec<T>(env: &T, args: &ArgMatches<'_>) -> DfxResult
29+
where
30+
T: ClientEnv + ProjectConfigEnv,
31+
{
32+
let subcommand = args.subcommand();
33+
34+
if let (name, Some(subcommand_args)) = subcommand {
35+
match builtins().into_iter().find(|x| name == x.get_name()) {
36+
Some(cmd) => cmd.execute(env, subcommand_args),
37+
None => Err(DfxError::UnknownCommand(format!(
38+
"Command {} not found.",
39+
name
40+
))),
41+
}
42+
} else {
43+
construct::<T>().write_help(&mut std::io::stderr())?;
44+
println!();
45+
println!();
46+
Ok(())
47+
}
48+
}

dfx/src/commands/mod.rs

+2
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ use clap::ArgMatches;
66

77
mod build;
88
mod call;
9+
mod canister;
910
mod new;
1011
mod start;
1112

@@ -41,6 +42,7 @@ where
4142
vec![
4243
CliCommand::new(build::construct(), build::exec),
4344
CliCommand::new(call::construct(), call::exec),
45+
CliCommand::new(canister::construct::<T>(), canister::exec),
4446
CliCommand::new(new::construct(), new::exec),
4547
CliCommand::new(start::construct(), start::exec),
4648
]

dfx/src/config/cache.rs

+8-15
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use std::io::{Error, ErrorKind, Result};
22
use std::path::PathBuf;
33

4+
use crate::config::dfx_version;
45
use crate::util;
56

67
pub fn get_bin_cache_root() -> Result<PathBuf> {
@@ -31,14 +32,7 @@ pub fn get_bin_cache_root() -> Result<PathBuf> {
3132

3233
pub fn get_bin_cache(v: &str) -> Result<PathBuf> {
3334
let root = get_bin_cache_root()?;
34-
35-
match v {
36-
"0.2.0" => Ok(root.join("0.2.0")),
37-
v => Err(Error::new(
38-
ErrorKind::Other,
39-
format!("Unknown version: {}", v),
40-
)),
41-
}
35+
Ok(root.join(v))
4236
}
4337

4438
pub fn is_version_installed(v: &str) -> Result<bool> {
@@ -60,15 +54,14 @@ pub fn install_version(v: &str) -> Result<PathBuf> {
6054
return Ok(p);
6155
}
6256

63-
match v {
64-
"0.2.0" => {
65-
util::assets::binary_cache()?.unpack(p.as_path())?;
66-
Ok(p)
67-
}
68-
v => Err(Error::new(
57+
if v == dfx_version() {
58+
util::assets::binary_cache()?.unpack(p.as_path())?;
59+
Ok(p)
60+
} else {
61+
Err(Error::new(
6962
ErrorKind::Other,
7063
format!("Unknown version: {}", v),
71-
)),
64+
))
7265
}
7366
}
7467

dfx/src/config/mod.rs

+28-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,31 @@
11
pub mod cache;
22
pub mod dfinity;
33

4-
pub const DFX_VERSION: &str = env!("CARGO_PKG_VERSION");
4+
static mut DFX_VERSION: Option<String> = None;
5+
/// Returns the version of DFX that was built.
6+
/// In debug, add a timestamp of the upstream compilation at the end of version to ensure all
7+
/// debug runs are unique (and cached uniquely).
8+
/// That timestamp is taken from the DFX_TIMESTAMP_DEBUG_MODE_ONLY env var that is set in
9+
/// Nix.
10+
pub fn dfx_version() -> &'static str {
11+
unsafe {
12+
match &DFX_VERSION {
13+
Some(x) => x.as_str(),
14+
None => {
15+
let version = env!("CARGO_PKG_VERSION");
16+
17+
#[cfg(debug_assertions)]
18+
{
19+
DFX_VERSION = Some(format!(
20+
"{}-{}",
21+
version,
22+
std::env::var("DFX_TIMESTAMP_DEBUG_MODE_ONLY")
23+
.unwrap_or_else(|_| "local-debug".to_owned())
24+
));
25+
}
26+
27+
dfx_version()
28+
}
29+
}
30+
}
31+
}

0 commit comments

Comments
 (0)