Skip to content

Commit

Permalink
feat(gcli): embed programs in commands (#3589)
Browse files Browse the repository at this point in the history
  • Loading branch information
clearloop authored Dec 24, 2023
1 parent 22e28d8 commit f424256
Show file tree
Hide file tree
Showing 27 changed files with 329 additions and 78 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

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

6 changes: 6 additions & 0 deletions examples/messager/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,14 @@ authors.workspace = true
license.workspace = true
edition.workspace = true

[[bin]]
name = "demo_messager"
path = "src/bin/demo_messager.rs"
required-features = ["gcli"]

[dependencies]
gstd.workspace = true
gcli = { workspace = true, optional = true, features = ["embed"] }

[build-dependencies]
gear-wasm-builder.workspace = true
Expand Down
52 changes: 28 additions & 24 deletions gcli/src/cmd/meta.rs → examples/messager/src/bin/demo_messager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,38 +15,42 @@
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
#![cfg(feature = "gcli")]

//! command `meta`
use crate::{metadata::Metadata, result::Result};
use clap::Parser;
use std::{fs, path::PathBuf};
use gcli::{
anyhow, async_trait,
clap::{self, Parser},
cmd::Upload,
color_eyre, tokio, App,
};

/// Show metadata structure, read types from registry, etc.
#[derive(Debug, Parser)]
pub enum Action {
/// Display the structure of the metadata.
Display,
pub enum Command {
Upload(Upload),
}

/// Show metadata structure, read types from registry, etc.
#[derive(Debug, Parser)]
pub struct Meta {
/// Path of "*.meta.wasm".
pub metadata: PathBuf,
#[command(subcommand)]
pub action: Action,
pub struct Messager {
#[clap(subcommand)]
command: Command,
}

impl Meta {
/// Run command meta.
pub fn exec(&self) -> Result<()> {
let wasm = fs::read(&self.metadata)?;
let meta = Metadata::of(&wasm)?;
#[async_trait]
impl App for Messager {
async fn exec(&self) -> anyhow::Result<()> {
let lookup = gcli::lookup!();
let signer = self.signer().await?;

match self.action {
Action::Display => println!("{}", format!("{meta:#}").replace('"', "")),
}

Ok(())
let Command::Upload(upload) = &self.command;
upload
.clone_with_code_overridden(lookup.opt)
.exec(signer)
.await
.map_err(Into::into)
}
}

#[tokio::main]
async fn main() -> color_eyre::Result<()> {
Messager::parse().run().await
}
1 change: 1 addition & 0 deletions gcli/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ gsdk = { workspace = true, features = ["testing"] }
which.workspace = true

[features]
embed = []
node-key = [ "libp2p" ]

[package.metadata.docs.rs]
Expand Down
2 changes: 1 addition & 1 deletion gcli/examples/mycli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.

use gcli::{async_trait, App, Command, Parser};
use gcli::{async_trait, clap::Parser, App, Command};

/// My customized sub commands.
#[derive(Debug, Parser)]
Expand Down
2 changes: 1 addition & 1 deletion gcli/src/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ use gsdk::{signer::Signer, Api};
/// Command line gear program application abstraction.
///
/// ```ignore
/// use gcli::{async_trait, App, Command, Parser};
/// use gcli::{async_trait, App, Command, clap::Parser, color_eyre, anyhow};
///
/// /// My customized sub commands.
/// #[derive(Debug, Parser)]
Expand Down
2 changes: 1 addition & 1 deletion gcli/src/bin/gcli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.

use gcli::{cmd::Opt, App, Parser};
use gcli::{clap::Parser, cmd::Opt, App};

#[tokio::main]
async fn main() -> color_eyre::Result<()> {
Expand Down
2 changes: 1 addition & 1 deletion gcli/src/cmd/claim.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ use clap::Parser;
use gsdk::signer::Signer;

/// Claim value from mailbox.
#[derive(Parser, Debug)]
#[derive(Clone, Debug, Parser)]
pub struct Claim {
/// Claim value from.
message_id: String,
Expand Down
2 changes: 1 addition & 1 deletion gcli/src/cmd/create.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ use clap::Parser;
use gsdk::signer::Signer;

/// Deploy program to gear node
#[derive(Parser, Debug)]
#[derive(Clone, Debug, Parser)]
pub struct Create {
/// gear program code id
code_id: String,
Expand Down
4 changes: 2 additions & 2 deletions gcli/src/cmd/info.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ use gsdk::{
};
use std::fmt;

#[derive(Debug, Parser)]
#[derive(Clone, Debug, Parser)]
pub enum Action {
/// Get balance info of the current account
Balance,
Expand All @@ -44,7 +44,7 @@ pub enum Action {
}

/// Get account info from ss58address.
#[derive(Debug, Parser)]
#[derive(Clone, Debug, Parser)]
pub struct Info {
/// Info of this address, if none, will use the logged in account.
pub address: Option<String>,
Expand Down
6 changes: 3 additions & 3 deletions gcli/src/cmd/key.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ use gsdk::ext::{
use std::{fmt::Display, result::Result as StdResult, str::FromStr};

/// Cryptography scheme
#[derive(Debug, Clone)]
#[derive(Clone, Debug)]
pub enum Scheme {
Ecdsa,
Ed25519,
Expand All @@ -45,7 +45,7 @@ impl FromStr for Scheme {
}
}

#[derive(Debug, Parser)]
#[derive(Clone, Debug, Parser)]
pub enum Action {
/// Generate a random account
Generate,
Expand Down Expand Up @@ -88,7 +88,7 @@ pub enum Action {
}

/// Keypair utils
#[derive(Debug, Parser)]
#[derive(Clone, Debug, Parser)]
pub struct Key {
/// Cryptography scheme
#[arg(short, long, default_value = "sr25519")]
Expand Down
2 changes: 1 addition & 1 deletion gcli/src/cmd/login.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ use clap::Parser;
use std::path::PathBuf;

/// Log in to account
#[derive(Debug, Parser)]
#[derive(Clone, Debug, Parser)]
pub struct Login {
/// The default keystore path is ~/.gear/keystore and ~/.gear/keystore.json
///
Expand Down
50 changes: 37 additions & 13 deletions gcli/src/cmd/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,22 +33,27 @@ pub mod transfer;
pub mod update;
pub mod upload;

pub use self::{
claim::Claim, create::Create, info::Info, key::Key, login::Login, new::New, program::Program,
reply::Reply, send::Send, transfer::Transfer, update::Update, upload::Upload,
};

/// All SubCommands of gear command line interface.
#[derive(Debug, Parser)]
#[derive(Clone, Debug, Parser)]
pub enum Command {
Claim(claim::Claim),
Create(create::Create),
Info(info::Info),
Key(key::Key),
Login(login::Login),
New(new::New),
Claim(Claim),
Create(Create),
Info(Info),
Key(Key),
Login(Login),
New(New),
#[clap(subcommand)]
Program(program::Program),
Reply(reply::Reply),
Send(send::Send),
Upload(upload::Upload),
Transfer(transfer::Transfer),
Update(update::Update),
Program(Program),
Reply(Reply),
Send(Send),
Upload(Upload),
Transfer(Transfer),
Update(Update),
}

impl Command {
Expand All @@ -71,6 +76,25 @@ impl Command {

Ok(())
}

#[cfg(feature = "embed")]
pub async fn exec_embedded(
&self,
app: &impl App,
artifact: crate::embed::Artifact,
) -> anyhow::Result<()> {
let this = match self {
Command::Upload(upload) => {
Command::Upload(upload.clone_with_code_overridden(artifact.opt))
}
Command::Program(program) => {
Command::Program(program.clone_with_meta_overridden(artifact.meta))
}
_ => self.clone(),
};

Self::exec(&this, app).await
}
}

/// Gear command-line interface.
Expand Down
2 changes: 1 addition & 1 deletion gcli/src/cmd/new.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ use crate::{result::Result, template};
use clap::Parser;

/// Create a new gear program
#[derive(Debug, Parser)]
#[derive(Clone, Debug, Parser)]
pub struct New {
/// Create gear program from templates.
#[arg(short, long, default_value = "dapp-template")]
Expand Down
42 changes: 35 additions & 7 deletions gcli/src/cmd/program.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ use gsdk::{ext::sp_core::H256, Api};
use std::{fs, path::PathBuf};

/// Read program state, etc.
#[derive(Debug, Parser)]
#[derive(Clone, Debug, Parser)]
pub enum Program {
/// Display metadata of the program.
///
Expand All @@ -33,7 +33,11 @@ pub enum Program {
///
/// - "*.meta.txt" describes the metadata of the program
/// - "*.meta.wasm" describes the wasm exports of the program
#[cfg_attr(feature = "embed", clap(skip))]
meta: PathBuf,
/// Overridden metadata binary if feature embed is enabled.
#[clap(skip)]
meta_override: Vec<u8>,
/// Derive the description of the specified type from registry.
#[arg(short, long)]
derive: Option<String>,
Expand All @@ -60,6 +64,15 @@ pub enum Program {
}

impl Program {
/// Clone self with metadata overridden.
pub fn clone_with_meta_overridden(&self, meta: Vec<u8>) -> Self {
let mut overridden = self.clone();
if let Program::Meta { meta_override, .. } = &mut overridden {
*meta_override = meta;
};
overridden
}

/// Run command program.
pub async fn exec(&self, app: &impl App) -> Result<()> {
match self {
Expand All @@ -79,7 +92,19 @@ impl Program {
Self::full_state(api, *pid, *at).await?;
}
}
Program::Meta { meta, derive } => Self::meta(meta, derive)?,
Program::Meta {
meta,
derive,
meta_override,
} => {
let meta = if meta_override.is_empty() {
Self::resolve_meta(meta)
} else {
Meta::decode_wasm(meta_override)
}?;

Self::meta(meta, derive)?
}
}

Ok(())
Expand All @@ -96,17 +121,17 @@ impl Program {
let state = api
.read_state_using_wasm(pid, Default::default(), method, wasm, args, at)
.await?;
println!("{}", state);
println!("{state}");
Ok(())
}

async fn full_state(api: Api, pid: H256, at: Option<H256>) -> Result<()> {
let state = api.read_state(pid, Default::default(), at).await?;
println!("{}", state);
println!("{state}");
Ok(())
}

fn meta(path: &PathBuf, name: &Option<String>) -> Result<()> {
fn resolve_meta(path: &PathBuf) -> Result<Meta> {
let ext = path
.extension()
.ok_or_else(|| anyhow::anyhow!("Invalid file extension"))?;
Expand All @@ -122,11 +147,14 @@ impl Program {
return Err(anyhow::anyhow!(format!("Unsupported file extension {:?}", ext)).into());
};

// Format types.
Ok(meta)
}

fn meta(meta: Meta, name: &Option<String>) -> Result<()> {
let fmt = if let Some(name) = name {
format!("{:#}", meta.derive(name)?)
} else {
format!("{:#}", meta)
format!("{meta:#}")
};

// println result.
Expand Down
2 changes: 1 addition & 1 deletion gcli/src/cmd/reply.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ use gsdk::signer::Signer;
/// - `value`: balance to be transferred to the program once it's been created.
///
/// - `DispatchMessageEnqueued(H256)` when dispatch message is placed in the queue.
#[derive(Parser, Debug)]
#[derive(Clone, Debug, Parser)]
pub struct Reply {
/// Reply to
reply_to_id: String,
Expand Down
2 changes: 1 addition & 1 deletion gcli/src/cmd/send.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ use gsdk::{
///
/// Emits the following events:
/// - `DispatchMessageEnqueued(MessageInfo)` when dispatch message is placed in the queue.
#[derive(Parser, Debug)]
#[derive(Clone, Debug, Parser)]
pub struct Send {
/// Send to
pub destination: String,
Expand Down
2 changes: 1 addition & 1 deletion gcli/src/cmd/transfer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ use gsdk::{
/// [the staging testnet][0], and the decimals of 1 UNIT is 12 by default.
///
/// [0]: https://github.com/gear-tech/gear/blob/c01d0390cdf1031cb4eba940d0199d787ea480e0/node/src/chain_spec.rs#L218
#[derive(Debug, Parser)]
#[derive(Clone, Debug, Parser)]
pub struct Transfer {
/// Transfer to (ss58address).
destination: String,
Expand Down
Loading

0 comments on commit f424256

Please sign in to comment.