From 8d35db17e474e33f8753fd46bbdb9997aca4f1f6 Mon Sep 17 00:00:00 2001 From: Greg Fitzgerald Date: Tue, 12 May 2020 16:06:04 -0600 Subject: [PATCH] Make --transaction-db option implicit (#34) --- Cargo.lock | 1 + Cargo.toml | 1 + README.md | 11 +++++++---- src/arg_parser.rs | 47 ++++++++++++++++++++++++++++++----------------- src/main.rs | 14 +++++++++++++- src/tokens.rs | 17 +++++++++++------ 6 files changed, 63 insertions(+), 28 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 787561018bbfd7..47e6c63af63890 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3445,6 +3445,7 @@ dependencies = [ "clap", "console 0.10.3", "csv", + "dirs", "indexmap", "indicatif", "itertools 0.9.0", diff --git a/Cargo.toml b/Cargo.toml index b0b463b404bcac..4324c0275a0485 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,6 +13,7 @@ chrono = { version = "0.4", features = ["serde"] } clap = "2.33.0" console = "0.10.3" csv = "1.1.3" +dirs = "2.0.2" indexmap = "1.3.2" indicatif = "0.14.0" itertools = "0.9.0" diff --git a/README.md b/README.md index 1dd3af9a0ced75..940183dfd71819 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ primary_address,bid_amount_dollars ``` ```bash -solana-tokens distribute-tokens --from --dollars-per-sol --from-bids --input-csv --transaction-db --fee-payer +solana-tokens distribute-tokens --from --dollars-per-sol --from-bids --input-csv --fee-payer ``` Example transaction log before: @@ -31,7 +31,7 @@ Send tokens to the recipients in `` if the distribution is not already recordered in the transaction log. ```bash -solana-tokens distribute-tokens --from --dollars-per-sol --from-bids --input-csv --transaction-db --fee-payer +solana-tokens distribute-tokens --from --dollars-per-sol --from-bids --input-csv --fee-payer ``` Example output: @@ -46,6 +46,10 @@ UKUcTXgbeTYh65RaVV5gSf6xBHevqHvAXMo3e8Q6np8k 43 Example transaction log after: +```bash +solana-tokens transaction-log --output-path transactions.csv +``` + ```text recipient,amount,signature 6Vo87BaDhp4v4GHwVDhw5huhxVF8CyxSXYtkUwVHbbPv,30,1111111111111111111111111111111111111111111111111111111111111111 @@ -60,7 +64,7 @@ List the differences between a list of expected distributions and the record of transactions have already been sent. ```bash -solana-tokens distribute-tokens --dollars-per-sol --dry-run --from-bids --input-csv --transaction-db +solana-tokens distribute-tokens --dollars-per-sol --dry-run --from-bids --input-csv ``` Example bids.csv: @@ -91,7 +95,6 @@ the new accounts inherit any lockup or custodian settings of the original. ```bash solana-tokens distribute-stake --stake-account-address \ --input-csv \ - --transaction-db \ --stake-authority --withdraw-authority --fee-payer ``` diff --git a/src/arg_parser.rs b/src/arg_parser.rs index 3ecaff543cab7c..96e38e208ed58a 100644 --- a/src/arg_parser.rs +++ b/src/arg_parser.rs @@ -36,12 +36,11 @@ where SubCommand::with_name("distribute-tokens") .about("Distribute tokens") .arg( - Arg::with_name("transaction_db") - .long("transaction-db") - .required(true) + Arg::with_name("campaign_name") + .long("campaign-name") .takes_value(true) - .value_name("FILE") - .help("Transaction database file"), + .value_name("NAME") + .help("Campaign name for storing transaction data"), ) .arg( Arg::with_name("from_bids") @@ -91,12 +90,11 @@ where SubCommand::with_name("distribute-stake") .about("Distribute stake accounts") .arg( - Arg::with_name("transaction_db") - .long("transaction-db") - .required(true) + Arg::with_name("campaign_name") + .long("campaign-name") .takes_value(true) - .value_name("FILE") - .help("Transaction database file"), + .value_name("NAME") + .help("Campaign name for storing transaction data"), ) .arg( Arg::with_name("input_csv") @@ -193,12 +191,11 @@ where SubCommand::with_name("transaction-log") .about("Print the database to a CSV file") .arg( - Arg::with_name("transaction_db") - .long("transaction-db") - .required(true) + Arg::with_name("campaign_name") + .long("campaign-name") .takes_value(true) - .value_name("FILE") - .help("Transactions database file"), + .value_name("NAME") + .help("Campaign name for storing transaction data"), ) .arg( Arg::with_name("output_path") @@ -212,11 +209,27 @@ where .get_matches_from(args) } +fn create_db_path(campaign_name: Option) -> String { + let (prefix, hyphen) = if let Some(name) = campaign_name { + (name, "-") + } else { + ("".to_string(), "") + }; + let path = dirs::home_dir().unwrap(); + let filename = format!("{}{}transactions.db", prefix, hyphen); + path.join(".config") + .join("solana-tokens") + .join(filename) + .to_str() + .unwrap() + .to_string() +} + fn parse_distribute_tokens_args(matches: &ArgMatches<'_>) -> DistributeTokensArgs { DistributeTokensArgs { input_csv: value_t_or_exit!(matches, "input_csv", String), from_bids: matches.is_present("from_bids"), - transaction_db: value_t_or_exit!(matches, "transaction_db", String), + transaction_db: create_db_path(value_t!(matches, "campaign_name", String).ok()), dollars_per_sol: value_t!(matches, "dollars_per_sol", f64).ok(), dry_run: matches.is_present("dry_run"), sender_keypair: value_t_or_exit!(matches, "sender_keypair", String), @@ -235,7 +248,7 @@ fn parse_distribute_stake_args(matches: &ArgMatches<'_>) -> DistributeTokensArgs DistributeTokensArgs { input_csv: value_t_or_exit!(matches, "input_csv", String), from_bids: false, - transaction_db: value_t_or_exit!(matches, "transaction_db", String), + transaction_db: create_db_path(value_t!(matches, "campaign_name", String).ok()), dollars_per_sol: None, dry_run: matches.is_present("dry_run"), sender_keypair: value_t_or_exit!(matches, "sender_keypair", String), diff --git a/src/main.rs b/src/main.rs index a2e9b63663a67c..379ae648211313 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,4 +1,5 @@ use solana_cli_config::Config; +use solana_cli_config::CONFIG_FILE; use solana_client::rpc_client::RpcClient; use solana_tokens::{ arg_parser::parse_args, @@ -8,10 +9,21 @@ use solana_tokens::{ }; use std::env; use std::error::Error; +use std::path::Path; +use std::process; fn main() -> Result<(), Box> { let command_args = parse_args(env::args_os()); - let config = Config::load(&command_args.config_file)?; + let config = if Path::new(&command_args.config_file).exists() { + Config::load(&command_args.config_file)? + } else { + let default_config_file = CONFIG_FILE.as_ref().unwrap(); + if command_args.config_file != *default_config_file { + eprintln!("Error: config file not found"); + process::exit(1); + } + Config::default() + }; let json_rpc_url = command_args.url.unwrap_or(config.json_rpc_url); let client = RpcClient::new(json_rpc_url); diff --git a/src/tokens.rs b/src/tokens.rs index 195884cf6352d4..634d728ba5c5c6 100644 --- a/src/tokens.rs +++ b/src/tokens.rs @@ -24,7 +24,7 @@ use solana_stake_program::{ use solana_transaction_status::TransactionStatus; use std::{ cmp::{self, Ordering}, - io, + fs, io, path::Path, thread::sleep, time::Duration, @@ -220,17 +220,22 @@ fn distribute_tokens( Ok(()) } -fn open_db(path: &str, dry_run: bool) -> Result { +fn open_db(path: &str, dry_run: bool) -> Result { let policy = if dry_run { PickleDbDumpPolicy::NeverDump } else { PickleDbDumpPolicy::AutoDump }; - if Path::new(path).exists() { - PickleDb::load_yaml(path, policy) + let path = Path::new(path); + let db = if path.exists() { + PickleDb::load_yaml(path, policy)? } else { - Ok(PickleDb::new_yaml(path, policy)) - } + if let Some(parent) = path.parent() { + fs::create_dir_all(parent)?; + } + PickleDb::new_yaml(path, policy) + }; + Ok(db) } fn compare_transaction_infos(a: &TransactionInfo, b: &TransactionInfo) -> Ordering {