Add cli-output helpers (#18933)
* Add OutputFormat helper to reduce copy-pasta * Add CliSignOnlyData constructor
This commit is contained in:
parent
14f0ce850d
commit
467c18e0d1
|
@ -4354,6 +4354,7 @@ dependencies = [
|
|||
"Inflector",
|
||||
"base64 0.13.0",
|
||||
"chrono",
|
||||
"clap 2.33.3",
|
||||
"console",
|
||||
"humantime",
|
||||
"indicatif",
|
||||
|
|
|
@ -12,6 +12,7 @@ documentation = "https://docs.rs/solana-cli-output"
|
|||
[dependencies]
|
||||
base64 = "0.13.0"
|
||||
chrono = { version = "0.4.11", features = ["serde"] }
|
||||
clap = "2.33.0"
|
||||
console = "0.14.1"
|
||||
humantime = "2.0.1"
|
||||
Inflector = "0.11.4"
|
||||
|
|
|
@ -8,6 +8,7 @@ use {
|
|||
QuietDisplay, VerboseDisplay,
|
||||
},
|
||||
chrono::{Local, TimeZone},
|
||||
clap::ArgMatches,
|
||||
console::{style, Emoji},
|
||||
inflector::cases::titlecase::to_title_case,
|
||||
serde::{Deserialize, Serialize},
|
||||
|
@ -47,7 +48,7 @@ use {
|
|||
|
||||
static WARNING: Emoji = Emoji("⚠️", "!");
|
||||
|
||||
#[derive(PartialEq)]
|
||||
#[derive(PartialEq, Debug)]
|
||||
pub enum OutputFormat {
|
||||
Display,
|
||||
Json,
|
||||
|
@ -77,6 +78,21 @@ impl OutputFormat {
|
|||
OutputFormat::JsonCompact => serde_json::to_value(item).unwrap().to_string(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_matches(matches: &ArgMatches<'_>, output_name: &str, verbose: bool) -> Self {
|
||||
matches
|
||||
.value_of(output_name)
|
||||
.map(|value| match value {
|
||||
"json" => OutputFormat::Json,
|
||||
"json-compact" => OutputFormat::JsonCompact,
|
||||
_ => unreachable!(),
|
||||
})
|
||||
.unwrap_or(if verbose {
|
||||
OutputFormat::DisplayVerbose
|
||||
} else {
|
||||
OutputFormat::Display
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
|
@ -1572,7 +1588,7 @@ impl fmt::Display for CliInflation {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Default)]
|
||||
#[derive(Serialize, Deserialize, Default, Debug, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct CliSignOnlyData {
|
||||
pub blockhash: String,
|
||||
|
@ -2024,6 +2040,11 @@ pub fn return_signers_with_config(
|
|||
output_format: &OutputFormat,
|
||||
config: &ReturnSignersConfig,
|
||||
) -> Result<String, Box<dyn std::error::Error>> {
|
||||
let cli_command = return_signers_data(tx, config);
|
||||
Ok(output_format.formatted_string(&cli_command))
|
||||
}
|
||||
|
||||
pub fn return_signers_data(tx: &Transaction, config: &ReturnSignersConfig) -> CliSignOnlyData {
|
||||
let verify_results = tx.verify_with_results();
|
||||
let mut signers = Vec::new();
|
||||
let mut absent = Vec::new();
|
||||
|
@ -2048,15 +2069,13 @@ pub fn return_signers_with_config(
|
|||
None
|
||||
};
|
||||
|
||||
let cli_command = CliSignOnlyData {
|
||||
CliSignOnlyData {
|
||||
blockhash: tx.message.recent_blockhash.to_string(),
|
||||
message,
|
||||
signers,
|
||||
absent,
|
||||
bad_sig,
|
||||
};
|
||||
|
||||
Ok(output_format.formatted_string(&cli_command))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn parse_sign_only_reply_string(reply: &str) -> SignOnly {
|
||||
|
@ -2438,6 +2457,7 @@ impl VerboseDisplay for CliGossipNodes {}
|
|||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use clap::{App, Arg};
|
||||
use solana_sdk::{
|
||||
message::Message,
|
||||
pubkey::Pubkey,
|
||||
|
@ -2498,6 +2518,22 @@ mod tests {
|
|||
assert_eq!(sign_only.absent_signers[0], absent.pubkey());
|
||||
assert_eq!(sign_only.bad_signers[0], bad.pubkey());
|
||||
|
||||
let res_data = return_signers_data(&tx, &ReturnSignersConfig::default());
|
||||
assert_eq!(
|
||||
res_data,
|
||||
CliSignOnlyData {
|
||||
blockhash: blockhash.to_string(),
|
||||
message: None,
|
||||
signers: vec![format!(
|
||||
"{}={}",
|
||||
present.pubkey().to_string(),
|
||||
tx.signatures[1]
|
||||
)],
|
||||
absent: vec![absent.pubkey().to_string()],
|
||||
bad_sig: vec![bad.pubkey().to_string()],
|
||||
}
|
||||
);
|
||||
|
||||
let expected_msg = "AwECBwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDgTl3Dqh9\
|
||||
F19Wo1Rmw0x+zMuNipG07jeiXfYPW4/Js5QEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQE\
|
||||
BAQEBAYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGBQUFBQUFBQUFBQUFBQUFBQUF\
|
||||
|
@ -2511,10 +2547,26 @@ mod tests {
|
|||
let res = return_signers_with_config(&tx, &OutputFormat::JsonCompact, &config).unwrap();
|
||||
let sign_only = parse_sign_only_reply_string(&res);
|
||||
assert_eq!(sign_only.blockhash, blockhash);
|
||||
assert_eq!(sign_only.message, Some(expected_msg));
|
||||
assert_eq!(sign_only.message, Some(expected_msg.clone()));
|
||||
assert_eq!(sign_only.present_signers[0].0, present.pubkey());
|
||||
assert_eq!(sign_only.absent_signers[0], absent.pubkey());
|
||||
assert_eq!(sign_only.bad_signers[0], bad.pubkey());
|
||||
|
||||
let res_data = return_signers_data(&tx, &config);
|
||||
assert_eq!(
|
||||
res_data,
|
||||
CliSignOnlyData {
|
||||
blockhash: blockhash.to_string(),
|
||||
message: Some(expected_msg),
|
||||
signers: vec![format!(
|
||||
"{}={}",
|
||||
present.pubkey().to_string(),
|
||||
tx.signatures[1]
|
||||
)],
|
||||
absent: vec![absent.pubkey().to_string()],
|
||||
bad_sig: vec![bad.pubkey().to_string()],
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -2563,4 +2615,50 @@ mod tests {
|
|||
"verbose"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_output_format_from_matches() {
|
||||
let app = App::new("test").arg(
|
||||
Arg::with_name("output_format")
|
||||
.long("output")
|
||||
.value_name("FORMAT")
|
||||
.global(true)
|
||||
.takes_value(true)
|
||||
.possible_values(&["json", "json-compact"])
|
||||
.help("Return information in specified output format"),
|
||||
);
|
||||
let matches = app
|
||||
.clone()
|
||||
.get_matches_from(vec!["test", "--output", "json"]);
|
||||
assert_eq!(
|
||||
OutputFormat::from_matches(&matches, "output_format", false),
|
||||
OutputFormat::Json
|
||||
);
|
||||
assert_eq!(
|
||||
OutputFormat::from_matches(&matches, "output_format", true),
|
||||
OutputFormat::Json
|
||||
);
|
||||
|
||||
let matches = app
|
||||
.clone()
|
||||
.get_matches_from(vec!["test", "--output", "json-compact"]);
|
||||
assert_eq!(
|
||||
OutputFormat::from_matches(&matches, "output_format", false),
|
||||
OutputFormat::JsonCompact
|
||||
);
|
||||
assert_eq!(
|
||||
OutputFormat::from_matches(&matches, "output_format", true),
|
||||
OutputFormat::JsonCompact
|
||||
);
|
||||
|
||||
let matches = app.clone().get_matches_from(vec!["test"]);
|
||||
assert_eq!(
|
||||
OutputFormat::from_matches(&matches, "output_format", false),
|
||||
OutputFormat::Display
|
||||
);
|
||||
assert_eq!(
|
||||
OutputFormat::from_matches(&matches, "output_format", true),
|
||||
OutputFormat::DisplayVerbose
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -200,18 +200,7 @@ pub fn parse_args<'a>(
|
|||
}
|
||||
|
||||
let verbose = matches.is_present("verbose");
|
||||
let output_format = matches
|
||||
.value_of("output_format")
|
||||
.map(|value| match value {
|
||||
"json" => OutputFormat::Json,
|
||||
"json-compact" => OutputFormat::JsonCompact,
|
||||
_ => unreachable!(),
|
||||
})
|
||||
.unwrap_or(if verbose {
|
||||
OutputFormat::DisplayVerbose
|
||||
} else {
|
||||
OutputFormat::Display
|
||||
});
|
||||
let output_format = OutputFormat::from_matches(matches, "output_format", verbose);
|
||||
|
||||
let (_, commitment) = CliConfig::compute_commitment_config(
|
||||
matches.value_of("commitment").unwrap_or(""),
|
||||
|
|
|
@ -385,18 +385,7 @@ pub fn bigtable_process_command(ledger_path: &Path, matches: &ArgMatches<'_>) {
|
|||
let runtime = tokio::runtime::Runtime::new().unwrap();
|
||||
|
||||
let verbose = matches.is_present("verbose");
|
||||
let output_format = matches
|
||||
.value_of("output_format")
|
||||
.map(|value| match value {
|
||||
"json" => OutputFormat::Json,
|
||||
"json-compact" => OutputFormat::JsonCompact,
|
||||
_ => unreachable!(),
|
||||
})
|
||||
.unwrap_or(if verbose {
|
||||
OutputFormat::DisplayVerbose
|
||||
} else {
|
||||
OutputFormat::Display
|
||||
});
|
||||
let output_format = OutputFormat::from_matches(matches, "output_format", verbose);
|
||||
|
||||
let future = match matches.subcommand() {
|
||||
("upload", Some(arg_matches)) => {
|
||||
|
|
|
@ -2807,6 +2807,7 @@ dependencies = [
|
|||
"Inflector",
|
||||
"base64 0.13.0",
|
||||
"chrono",
|
||||
"clap",
|
||||
"console",
|
||||
"humantime",
|
||||
"indicatif",
|
||||
|
|
Loading…
Reference in New Issue