Skip to content

Commit

Permalink
chore: upgrade to clap 4.1
Browse files Browse the repository at this point in the history
  • Loading branch information
Byron committed Jan 15, 2023
1 parent 6396967 commit 1d9a5e9
Show file tree
Hide file tree
Showing 6 changed files with 215 additions and 47 deletions.
22 changes: 2 additions & 20 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ gitoxide-core = { version = "^0.23.0", path = "gitoxide-core" }
git-features = { version = "^0.26.1", path = "git-features" }
git-repository = { version = "^0.33.0", path = "git-repository", default-features = false }

clap = { version = "3.2.5", features = ["derive", "cargo"] }
clap = { version = "4.1.1", features = ["derive", "cargo"] }
prodash = { version = "23.0", optional = true, default-features = false }
is-terminal = { version = "0.4.0", optional = true }
env_logger = { version = "0.10.0", default-features = false }
Expand Down
105 changes: 99 additions & 6 deletions src/plumbing/options/free.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ pub mod index {
#[derive(Debug, clap::Parser)]
pub struct Platform {
/// The object format to assume when reading files that don't inherently know about it, or when writing files.
#[clap(long, default_value_t = git_repository::hash::Kind::default(), possible_values(&["SHA1"]))]
#[clap(long, default_value_t = git_repository::hash::Kind::default(), value_parser = crate::shared::AsHashKind)]
pub object_hash: git_repository::hash::Kind,

/// The path to the index file.
Expand Down Expand Up @@ -101,7 +101,7 @@ pub mod pack {
/// the directory containing the '.git' repository from which objects should be read.
repository: Option<PathBuf>,

#[clap(long, short = 'e', possible_values(core::pack::create::ObjectExpansion::variants()))]
#[clap(long, short = 'e', value_parser = AsObjectExpansion)]
/// the way objects are expanded. They differ in costs.
///
/// Possible values are "none" and "tree-traversal". Default is "none".
Expand Down Expand Up @@ -211,7 +211,7 @@ pub mod pack {
long,
short = 'c',
default_value = "all",
possible_values(core::pack::explode::SafetyCheck::variants())
value_parser = AsSafetyCheck
)]
check: core::pack::explode::SafetyCheck,

Expand Down Expand Up @@ -249,11 +249,11 @@ pub mod pack {
long,
short = 'a',
default_value = "less-time",
possible_values(core::pack::verify::Algorithm::variants())
value_parser = AsAlgorithm
)]
pub algorithm: core::pack::verify::Algorithm,

#[clap(long, conflicts_with("re-encode"))]
#[clap(long, conflicts_with("re_encode"))]
/// Decode and parse tags, commits and trees to validate their correctness beyond hashing correctly.
///
/// Malformed objects should not usually occur, but could be injected on purpose or accident.
Expand Down Expand Up @@ -308,6 +308,7 @@ pub mod pack {
pub mod index {
use std::path::PathBuf;

use super::AsIterationMode;
use gitoxide_core as core;

#[derive(Debug, clap::Subcommand)]
Expand All @@ -326,7 +327,7 @@ pub mod pack {
long,
short = 'i',
default_value = "verify",
possible_values(core::pack::index::IterationMode::variants())
value_parser = AsIterationMode
)]
iteration_mode: core::pack::index::IterationMode,

Expand All @@ -343,6 +344,98 @@ pub mod pack {
},
}
}

mod clap_util {
use clap::builder::{NonEmptyStringValueParser, PossibleValue, TypedValueParser};
use clap::{Arg, Command, Error};
use std::ffi::OsStr;
use std::str::FromStr;

#[derive(Clone)]
pub struct AsObjectExpansion;

impl TypedValueParser for AsObjectExpansion {
type Value = gitoxide_core::pack::create::ObjectExpansion;

fn parse_ref(&self, cmd: &Command, arg: Option<&Arg>, value: &OsStr) -> Result<Self::Value, Error> {
NonEmptyStringValueParser::new()
.try_map(|arg| gitoxide_core::pack::create::ObjectExpansion::from_str(&arg))
.parse_ref(cmd, arg, value)
}

fn possible_values(&self) -> Option<Box<dyn Iterator<Item = PossibleValue> + '_>> {
Some(Box::new(
gitoxide_core::pack::create::ObjectExpansion::variants()
.iter()
.map(PossibleValue::new),
))
}
}

#[derive(Clone)]
pub struct AsSafetyCheck;

