Skip to content

Commit

Permalink
fix(rm): use clap builder instead of derive
Browse files Browse the repository at this point in the history
  • Loading branch information
cassaundra committed Aug 29, 2022
1 parent cdf1214 commit 4372325
Show file tree
Hide file tree
Showing 5 changed files with 150 additions and 65 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ $ cargo rm regex --build

#### Usage

```console
```console,ignore
$ cargo-rm rm --help
cargo-rm [..]
Remove a dependency from a Cargo.toml manifest file
Expand Down
2 changes: 1 addition & 1 deletion crates/cargo-rm/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ anyhow = "1.0"
cargo-util.git = "https://github.com/rust-lang/cargo"
cargo.git = "https://github.com/rust-lang/cargo"
cargo_metadata = "0.15.0"
clap = { version = "3.2", features = ["derive", "wrap_help"], optional = true }
clap = { version = "3.2", features = ["wrap_help"], optional = true }
concolor-control = { version = "0.0.7", default-features = false }
crates-index = "0.18.9"
dirs-next = "2.0.0"
Expand Down
55 changes: 21 additions & 34 deletions crates/cargo-rm/src/bin/cargo/cli.rs
Original file line number Diff line number Diff line change
@@ -1,47 +1,34 @@
use cargo::util::command_prelude::*;
use cargo::CargoResult;
use clap::{Parser, Subcommand};
use clap::Command;

pub fn main(config: &mut Config) -> CliResult {
let args = Cli::try_parse()?;
execute_subcommand(config, &args)?;
let args = cli().try_get_matches()?;
let (cmd, subcommand_args) = args.subcommand().expect("subcommand_required(true)");
execute_subcommand(config, cmd, subcommand_args)?;
Ok(())
}

#[derive(Debug, Parser)]
#[clap(bin_name = "cargo")]
pub struct Cli {
/// Unstable (nightly-only) flags
#[clap(short = 'Z', value_name = "FLAG", global = true, arg_enum)]
unstable_features: Vec<UnstableOptions>,

#[clap(subcommand)]
subcommand: Command,
}

#[derive(Debug, Subcommand)]
pub enum Command {
Rm(crate::commands::rm::RmArgs),
fn cli() -> Command<'static> {
Command::new("cargo")
.bin_name("cargo")
.arg(
Arg::new("unstable-features")
.help("Unstable (nightly-only) flags")
.short('Z')
.value_name("FLAG")
.action(ArgAction::Append)
.global(true),
)
.subcommands(crate::commands::builtin())
.subcommand_required(true)
}

impl Command {
pub fn exec(&self) -> CargoResult<()> {
match self {
Self::Rm(rm) => rm.exec(),
}
}
}

#[derive(Copy, Clone, Debug, PartialEq, Eq, clap::ArgEnum)]
enum UnstableOptions {}

