Redo using clap derive instead of builder

This commit is contained in:
Tony Garnock-Jones 2022-10-26 13:44:31 +02:00
parent 4ce2093e52
commit 181523d05c
1 changed files with 72 additions and 51 deletions

View File

@ -1,70 +1,91 @@
use std::io; use std::io;
use std::str::FromStr;
use clap::arg;
use clap::value_parser;
use clap::ArgGroup; use clap::ArgGroup;
use clap::Command; use clap::CommandFactory;
use clap::Id; use clap::Parser;
use clap::Subcommand;
use clap::arg;
use clap_complete::{generate, Shell}; use clap_complete::{generate, Shell};
use preserves::hex::HexParser; use preserves::hex::HexParser;
use preserves::value::BytesBinarySource;
use preserves::value::NestedValue;
use preserves::value::NoEmbeddedDomainCodec; use preserves::value::NoEmbeddedDomainCodec;
use preserves::value::Reader;
use preserves::value::TextReader;
use preserves::value::ViaCodec; use preserves::value::ViaCodec;
use preserves::value::TextWriter; use preserves::value::TextWriter;
use syndicate::language; use syndicate::language;
use syndicate::preserves_schema::Codec; use syndicate::preserves_schema::Codec;
use syndicate::preserves_schema::ParseError;
use syndicate::sturdy::_Any;
fn cli() -> Command { #[derive(Clone, Debug)]
Command::new("syndicate-macaroon") struct Preserves<N: NestedValue>(N);
.subcommand_required(true)
.subcommand( #[derive(Subcommand, Debug)]
Command::new("mint") enum Action {
.about("Mint a fresh macaroon") #[command(group(ArgGroup::new("key").required(true)))]
.arg(arg!(--oid <value> "Preserves value to use as SturdyRef OID").required(true)) /// Generate a fresh SturdyRef from an OID value and a key
.arg(arg!(--phrase <text> "Key phrase")) Mint {
.arg(arg!(--hex <hex> "Key bytes, encoded as hex")) #[arg(long, value_name="VALUE")]
.group( /// Preserves value to use as SturdyRef OID
ArgGroup::new("key") oid: Preserves<_Any>,
.args(["phrase", "hex"])
.required(true))) #[arg(long, group="key")]
.subcommand( /// Key phrase
Command::new("completions") phrase: Option<String>,
.about("Generate shell completions for this command")
.arg(arg!(<shell> "Shell dialect to generate").value_parser(value_parser!(Shell)))) #[arg(long, group="key")]
/// Key bytes, encoded as hex
hex: Option<String>,
},
/// Emit shell completion code
Completions {
/// Shell dialect to generate
shell: Shell,
}
}
#[derive(Parser, Debug)]
#[command(version)]
struct Cli {
#[command(subcommand)]
action: Action,
}
impl<N: NestedValue> FromStr for Preserves<N> {
type Err = ParseError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
Ok(Preserves(TextReader::new(&mut BytesBinarySource::new(s.as_bytes()),
ViaCodec::new(NoEmbeddedDomainCodec)).demand_next(false)?))
}
} }
fn main() -> io::Result<()> { fn main() -> io::Result<()> {
let args = cli().get_matches(); let args = <Cli as Parser>::parse();
if let Some(args) = args.subcommand_matches("completions") { match args.action {
let shell = args.get_one::<Shell>("shell").unwrap().clone(); Action::Completions { shell } => {
let mut cmd = cli(); let mut cmd = <Cli as CommandFactory>::command();
let name = cmd.get_name().to_string(); let name = cmd.get_name().to_string();
generate(shell, &mut cmd, name, &mut io::stdout()); generate(shell, &mut cmd, name, &mut io::stdout());
} }
if let Some(args) = args.subcommand_matches("mint") { Action::Mint { oid, phrase, hex } => {
let oid_str = args.get_one::<String>("oid").unwrap(); let key =
let oid = match preserves::value::text::from_str(&oid_str, ViaCodec::new(NoEmbeddedDomainCodec)) { if let Some(hex) = hex {
Ok(oid) => oid, HexParser::Liberal.decode(&hex).expect("hex encoded sturdyref")
Err(e) => { } else if let Some(phrase) = phrase {
eprintln!("Could not parse oid: {}", e); phrase.as_bytes().to_owned()
std::process::exit(1); } else {
} unreachable!()
}; };
let key = match args.get_one::<Id>("key").unwrap().as_str() { let m = syndicate::sturdy::SturdyRef::mint(oid.0, &key);
"hex" => { println!("{}", TextWriter::encode(&mut NoEmbeddedDomainCodec,
let hex = args.get_one::<String>("hex").unwrap(); &language().unparse(&m))?);
HexParser::Liberal.decode(hex).expect("hex encoded sturdyref") }
}
"phrase" => {
let text = args.get_one::<String>("phrase").unwrap();
text.as_bytes().to_owned()
}
&_ => unreachable!(),
};
let m = syndicate::sturdy::SturdyRef::mint(oid, &key);
println!("{}", TextWriter::encode(&mut NoEmbeddedDomainCodec,
&language().unparse(&m))?);
} }
Ok(()) Ok(())