impl TypedValueParser for AsSafetyCheck {
type Value = gitoxide_core::pack::explode::SafetyCheck;

fn parse_ref(&self, cmd: &Command, arg: Option<&Arg>, value: &OsStr) -> Result<Self::Value, Error> {
NonEmptyStringValueParser::new()
.try_map(|arg| gitoxide_core::pack::explode::SafetyCheck::from_str(&arg))
.parse_ref(cmd, arg, value)
}

fn possible_values(&self) -> Option<Box<dyn Iterator<Item = PossibleValue> + '_>> {
Some(Box::new(
gitoxide_core::pack::explode::SafetyCheck::variants()
.iter()
.map(PossibleValue::new),
))
}
}

#[derive(Clone)]
pub struct AsAlgorithm;

impl TypedValueParser for AsAlgorithm {
type Value = gitoxide_core::pack::verify::Algorithm;

fn parse_ref(&self, cmd: &Command, arg: Option<&Arg>, value: &OsStr) -> Result<Self::Value, Error> {
NonEmptyStringValueParser::new()
.try_map(|arg| gitoxide_core::pack::verify::Algorithm::from_str(&arg))
.parse_ref(cmd, arg, value)
}

fn possible_values(&self) -> Option<Box<dyn Iterator<Item = PossibleValue> + '_>> {
Some(Box::new(
gitoxide_core::pack::verify::Algorithm::variants()
.iter()
.map(PossibleValue::new),
))
}
}

#[derive(Clone)]
pub struct AsIterationMode;

impl TypedValueParser for AsIterationMode {
type Value = gitoxide_core::pack::index::IterationMode;

fn parse_ref(&self, cmd: &Command, arg: Option<&Arg>, value: &OsStr) -> Result<Self::Value, Error> {
NonEmptyStringValueParser::new()
.try_map(|arg| gitoxide_core::pack::index::IterationMode::from_str(&arg))
.parse_ref(cmd, arg, value)
}

fn possible_values(&self) -> Option<Box<dyn Iterator<Item = PossibleValue> + '_>> {
Some(Box::new(
gitoxide_core::pack::index::IterationMode::variants()
.iter()
.map(PossibleValue::new),
))
}
}
}
use clap_util::{AsAlgorithm, AsIterationMode, AsObjectExpansion, AsSafetyCheck};
}

///
Expand Down
41 changes: 29 additions & 12 deletions src/plumbing/options/mod.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
use std::path::PathBuf;

use git_repository as git;
use git_repository::bstr::BString;
use gitoxide_core as core;

Expand All @@ -17,7 +16,7 @@ pub struct Args {
///
/// For example, if `key` is `core.abbrev`, set configuration like `[core] abbrev = key`,
/// or `remote.origin.url = foo` to set `[remote "origin"] url = foo`.
#[clap(long, short = 'c', parse(try_from_os_str = git::env::os_str_to_bstring))]
#[clap(long, short = 'c', value_parser = crate::shared::AsBString)]
pub config: Vec<BString>,

#[clap(long, short = 't')]
Expand Down Expand Up @@ -59,12 +58,12 @@ pub struct Args {
long,
short = 'f',
default_value = "human",
possible_values(core::OutputFormat::variants())
value_parser = crate::shared::AsOutputFormat
)]
pub format: core::OutputFormat,

/// The object format to assume when reading files that don't inherently know about it, or when writing files.
#[clap(long, default_value_t = git_repository::hash::Kind::default(), possible_values(&["SHA1"]))]
#[clap(long, default_value_t = git_repository::hash::Kind::default(), value_parser = crate::shared::AsHashKind)]
pub object_hash: git_repository::hash::Kind,

#[clap(subcommand)]
Expand Down Expand Up @@ -129,15 +128,13 @@ pub mod config {
///
/// Typical filters are `branch` or `remote.origin` or `remote.or*` - git-style globs are supported
/// and comparisons are case-insensitive.
#[clap(parse(try_from_os_str = git::env::os_str_to_bstring))]
#[clap(value_parser = crate::shared::AsBString)]
pub filter: Vec<BString>,
}
}

