Enable json output from solana feature status (#12554)

This commit is contained in:
Tyera Eulberg
2020-09-29 13:26:08 -06:00
committed by GitHub
parent 182552c2e7
commit adf06b635b

View File

@ -4,15 +4,19 @@ use crate::{
}; };
use clap::{App, AppSettings, Arg, ArgMatches, SubCommand}; use clap::{App, AppSettings, Arg, ArgMatches, SubCommand};
use console::style; use console::style;
use serde::{Deserialize, Serialize};
use solana_clap_utils::{input_parsers::*, input_validators::*, keypair::*}; use solana_clap_utils::{input_parsers::*, input_validators::*, keypair::*};
use solana_cli_output::{QuietDisplay, VerboseDisplay};
use solana_client::{client_error::ClientError, rpc_client::RpcClient}; use solana_client::{client_error::ClientError, rpc_client::RpcClient};
use solana_remote_wallet::remote_wallet::RemoteWalletManager; use solana_remote_wallet::remote_wallet::RemoteWalletManager;
use solana_runtime::{ use solana_runtime::{
feature::{self, Feature}, feature::{self, Feature},
feature_set::FEATURE_NAMES, feature_set::FEATURE_NAMES,
}; };
use solana_sdk::{message::Message, pubkey::Pubkey, system_instruction, transaction::Transaction}; use solana_sdk::{
use std::{collections::HashMap, sync::Arc}; clock::Slot, message::Message, pubkey::Pubkey, system_instruction, transaction::Transaction,
};
use std::{collections::HashMap, fmt, sync::Arc};
#[derive(Debug, PartialEq)] #[derive(Debug, PartialEq)]
#[allow(clippy::large_enum_variant)] #[allow(clippy::large_enum_variant)]
@ -21,6 +25,75 @@ pub enum FeatureCliCommand {
Activate { feature: Pubkey }, Activate { feature: Pubkey },
} }
#[derive(Serialize, Deserialize)]
#[serde(rename_all = "camelCase", tag = "status", content = "sinceSlot")]
pub enum CliFeatureStatus {
Inactive,
Pending,
Active(Slot),
}
#[derive(Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct CliFeature {
pub id: String,
pub description: String,
#[serde(flatten)]
pub status: CliFeatureStatus,
}
#[derive(Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct CliFeatures {
pub features: Vec<CliFeature>,
pub feature_activation_allowed: bool,
#[serde(skip)]
pub inactive: bool,
}
impl fmt::Display for CliFeatures {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
if self.features.len() > 1 {
writeln!(
f,
"{}",
style(format!(
"{:<44} {:<40} {}",
"Feature", "Description", "Status"
))
.bold()
)?;
}
for feature in &self.features {
writeln!(
f,
"{:<44} {:<40} {}",
feature.id,
feature.description,
match feature.status {
CliFeatureStatus::Inactive => style("inactive".to_string()).red(),
CliFeatureStatus::Pending => style("activation pending".to_string()).yellow(),
CliFeatureStatus::Active(activation_slot) =>
style(format!("active since slot {}", activation_slot)).green(),
}
)?;
}
if self.inactive && !self.feature_activation_allowed {
writeln!(
f,
"{}",
style("\nFeature activation is not allowed at this time")
.bold()
.red()
)?;
}
Ok(())
}
}
impl QuietDisplay for CliFeatures {}
impl VerboseDisplay for CliFeatures {}
pub trait FeatureSubCommands { pub trait FeatureSubCommands {
fn feature_subcommands(self) -> Self; fn feature_subcommands(self) -> Self;
} }
@ -115,7 +188,7 @@ pub fn process_feature_subcommand(
feature_subcommand: &FeatureCliCommand, feature_subcommand: &FeatureCliCommand,
) -> ProcessResult { ) -> ProcessResult {
match feature_subcommand { match feature_subcommand {
FeatureCliCommand::Status { features } => process_status(rpc_client, features), FeatureCliCommand::Status { features } => process_status(rpc_client, config, features),
FeatureCliCommand::Activate { feature } => process_activate(rpc_client, config, *feature), FeatureCliCommand::Activate { feature } => process_activate(rpc_client, config, *feature),
} }
} }
@ -191,18 +264,12 @@ fn feature_activation_allowed(rpc_client: &RpcClient) -> Result<bool, ClientErro
Ok(feature_activation_allowed) Ok(feature_activation_allowed)
} }
fn process_status(rpc_client: &RpcClient, feature_ids: &[Pubkey]) -> ProcessResult { fn process_status(
if feature_ids.len() > 1 { rpc_client: &RpcClient,
println!( config: &CliConfig,
"{}", feature_ids: &[Pubkey],
style(format!( ) -> ProcessResult {
"{:<44} {:<40} {}", let mut features: Vec<CliFeature> = vec![];
"Feature", "Description", "Status"
))
.bold()
);
}
let mut inactive = false; let mut inactive = false;
for (i, account) in rpc_client for (i, account) in rpc_client
.get_multiple_accounts(feature_ids)? .get_multiple_accounts(feature_ids)?
@ -213,43 +280,32 @@ fn process_status(rpc_client: &RpcClient, feature_ids: &[Pubkey]) -> ProcessResu
let feature_name = FEATURE_NAMES.get(feature_id).unwrap(); let feature_name = FEATURE_NAMES.get(feature_id).unwrap();
if let Some(account) = account { if let Some(account) = account {
if let Some(feature) = Feature::from_account(&account) { if let Some(feature) = Feature::from_account(&account) {
match feature.activated_at { let feature_status = match feature.activated_at {
None => println!( None => CliFeatureStatus::Pending,
"{:<44} {:<40} {}", Some(activation_slot) => CliFeatureStatus::Active(activation_slot),
feature_id, };
feature_name, features.push(CliFeature {
style("activation pending").yellow() id: feature_id.to_string(),
), description: feature_name.to_string(),
Some(activation_slot) => { status: feature_status,
println!( });
"{:<44} {:<40} {}",
feature_id,
feature_name,
style(format!("active since slot {}", activation_slot)).green()
);
}
}
continue; continue;
} }
} }
inactive = true; inactive = true;
println!( features.push(CliFeature {
"{:<44} {:<40} {}", id: feature_id.to_string(),
feature_id, description: feature_name.to_string(),
feature_name, status: CliFeatureStatus::Inactive,
style("inactive").red() });
);
} }
if inactive && !feature_activation_allowed(rpc_client)? { let feature_set = CliFeatures {
println!( features,
"{}", feature_activation_allowed: feature_activation_allowed(rpc_client)?,
style("\nFeature activation is not allowed at this time") inactive,
.bold() };
.red() Ok(config.output_format.formatted_string(&feature_set))
);
}
Ok("".to_string())
} }
fn process_activate( fn process_activate(