Skip to content

Commit

Permalink
Move the CLI functionality into the library (#326)
Browse files Browse the repository at this point in the history
* Move the CLI functionality into the library

* comments

* fix

* fix todo

* pub root

* todo

* dont treat help as error

* empty commit
  • Loading branch information
leighmcculloch authored Dec 1, 2023
1 parent 77f3744 commit 5dcb7a4
Show file tree
Hide file tree
Showing 9 changed files with 177 additions and 160 deletions.
81 changes: 10 additions & 71 deletions src/bin/stellar-xdr/main.rs
Original file line number Diff line number Diff line change
@@ -1,75 +1,14 @@
mod decode;
mod encode;
mod guess;
mod types;
mod version;

use clap::{CommandFactory, Parser, Subcommand, ValueEnum};
use std::{error::Error, fmt::Debug};

#[derive(Parser, Debug, Clone)]
#[command(
author,
version,
about,
long_about = None,
disable_help_subcommand = true,
disable_version_flag = true,
disable_colored_help = true,
infer_subcommands = true,
)]
struct Root {
/// Channel of XDR to operate on
#[arg(value_enum, default_value_t)]
channel: Channel,
#[command(subcommand)]
cmd: Cmd,
}

#[derive(ValueEnum, Debug, Clone)]
pub enum Channel {
#[value(name = "+curr")]
Curr,
#[value(name = "+next")]
Next,
}

impl Default for Channel {
fn default() -> Self {
Self::Curr
}
}

#[derive(Subcommand, Debug, Clone)]
enum Cmd {
/// View information about types
Types(types::Cmd),
/// Guess the XDR type
Guess(guess::Cmd),
/// Decode XDR
Decode(decode::Cmd),
/// Encode XDR
Encode(encode::Cmd),
/// Print version information
Version,
}

fn run() -> Result<(), Box<dyn Error>> {
let root = Root::parse();
match root.cmd {
Cmd::Types(c) => c.run(&root.channel)?,
Cmd::Guess(c) => c.run(&root.channel)?,
Cmd::Decode(c) => c.run(&root.channel)?,
Cmd::Encode(c) => c.run(&root.channel)?,
Cmd::Version => version::Cmd::run(),
}
Ok(())
}
use clap::Error;
use std::env;
use stellar_xdr::cli;

