2020-01-20 22:06:47 -08:00
|
|
|
use clap::{crate_description, crate_name, AppSettings, Arg, ArgGroup, ArgMatches, SubCommand};
|
2019-08-07 12:17:11 -07:00
|
|
|
use console::style;
|
2019-11-11 16:42:08 -08:00
|
|
|
|
2019-11-23 08:55:43 -08:00
|
|
|
use solana_clap_utils::{
|
2020-02-07 10:26:56 -08:00
|
|
|
input_parsers::derivation_of,
|
|
|
|
input_validators::{is_derivation, is_url},
|
2020-02-24 16:03:30 -08:00
|
|
|
keypair::SKIP_SEED_PHRASE_VALIDATION_ARG,
|
2019-11-23 08:55:43 -08:00
|
|
|
};
|
2019-09-03 10:38:12 -07:00
|
|
|
use solana_cli::{
|
2020-02-24 16:03:30 -08:00
|
|
|
cli::{app, parse_command, process_command, CliCommandInfo, CliConfig, CliSigners},
|
2019-09-05 10:14:23 -07:00
|
|
|
display::{println_name_value, println_name_value_or},
|
2019-09-03 10:38:12 -07:00
|
|
|
};
|
2020-01-31 18:27:37 -08:00
|
|
|
use solana_cli_config::config::{Config, CONFIG_FILE};
|
2020-02-24 16:03:30 -08:00
|
|
|
use solana_remote_wallet::remote_wallet::{maybe_wallet_manager, RemoteWalletManager};
|
|
|
|
use std::{error, sync::Arc};
|
2018-06-29 10:38:00 -07:00
|
|
|
|
2019-08-07 12:17:11 -07:00
|
|
|
fn parse_settings(matches: &ArgMatches<'_>) -> Result<bool, Box<dyn error::Error>> {
|
|
|
|
let parse_args = match matches.subcommand() {
|
2020-01-20 22:06:47 -08:00
|
|
|
("config", Some(matches)) => match matches.subcommand() {
|
|
|
|
("get", Some(subcommand_matches)) => {
|
|
|
|
if let Some(config_file) = matches.value_of("config_file") {
|
|
|
|
let config = Config::load(config_file).unwrap_or_default();
|
|
|
|
if let Some(field) = subcommand_matches.value_of("specific_setting") {
|
2020-02-05 10:14:44 -08:00
|
|
|
let (field_name, value, default_value) = match field {
|
2020-02-07 10:26:56 -08:00
|
|
|
"url" => ("RPC URL", config.url, CliConfig::default_json_rpc_url()),
|
2020-02-05 10:14:44 -08:00
|
|
|
"keypair" => (
|
|
|
|
"Key Path",
|
|
|
|
config.keypair_path,
|
|
|
|
CliConfig::default_keypair_path(),
|
|
|
|
),
|
2020-01-20 22:06:47 -08:00
|
|
|
_ => unreachable!(),
|
|
|
|
};
|
2020-02-05 10:14:44 -08:00
|
|
|
println_name_value_or(&format!("{}:", field_name), &value, &default_value);
|
2020-01-20 22:06:47 -08:00
|
|
|
} else {
|
2020-02-05 10:14:44 -08:00
|
|
|
println_name_value("Config File:", config_file);
|
2020-01-20 22:06:47 -08:00
|
|
|
println_name_value_or(
|
2020-02-07 10:26:56 -08:00
|
|
|
"RPC URL:",
|
2020-01-20 22:06:47 -08:00
|
|
|
&config.url,
|
|
|
|
&CliConfig::default_json_rpc_url(),
|
|
|
|
);
|
|
|
|
println_name_value_or(
|
2020-02-07 10:26:56 -08:00
|
|
|
"Keypair Path:",
|
2020-01-20 22:06:47 -08:00
|
|
|
&config.keypair_path,
|
|
|
|
&CliConfig::default_keypair_path(),
|
|
|
|
);
|
|
|
|
}
|
2019-08-07 12:17:11 -07:00
|
|
|
} else {
|
2020-01-20 22:06:47 -08:00
|
|
|
println!(
|
|
|
|
"{} Either provide the `--config` arg or ensure home directory exists to use the default config location",
|
|
|
|
style("No config file found.").bold()
|
2019-09-05 10:14:23 -07:00
|
|
|
);
|
2019-08-07 12:17:11 -07:00
|
|
|
}
|
2020-01-20 22:06:47 -08:00
|
|
|
false
|
2019-08-07 12:17:11 -07:00
|
|
|
}
|
2020-01-20 22:06:47 -08:00
|
|
|
("set", Some(subcommand_matches)) => {
|
|
|
|
if let Some(config_file) = matches.value_of("config_file") {
|
|
|
|
let mut config = Config::load(config_file).unwrap_or_default();
|
|
|
|
if let Some(url) = subcommand_matches.value_of("json_rpc_url") {
|
|
|
|
config.url = url.to_string();
|
|
|
|
}
|
|
|
|
if let Some(keypair) = subcommand_matches.value_of("keypair") {
|
|
|
|
config.keypair_path = keypair.to_string();
|
|
|
|
}
|
|
|
|
config.save(config_file)?;
|
2020-02-05 10:14:44 -08:00
|
|
|
println_name_value("Config File:", config_file);
|
|
|
|
println_name_value("RPC URL:", &config.url);
|
|
|
|
println_name_value("Keypair Path:", &config.keypair_path);
|
2020-01-20 22:06:47 -08:00
|
|
|
} else {
|
|
|
|
println!(
|
|
|
|
"{} Either provide the `--config` arg or ensure home directory exists to use the default config location",
|
|
|
|
style("No config file found.").bold()
|
|
|
|
);
|
2019-08-07 12:17:11 -07:00
|
|
|
}
|
2020-01-20 22:06:47 -08:00
|
|
|
false
|
2019-08-07 12:17:11 -07:00
|
|
|
}
|
2020-01-20 22:06:47 -08:00
|
|
|
_ => unreachable!(),
|
|
|
|
},
|
2019-08-07 12:17:11 -07:00
|
|
|
_ => true,
|
|
|
|
};
|
|
|
|
Ok(parse_args)
|
|
|
|
}
|
|
|
|
|
2020-02-24 16:03:30 -08:00
|
|
|
pub fn parse_args<'a>(
|
|
|
|
matches: &ArgMatches<'_>,
|
|
|
|
wallet_manager: Option<Arc<RemoteWalletManager>>,
|
|
|
|
) -> Result<(CliConfig<'a>, CliSigners), Box<dyn error::Error>> {
|
2019-08-07 12:17:11 -07:00
|
|
|
let config = if let Some(config_file) = matches.value_of("config_file") {
|
|
|
|
Config::load(config_file).unwrap_or_default()
|
|
|
|
} else {
|
|
|
|
Config::default()
|
|
|
|
};
|
|
|
|
let json_rpc_url = if let Some(url) = matches.value_of("json_rpc_url") {
|
|
|
|
url.to_string()
|
|
|
|
} else if config.url != "" {
|
|
|
|
config.url
|
|
|
|
} else {
|
2019-10-04 15:13:21 -07:00
|
|
|
let default = CliConfig::default();
|
2019-08-07 12:17:11 -07:00
|
|
|
default.json_rpc_url
|
|
|
|
};
|
2019-01-16 20:43:00 -08:00
|
|
|
|
2020-02-24 16:03:30 -08:00
|
|
|
let default_signer_path = if matches.is_present("keypair") {
|
|
|
|
matches.value_of("keypair").unwrap().to_string()
|
|
|
|
} else if config.keypair_path != "" {
|
|
|
|
config.keypair_path
|
2018-09-14 01:58:39 -07:00
|
|
|
} else {
|
2020-02-24 16:03:30 -08:00
|
|
|
CliConfig::default_keypair_path()
|
2018-09-14 01:58:39 -07:00
|
|
|
};
|
|
|
|
|
2020-02-24 16:03:30 -08:00
|
|
|
let CliCommandInfo { command, signers } =
|
|
|
|
parse_command(&matches, &default_signer_path, wallet_manager.as_ref())?;
|
|
|
|
|
|
|
|
Ok((
|
|
|
|
CliConfig {
|
|
|
|
command,
|
|
|
|
json_rpc_url,
|
|
|
|
signers: vec![],
|
|
|
|
keypair_path: default_signer_path,
|
|
|
|
derivation_path: derivation_of(matches, "derivation_path"),
|
|
|
|
rpc_client: None,
|
|
|
|
verbose: matches.is_present("verbose"),
|
|
|
|
},
|
|
|
|
signers,
|
|
|
|
))
|
2018-06-29 10:38:00 -07:00
|
|
|
}
|
|
|
|
|
2018-12-08 21:44:20 -08:00
|
|
|
fn main() -> Result<(), Box<dyn error::Error>> {
|
2018-12-14 12:36:50 -08:00
|
|
|
solana_logger::setup();
|
2019-11-13 20:10:38 -08:00
|
|
|
let matches = app(
|
|
|
|
crate_name!(),
|
|
|
|
crate_description!(),
|
|
|
|
solana_clap_utils::version!(),
|
|
|
|
)
|
|
|
|
.arg({
|
|
|
|
let arg = Arg::with_name("config_file")
|
|
|
|
.short("C")
|
|
|
|
.long("config")
|
|
|
|
.value_name("PATH")
|
|
|
|
.takes_value(true)
|
|
|
|
.global(true)
|
|
|
|
.help("Configuration file to use");
|
2020-01-31 18:27:37 -08:00
|
|
|
if let Some(ref config_file) = *CONFIG_FILE {
|
2019-11-13 20:10:38 -08:00
|
|
|
arg.default_value(&config_file)
|
|
|
|
} else {
|
|
|
|
arg
|
|
|
|
}
|
|
|
|
})
|
|
|
|
.arg(
|
|
|
|
Arg::with_name("json_rpc_url")
|
|
|
|
.short("u")
|
|
|
|
.long("url")
|
|
|
|
.value_name("URL")
|
|
|
|
.takes_value(true)
|
|
|
|
.global(true)
|
|
|
|
.validator(is_url)
|
|
|
|
.help("JSON RPC URL for the solana cluster"),
|
|
|
|
)
|
|
|
|
.arg(
|
|
|
|
Arg::with_name("keypair")
|
|
|
|
.short("k")
|
|
|
|
.long("keypair")
|
|
|
|
.value_name("PATH")
|
|
|
|
.global(true)
|
|
|
|
.takes_value(true)
|
2020-02-07 10:26:56 -08:00
|
|
|
.help("/path/to/id.json or usb://remote/wallet/path"),
|
|
|
|
)
|
|
|
|
.arg(
|
|
|
|
Arg::with_name("derivation_path")
|
|
|
|
.long("derivation-path")
|
|
|
|
.value_name("ACCOUNT or ACCOUNT/CHANGE")
|
2020-02-21 13:55:53 -08:00
|
|
|
.global(true)
|
2020-02-07 10:26:56 -08:00
|
|
|
.takes_value(true)
|
|
|
|
.validator(is_derivation)
|
|
|
|
.help("Derivation path to use: m/44'/501'/ACCOUNT'/CHANGE'; default key is device base pubkey: m/44'/501'/0'")
|
2019-11-13 20:10:38 -08:00
|
|
|
)
|
2019-11-24 16:34:18 -08:00
|
|
|
.arg(
|
2019-12-19 14:37:47 -08:00
|
|
|
Arg::with_name("verbose")
|
|
|
|
.long("verbose")
|
|
|
|
.short("v")
|
2019-11-24 16:34:18 -08:00
|
|
|
.global(true)
|
2019-12-19 14:37:47 -08:00
|
|
|
.help("Show extra information header"),
|
2019-11-24 16:34:18 -08:00
|
|
|
)
|
2019-11-23 08:55:43 -08:00
|
|
|
.arg(
|
|
|
|
Arg::with_name(SKIP_SEED_PHRASE_VALIDATION_ARG.name)
|
|
|
|
.long(SKIP_SEED_PHRASE_VALIDATION_ARG.long)
|
|
|
|
.global(true)
|
|
|
|
.help(SKIP_SEED_PHRASE_VALIDATION_ARG.help),
|
|
|
|
)
|
2019-11-13 20:10:38 -08:00
|
|
|
.subcommand(
|
2020-01-20 22:06:47 -08:00
|
|
|
SubCommand::with_name("config")
|
|
|
|
.about("Solana command-line tool configuration settings")
|
|
|
|
.aliases(&["get", "set"])
|
|
|
|
.setting(AppSettings::SubcommandRequiredElseHelp)
|
|
|
|
.subcommand(
|
|
|
|
SubCommand::with_name("get")
|
|
|
|
.about("Get current config settings")
|
|
|
|
.arg(
|
|
|
|
Arg::with_name("specific_setting")
|
|
|
|
.index(1)
|
|
|
|
.value_name("CONFIG_FIELD")
|
|
|
|
.takes_value(true)
|
|
|
|
.possible_values(&["url", "keypair"])
|
|
|
|
.help("Return a specific config setting"),
|
|
|
|
),
|
|
|
|
)
|
|
|
|
.subcommand(
|
|
|
|
SubCommand::with_name("set")
|
|
|
|
.about("Set a config setting")
|
|
|
|
.group(
|
|
|
|
ArgGroup::with_name("config_settings")
|
|
|
|
.args(&["json_rpc_url", "keypair"])
|
|
|
|
.multiple(true)
|
|
|
|
.required(true),
|
|
|
|
),
|
2019-11-13 20:10:38 -08:00
|
|
|
),
|
|
|
|
)
|
|
|
|
.get_matches();
|
2018-06-26 22:52:34 -07:00
|
|
|
|
2019-08-07 12:17:11 -07:00
|
|
|
if parse_settings(&matches)? {
|
2020-02-24 16:03:30 -08:00
|
|
|
let wallet_manager = maybe_wallet_manager()?;
|
|
|
|
|
|
|
|
let (mut config, signers) = parse_args(&matches, wallet_manager)?;
|
|
|
|
config.signers = signers.iter().map(|s| s.as_ref()).collect();
|
2019-08-07 12:17:11 -07:00
|
|
|
let result = process_command(&config)?;
|
|
|
|
println!("{}", result);
|
|
|
|
}
|
2018-09-17 12:15:26 -07:00
|
|
|
Ok(())
|
2018-06-29 10:38:00 -07:00
|
|
|
}
|