diff --git a/Cargo.lock b/Cargo.lock index 76aad05ac66..6b9f42c882a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -21,6 +21,35 @@ version = "1.0.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "85bb70cc08ec97ca5450e6eba421deeea5f172c0fc61f78b5357b2a8e8be195f" +[[package]] +name = "argh" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca1877e24cecacd700d469066e0160c4f8497cc5635367163f50c8beec820154" +dependencies = [ + "argh_derive", + "argh_shared", +] + +[[package]] +name = "argh_derive" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e742194e0f43fc932bcb801708c2b279d3ec8f527e3acda05a6a9f342c5ef764" +dependencies = [ + "argh_shared", + "heck", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "argh_shared" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1ba68f4276a778591e36a0c348a269888f3a177c8d2054969389e3b59611ff5" + [[package]] name = "arrayvec" version = "0.5.1" @@ -315,6 +344,7 @@ name = "gitoxide" version = "1.0.0" dependencies = [ "anyhow", + "argh", "git-features", "gitoxide-core", "structopt", diff --git a/Cargo.toml b/Cargo.toml index 80b8f57b159..b82d5e84551 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,12 +17,16 @@ doctest = false default = ["fast", "pretty-cli"] fast = ["git-features/parallel", "git-features/fast-sha1"] pretty-cli = ["structopt"] +lean-cli = ["argh"] [dependencies] +anyhow = "1.0.31" + gitoxide-core = { version = "0.1.0", path = "gitoxide-core" } git-features = { version = "0.1.0", path = "git-features" } + structopt = { version = "0.3.14", optional = true } -anyhow = "1.0.31" +argh = { version = "0.1.3", optional = true } [profile.release] overflow-checks = false diff --git a/Makefile b/Makefile index b5f87717596..6f5ec6aa511 100644 --- a/Makefile +++ b/Makefile @@ -14,7 +14,7 @@ interactive-developer-environment-in-docker: ## Use docker for all dependencies ##@ Development target/debug/gio: always - cargo build + cargo build --no-default-features --features pretty-cli target/release/gio: always cargo build --release @@ -29,7 +29,7 @@ profile: target/release/gio ## run callgrind and annotate its output - linux onl benchmark: target/release/gio ## see how fast things are, powered by hyperfine hyperfine '$<' -tests: check unit-tests journey-tests ## run all tests, including journey tests +tests: check unit-tests journey-tests journey-tests-lean-cli ## run all tests, including journey tests check: ## Build all code in suitable configurations cargo check --all @@ -43,9 +43,13 @@ unit-tests: ## run all unit tests continuous-unit-tests: ## run all unit tests whenever something changes watchexec -w src $(MAKE) unit-tests -journey-tests: target/debug/gio ## run stateless journey tests +journey-tests: target/debug/gio ## run stateless journey tests (pretty-cli) ./tests/stateless-journey.sh $< +journey-tests-lean-cli: always ## run stateless journey tests (lean-cli) + cargo build --no-default-features --features lean-cli + ./tests/stateless-journey.sh target/debug/gio + continuous-journey-tests: ## run stateless journey tests whenever something changes watchexec $(MAKE) journey-tests diff --git a/README.md b/README.md index da3abf19848..93b30783bc7 100644 --- a/README.md +++ b/README.md @@ -163,7 +163,7 @@ The top-level command-line interface. * If disabled, the binary will be visibly smaller. * **pretty-cli** _(default)_ * Use `clap` + `structopt` to build the prettiest, best documented and most user-friendly CLI at the expense of file size. -* **small-cli** _(mutually exclusive to pretty-cli)_ +* **lean-cli** _(mutually exclusive to pretty-cli)_ * Use `argh` to produce a usable binary with decent documentation that is smallest in size. * If `pretty-cli` is enabled as well, `small-cli` will take precedence, and you pay for building unnecessary dependencies. diff --git a/src/main.rs b/src/main.rs index 3488d9fbacb..c66c5446798 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,61 +1,124 @@ #![forbid(unsafe_code)] -use anyhow::Result; -use gitoxide_core as core; -use std::io::{stderr, stdout}; -use structopt::StructOpt; - -mod options { - use std::path::PathBuf; - use structopt::clap::AppSettings; +#[cfg(feature = "pretty-cli")] +mod pretty { + use anyhow::Result; + use gitoxide_core as core; + use std::io::{stderr, stdout}; use structopt::StructOpt; - #[derive(Debug, StructOpt)] - #[structopt(about = "The git, simply swift")] - #[structopt(settings = &[AppSettings::SubcommandRequired, + mod options { + use std::path::PathBuf; + use structopt::clap::AppSettings; + use structopt::StructOpt; + + #[derive(Debug, StructOpt)] + #[structopt(about = "The git, simply swift")] + #[structopt(settings = &[AppSettings::SubcommandRequired, AppSettings::ColoredHelp])] - pub struct Args { - #[structopt(subcommand)] - pub cmd: Subcommands, + pub struct Args { + #[structopt(subcommand)] + pub cmd: Subcommands, + } + + /// Low-level commands that are not used every day + #[derive(Debug, StructOpt)] + pub enum Plumbing { + /// Verify the integrity of a pack or index file + #[structopt(setting = AppSettings::ColoredHelp)] + VerifyPack { + /// The '.pack' or '.idx' file whose checksum to validate. + #[structopt(parse(from_os_str))] + path: PathBuf, + }, + } + + #[derive(Debug, StructOpt)] + pub enum Subcommands { + /// Initialize the repository in the current directory. + #[structopt(alias = "initialize")] + #[structopt(setting = AppSettings::ColoredHelp)] + Init, + + #[structopt(alias = "p")] + #[structopt(setting = AppSettings::ColoredHelp)] + Plumbing(Plumbing), + } } - /// Low-level commands that are not used every day - #[derive(Debug, StructOpt)] - pub enum Plumbing { - /// Verify the integrity of a pack or index file - #[structopt(setting = AppSettings::ColoredHelp)] - VerifyPack { - /// The '.pack' file whose checksum to validate. - /// - /// '.pack' files have a 20 byte trailer representing the Sha1 over all the bytes that - /// preceded it. - #[structopt(parse(from_os_str))] - path: PathBuf, - }, + pub fn main() -> Result<()> { + use options::*; + let args = Args::from_args(); + match args.cmd { + Subcommands::Init => core::init(), + Subcommands::Plumbing(cmd) => match cmd { + Plumbing::VerifyPack { path } => { + core::verify_pack_or_pack_index(path, stdout(), stderr()) + } + }, + }?; + Ok(()) } +} - #[derive(Debug, StructOpt)] - pub enum Subcommands { - /// Initialize the repository in the current directory. - #[structopt(alias = "initialize")] - #[structopt(setting = AppSettings::ColoredHelp)] - Init, +#[cfg(all(feature = "lean-cli", not(feature = "pretty-cli")))] +mod lean { + use argh::FromArgs; - #[structopt(alias = "p")] - #[structopt(setting = AppSettings::ColoredHelp)] - Plumbing(Plumbing), + #[derive(FromArgs)] + /// A simple calculation tool + struct Args { + #[argh(subcommand)] + subcommand: SubCommands, } -} -fn main() -> Result<()> { - let args = options::Args::from_args(); - match args.cmd { - options::Subcommands::Init => core::init(), - options::Subcommands::Plumbing(cmd) => match cmd { - options::Plumbing::VerifyPack { path } => { + #[derive(FromArgs, PartialEq, Debug)] + #[argh(subcommand)] + enum SubCommands { + Init(Init), + VerifyPack(VerifyPack), + } + + /// Initialize the repository in the current directory. + #[derive(FromArgs, PartialEq, Debug)] + #[argh(subcommand, name = "init")] + struct Init {} + + /// Initialize the repository in the current directory. + #[derive(FromArgs, PartialEq, Debug)] + #[argh(subcommand, name = "verify-pack")] + struct VerifyPack { + /// the '.pack' or '.idx' file whose checksum to validate. + #[argh(option)] + path: PathBuf, + } + + use anyhow::Result; + use gitoxide_core as core; + use std::{ + io::{stderr, stdout}, + path::PathBuf, + }; + + pub fn main() -> Result<()> { + let cli: Args = argh::from_env(); + match cli.subcommand { + SubCommands::Init(_) => core::init(), + SubCommands::VerifyPack(VerifyPack { path }) => { core::verify_pack_or_pack_index(path, stdout(), stderr()) } - }, - }?; - Ok(()) + } + } +} + +use anyhow::Result; + +#[cfg(feature = "pretty-cli")] +fn main() -> Result<()> { + pretty::main() +} + +#[cfg(all(feature = "lean-cli", not(feature = "pretty-cli")))] +fn main() -> Result<()> { + lean::main() }