Extract duplicate clap helpers into clap-utils (#6812)
This commit is contained in:
@ -27,6 +27,7 @@ serde_derive = "1.0.102"
|
||||
serde_json = "1.0.41"
|
||||
serde_yaml = "0.8.11"
|
||||
solana-budget-api = { path = "../programs/budget_api", version = "0.21.0" }
|
||||
solana-clap-utils = { path = "../clap-utils", version = "0.21.0" }
|
||||
solana-client = { path = "../client", version = "0.21.0" }
|
||||
solana-config-api = { path = "../programs/config_api", version = "0.21.0" }
|
||||
solana-drone = { path = "../drone", version = "0.21.0" }
|
||||
|
@ -1,13 +1,14 @@
|
||||
use crate::{
|
||||
cluster_query::*, display::println_name_value, input_parsers::*, input_validators::*, stake::*,
|
||||
storage::*, validator_info::*, vote::*,
|
||||
cluster_query::*, display::println_name_value, stake::*, storage::*, validator_info::*, vote::*,
|
||||
};
|
||||
use chrono::prelude::*;
|
||||
use clap::{App, AppSettings, Arg, ArgMatches, SubCommand};
|
||||
use log::*;
|
||||
use num_traits::FromPrimitive;
|
||||
use serde_json::{self, json, Value};
|
||||
|
||||
use solana_budget_api::budget_instruction::{self, BudgetError};
|
||||
use solana_clap_utils::{input_parsers::*, input_validators::*};
|
||||
use solana_client::{client_error::ClientError, rpc_client::RpcClient};
|
||||
#[cfg(not(test))]
|
||||
use solana_drone::drone::request_airdrop_transaction;
|
||||
@ -32,6 +33,7 @@ use solana_sdk::{
|
||||
use solana_stake_api::stake_state::{Lockup, StakeAuthorize};
|
||||
use solana_storage_api::storage_instruction::StorageAccountType;
|
||||
use solana_vote_api::vote_state::VoteAuthorize;
|
||||
|
||||
use std::{
|
||||
fs::File,
|
||||
io::{Read, Write},
|
||||
|
@ -1,169 +0,0 @@
|
||||
use clap::ArgMatches;
|
||||
use solana_sdk::{
|
||||
native_token::sol_to_lamports,
|
||||
pubkey::Pubkey,
|
||||
signature::{read_keypair_file, Keypair, KeypairUtil},
|
||||
};
|
||||
|
||||
// Return parsed values from matches at `name`
|
||||
pub fn values_of<T>(matches: &ArgMatches<'_>, name: &str) -> Option<Vec<T>>
|
||||
where
|
||||
T: std::str::FromStr,
|
||||
<T as std::str::FromStr>::Err: std::fmt::Debug,
|
||||
{
|
||||
matches
|
||||
.values_of(name)
|
||||
.map(|xs| xs.map(|x| x.parse::<T>().unwrap()).collect())
|
||||
}
|
||||
|
||||
// Return a parsed value from matches at `name`
|
||||
pub fn value_of<T>(matches: &ArgMatches<'_>, name: &str) -> Option<T>
|
||||
where
|
||||
T: std::str::FromStr,
|
||||
<T as std::str::FromStr>::Err: std::fmt::Debug,
|
||||
{
|
||||
if let Some(value) = matches.value_of(name) {
|
||||
value.parse::<T>().ok()
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
// Return the keypair for an argument with filename `name` or None if not present.
|
||||
pub fn keypair_of(matches: &ArgMatches<'_>, name: &str) -> Option<Keypair> {
|
||||
if let Some(value) = matches.value_of(name) {
|
||||
read_keypair_file(value).ok()
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
// Return a pubkey for an argument that can itself be parsed into a pubkey,
|
||||
// or is a filename that can be read as a keypair
|
||||
pub fn pubkey_of(matches: &ArgMatches<'_>, name: &str) -> Option<Pubkey> {
|
||||
value_of(matches, name).or_else(|| keypair_of(matches, name).map(|keypair| keypair.pubkey()))
|
||||
}
|
||||
|
||||
pub fn amount_of(matches: &ArgMatches<'_>, name: &str, unit: &str) -> Option<u64> {
|
||||
if matches.value_of(unit) == Some("lamports") {
|
||||
value_of(matches, name)
|
||||
} else {
|
||||
value_of(matches, name).map(sol_to_lamports)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use clap::{App, Arg};
|
||||
use solana_sdk::signature::write_keypair_file;
|
||||
use std::fs;
|
||||
|
||||
fn app<'ab, 'v>() -> App<'ab, 'v> {
|
||||
App::new("test")
|
||||
.arg(
|
||||
Arg::with_name("multiple")
|
||||
.long("multiple")
|
||||
.takes_value(true)
|
||||
.multiple(true),
|
||||
)
|
||||
.arg(Arg::with_name("single").takes_value(true).long("single"))
|
||||
}
|
||||
|
||||
fn tmp_file_path(name: &str, pubkey: &Pubkey) -> String {
|
||||
use std::env;
|
||||
let out_dir = env::var("FARF_DIR").unwrap_or_else(|_| "farf".to_string());
|
||||
|
||||
format!("{}/tmp/{}-{}", out_dir, name, pubkey.to_string())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_values_of() {
|
||||
let matches =
|
||||
app()
|
||||
.clone()
|
||||
.get_matches_from(vec!["test", "--multiple", "50", "--multiple", "39"]);
|
||||
assert_eq!(values_of(&matches, "multiple"), Some(vec![50, 39]));
|
||||
assert_eq!(values_of::<u64>(&matches, "single"), None);
|
||||
|
||||
let pubkey0 = Pubkey::new_rand();
|
||||
let pubkey1 = Pubkey::new_rand();
|
||||
let matches = app().clone().get_matches_from(vec![
|
||||
"test",
|
||||
"--multiple",
|
||||
&pubkey0.to_string(),
|
||||
"--multiple",
|
||||
&pubkey1.to_string(),
|
||||
]);
|
||||
assert_eq!(
|
||||
values_of(&matches, "multiple"),
|
||||
Some(vec![pubkey0, pubkey1])
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_value_of() {
|
||||
let matches = app()
|
||||
.clone()
|
||||
.get_matches_from(vec!["test", "--single", "50"]);
|
||||
assert_eq!(value_of(&matches, "single"), Some(50));
|
||||
assert_eq!(value_of::<u64>(&matches, "multiple"), None);
|
||||
|
||||
let pubkey = Pubkey::new_rand();
|
||||
let matches = app()
|
||||
.clone()
|
||||
.get_matches_from(vec!["test", "--single", &pubkey.to_string()]);
|
||||
assert_eq!(value_of(&matches, "single"), Some(pubkey));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_keypair_of() {
|
||||
let keypair = Keypair::new();
|
||||
let outfile = tmp_file_path("test_gen_keypair_file.json", &keypair.pubkey());
|
||||
let _ = write_keypair_file(&keypair, &outfile).unwrap();
|
||||
|
||||
let matches = app()
|
||||
.clone()
|
||||
.get_matches_from(vec!["test", "--single", &outfile]);
|
||||
assert_eq!(
|
||||
keypair_of(&matches, "single").unwrap().pubkey(),
|
||||
keypair.pubkey()
|
||||
);
|
||||
assert!(keypair_of(&matches, "multiple").is_none());
|
||||
|
||||
let matches =
|
||||
app()
|
||||
.clone()
|
||||
.get_matches_from(vec!["test", "--single", "random_keypair_file.json"]);
|
||||
assert!(keypair_of(&matches, "single").is_none());
|
||||
|
||||
fs::remove_file(&outfile).unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_pubkey_of() {
|
||||
let keypair = Keypair::new();
|
||||
let outfile = tmp_file_path("test_gen_keypair_file.json", &keypair.pubkey());
|
||||
let _ = write_keypair_file(&keypair, &outfile).unwrap();
|
||||
|
||||
let matches = app()
|
||||
.clone()
|
||||
.get_matches_from(vec!["test", "--single", &outfile]);
|
||||
assert_eq!(pubkey_of(&matches, "single"), Some(keypair.pubkey()));
|
||||
assert_eq!(pubkey_of(&matches, "multiple"), None);
|
||||
|
||||
let matches =
|
||||
app()
|
||||
.clone()
|
||||
.get_matches_from(vec!["test", "--single", &keypair.pubkey().to_string()]);
|
||||
assert_eq!(pubkey_of(&matches, "single"), Some(keypair.pubkey()));
|
||||
|
||||
let matches =
|
||||
app()
|
||||
.clone()
|
||||
.get_matches_from(vec!["test", "--single", "random_keypair_file.json"]);
|
||||
assert_eq!(pubkey_of(&matches, "single"), None);
|
||||
|
||||
fs::remove_file(&outfile).unwrap();
|
||||
}
|
||||
}
|
@ -1,36 +0,0 @@
|
||||
use solana_sdk::pubkey::Pubkey;
|
||||
use solana_sdk::signature::read_keypair_file;
|
||||
|
||||
// Return an error if a pubkey cannot be parsed.
|
||||
pub fn is_pubkey(string: String) -> Result<(), String> {
|
||||
match string.parse::<Pubkey>() {
|
||||
Ok(_) => Ok(()),
|
||||
Err(err) => Err(format!("{:?}", err)),
|
||||
}
|
||||
}
|
||||
|
||||
// Return an error if a keypair file cannot be parsed.
|
||||
pub fn is_keypair(string: String) -> Result<(), String> {
|
||||
read_keypair_file(&string)
|
||||
.map(|_| ())
|
||||
.map_err(|err| format!("{:?}", err))
|
||||
}
|
||||
|
||||
// Return an error if string cannot be parsed as pubkey string or keypair file location
|
||||
pub fn is_pubkey_or_keypair(string: String) -> Result<(), String> {
|
||||
is_pubkey(string.clone()).or_else(|_| is_keypair(string))
|
||||
}
|
||||
|
||||
// Return an error if a url cannot be parsed.
|
||||
pub fn is_url(string: String) -> Result<(), String> {
|
||||
match url::Url::parse(&string) {
|
||||
Ok(url) => {
|
||||
if url.has_host() {
|
||||
Ok(())
|
||||
} else {
|
||||
Err("no host provided".to_string())
|
||||
}
|
||||
}
|
||||
Err(err) => Err(format!("{:?}", err)),
|
||||
}
|
||||
}
|
@ -5,8 +5,6 @@ pub mod cli;
|
||||
pub mod cluster_query;
|
||||
pub mod config;
|
||||
pub mod display;
|
||||
pub mod input_parsers;
|
||||
pub mod input_validators;
|
||||
pub mod stake;
|
||||
pub mod storage;
|
||||
pub mod validator_info;
|
||||
|
@ -1,12 +1,14 @@
|
||||
use clap::{crate_description, crate_name, crate_version, Arg, ArgGroup, ArgMatches, SubCommand};
|
||||
use console::style;
|
||||
|
||||
use solana_clap_utils::input_validators::is_url;
|
||||
use solana_cli::{
|
||||
cli::{app, parse_command, process_command, CliCommandInfo, CliConfig, CliError},
|
||||
config::{self, Config},
|
||||
display::{println_name_value, println_name_value_or},
|
||||
input_validators::is_url,
|
||||
};
|
||||
use solana_sdk::signature::read_keypair_file;
|
||||
|
||||
use std::error;
|
||||
|
||||
fn parse_settings(matches: &ArgMatches<'_>) -> Result<bool, Box<dyn error::Error>> {
|
||||
|
@ -1,14 +1,10 @@
|
||||
use crate::{
|
||||
cli::{
|
||||
build_balance_message, check_account_for_fee, check_unique_pubkeys,
|
||||
log_instruction_custom_error, CliCommand, CliCommandInfo, CliConfig, CliError,
|
||||
ProcessResult,
|
||||
},
|
||||
input_parsers::*,
|
||||
input_validators::*,
|
||||
use crate::cli::{
|
||||
build_balance_message, check_account_for_fee, check_unique_pubkeys,
|
||||
log_instruction_custom_error, CliCommand, CliCommandInfo, CliConfig, CliError, ProcessResult,
|
||||
};
|
||||
use clap::{App, Arg, ArgMatches, SubCommand};
|
||||
use console::style;
|
||||
use solana_clap_utils::{input_parsers::*, input_validators::*};
|
||||
use solana_client::rpc_client::RpcClient;
|
||||
use solana_sdk::signature::Keypair;
|
||||
use solana_sdk::{
|
||||
|
@ -1,12 +1,9 @@
|
||||
use crate::{
|
||||
cli::{
|
||||
check_account_for_fee, check_unique_pubkeys, log_instruction_custom_error, CliCommand,
|
||||
CliCommandInfo, CliConfig, CliError, ProcessResult,
|
||||
},
|
||||
input_parsers::*,
|
||||
input_validators::*,
|
||||
use crate::cli::{
|
||||
check_account_for_fee, check_unique_pubkeys, log_instruction_custom_error, CliCommand,
|
||||
CliCommandInfo, CliConfig, CliError, ProcessResult,
|
||||
};
|
||||
use clap::{App, Arg, ArgMatches, SubCommand};
|
||||
use solana_clap_utils::{input_parsers::*, input_validators::*};
|
||||
use solana_client::rpc_client::RpcClient;
|
||||
use solana_sdk::signature::Keypair;
|
||||
use solana_sdk::{
|
||||
|
@ -1,14 +1,17 @@
|
||||
use crate::{
|
||||
cli::{check_account_for_fee, CliCommand, CliCommandInfo, CliConfig, CliError, ProcessResult},
|
||||
display::println_name_value,
|
||||
input_parsers::pubkey_of,
|
||||
input_validators::{is_pubkey, is_url},
|
||||
};
|
||||
use bincode::deserialize;
|
||||
use clap::{App, Arg, ArgMatches, SubCommand};
|
||||
use reqwest::Client;
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
use serde_json::{Map, Value};
|
||||
|
||||
use solana_clap_utils::{
|
||||
input_parsers::pubkey_of,
|
||||
input_validators::{is_pubkey, is_url},
|
||||
};
|
||||
use solana_client::rpc_client::RpcClient;
|
||||
use solana_config_api::{config_instruction, get_config_data, ConfigKeys, ConfigState};
|
||||
use solana_sdk::{
|
||||
@ -19,6 +22,7 @@ use solana_sdk::{
|
||||
signature::{Keypair, KeypairUtil},
|
||||
transaction::Transaction,
|
||||
};
|
||||
|
||||
use std::error;
|
||||
|
||||
pub const MAX_SHORT_FIELD_LENGTH: usize = 70;
|
||||
|
@ -1,13 +1,9 @@
|
||||
use crate::{
|
||||
cli::{
|
||||
build_balance_message, check_account_for_fee, check_unique_pubkeys,
|
||||
log_instruction_custom_error, CliCommand, CliCommandInfo, CliConfig, CliError,
|
||||
ProcessResult,
|
||||
},
|
||||
input_parsers::*,
|
||||
input_validators::*,
|
||||
use crate::cli::{
|
||||
build_balance_message, check_account_for_fee, check_unique_pubkeys,
|
||||
log_instruction_custom_error, CliCommand, CliCommandInfo, CliConfig, CliError, ProcessResult,
|
||||
};
|
||||
use clap::{value_t_or_exit, App, Arg, ArgMatches, SubCommand};
|
||||
use solana_clap_utils::{input_parsers::*, input_validators::*};
|
||||
use solana_client::rpc_client::RpcClient;
|
||||
use solana_sdk::signature::Keypair;
|
||||
use solana_sdk::{
|
||||
|
Reference in New Issue
Block a user