#[cfg(feature = "gitoxide-core-blocking-client")]
pub mod fetch {
use git_repository as git;

#[derive(Debug, clap::Parser)]
pub struct Platform {
/// Don't change the local repository, but otherwise try to be as accurate as possible.
Expand All @@ -155,7 +152,7 @@ pub mod fetch {
pub remote: Option<String>,

/// Override the built-in and configured ref-specs with one or more of the given ones.
#[clap(parse(try_from_os_str = git::env::os_str_to_bstring))]
#[clap(value_parser = crate::shared::AsBString)]
pub ref_spec: Vec<git_repository::bstr::BString>,
}
}
Expand Down Expand Up @@ -188,8 +185,6 @@ pub mod clone {

#[cfg(any(feature = "gitoxide-core-async-client", feature = "gitoxide-core-blocking-client"))]
pub mod remote {
use git_repository as git;

#[derive(Debug, clap::Parser)]
pub struct Platform {
/// The name of the remote to connect to, or the URL of the remote to connect to directly.
Expand Down Expand Up @@ -218,7 +213,7 @@ pub mod remote {
#[clap(long, short = 'u')]
show_unmapped_remote_refs: bool,
/// Override the built-in and configured ref-specs with one or more of the given ones.
#[clap(parse(try_from_os_str = git::env::os_str_to_bstring))]
#[clap(value_parser = crate::shared::AsBString)]
ref_spec: Vec<git_repository::bstr::BString>,
},
}
Expand Down Expand Up @@ -360,6 +355,7 @@ pub mod revision {
pub mod exclude {
use std::ffi::OsString;

use super::AsPathSpec;
use git_repository as git;

#[derive(Debug, clap::Subcommand)]
Expand All @@ -377,7 +373,7 @@ pub mod exclude {
#[clap(long, short = 'p')]
patterns: Vec<OsString>,
/// The git path specifications to check for exclusion, or unset to read from stdin one per line.
#[clap(parse(try_from_os_str = std::convert::TryFrom::try_from))]
#[clap(value_parser = AsPathSpec)]
pathspecs: Vec<git::path::Spec>,
},
}
Expand Down Expand Up @@ -407,3 +403,24 @@ pub mod index {

///
pub mod free;

mod clap_util {
use clap::builder::{OsStringValueParser, TypedValueParser};
use clap::{Arg, Command, Error};
use git_repository as git;
use std::ffi::OsStr;

#[derive(Clone)]
pub struct AsPathSpec;

impl TypedValueParser for AsPathSpec {
type Value = git::path::Spec;

fn parse_ref(&self, cmd: &Command, arg: Option<&Arg>, value: &OsStr) -> Result<Self::Value, Error> {
OsStringValueParser::new()
.try_map(|arg| git::path::Spec::try_from(arg.as_os_str()))
.parse_ref(cmd, arg, value)
}
}
}
use clap_util::AsPathSpec;
35 changes: 27 additions & 8 deletions src/porcelain/options.rs
Original file line number Diff line number Diff line change
Expand Up @@ -92,12 +92,11 @@ pub enum ToolCommands {
]
pub struct EstimateHours {
/// The directory containing a '.git/' folder.
#[clap(parse(from_os_str))]
#[clap(validator_os = validator::is_repo)]
#[clap(value_parser = validator::IsRepo)]
#[clap(default_value = ".")]
pub working_dir: PathBuf,
/// The name of the revision as spec, like 'HEAD' or 'main' at which to start iterating the commit graph.
#[clap(default_value("HEAD"), parse(try_from_os_str = git::env::os_str_to_bstring))]
#[clap(default_value("HEAD"), value_parser = crate::shared::AsBString)]
pub rev_spec: BString,
/// Ignore github bots which match the `[bot]` search string.
#[clap(short = 'b', long)]
Expand Down Expand Up @@ -128,7 +127,31 @@ mod validator {
use anyhow::Context;
use git_repository as git;

fn is_repo_inner(dir: &OsStr) -> anyhow::Result<()> {
#[derive(Clone)]
pub struct IsRepo;

impl clap::builder::TypedValueParser for IsRepo {
type Value = PathBuf;

fn parse_ref(
&self,
cmd: &clap::Command,
_arg: Option<&clap::Arg>,
value: &OsStr,
) -> Result<Self::Value, clap::Error> {
assure_is_repo(value).map_err(|e| {
let mut err = clap::Error::new(clap::error::ErrorKind::InvalidValue).with_cmd(cmd);
err.insert(
clap::error::ContextKind::InvalidValue,
clap::error::ContextValue::String(e.to_string()),
);
err
})?;
Ok(value.into())
}
}

fn assure_is_repo(dir: &OsStr) -> anyhow::Result<()> {
let git_dir = PathBuf::from(dir).join(".git");
let p = git::path::realpath(&git_dir)
.with_context(|| format!("Could not canonicalize git repository at '{}'", git_dir.display()))?;
Expand All @@ -144,8 +167,4 @@ mod validator {
))
}
}

pub fn is_repo(dir: &OsStr) -> Result<(), String> {
is_repo_inner(dir).map_err(|err| format!("{:#}", err))
}
}
Loading

0 comments on commit 1d9a5e9

Please sign in to comment.