Rename solana-wallet program to just solana (#5604)

* Rename wallet/ to cli/

* Rename the solana-wallet crate to solana-cli

* Rename solana-wallet program to solana

* cargo fmt
This commit is contained in:
Michael Vines
2019-08-22 13:51:16 -07:00
committed by GitHub
parent 19d16e75c6
commit 1207664bbb
29 changed files with 162 additions and 145 deletions

49
cli/src/config.rs Normal file
View File

@@ -0,0 +1,49 @@
// Wallet settings that can be configured for long-term use
use serde_derive::{Deserialize, Serialize};
use std::fs::{create_dir_all, File};
use std::io::{self, Write};
use std::path::Path;
lazy_static! {
pub static ref CONFIG_FILE: Option<String> = {
dirs::home_dir().map(|mut path| {
path.extend(&[".config", "solana", "wallet", "config.yml"]);
path.to_str().unwrap().to_string()
})
};
}
#[derive(Serialize, Deserialize, Default, Debug, PartialEq)]
pub struct Config {
pub url: String,
pub keypair: String,
}
impl Config {
pub fn new(url: &str, keypair: &str) -> Self {
Self {
url: url.to_string(),
keypair: keypair.to_string(),
}
}
pub fn load(config_file: &str) -> Result<Self, io::Error> {
let file = File::open(config_file.to_string())?;
let config = serde_yaml::from_reader(file)
.map_err(|err| io::Error::new(io::ErrorKind::Other, format!("{:?}", err)))?;
Ok(config)
}
pub fn save(&self, config_file: &str) -> Result<(), io::Error> {
let serialized = serde_yaml::to_string(self)
.map_err(|err| io::Error::new(io::ErrorKind::Other, format!("{:?}", err)))?;
if let Some(outdir) = Path::new(&config_file).parent() {
create_dir_all(outdir)?;
}
let mut file = File::create(config_file)?;
file.write_all(&serialized.into_bytes())?;
Ok(())
}
}

11
cli/src/display.rs Normal file
View File

@@ -0,0 +1,11 @@
use console::style;
// Pretty print a "name value"
pub fn println_name_value(name: &str, value: &str) {
let styled_value = if value == "" {
style("(not set)").italic()
} else {
style(value)
};
println!("{} {}", style(name).bold(), styled_value);
}

6
cli/src/lib.rs Normal file
View File

@@ -0,0 +1,6 @@
#[macro_use]
extern crate lazy_static;
pub mod config;
pub mod display;
pub mod wallet;

237
cli/src/main.rs Normal file
View File

@@ -0,0 +1,237 @@
use clap::{crate_description, crate_name, crate_version, Arg, ArgGroup, ArgMatches, SubCommand};
use console::style;
use solana_cli::config::{self, Config};
use solana_cli::display::println_name_value;
use solana_cli::wallet::{app, parse_command, process_command, WalletConfig, WalletError};
use solana_sdk::signature::{gen_keypair_file, read_keypair, KeypairUtil};
use std::error;
fn parse_settings(matches: &ArgMatches<'_>) -> Result<bool, Box<dyn error::Error>> {
let parse_args = 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") {
let value = match field {
"url" => config.url,
"keypair" => config.keypair,
_ => unreachable!(),
};
println_name_value(&format!("* {}:", field), &value);
} else {
println_name_value("Wallet Config:", config_file);
println_name_value("* url:", &config.url);
println_name_value("* keypair:", &config.keypair);
}
} else {
println!("{} Either provide the `--config` arg or ensure home directory exists to use the default config location", style("No config file found.").bold());
}
false
}
("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("url") {
config.url = url.to_string();
}
if let Some(keypair) = subcommand_matches.value_of("keypair") {
config.keypair = keypair.to_string();
}
config.save(config_file)?;
println_name_value("Wallet Config Updated:", config_file);
println_name_value("* url:", &config.url);
println_name_value("* keypair:", &config.keypair);
} else {
println!("{} Either provide the `--config` arg or ensure home directory exists to use the default config location", style("No config file found.").bold());
}
false
}
_ => true,
};
Ok(parse_args)
}
pub fn parse_args(matches: &ArgMatches<'_>) -> Result<WalletConfig, Box<dyn error::Error>> {
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 {
let default = WalletConfig::default();
default.json_rpc_url
};
let drone_host = if let Some(drone_host) = matches.value_of("drone_host") {
Some(solana_netutil::parse_host(drone_host).or_else(|err| {
Err(WalletError::BadParameter(format!(
"Invalid drone host: {:?}",
err
)))
})?)
} else {
None
};
let drone_port = matches
.value_of("drone_port")
.unwrap()
.parse()
.or_else(|err| {
Err(WalletError::BadParameter(format!(
"Invalid drone port: {:?}",
err
)))
})?;
let mut path = dirs::home_dir().expect("home directory");
let id_path = if matches.is_present("keypair") {
matches.value_of("keypair").unwrap()
} else if config.keypair != "" {
&config.keypair
} else {
path.extend(&[".config", "solana", "id.json"]);
if !path.exists() {
gen_keypair_file(path.to_str().unwrap())?;
println!("New keypair generated at: {}", path.to_str().unwrap());
}
path.to_str().unwrap()
};
let keypair = read_keypair(id_path).or_else(|err| {
Err(WalletError::BadParameter(format!(
"{}: Unable to open keypair file: {}",
err, id_path
)))
})?;
let command = parse_command(&keypair.pubkey(), &matches)?;
Ok(WalletConfig {
command,
drone_host,
drone_port,
json_rpc_url,
keypair,
rpc_client: None,
})
}
// Return an error if a url cannot be parsed.
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)),
}
}
fn main() -> Result<(), Box<dyn error::Error>> {
solana_logger::setup();
let default = WalletConfig::default();
let default_drone_port = format!("{}", default.drone_port);
let matches = app(crate_name!(), crate_description!(), crate_version!())
.arg({
let arg = Arg::with_name("config_file")
.short("c")
.long("config")
.value_name("PATH")
.takes_value(true)
.help("Configuration file to use");
if let Some(ref config_file) = *config::CONFIG_FILE {
arg.default_value(&config_file)
} else {
arg
}
})
.arg(
Arg::with_name("json_rpc_url")
.short("u")
.long("url")
.value_name("URL")
.takes_value(true)
.validator(is_url)
.help("JSON RPC URL for the solana cluster"),
)
.arg(
Arg::with_name("drone_host")
.long("drone-host")
.value_name("HOST")
.takes_value(true)
.help("Drone host to use [default: same as the --url host]"),
)
.arg(
Arg::with_name("drone_port")
.long("drone-port")
.value_name("PORT")
.takes_value(true)
.default_value(&default_drone_port)
.help("Drone port to use"),
)
.arg(
Arg::with_name("keypair")
.short("k")
.long("keypair")
.value_name("PATH")
.takes_value(true)
.help("/path/to/id.json"),
)
.subcommand(
SubCommand::with_name("get")
.about("Get wallet 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 wallet config setting")
.arg(
Arg::with_name("url")
.short("u")
.long("url")
.value_name("URL")
.takes_value(true)
.validator(is_url)
.help("Set default JSON RPC URL to query"),
)
.arg(
Arg::with_name("keypair")
.short("k")
.long("keypair")
.value_name("PATH")
.takes_value(true)
.help("/path/to/id.json"),
)
.group(
ArgGroup::with_name("config_settings")
.args(&["url", "keypair"])
.multiple(true)
.required(true),
),
)
.get_matches();
if parse_settings(&matches)? {
let config = parse_args(&matches)?;
let result = process_command(&config)?;
println!("{}", result);
}
Ok(())
}

2766
cli/src/wallet.rs Normal file

File diff suppressed because it is too large Load Diff