fn execute_subcommand(_config: &mut Config, args: &Cli) -> CliResult {
args.subcommand.exec()?;
Ok(())
fn execute_subcommand(config: &mut Config, cmd: &str, subcommand_args: &ArgMatches) -> CliResult {
let exec = crate::commands::builtin_exec(cmd).expect("all of `builtin` supported");
exec(config, subcommand_args)
}

#[test]
fn verify_app() {
use clap::CommandFactory;
Cli::command().debug_assert()
cli().debug_assert()
}
14 changes: 14 additions & 0 deletions crates/cargo-rm/src/bin/cargo/commands/mod.rs
Original file line number Diff line number Diff line change
@@ -1 +1,15 @@
use cargo::CliResult;

pub mod rm;

pub fn builtin() -> [clap::Command<'static>; 1] {
[rm::cli()]
}

pub fn builtin_exec(cmd: &str) -> Option<fn(&mut cargo::Config, &clap::ArgMatches) -> CliResult> {
let f = match cmd {
"rm" => rm::exec,
_ => return None,
};
Some(f)
}
142 changes: 113 additions & 29 deletions crates/cargo-rm/src/bin/cargo/commands/rm.rs
Original file line number Diff line number Diff line change
@@ -1,54 +1,34 @@
use cargo::util::command_prelude::*;
use cargo::CargoResult;
use cargo_rm::shell_status;
use cargo_rm::shell_warn;
use cargo_rm::{manifest_from_pkgid, LocalManifest};
use clap::Args;

use std::borrow::Cow;
use std::path::PathBuf;

/// Remove a dependency from a Cargo.toml manifest file.
#[derive(Debug, Args)]
#[clap(version)]
#[clap(setting = clap::AppSettings::DeriveDisplayOrder)]
pub struct RmArgs {
#[derive(Debug)]
pub struct RmOptions {
/// Dependencies to be removed
#[clap(value_name = "DEP_ID", required = true)]
crates: Vec<String>,

/// Remove as development dependency
#[clap(long, short = 'D', conflicts_with = "build", help_heading = "SECTION")]
dev: bool,

/// Remove as build dependency
#[clap(long, short = 'B', conflicts_with = "dev", help_heading = "SECTION")]
build: bool,

/// Remove as dependency from the given target platform
#[clap(long, value_parser = clap::builder::NonEmptyStringValueParser::new(), help_heading = "SECTION")]
target: Option<String>,

/// Path to the manifest to remove a dependency from
#[clap(long, value_name = "PATH", action)]
manifest_path: Option<PathBuf>,

/// Package to remove from
#[clap(long = "package", short = 'p', value_name = "PKGID")]
pkgid: Option<String>,

pkg_id: Option<String>,
/// Don't actually write the manifest
#[clap(long)]
dry_run: bool,

/// Do not print any output in case of success
#[clap(long, short)]
quiet: bool,
}

impl RmArgs {
pub fn exec(&self) -> CargoResult<()> {
exec(self)
}

impl RmOptions {
/// Get dependency section
pub fn get_section(&self) -> Vec<String> {
let section_name = if self.dev {
Expand All @@ -69,9 +49,113 @@ impl RmArgs {
}
}

fn exec(args: &RmArgs) -> CargoResult<()> {
let manifest_path = if let Some(ref pkgid) = args.pkgid {
let pkg = manifest_from_pkgid(args.manifest_path.as_deref(), pkgid)?;
pub fn cli() -> clap::Command<'static> {
clap::Command::new("rm")
.setting(clap::AppSettings::DeriveDisplayOrder)
.about("Remove a dependency from a Cargo.toml manifest file")
.args([
clap::Arg::new("dependencies")
.action(clap::ArgAction::Append)
.required(true)
.multiple_values(true)
.takes_value(true)
.value_name("DEP_ID")
.help("Dependencies to be removed"),
clap::Arg::new("manifest_path")
.long("manifest-path")
.takes_value(true)
.value_name("PATH")
.value_parser(clap::builder::PathBufValueParser::new())
.help("Path to the manifest to remove a dependency from"),
clap::Arg::new("pkg_id")
.short('p')
.long("package")
.takes_value(true)
.value_name("PKGID")
.help("Package to remove from"),
clap::Arg::new("dry_run")
.long("dry-run")
.action(clap::ArgAction::SetTrue)
.help("Don't actually write the manifest"),
clap::Arg::new("quiet")
.short('q')
.long("quiet")
.action(clap::ArgAction::SetTrue)
.help("Do not print any output in case of success"),
])
.next_help_heading("SECTION")
.args([
clap::Arg::new("dev")
.short('D')
.long("dev")
.conflicts_with("build")
.action(clap::ArgAction::SetTrue)
.group("section")
.help("Remove as development dependency"),
clap::Arg::new("build")
.short('B')
.long("build")
.conflicts_with("dev")
.action(clap::ArgAction::SetTrue)
.group("section")
.help("Remove as build dependency"),
clap::Arg::new("target")
.long("target")
.takes_value(true)
.value_name("TARGET")
.value_parser(clap::builder::NonEmptyStringValueParser::new())
.help("Remove as dependency from the given target platform"),
])
}

#[derive(Copy, Clone, Debug, PartialEq, Eq)]
enum UnstableOptions {}

pub fn exec(_config: &mut Config, args: &ArgMatches) -> CliResult {
let crates = args
.get_many("dependencies")
.expect("required(true)")
.cloned()
.collect();
let dev = args
.get_one::<bool>("dev")
.copied()
.expect("action(ArgAction::SetTrue)");
let build = args
.get_one::<bool>("build")
.copied()
.expect("action(ArgAction::SetTrue)");
let target = args.get_one("target").cloned();
let manifest_path = args.get_one("manifest_path").cloned();
let pkg_id = args.get_one("pkg_id").cloned();
let dry_run = args
.get_one::<bool>("dry_run")
.copied()
.expect("action(ArgAction::SetTrue)");
let quiet = args
.get_one::<bool>("quiet")
.copied()
.expect("action(ArgAction::SetTrue)");

let options = RmOptions {
crates,
dev,
build,
target,
manifest_path,
pkg_id,
dry_run,
quiet,
};

rm(&options)?;

Ok(())
}

fn rm(args: &RmOptions) -> CargoResult<()> {
let manifest_path = if let Some(ref pkg_id) = args.pkg_id {
let pkg = manifest_from_pkgid(args.manifest_path.as_deref(), pkg_id)?;
Cow::Owned(Some(pkg.manifest_path.into_std_path_buf()))
} else {
Cow::Borrowed(&args.manifest_path)
Expand Down

0 comments on commit 4372325

Please sign in to comment.