Skip to content

Commit

Permalink
Replace structopt by clap (#155)
Browse files Browse the repository at this point in the history
  • Loading branch information
theredfish committed Dec 17, 2021
1 parent 0c7908e commit 9bf9fe8
Show file tree
Hide file tree
Showing 10 changed files with 72 additions and 91 deletions.
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ linked-hash-map = "0.5.3"
once_cell = { version = "1.8", features = ["parking_lot"] }
regex = "1.5"
sealed = "0.3"
structopt = "0.3.25"
clap = { version = "3.0.0-rc.7", features = ["derive"] }

# "macros" feature dependencies.
cucumber-codegen = { version = "0.11.0-dev", path = "./codegen", optional = true }
Expand Down
70 changes: 32 additions & 38 deletions src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,9 @@
//! [`Writer`]: crate::Writer
//! [1]: https://cucumber.io/docs/cucumber/api#tag-expressions
use clap::{Args, Parser as ClapParser};
use gherkin::tagexpr::TagOperation;
use regex::Regex;
use structopt::StructOpt;

// Workaround for overwritten doc-comments.
// https://github.com/TeXitoi/structopt/issues/333#issuecomment-712265332
Expand All @@ -47,9 +47,9 @@ and may be extended with custom CLI options additionally.
# use std::{convert::Infallible, time::Duration};
#
# use async_trait::async_trait;
# use clap::Parser as ClapParser;
# use cucumber::{cli, WorldInit};
# use futures::FutureExt as _;
# use structopt::StructOpt;
# use tokio::time;
#
# #[derive(Debug, WorldInit)]
Expand All @@ -66,17 +66,17 @@ and may be extended with custom CLI options additionally.
#
# #[tokio::main(flavor = "current_thread")]
# async fn main() {
#[derive(StructOpt)]
#[derive(ClapParser)]
struct CustomOpts {
/// Additional time to wait in before hook.
#[structopt(
#[clap(
long,
parse(try_from_str = humantime::parse_duration)
)]
pre_pause: Option<Duration>,
}
let opts = cli::Opts::<_, _, _, CustomOpts>::from_args();
let opts = cli::Opts::<_, _, _, CustomOpts>::parse();
let pre_pause = opts.custom.pre_pause.unwrap_or_default();
MyWorld::cucumber()
Expand All @@ -94,18 +94,18 @@ MyWorld::cucumber()
"#
)]
#[cfg_attr(not(doc), doc = "Run the tests, pet a dog!.")]
#[derive(Debug, Clone, StructOpt)]
#[structopt(name = "cucumber", about = "Run the tests, pet a dog!.")]
#[derive(Debug, Clone, ClapParser)]
#[clap(name = "cucumber", about = "Run the tests, pet a dog!.")]
pub struct Opts<Parser, Runner, Writer, Custom = Empty>
where
Parser: StructOpt,
Runner: StructOpt,
Writer: StructOpt,
Custom: StructOpt,
Parser: Args,
Runner: Args,
Writer: Args,
Custom: Args,
{
/// Regex to filter scenarios by their name.
#[structopt(
short = "n",
#[clap(
short = 'n',
long = "name",
name = "regex",
visible_alias = "scenario-name"
Expand All @@ -116,8 +116,8 @@ where
///
/// Note: Tags from Feature, Rule and Scenario are merged together on
/// filtering, so be careful about conflicting tags on different levels.
#[structopt(
short = "t",
#[clap(
short = 't',
long = "tags",
name = "tagexpr",
conflicts_with = "regex"
Expand All @@ -127,23 +127,23 @@ where
/// [`Parser`] CLI options.
///
/// [`Parser`]: crate::Parser
#[structopt(flatten)]
#[clap(flatten)]
pub parser: Parser,

/// [`Runner`] CLI options.
///
/// [`Runner`]: crate::Runner
#[structopt(flatten)]
#[clap(flatten)]
pub runner: Runner,

/// [`Writer`] CLI options.
///
/// [`Writer`]: crate::Writer
#[structopt(flatten)]
#[clap(flatten)]
pub writer: Writer,

/// Additional custom CLI options.
#[structopt(flatten)]
#[clap(flatten)]
pub custom: Custom,
}

Expand All @@ -154,21 +154,15 @@ where
not(doc),
allow(missing_docs, clippy::missing_docs_in_private_items)
)]
#[derive(Clone, Copy, Debug, StructOpt)]
pub struct Empty {
/// This field exists only because [`StructOpt`] derive macro doesn't
/// support unit structs.
#[allow(dead_code)]
#[structopt(skip)]
skipped: (),
}
#[derive(Clone, Copy, Debug, Args)]
pub struct Empty;

