From a4cecb67e37e338b3f479702ae8d86bbcc6f302d Mon Sep 17 00:00:00 2001 From: FroVolod <36816899+FroVolod@users.noreply.github.com> Date: Thu, 19 Oct 2023 12:27:58 +0300 Subject: [PATCH] feat: New command - deploy (#113) --- Cargo.lock | 7 +- cargo-near/Cargo.toml | 12 ++- cargo-near/src/commands/deploy/mod.rs | 127 ++++++++++++++++++++++++++ cargo-near/src/commands/mod.rs | 4 + cargo-near/src/lib.rs | 2 + cargo-near/src/types/utf8_path_buf.rs | 9 ++ integration-tests/src/lib.rs | 1 + 7 files changed, 157 insertions(+), 5 deletions(-) create mode 100644 cargo-near/src/commands/deploy/mod.rs diff --git a/Cargo.lock b/Cargo.lock index 29bb992a..25fec2de 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -821,6 +821,10 @@ dependencies = [ "names", "near-abi", "near-cli-rs", + "near-crypto 0.17.0", + "near-jsonrpc-client", + "near-jsonrpc-primitives", + "near-primitives 0.17.0", "rustc_version", "schemars", "serde_json", @@ -2835,7 +2839,8 @@ dependencies = [ [[package]] name = "near-cli-rs" version = "0.6.2" -source = "git+https://github.com/near/near-cli-rs#809d62827532ece7724c7f62eee162e066ff6a1f" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c80aaad38d0bf04a9056ca97d1f46e8b052b7a9a8b9f4af1f417c07b8f56e25" dependencies = [ "bip39", "bs58 0.5.0", diff --git a/cargo-near/Cargo.toml b/cargo-near/Cargo.toml index 3209b801..a326a927 100644 --- a/cargo-near/Cargo.toml +++ b/cargo-near/Cargo.toml @@ -37,11 +37,15 @@ color-eyre = "0.6" inquire = "0.6" strum = { version = "0.24", features = ["derive"] } strum_macros = "0.24" -interactive-clap = "0.2.6" -interactive-clap-derive = "0.2.6" linked-hash-map = { version = "0.5", features = ["serde_impl"] } names = { version = "0.14.0", default-features = false } -near-cli-rs = { git = "https://github.com/near/near-cli-rs" } derive_more = "0.99.9" shell-words = "1.0.0" -dunce = "1" \ No newline at end of file +interactive-clap = "0.2.7" +interactive-clap-derive = "0.2.7" +near-cli-rs = { version = "0.6.2" } +near-crypto = "0.17.0" +near-primitives = "0.17.0" +near-jsonrpc-client = "0.6.0" +near-jsonrpc-primitives = "0.17.0" +dunce = "1" diff --git a/cargo-near/src/commands/deploy/mod.rs b/cargo-near/src/commands/deploy/mod.rs new file mode 100644 index 00000000..e561eb6e --- /dev/null +++ b/cargo-near/src/commands/deploy/mod.rs @@ -0,0 +1,127 @@ +use near_cli_rs::commands::contract::deploy::initialize_mode::InitializeMode; + +use crate::commands::build_command; + +#[derive(Debug, Clone, interactive_clap::InteractiveClap)] +#[interactive_clap(input_context = near_cli_rs::GlobalContext)] +#[interactive_clap(output_context = ContractContext)] +#[interactive_clap(skip_default_from_cli)] +pub struct Contract { + #[interactive_clap(skip_default_input_arg)] + #[interactive_clap(flatten)] + /// Specify a build command args: + build_command_args: build_command::BuildCommand, + #[interactive_clap(skip_default_input_arg)] + /// What is the contract account ID? + contract_account_id: near_cli_rs::types::account_id::AccountId, + #[interactive_clap(subcommand)] + initialize: InitializeMode, +} + +#[derive(Debug, Clone)] +pub struct ContractContext(near_cli_rs::commands::contract::deploy::ContractFileContext); + +impl ContractContext { + pub fn from_previous_context( + previous_context: near_cli_rs::GlobalContext, + scope: &::InteractiveClapContextScope, + ) -> color_eyre::eyre::Result { + let file_path = build_command::build::run(scope.build_command_args.clone())?.path; + Ok(Self( + near_cli_rs::commands::contract::deploy::ContractFileContext { + global_context: previous_context, + receiver_account_id: scope.contract_account_id.clone().into(), + signer_account_id: scope.contract_account_id.clone().into(), + code: std::fs::read(file_path)?, + }, + )) + } +} + +impl From for near_cli_rs::commands::contract::deploy::ContractFileContext { + fn from(item: ContractContext) -> Self { + item.0 + } +} + +impl interactive_clap::FromCli for Contract { + type FromCliContext = near_cli_rs::GlobalContext; + type FromCliError = color_eyre::eyre::Error; + fn from_cli( + optional_clap_variant: Option<::CliVariant>, + context: Self::FromCliContext, + ) -> interactive_clap::ResultFromCli< + ::CliVariant, + Self::FromCliError, + > + where + Self: Sized + interactive_clap::ToCli, + { + let mut clap_variant = optional_clap_variant.unwrap_or_default(); + + let build_command_args = + if let Some(cli_build_command_args) = &clap_variant.build_command_args { + build_command::BuildCommand { + release: cli_build_command_args.release, + embed_abi: cli_build_command_args.embed_abi, + doc: cli_build_command_args.doc, + no_abi: cli_build_command_args.no_abi, + out_dir: cli_build_command_args.out_dir.clone(), + manifest_path: cli_build_command_args.manifest_path.clone(), + color: cli_build_command_args.color.clone(), + } + } else { + build_command::BuildCommand::default() + }; + + if clap_variant.contract_account_id.is_none() { + clap_variant.contract_account_id = match Self::input_contract_account_id(&context) { + Ok(Some(contract_account_id)) => Some(contract_account_id), + Ok(None) => return interactive_clap::ResultFromCli::Cancel(Some(clap_variant)), + Err(err) => return interactive_clap::ResultFromCli::Err(Some(clap_variant), err), + }; + } + let contract_account_id = clap_variant + .contract_account_id + .clone() + .expect("Unexpected error"); + + let new_context_scope = InteractiveClapContextScopeForContract { + build_command_args, + contract_account_id, + }; + + let output_context = + match ContractContext::from_previous_context(context, &new_context_scope) { + Ok(new_context) => new_context, + Err(err) => return interactive_clap::ResultFromCli::Err(Some(clap_variant), err), + }; + + match InitializeMode::from_cli(clap_variant.initialize.take(), output_context.into()) { + interactive_clap::ResultFromCli::Ok(initialize) => { + clap_variant.initialize = Some(initialize); + interactive_clap::ResultFromCli::Ok(clap_variant) + } + interactive_clap::ResultFromCli::Cancel(optional_initialize) => { + clap_variant.initialize = optional_initialize; + interactive_clap::ResultFromCli::Cancel(Some(clap_variant)) + } + interactive_clap::ResultFromCli::Back => interactive_clap::ResultFromCli::Back, + interactive_clap::ResultFromCli::Err(optional_initialize, err) => { + clap_variant.initialize = optional_initialize; + interactive_clap::ResultFromCli::Err(Some(clap_variant), err) + } + } + } +} + +impl Contract { + pub fn input_contract_account_id( + context: &near_cli_rs::GlobalContext, + ) -> color_eyre::eyre::Result> { + near_cli_rs::common::input_signer_account_id_from_used_account_list( + &context.config.credentials_home_dir, + "What is the contract account ID?", + ) + } +} diff --git a/cargo-near/src/commands/mod.rs b/cargo-near/src/commands/mod.rs index f06a42a8..2ef1f5e2 100644 --- a/cargo-near/src/commands/mod.rs +++ b/cargo-near/src/commands/mod.rs @@ -3,6 +3,7 @@ use strum::{EnumDiscriminants, EnumIter, EnumMessage}; pub mod abi_command; pub mod build_command; pub mod create_dev_account; +pub mod deploy; #[derive(Debug, EnumDiscriminants, Clone, interactive_clap::InteractiveClap)] #[interactive_clap(context = near_cli_rs::GlobalContext)] @@ -28,4 +29,7 @@ pub enum NearCommand { ))] /// Create a development account using the faucet service sponsor to cover the cost of creating an account (testnet only for now) CreateDevAccount(self::create_dev_account::CreateAccount), + #[strum_discriminants(strum(message = "deploy - Add a new contract code"))] + /// Add a new contract code + Deploy(self::deploy::Contract), } diff --git a/cargo-near/src/lib.rs b/cargo-near/src/lib.rs index d8acc010..9e99e766 100644 --- a/cargo-near/src/lib.rs +++ b/cargo-near/src/lib.rs @@ -1,3 +1,5 @@ +#![allow(clippy::large_enum_variant)] + pub use near_cli_rs::CliResult; use strum::{EnumDiscriminants, EnumIter, EnumMessage}; diff --git a/cargo-near/src/types/utf8_path_buf.rs b/cargo-near/src/types/utf8_path_buf.rs index 70c86fea..c9e7721f 100644 --- a/cargo-near/src/types/utf8_path_buf.rs +++ b/cargo-near/src/types/utf8_path_buf.rs @@ -1,3 +1,5 @@ +use color_eyre::eyre::Context; + #[derive( Debug, Default, @@ -19,3 +21,10 @@ impl std::fmt::Display for Utf8PathBufInner { impl interactive_clap::ToCli for Utf8PathBufInner { type CliVariant = Utf8PathBufInner; } + +impl Utf8PathBufInner { + pub fn read_bytes(&self) -> color_eyre::Result> { + std::fs::read(self.0.clone().into_std_path_buf()) + .wrap_err_with(|| format!("Error reading data from file: {:?}", self.0)) + } +} diff --git a/integration-tests/src/lib.rs b/integration-tests/src/lib.rs index dddd7a17..15688551 100644 --- a/integration-tests/src/lib.rs +++ b/integration-tests/src/lib.rs @@ -68,6 +68,7 @@ macro_rules! invoke_cargo_near { cargo_near::commands::build_command::build::run(args)?; }, Some(cargo_near::commands::CliNearCommand::CreateDevAccount(_)) => todo!(), + Some(cargo_near::commands::CliNearCommand::Deploy(_)) => todo!(), None => () }