Update cli module to use StructOpt and add docs

This commit is contained in:
Steve Myers 2020-11-30 22:03:39 -08:00
parent 2e7f98a371
commit 364b47bfcb
No known key found for this signature in database
GPG Key ID: 8105A46B22C2D051
3 changed files with 748 additions and 620 deletions

View File

@ -27,6 +27,7 @@ cc = { version = "=1.0.62", optional = true }
socks = { version = "0.3", optional = true }
lazy_static = { version = "1.4", optional = true }
tiny-bip39 = { version = "^0.8", optional = true }
structopt = { version = "^0.3", optional = true }
# Platform-specific dependencies
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
@ -45,7 +46,7 @@ electrum = ["electrum-client"]
esplora = ["reqwest", "futures"]
compact_filters = ["rocksdb", "socks", "lazy_static", "cc"]
key-value-db = ["sled"]
cli-utils = ["clap", "base64"]
cli-utils = ["clap", "base64", "structopt"]
async-interface = ["async-trait"]
all-keys = ["keys-bip39"]
keys-bip39 = ["tiny-bip39"]

View File

@ -24,27 +24,34 @@
use std::fs;
use std::path::PathBuf;
use std::str::FromStr;
use std::sync::Arc;
use bitcoin::Network;
use clap::AppSettings;
use log::{debug, error, info, trace, warn, LevelFilter};
use rustyline::error::ReadlineError;
use rustyline::Editor;
use clap::AppSettings;
#[allow(unused_imports)]
use log::{debug, error, info, trace, LevelFilter};
use bitcoin::Network;
use structopt::StructOpt;
use bdk::bitcoin;
use bdk::blockchain::esplora::EsploraBlockchainConfig;
use bdk::blockchain::{
AnyBlockchain, AnyBlockchainConfig, ConfigurableBlockchain, ElectrumBlockchainConfig,
};
use bdk::cli;
use bdk::cli::{self, WalletOpt, WalletSubCommand};
use bdk::sled;
use bdk::Wallet;
use bdk::blockchain::esplora::EsploraBlockchainConfig;
#[derive(Debug, StructOpt, Clone, PartialEq)]
#[structopt(name = "BDK Wallet", setting = AppSettings::NoBinaryName,
version = option_env ! ("CARGO_PKG_VERSION").unwrap_or("unknown"),
author = option_env ! ("CARGO_PKG_AUTHORS").unwrap_or(""))]
struct ReplOpt {
/// Wallet sub-command
#[structopt(subcommand)]
pub subcommand: WalletSubCommand,
}
fn prepare_home_dir() -> PathBuf {
let mut dir = PathBuf::new();
@ -61,100 +68,96 @@ fn prepare_home_dir() -> PathBuf {
}
fn main() {
env_logger::init();
let cli_opt: WalletOpt = WalletOpt::from_args();
let app = cli::make_cli_subcommands();
let mut repl_app = app.clone().setting(AppSettings::NoBinaryName);
let level = LevelFilter::from_str(cli_opt.log_level.as_str()).unwrap_or(LevelFilter::Info);
env_logger::builder().filter_level(level).init();
let app = cli::add_global_flags(app);
let network = Network::from_str(cli_opt.network.as_str()).unwrap_or(Network::Testnet);
debug!("network: {:?}", network);
if network == Network::Bitcoin {
warn!("This is experimental software and not currently recommended for use on Bitcoin mainnet, proceed with caution.")
}
let matches = app.get_matches();
// TODO
// let level = match matches.occurrences_of("v") {
// 0 => LevelFilter::Info,
// 1 => LevelFilter::Debug,
// _ => LevelFilter::Trace,
// };
let network = match matches.value_of("network") {
Some("regtest") => Network::Regtest,
Some("testnet") | _ => Network::Testnet,
};
let descriptor = matches.value_of("descriptor").unwrap();
let change_descriptor = matches.value_of("change_descriptor");
let descriptor = cli_opt.descriptor.as_str();
let change_descriptor = cli_opt.change_descriptor.as_deref();
debug!("descriptors: {:?} {:?}", descriptor, change_descriptor);
let database = sled::open(prepare_home_dir().to_str().unwrap()).unwrap();
let tree = database
.open_tree(matches.value_of("wallet").unwrap())
.unwrap();
let tree = database.open_tree(cli_opt.wallet).unwrap();
debug!("database opened successfully");
let config = match matches.value_of("esplora") {
let config = match cli_opt.esplora {
Some(base_url) => AnyBlockchainConfig::Esplora(EsploraBlockchainConfig {
base_url: base_url.to_string(),
concurrency: matches
.value_of("esplora_concurrency")
.and_then(|v| v.parse::<u8>().ok()),
concurrency: Some(cli_opt.esplora_concurrency),
}),
None => AnyBlockchainConfig::Electrum(ElectrumBlockchainConfig {
url: matches.value_of("server").unwrap().to_string(),
socks5: matches.value_of("proxy").map(ToString::to_string),
url: cli_opt.electrum,
socks5: cli_opt.proxy,
retry: 10,
timeout: 10,
}),
};
let wallet = Arc::new(
Wallet::new(
descriptor,
change_descriptor,
network,
tree,
AnyBlockchain::from_config(&config).unwrap(),
)
.unwrap(),
);
if let Some(_sub_matches) = matches.subcommand_matches("repl") {
let mut rl = Editor::<()>::new();
let wallet = Wallet::new(
descriptor,
change_descriptor,
network,
tree,
AnyBlockchain::from_config(&config).unwrap(),
)
.unwrap();
// if rl.load_history("history.txt").is_err() {
// println!("No previous history.");
// }
let wallet = Arc::new(wallet);
loop {
let readline = rl.readline(">> ");
match readline {
Ok(line) => {
if line.trim() == "" {
continue;
match cli_opt.subcommand {
WalletSubCommand::Other(external) if external.contains(&"repl".to_string()) => {
let mut rl = Editor::<()>::new();
// if rl.load_history("history.txt").is_err() {
// println!("No previous history.");
// }
loop {
let readline = rl.readline(">> ");
match readline {
Ok(line) => {
if line.trim() == "" {
continue;
}
rl.add_history_entry(line.as_str());
let split_line: Vec<&str> = line.split(" ").collect();
let repl_subcommand: Result<ReplOpt, clap::Error> =
ReplOpt::from_iter_safe(split_line);
debug!("repl_subcommand = {:?}", repl_subcommand);
if let Err(err) = repl_subcommand {
println!("{}", err.message);
continue;
}
let result = cli::handle_wallet_subcommand(
&Arc::clone(&wallet),
repl_subcommand.unwrap().subcommand,
)
.unwrap();
println!("{}", serde_json::to_string_pretty(&result).unwrap());
}
rl.add_history_entry(line.as_str());
let matches = repl_app.get_matches_from_safe_borrow(line.split(" "));
if let Err(err) = matches {
println!("{}", err.message);
continue;
Err(ReadlineError::Interrupted) => continue,
Err(ReadlineError::Eof) => break,
Err(err) => {
println!("{:?}", err);
break;
}
let result =
cli::handle_matches(&Arc::clone(&wallet), matches.unwrap()).unwrap();
println!("{}", serde_json::to_string_pretty(&result).unwrap());
}
Err(ReadlineError::Interrupted) => continue,
Err(ReadlineError::Eof) => break,
Err(err) => {
println!("{:?}", err);
break;
}
}
}
// rl.save_history("history.txt").unwrap();
} else {
let result = cli::handle_matches(&wallet, matches).unwrap();
println!("{}", serde_json::to_string_pretty(&result).unwrap());
// rl.save_history("history.txt").unwrap();
}
_ => {
let result = cli::handle_wallet_subcommand(&wallet, cli_opt.subcommand).unwrap();
println!("{}", serde_json::to_string_pretty(&result).unwrap());
}
}
}

1202
src/cli.rs

File diff suppressed because it is too large Load Diff