// Workaround for overwritten doc-comments.
// https://github.com/TeXitoi/structopt/issues/333#issuecomment-712265332
#[cfg_attr(
doc,
doc = r#"
Composes two [`StructOpt`] derivers together.
Composes two [`Args`] derivers together.
# Example
Expand All @@ -177,13 +171,13 @@ another one:
```rust
# use async_trait::async_trait;
# use cucumber::{cli, event, parser, writer, Event, World, Writer};
# use structopt::StructOpt;
# use clap::Args;
#
struct CustomWriter<Wr>(Wr);
#[derive(StructOpt)]
#[derive(Args)]
struct Cli {
#[structopt(long)]
#[clap(long)]
custom_option: Option<String>,
}
Expand Down Expand Up @@ -257,18 +251,18 @@ impl<Wr: writer::NonTransforming> writer::NonTransforming
not(doc),
allow(missing_docs, clippy::missing_docs_in_private_items)
)]
#[derive(Debug, StructOpt)]
pub struct Compose<L: StructOpt, R: StructOpt> {
/// Left [`StructOpt`] deriver.
#[structopt(flatten)]
#[derive(Debug, Args)]
pub struct Compose<L: Args, R: Args> {
/// Left [`Args`] deriver.
#[clap(flatten)]
pub left: L,

/// Right [`StructOpt`] deriver.
#[structopt(flatten)]
/// Right [`Args`] deriver.
#[clap(flatten)]
pub right: R,
}

impl<L: StructOpt, R: StructOpt> Compose<L, R> {
impl<L: Args, R: Args> Compose<L, R> {
/// Unpacks this [`Compose`] into the underlying CLIs.
#[must_use]
pub fn into_inner(self) -> (L, R) {
Expand Down
37 changes: 18 additions & 19 deletions src/cucumber.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,13 @@ use std::{
path::Path,
};

use futures::{future::LocalBoxFuture, StreamExt as _};
use regex::Regex;
use structopt::{StructOpt, StructOptInternal};

use crate::{
cli, event, parser, runner, step, tag::Ext as _, writer, Event, Parser,
Runner, ScenarioType, Step, World, Writer, WriterExt as _,
};
use clap::{Args, Parser as _};
use futures::{future::LocalBoxFuture, StreamExt as _};
use regex::Regex;

/// Top-level [Cucumber] executor.
///
Expand All @@ -54,7 +53,7 @@ where
P: Parser<I>,
R: Runner<W>,
Wr: Writer<W>,
Cli: StructOpt,
Cli: Args,
{
/// [`Parser`] sourcing [`Feature`]s for execution.
///
Expand Down Expand Up @@ -88,7 +87,7 @@ where
P: Parser<I>,
R: Runner<W>,
Wr: Writer<W>,
Cli: StructOpt,
Cli: Args,
{
/// Creates a custom [`Cucumber`] executor with the provided [`Parser`],
/// [`Runner`] and [`Writer`].
Expand Down Expand Up @@ -437,7 +436,7 @@ where
P: Parser<I>,
R: Runner<W>,
Wr: Writer<W> + for<'val> writer::Arbitrary<'val, W, String>,
Cli: StructOpt,
Cli: Args,
{
/// Consider [`Skipped`] steps as [`Failed`] if their [`Scenario`] isn't
/// marked with `@allow.skipped` tag.
Expand Down Expand Up @@ -627,7 +626,7 @@ where
P: Parser<I>,
R: Runner<W>,
Wr: Writer<W> + writer::Normalized,
Cli: StructOpt + StructOptInternal,
Cli: Args,
{
/// Runs [`Cucumber`].
///
Expand All @@ -645,7 +644,7 @@ where
/// using them inside [`Cucumber`].
///
/// Also, any additional custom CLI options may be specified as a
/// [`StructOpt`] deriving type, used as the last type parameter of
/// [`Args`] deriving type, used as the last type parameter of
/// [`cli::Opts`].
///
/// > ⚠️ __WARNING__: Any CLI options of [`Parser`], [`Runner`], [`Writer`]
Expand All @@ -658,9 +657,9 @@ where
/// # use std::{convert::Infallible, time::Duration};
/// #
/// # use async_trait::async_trait;
/// # use clap::{Args, Parser as _};
/// # use cucumber::{cli, WorldInit};
/// # use futures::FutureExt as _;
/// # use structopt::StructOpt;
/// # use tokio::time;
/// #
/// # #[derive(Debug, WorldInit)]
Expand All @@ -677,17 +676,17 @@ where
/// #
/// # #[tokio::main(flavor = "current_thread")]
/// # async fn main() {
/// #[derive(StructOpt)]
/// #[derive(Args)]
/// struct CustomCli {
/// /// Additional time to wait in a before hook.
/// #[structopt(
/// #[clap(
/// long,
/// parse(try_from_str = humantime::parse_duration)
/// )]
/// before_time: Option<Duration>,
/// }
///
/// let cli = cli::Opts::<_, _, _, CustomCli>::from_args();
/// let cli = cli::Opts::<_, _, _, CustomCli>::parse();
/// let time = cli.custom.before_time.unwrap_or_default();
///
/// MyWorld::cucumber()
Expand Down Expand Up @@ -719,7 +718,7 @@ where
cli: cli::Opts<P::Cli, R::Cli, Wr::Cli, CustomCli>,
) -> Cucumber<W, P, I, R, Wr, CustomCli>
where
CustomCli: StructOpt,
CustomCli: Args,
{
let Cucumber {
parser,
Expand Down Expand Up @@ -811,7 +810,7 @@ where
runner: runner_cli,
writer: writer_cli,
..
} = self.cli.unwrap_or_else(cli::Opts::<_, _, _, _>::from_args);
} = self.cli.unwrap_or_else(cli::Opts::<_, _, _, _>::parse);

let filter = move |feat: &gherkin::Feature,
rule: Option<&gherkin::Rule>,
Expand Down Expand Up @@ -884,7 +883,7 @@ where
P: Debug + Parser<I>,
R: Debug + Runner<W>,
Wr: Debug + Writer<W>,
Cli: StructOpt,
Cli: Args,
{
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Cucumber")
Expand Down Expand Up @@ -954,7 +953,7 @@ where
W: World,
R: Runner<W>,
Wr: Writer<W>,
Cli: StructOpt,
Cli: Args,
I: AsRef<Path>,
{
/// Sets the provided language of [`gherkin`] files.
Expand All @@ -977,7 +976,7 @@ where
W: World,
P: Parser<I>,
Wr: Writer<W>,
Cli: StructOpt,
Cli: Args,
F: Fn(
&gherkin::Feature,
Option<&gherkin::Rule>,
Expand Down Expand Up @@ -1176,7 +1175,7 @@ where
P: Parser<I>,
R: Runner<W>,
Wr: writer::Failure<W> + writer::Normalized,
Cli: StructOpt + StructOptInternal,
Cli: Args,
{
/// Runs [`Cucumber`].
///
Expand Down
6 changes: 3 additions & 3 deletions src/parser/basic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,12 @@ use std::{
vec,
};

use clap::Parser as ClapParser;
use derive_more::{Display, Error};
use futures::stream;
use gherkin::GherkinEnv;
use globwalk::{GlobWalker, GlobWalkerBuilder};
use itertools::Itertools as _;
use structopt::StructOpt;

use crate::feature::Ext as _;

Expand All @@ -36,11 +36,11 @@ use super::{Error as ParseError, Parser};
not(doc),
allow(missing_docs, clippy::missing_docs_in_private_items)
)]
#[derive(Debug, StructOpt)]
#[derive(Debug, ClapParser)]
pub struct Cli {
/// Glob pattern to look for feature files with. By default, looks for
/// `*.feature`s in the path configured tests runner.
#[structopt(long = "input", short = "i", name = "glob")]
#[clap(long = "input", short = 'i', name = "glob")]
pub features: Option<Walker>,
}

Expand Down
10 changes: 3 additions & 7 deletions src/parser/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,10 @@
pub mod basic;

use std::sync::Arc;

use clap::Args;
use derive_more::{Display, Error};
use futures::Stream;
use structopt::StructOptInternal;
use std::sync::Arc;

use crate::feature::ExpandExamplesError;

Expand All @@ -38,10 +37,7 @@ pub trait Parser<I> {
/// [`cli::Empty`]: crate::cli::Empty
/// [`Runner`]: crate::Runner
/// [`Writer`]: crate::Writer
// We do use `StructOptInternal` here only because `StructOpt::from_args()`
// requires exactly this trait bound. We don't touch any `StructOptInternal`
// details being a subject of instability.
type Cli: StructOptInternal + 'static;
type Cli: Args;

/// Output [`Stream`] of parsed [`Feature`]s.
///
Expand Down
Loading

0 comments on commit 9bf9fe8

Please sign in to comment.