use std::{
fmt::{self, Display, Formatter},
str::FromStr,
};
use serde::Serialize;
use structopt::StructOpt;
use thiserror::Error;
use super::StopAtSpec;
#[derive(Debug, Error)]
pub(super) enum Error {
#[error("failed to split line using shell lexing rules")]
ShlexFailure,
#[error(transparent)]
Invalid(#[from] structopt::clap::Error),
}
#[derive(Clone, Copy, Debug, Eq, PartialEq, Serialize, Default)]
pub(super) enum OutputFormat {
#[default]
Interactive,
Json,
Bincode,
}
impl Display for OutputFormat {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
match self {
OutputFormat::Interactive => f.write_str("interactive"),
OutputFormat::Json => f.write_str("json"),
OutputFormat::Bincode => f.write_str("bincode"),
}
}
}
impl FromStr for OutputFormat {
type Err = &'static str;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s.to_lowercase().as_str() {
"interactive" | "i" => Ok(OutputFormat::Interactive),
"json" | "j" => Ok(OutputFormat::Json),
"bincode" | "b" => Ok(OutputFormat::Bincode),
_ => Err("invalid output format, must be one of 'interactive', 'json', 'bincode'"),
}
}
}
#[derive(Debug, StructOpt)]
pub(super) enum Action {
Session,
Set {
#[structopt(short, long)]
quiet: Option<bool>,
#[structopt(short, long)]
output: Option<OutputFormat>,
},
GetLogFilter,
SetLogFilter { directive: String },
DumpConsensus {
era: Option<u64>,
},
DumpQueues,
NetInfo,
Stop {
#[structopt(short, long, default_value)]
at: StopAtSpec,
#[structopt(short, long)]
clear: bool,
},
SetFailpoint {
activation: String,
},
Quit,
}
#[derive(Debug, StructOpt)]
pub(super) struct Command {
#[structopt(subcommand)]
pub(super) action: Action,
}
impl Command {
pub(super) fn from_line(line: &str) -> Result<Self, Error> {
let mut parts = vec!["casper-diagnostics-port".to_owned()];
parts.extend(shlex::split(line).ok_or(Error::ShlexFailure)?);
Ok(Self::from_iter_safe(parts.into_iter())?)
}
}
#[cfg(test)]
mod tests {
use crate::components::diagnostics_port::command::{Action, Command};
#[test]
fn can_parse_simple_commands() {
let cmd = Command::from_line("dump-consensus 123").expect("command parsing failed");
assert!(matches!(cmd.action, Action::DumpConsensus { era } if era == Some(123)));
let cmd = Command::from_line("dump-queues").expect("command parsing failed");
assert!(matches!(cmd.action, Action::DumpQueues));
}
}