fn main() {
if let Err(e) = run() {
Root::command()
.error(clap::error::ErrorKind::ValueValidation, e)
.exit()
if let Err(e) = cli::run(env::args_os()) {
match e {
cli::Error::Clap(e) => e.exit(),
cli::Error::Guess(_) | cli::Error::Decode(_) | cli::Error::Encode(_) => {
Error::raw(clap::error::ErrorKind::ValueValidation, e).exit()
}
}
}
}
25 changes: 11 additions & 14 deletions src/bin/stellar-xdr/decode.rs → src/cli/decode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,16 @@ use std::{
use clap::{Args, ValueEnum};
use serde::Serialize;

use crate::Channel;
use crate::cli::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] stellar_xdr::curr::Error),
ReadXdrCurr(#[from] crate::curr::Error),
#[error("error decoding XDR: {0}")]
ReadXdrNext(#[from] stellar_xdr::next::Error),
ReadXdrNext(#[from] crate::next::Error),
#[error("error reading file: {0}")]
ReadFile(#[from] std::io::Error),
#[error("error generating JSON: {0}")]
Expand Down Expand Up @@ -75,35 +75,32 @@ macro_rules! run_x {
($f:ident, $m:ident) => {
fn $f(&self) -> Result<(), Error> {
let mut files = self.files()?;
let r#type = stellar_xdr::$m::TypeVariant::from_str(&self.r#type).map_err(|_| {
Error::UnknownType(
self.r#type.clone(),
&stellar_xdr::$m::TypeVariant::VARIANTS_STR,
)
let r#type = crate::$m::TypeVariant::from_str(&self.r#type).map_err(|_| {
Error::UnknownType(self.r#type.clone(), &crate::$m::TypeVariant::VARIANTS_STR)
})?;
for f in &mut files {
let mut f = stellar_xdr::$m::Limited::new(f, stellar_xdr::$m::Limits::none());
let mut f = crate::$m::Limited::new(f, crate::$m::Limits::none());
match self.input {
InputFormat::Single => {
let t = stellar_xdr::$m::Type::read_xdr_to_end(r#type, &mut f)?;
let t = crate::$m::Type::read_xdr_to_end(r#type, &mut f)?;
self.out(&t)?;
}
InputFormat::SingleBase64 => {
let t = stellar_xdr::$m::Type::read_xdr_base64_to_end(r#type, &mut f)?;
let t = crate::$m::Type::read_xdr_base64_to_end(r#type, &mut f)?;
self.out(&t)?;
}
InputFormat::Stream => {
for t in stellar_xdr::$m::Type::read_xdr_iter(r#type, &mut f) {
for t in crate::$m::Type::read_xdr_iter(r#type, &mut f) {
self.out(&t?)?;
}
}
InputFormat::StreamBase64 => {
for t in stellar_xdr::$m::Type::read_xdr_base64_iter(r#type, &mut f) {
for t in crate::$m::Type::read_xdr_base64_iter(r#type, &mut f) {
self.out(&t?)?;
}
}
InputFormat::StreamFramed => {
for t in stellar_xdr::$m::Type::read_xdr_framed_iter(r#type, &mut f) {
for t in crate::$m::Type::read_xdr_framed_iter(r#type, &mut f) {
self.out(&t?)?;
}
}
Expand Down
75 changes: 36 additions & 39 deletions src/bin/stellar-xdr/encode.rs → src/cli/encode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,56 +7,56 @@ use std::{

use clap::{Args, ValueEnum};

use crate::Channel;
use crate::cli::Channel;

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

impl From<stellar_xdr::curr::Error> for Error {
fn from(e: stellar_xdr::curr::Error) -> Self {
impl From<crate::curr::Error> for Error {
fn from(e: crate::curr::Error) -> Self {
match e {
stellar_xdr::curr::Error::Invalid
| stellar_xdr::curr::Error::Unsupported
| stellar_xdr::curr::Error::LengthExceedsMax
| stellar_xdr::curr::Error::LengthMismatch
| stellar_xdr::curr::Error::NonZeroPadding
| stellar_xdr::curr::Error::Utf8Error(_)
| stellar_xdr::curr::Error::InvalidHex
| stellar_xdr::curr::Error::Io(_)
| stellar_xdr::curr::Error::DepthLimitExceeded
| stellar_xdr::curr::Error::LengthLimitExceeded => Error::WriteXdrCurr(e),
stellar_xdr::curr::Error::Json(_) => Error::ReadJsonCurr(e),
crate::curr::Error::Invalid
| crate::curr::Error::Unsupported
| crate::curr::Error::LengthExceedsMax
| crate::curr::Error::LengthMismatch
| crate::curr::Error::NonZeroPadding
| crate::curr::Error::Utf8Error(_)
| crate::curr::Error::InvalidHex
| crate::curr::Error::Io(_)
| crate::curr::Error::DepthLimitExceeded
| crate::curr::Error::LengthLimitExceeded => Error::WriteXdrCurr(e),
crate::curr::Error::Json(_) => Error::ReadJsonCurr(e),
}
}
}

impl From<stellar_xdr::next::Error> for Error {
fn from(e: stellar_xdr::next::Error) -> Self {
impl From<crate::next::Error> for Error {
fn from(e: crate::next::Error) -> Self {
match e {
stellar_xdr::next::Error::Invalid
| stellar_xdr::next::Error::Unsupported
| stellar_xdr::next::Error::LengthExceedsMax
| stellar_xdr::next::Error::LengthMismatch
| stellar_xdr::next::Error::NonZeroPadding
| stellar_xdr::next::Error::Utf8Error(_)
| stellar_xdr::next::Error::InvalidHex
| stellar_xdr::next::Error::Io(_)
| stellar_xdr::next::Error::DepthLimitExceeded
| stellar_xdr::next::Error::LengthLimitExceeded => Error::WriteXdrNext(e),
stellar_xdr::next::Error::Json(_) => Error::ReadJsonNext(e),
crate::next::Error::Invalid
| crate::next::Error::Unsupported
| crate::next::Error::LengthExceedsMax
| crate::next::Error::LengthMismatch
| crate::next::Error::NonZeroPadding
| crate::next::Error::Utf8Error(_)
| crate::next::Error::InvalidHex
| crate::next::Error::Io(_)
| crate::next::Error::DepthLimitExceeded
| crate::next::Error::LengthLimitExceeded => Error::WriteXdrNext(e),
crate::next::Error::Json(_) => Error::ReadJsonNext(e),
}
}
}
Expand Down Expand Up @@ -107,19 +107,16 @@ impl Default for OutputFormat {
macro_rules! run_x {
($f:ident, $m:ident) => {
fn $f(&self) -> Result<(), Error> {
use stellar_xdr::$m::WriteXdr;
use crate::$m::WriteXdr;
let mut files = self.files()?;
let r#type = stellar_xdr::$m::TypeVariant::from_str(&self.r#type).map_err(|_| {
Error::UnknownType(
self.r#type.clone(),
&stellar_xdr::$m::TypeVariant::VARIANTS_STR,
)
let r#type = crate::$m::TypeVariant::from_str(&self.r#type).map_err(|_| {
Error::UnknownType(self.r#type.clone(), &crate::$m::TypeVariant::VARIANTS_STR)
})?;
for f in &mut files {
match self.input {
InputFormat::Json => {
let t = stellar_xdr::$m::Type::read_json(r#type, f)?;
let l = stellar_xdr::$m::Limits::none();
let t = crate::$m::Type::read_json(r#type, f)?;
let l = crate::$m::Limits::none();

match self.output {
OutputFormat::Single => stdout().write_all(&t.to_xdr(l)?)?,
Expand Down
37 changes: 16 additions & 21 deletions src/bin/stellar-xdr/guess.rs → src/cli/guess.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,15 @@ use std::{

use clap::{Args, ValueEnum};

use crate::Channel;
use crate::cli::Channel;

#[derive(thiserror::Error, Debug)]
#[allow(clippy::enum_variant_names)]
pub enum Error {
#[error("error decoding XDR: {0}")]
ReadXdrCurr(#[from] stellar_xdr::curr::Error),
ReadXdrCurr(#[from] crate::curr::Error),
#[error("error decoding XDR: {0}")]
ReadXdrNext(#[from] stellar_xdr::next::Error),
ReadXdrNext(#[from] crate::next::Error),
#[error("error reading file: {0}")]
ReadFile(#[from] std::io::Error),
}
Expand Down Expand Up @@ -69,26 +69,21 @@ impl Default for OutputFormat {
macro_rules! run_x {
($f:ident, $m:ident) => {
fn $f(&self) -> Result<(), Error> {
let mut f = stellar_xdr::$m::Limited::new(
ResetRead::new(self.file()?),
stellar_xdr::$m::Limits::none(),
);
'variants: for v in stellar_xdr::$m::TypeVariant::VARIANTS {
let mut f =
crate::$m::Limited::new(ResetRead::new(self.file()?), crate::$m::Limits::none());
'variants: for v in crate::$m::TypeVariant::VARIANTS {
f.inner.reset();
let count: usize = match self.input {
InputFormat::Single => stellar_xdr::$m::Type::read_xdr_to_end(v, &mut f)
InputFormat::Single => crate::$m::Type::read_xdr_to_end(v, &mut f)
.ok()
.map(|_| 1)
.unwrap_or_default(),
InputFormat::SingleBase64 => crate::$m::Type::read_xdr_base64_to_end(v, &mut f)
.ok()
.map(|_| 1)
.unwrap_or_default(),
InputFormat::SingleBase64 => {
stellar_xdr::$m::Type::read_xdr_base64_to_end(v, &mut f)
.ok()
.map(|_| 1)
.unwrap_or_default()
}
InputFormat::Stream => {
let iter =
stellar_xdr::$m::Type::read_xdr_iter(v, &mut f).take(self.certainty);
let iter = crate::$m::Type::read_xdr_iter(v, &mut f).take(self.certainty);
let mut count = 0;
for v in iter {
match v {
Expand All @@ -99,8 +94,8 @@ macro_rules! run_x {
count
}
InputFormat::StreamBase64 => {
let iter = stellar_xdr::$m::Type::read_xdr_base64_iter(v, &mut f)
.take(self.certainty);
let iter =
crate::$m::Type::read_xdr_base64_iter(v, &mut f).take(self.certainty);
let mut count = 0;
for v in iter {
match v {
Expand All @@ -111,8 +106,8 @@ macro_rules! run_x {
count
}
InputFormat::StreamFramed => {
let iter = stellar_xdr::$m::Type::read_xdr_framed_iter(v, &mut f)
.take(self.certainty);
let iter =
crate::$m::Type::read_xdr_framed_iter(v, &mut f).take(self.certainty);
let mut count = 0;
for v in iter {
match v {
Expand Down
Loading

0 comments on commit 5dcb7a4

Please sign in to comment.