Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add compare sub-command to cli #398

Merged
merged 4 commits into from
Oct 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion src/bin/stellar-xdr/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ fn main() {
cli::Error::Types(_)
| cli::Error::Guess(_)
| cli::Error::Decode(_)
| cli::Error::Encode(_) => {
| cli::Error::Encode(_)
| cli::Error::Compare(_) => {
Error::raw(clap::error::ErrorKind::ValueValidation, e).exit()
}
}
Expand Down
114 changes: 114 additions & 0 deletions src/cli/compare.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
use std::{fmt::Debug, fs::File, path::PathBuf, str::FromStr};

use clap::{Args, ValueEnum};

use crate::cli::{skip_whitespace::SkipWhitespace, Channel};

#[derive(thiserror::Error, Debug)]
pub enum Error {
#[error("unknown type {0}, choose one of {1:?}")]
UnknownType(String, &'static [&'static str]),
#[error("error decoding XDR: {0}")]
ReadXdrCurr(#[from] crate::curr::Error),
#[error("error decoding XDR: {0}")]
ReadXdrNext(#[from] crate::next::Error),
#[error("error reading file: {0}")]
ReadFile(#[from] std::io::Error),
}

/// Compare two XDR values with each other
///
/// Outputs:
/// `-1` when the left XDR value is less than the right XDR value,
/// `0` when the left XDR value is equal to the right XDR value,
/// `1` when the left XDR value is greater than the right XDR value
#[derive(Args, Debug, Clone)]
#[command()]
pub struct Cmd {
/// XDR file to decode and compare with the right value
#[arg()]
left: PathBuf,

/// XDR file to decode and compare with the left value
#[arg()]
right: PathBuf,

/// XDR type of both inputs
#[arg(long)]
r#type: String,

// Input format of the XDR
#[arg(long, value_enum, default_value_t)]
input: InputFormat,
}

#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, ValueEnum)]
pub enum InputFormat {
Single,
SingleBase64,
}

impl Default for InputFormat {
fn default() -> Self {
Self::SingleBase64
}
}

macro_rules! run_x {
($f:ident, $m:ident) => {
fn $f(&self) -> Result<(), Error> {
let f1 = File::open(&self.left)?;
let f2 = File::open(&self.right)?;
let r#type = crate::$m::TypeVariant::from_str(&self.r#type).map_err(|_| {
Error::UnknownType(self.r#type.clone(), &crate::$m::TypeVariant::VARIANTS_STR)
})?;
let (t1, t2) = match self.input {
InputFormat::Single => {
let t1 = {
let mut l1 = crate::$m::Limited::new(f1, crate::$m::Limits::none());
crate::$m::Type::read_xdr_to_end(r#type, &mut l1)?
};
let t2 = {
let mut l = crate::$m::Limited::new(f2, crate::$m::Limits::none());
crate::$m::Type::read_xdr_to_end(r#type, &mut l)?
};
(t1, t2)
}
InputFormat::SingleBase64 => {
let t1 = {
let sw = SkipWhitespace::new(f1);
let mut l = crate::$m::Limited::new(sw, crate::$m::Limits::none());
crate::$m::Type::read_xdr_base64_to_end(r#type, &mut l)?
};
let t2 = {
let sw = SkipWhitespace::new(f2);
let mut l = crate::$m::Limited::new(sw, crate::$m::Limits::none());
crate::$m::Type::read_xdr_base64_to_end(r#type, &mut l)?
};
(t1, t2)
}
};
let cmp = t1.cmp(&t2) as i8;
println!("{cmp}");
Ok(())
}
};
}

impl Cmd {
/// Run the CLIs decode command.
///
/// ## Errors
///
/// If the command is configured with state that is invalid.
pub fn run(&self, channel: &Channel) -> Result<(), Error> {
match channel {
Channel::Curr => self.run_curr()?,
Channel::Next => self.run_next()?,
}
Ok(())
}

run_x!(run_curr, curr);
run_x!(run_next, next);
}
5 changes: 5 additions & 0 deletions src/cli/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
pub mod compare;
pub mod decode;
pub mod encode;
pub mod guess;
Expand Down Expand Up @@ -39,6 +40,7 @@ impl Root {
Cmd::Guess(c) => c.run(&self.channel)?,
Cmd::Decode(c) => c.run(&self.channel)?,
Cmd::Encode(c) => c.run(&self.channel)?,
Cmd::Compare(c) => c.run(&self.channel)?,
Cmd::Version => version::Cmd::run(),
}
Ok(())
Expand Down Expand Up @@ -69,6 +71,7 @@ pub enum Cmd {
Decode(decode::Cmd),
/// Encode XDR
Encode(encode::Cmd),
Compare(compare::Cmd),
/// Print version information
Version,
}
Expand All @@ -86,6 +89,8 @@ pub enum Error {
Decode(#[from] decode::Error),
#[error("error reading file: {0}")]
Encode(#[from] encode::Error),
#[error(transparent)]
Compare(#[from] compare::Error),
}

/// Run the CLI with the given args.
Expand Down
Loading