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
|
|
|
|
2020-03-12 23:20:49 -07:00
|
|
|
use solana_clap_utils::{
|
2020-05-06 21:21:48 -07:00
|
|
|
input_validators::is_url, keypair::SKIP_SEED_PHRASE_VALIDATION_ARG, DisplayError,
|
2020-03-12 23:20:49 -07: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},
|
2020-04-14 12:10:25 -07:00
|
|
|
cli_output::OutputFormat,
|
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-03-09 12:29:31 -07:00
|
|
|
use solana_cli_config::{Config, CONFIG_FILE};
|
2020-04-18 11:54:21 -07:00
|
|
|
use solana_remote_wallet::remote_wallet::RemoteWalletManager;
|
2020-02-24 16:03:30 -08:00
|
|
|
use std::{error, sync::Arc};
|
2018-06-29 10:38:00 -07:00
|
|
|
|
2020-04-18 11:54:21 -07:00
|
|
|
fn parse_settings(matches: &ArgMatches<'_>) -> Result<bool, Box<dyn error::Error>> {
|
2019-08-07 12:17:11 -07:00
|
|
|
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();
|
2020-02-29 08:39:07 -08:00
|
|
|
|
|
|
|
let (url_setting_type, json_rpc_url) =
|
2020-03-09 12:14:17 -07:00
|
|
|
CliConfig::compute_json_rpc_url_setting("", &config.json_rpc_url);
|
2020-02-29 08:39:07 -08:00
|
|
|
let (ws_setting_type, websocket_url) = CliConfig::compute_websocket_url_setting(
|
|
|
|
"",
|
|
|
|
&config.websocket_url,
|
|
|
|
"",
|
2020-03-09 12:14:17 -07:00
|
|
|
&config.json_rpc_url,
|
2020-02-29 08:39:07 -08:00
|
|
|
);
|
|
|
|
let (keypair_setting_type, keypair_path) =
|
|
|
|
CliConfig::compute_keypair_path_setting("", &config.keypair_path);
|
|
|
|
|
2020-01-20 22:06:47 -08:00
|
|
|
if let Some(field) = subcommand_matches.value_of("specific_setting") {
|
2020-02-29 08:39:07 -08:00
|
|
|
let (field_name, value, setting_type) = match field {
|
|
|
|
"json_rpc_url" => ("RPC URL", json_rpc_url, url_setting_type),
|
2020-03-16 08:24:59 -07:00
|
|
|
"websocket_url" => ("WebSocket URL", websocket_url, ws_setting_type),
|
2020-02-29 08:39:07 -08:00
|
|
|
"keypair" => ("Key Path", keypair_path, keypair_setting_type),
|
2020-01-20 22:06:47 -08:00
|
|
|
_ => unreachable!(),
|
|
|
|
};
|
2020-02-29 08:39:07 -08:00
|
|
|
println_name_value_or(&format!("{}:", field_name), &value, setting_type);
|
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-02-29 08:39:07 -08:00
|
|
|
println_name_value_or("RPC URL:", &json_rpc_url, url_setting_type);
|
2020-03-16 08:24:59 -07:00
|
|
|
println_name_value_or("WebSocket URL:", &websocket_url, ws_setting_type);
|
2020-02-29 08:39:07 -08:00
|
|
|
println_name_value_or("Keypair Path:", &keypair_path, keypair_setting_type);
|
2020-01-20 22:06:47 -08:00
|
|
|
}
|
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-04-18 11:54:21 -07: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") {
|
2020-03-09 12:14:17 -07:00
|
|
|
config.json_rpc_url = url.to_string();
|
2020-03-10 14:09:59 -07:00
|
|
|
// Revert to a computed `websocket_url` value when `json_rpc_url` is
|
|
|
|
// changed
|
|
|
|
config.websocket_url = "".to_string();
|
2020-01-20 22:06:47 -08:00
|
|
|
}
|
2020-02-29 08:39:07 -08:00
|
|
|
if let Some(url) = subcommand_matches.value_of("websocket_url") {
|
|
|
|
config.websocket_url = url.to_string();
|
|
|
|
}
|
2020-01-20 22:06:47 -08:00
|
|
|
if let Some(keypair) = subcommand_matches.value_of("keypair") {
|
|
|
|
config.keypair_path = keypair.to_string();
|
|
|
|
}
|
|
|
|
config.save(config_file)?;
|
2020-02-29 08:39:07 -08:00
|
|
|
|
|
|
|
let (url_setting_type, json_rpc_url) =
|
2020-03-09 12:14:17 -07:00
|
|
|
CliConfig::compute_json_rpc_url_setting("", &config.json_rpc_url);
|
2020-02-29 08:39:07 -08:00
|
|
|
let (ws_setting_type, websocket_url) = CliConfig::compute_websocket_url_setting(
|
|
|
|
"",
|
|
|
|
&config.websocket_url,
|
|
|
|
"",
|
2020-03-09 12:14:17 -07:00
|
|
|
&config.json_rpc_url,
|
2020-02-29 08:39:07 -08:00
|
|
|
);
|
|
|
|
let (keypair_setting_type, keypair_path) =
|
|
|
|
CliConfig::compute_keypair_path_setting("", &config.keypair_path);
|
|
|
|
|
2020-02-05 10:14:44 -08:00
|
|
|
println_name_value("Config File:", config_file);
|
2020-02-29 08:39:07 -08:00
|
|
|
println_name_value_or("RPC URL:", &json_rpc_url, url_setting_type);
|
2020-03-16 08:24:59 -07:00
|
|
|
println_name_value_or("WebSocket URL:", &websocket_url, ws_setting_type);
|
2020-02-29 08:39:07 -08:00
|
|
|
println_name_value_or("Keypair Path:", &keypair_path, keypair_setting_type);
|
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-04-18 11:54:21 -07:00
|
|
|
false
|
2019-08-07 12:17:11 -07:00
|
|
|
}
|
2020-01-20 22:06:47 -08:00
|
|
|
_ => unreachable!(),
|
|
|
|
},
|
2020-04-18 11:54:21 -07:00
|
|
|
_ => true,
|
2019-08-07 12:17:11 -07:00
|
|
|
};
|
|
|
|
Ok(parse_args)
|
|
|
|
}
|
|
|
|
|
2020-02-24 16:03:30 -08:00
|
|
|
pub fn parse_args<'a>(
|
|
|
|
matches: &ArgMatches<'_>,
|
2020-04-18 11:54:21 -07:00
|
|
|
mut wallet_manager: &mut Option<Arc<RemoteWalletManager>>,
|
2020-02-24 16:03:30 -08:00
|
|
|
) -> 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()
|
|
|
|
};
|
2020-02-29 08:39:07 -08:00
|
|
|
let (_, json_rpc_url) = CliConfig::compute_json_rpc_url_setting(
|
|
|
|
matches.value_of("json_rpc_url").unwrap_or(""),
|
2020-03-09 12:14:17 -07:00
|
|
|
&config.json_rpc_url,
|
2020-02-29 08:39:07 -08:00
|
|
|
);
|
|
|
|
let (_, websocket_url) = CliConfig::compute_websocket_url_setting(
|
|
|
|
matches.value_of("websocket_url").unwrap_or(""),
|
|
|
|
&config.websocket_url,
|
|
|
|
matches.value_of("json_rpc_url").unwrap_or(""),
|
2020-03-09 12:14:17 -07:00
|
|
|
&config.json_rpc_url,
|
2020-02-29 08:39:07 -08:00
|
|
|
);
|
|
|
|
let (_, default_signer_path) = CliConfig::compute_keypair_path_setting(
|
|
|
|
matches.value_of("keypair").unwrap_or(""),
|
|
|
|
&config.keypair_path,
|
|
|
|
);
|
2018-09-14 01:58:39 -07:00
|
|
|
|
2020-02-24 16:03:30 -08:00
|
|
|
let CliCommandInfo { command, signers } =
|
2020-04-18 11:54:21 -07:00
|
|
|
parse_command(&matches, &default_signer_path, &mut wallet_manager)?;
|
2020-02-24 16:03:30 -08:00
|
|
|
|
2020-04-14 12:10:25 -07:00
|
|
|
let output_format = matches
|
|
|
|
.value_of("output_format")
|
|
|
|
.map(|value| match value {
|
|
|
|
"json" => OutputFormat::Json,
|
|
|
|
"json-compact" => OutputFormat::JsonCompact,
|
|
|
|
_ => unreachable!(),
|
|
|
|
})
|
|
|
|
.unwrap_or(OutputFormat::Display);
|
|
|
|
|
2020-02-24 16:03:30 -08:00
|
|
|
Ok((
|
|
|
|
CliConfig {
|
|
|
|
command,
|
|
|
|
json_rpc_url,
|
2020-02-29 08:39:07 -08:00
|
|
|
websocket_url,
|
2020-02-24 16:03:30 -08:00
|
|
|
signers: vec![],
|
|
|
|
keypair_path: default_signer_path,
|
|
|
|
rpc_client: None,
|
|
|
|
verbose: matches.is_present("verbose"),
|
2020-04-14 12:10:25 -07:00
|
|
|
output_format,
|
2020-02-24 16:03:30 -08:00
|
|
|
},
|
|
|
|
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")
|
2020-03-16 08:24:59 -07:00
|
|
|
.value_name("FILEPATH")
|
2019-11-13 20:10:38 -08:00
|
|
|
.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"),
|
|
|
|
)
|
2020-02-29 08:39:07 -08:00
|
|
|
.arg(
|
|
|
|
Arg::with_name("websocket_url")
|
|
|
|
.long("ws")
|
|
|
|
.value_name("URL")
|
|
|
|
.takes_value(true)
|
|
|
|
.global(true)
|
|
|
|
.validator(is_url)
|
|
|
|
.help("WebSocket URL for the solana cluster"),
|
|
|
|
)
|
2019-11-13 20:10:38 -08:00
|
|
|
.arg(
|
|
|
|
Arg::with_name("keypair")
|
|
|
|
.short("k")
|
|
|
|
.long("keypair")
|
2020-03-16 11:27:09 -07:00
|
|
|
.value_name("KEYPAIR")
|
2019-11-13 20:10:38 -08:00
|
|
|
.global(true)
|
|
|
|
.takes_value(true)
|
2020-03-16 08:24:59 -07:00
|
|
|
.help("Filepath or URL to a keypair"),
|
2020-02-07 10:26:56 -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)
|
2020-03-16 08:24:59 -07:00
|
|
|
.help("Show additional information"),
|
2019-11-24 16:34:18 -08:00
|
|
|
)
|
2020-04-14 12:10:25 -07:00
|
|
|
.arg(
|
|
|
|
Arg::with_name("output_format")
|
|
|
|
.long("output")
|
|
|
|
.global(true)
|
|
|
|
.takes_value(true)
|
|
|
|
.possible_values(&["json", "json-compact"])
|
|
|
|
.help("Return information in specified output format. Supports: json, json-compact"),
|
|
|
|
)
|
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)
|
2020-02-29 08:39:07 -08:00
|
|
|
.possible_values(&["json_rpc_url", "websocket_url", "keypair"])
|
2020-01-20 22:06:47 -08:00
|
|
|
.help("Return a specific config setting"),
|
|
|
|
),
|
|
|
|
)
|
|
|
|
.subcommand(
|
|
|
|
SubCommand::with_name("set")
|
|
|
|
.about("Set a config setting")
|
|
|
|
.group(
|
|
|
|
ArgGroup::with_name("config_settings")
|
2020-02-29 08:39:07 -08:00
|
|
|
.args(&["json_rpc_url", "websocket_url", "keypair"])
|
2020-01-20 22:06:47 -08:00
|
|
|
.multiple(true)
|
|
|
|
.required(true),
|
|
|
|
),
|
2019-11-13 20:10:38 -08:00
|
|
|
),
|
|
|
|
)
|
|
|
|
.get_matches();
|
2018-06-26 22:52:34 -07:00
|
|
|
|
2020-04-18 11:54:21 -07:00
|
|
|
do_main(&matches).map_err(|err| DisplayError::new_as_boxed(err).into())
|
2020-03-12 23:20:49 -07:00
|
|
|
}
|
|
|
|
|
2020-04-18 11:54:21 -07:00
|
|
|
fn do_main(matches: &ArgMatches<'_>) -> Result<(), Box<dyn error::Error>> {
|
|
|
|
if parse_settings(&matches)? {
|
|
|
|
let mut wallet_manager = None;
|
2020-02-24 16:03:30 -08:00
|
|
|
|
2020-04-18 11:54:21 -07:00
|
|
|
let (mut config, signers) = parse_args(&matches, &mut wallet_manager)?;
|
2020-02-24 16:03:30 -08:00
|
|
|
config.signers = signers.iter().map(|s| s.as_ref()).collect();
|
2019-08-07 12:17:11 -07:00
|
|
|
let result = process_command(&config)?;
|
2020-05-06 21:21:48 -07:00
|
|
|
println!("{}", result);
|
2020-03-12 23:20:49 -07:00
|
|
|
};
|
2018-09-17 12:15:26 -07:00
|
|
|
Ok(())
|
2018-06-29 10:38:00 -07:00
|
|
|
}
|