Skip to content

Commit

Permalink
parse up to subcommand name
Browse files Browse the repository at this point in the history
  • Loading branch information
cosmicexplorer committed Aug 14, 2024
1 parent d588c1b commit cad03b6
Showing 1 changed file with 124 additions and 5 deletions.
129 changes: 124 additions & 5 deletions cli/src/args.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,18 @@
#[cfg(not(feature = "clap"))]
use eyre::Report;
use eyre::{Report, WrapErr};

#[cfg(feature = "clap")]
use clap::{
builder::ValueParser, value_parser, Arg, ArgAction, ArgGroup, ArgMatches, Args, Command,
FromArgMatches, Parser, Subcommand, ValueEnum,
};

#[cfg(feature = "clap")]
use std::collections::VecDeque;
use std::{ffi::OsString, num::ParseIntError, path::PathBuf};
use std::{collections::VecDeque, ffi::OsString, num::ParseIntError, path::PathBuf};
#[cfg(not(feature = "clap"))]
use std::{
io::{self, Write},
process,
};

#[derive(Debug)]
#[cfg_attr(feature = "clap", derive(Parser))]
Expand All @@ -22,9 +25,125 @@ pub struct ZipCli {
pub command: ZipCommand,
}

#[cfg(not(feature = "clap"))]
#[derive(Debug)]
enum SubcommandName {
Compress,
Info,
Extract,
}

#[cfg(not(feature = "clap"))]
impl ZipCli {
pub fn parse_argv(_argv: impl IntoIterator<Item = OsString>) -> Result<Self, Report> {
const VERSION: &'static str = env!("CARGO_PKG_VERSION");
const DESCRIPTION: &'static str = env!("CARGO_PKG_DESCRIPTION");
/* This should really be CARGO_BIN_NAME according to clap and cargo's own docs, but that env
* var wasn't found for some reason, so we use the crate name since that's the same for zip-cli
* and zip-clite at least. https://doc.rust-lang.org/cargo/reference/environment-variables.html#environment-variables-cargo-sets-for-crates */
const BIN_NAME: &'static str = env!("CARGO_CRATE_NAME");
const ARGV_PARSE_FAILED_EXIT_CODE: i32 = 2;
const NON_FAILURE_EXIT_CODE: i32 = 0;

fn generate_version_text() -> String {
format!("{} {}\n", Self::BIN_NAME, Self::VERSION)
}

fn generate_full_help_text() -> String {
format!(
r"
{}
Usage: {} [OPTIONS] <COMMAND>
Commands:
compress
info
extract
Options:
-v, --verbose
-h, --help
-V, --version
Build this binary with '--features clap' for more thorough help text.
",
Self::DESCRIPTION,
Self::BIN_NAME
)
}

fn generate_brief_help_text(context: &str) -> String {
format!(
r"
error: {context}
Usage: {} [OPTIONS] <COMMAND>
For more information, try '--help'.
",
Self::BIN_NAME
)
}

fn parse_up_to_subcommand_name(argv: &mut VecDeque<OsString>) -> (bool, SubcommandName) {
let mut verbose: bool = false;
let mut subcommand_name: Option<SubcommandName> = None;
while subcommand_name.is_none() {
match argv.pop_front() {
None => {
let help_text = Self::generate_full_help_text();
io::stderr()
.write_all(help_text.as_bytes())
.wrap_err("Failed to write zero-arg help text to stderr")
.unwrap();
process::exit(Self::ARGV_PARSE_FAILED_EXIT_CODE);
}
Some(arg) => match arg.as_encoded_bytes() {
b"-v" | b"--verbose" => verbose = true,
b"-V" | b"--version" => {
let version_text = Self::generate_version_text();
io::stdout()
.write_all(version_text.as_bytes())
.wrap_err("Failed to write version to stdout")
.unwrap();
process::exit(Self::NON_FAILURE_EXIT_CODE)
}
b"-h" | b"--help" => {
let help_text = Self::generate_full_help_text();
io::stdout()
.write_all(help_text.as_bytes())
.wrap_err("Failed to write -h/--help help text to stdout")
.unwrap();
process::exit(Self::NON_FAILURE_EXIT_CODE);
}
b"compress" => subcommand_name = Some(SubcommandName::Compress),
b"info" => subcommand_name = Some(SubcommandName::Info),
b"extract" => subcommand_name = Some(SubcommandName::Extract),
arg_bytes => {
let context = if arg_bytes.starts_with(b"-") {
format!("unrecognized flag {arg:?}")
} else {
format!("unrecognized subcommand name {arg:?}")
};
let help_text = Self::generate_brief_help_text(&context);
io::stderr()
.write_all(help_text.as_bytes())
.wrap_err("Failed to write unrecognized arg text to stderr")
.unwrap();
process::exit(Self::ARGV_PARSE_FAILED_EXIT_CODE)
}
},
}
}
(verbose, subcommand_name.unwrap())
}

pub fn parse_argv(argv: impl IntoIterator<Item = OsString>) -> Result<Self, Report> {
let mut argv: VecDeque<OsString> = argv.into_iter().collect();
let _exe_name = argv.pop_front().unwrap();
let (verbose, subcommand_name) = Self::parse_up_to_subcommand_name(&mut argv);
dbg!(verbose);
dbg!(subcommand_name);
todo!()
}
}
Expand Down

0 comments on commit cad03b6

Please sign in to comment.