From cef69644e655b1577bdc59845ae924c77b56c4fc Mon Sep 17 00:00:00 2001 From: Ian Chamberlain Date: Sat, 15 Oct 2022 20:34:09 -0400 Subject: [PATCH] Upgrade to clap4, add extra args and help strings --- Cargo.toml | 4 +- src/command.rs | 133 ++++++++++++++++++++++++++++++++++++++++--------- src/main.rs | 49 ++++++++++-------- 3 files changed, 140 insertions(+), 46 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index fbe3b4a..23ebc65 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,7 +11,7 @@ edition = "2021" cargo_metadata = "0.14.0" rustc_version = "0.4.0" semver = "1.0.10" -serde = {version = "1.0.139", features = ['derive']} +serde = { version = "1.0.139", features = ['derive'] } tee = "0.1.0" toml = "0.5.6" -clap = { version = "3.2.12", features = ["derive"]} \ No newline at end of file +clap = { version = "4.0.15", features = ["derive", "wrap_help"] } diff --git a/src/command.rs b/src/command.rs index 54f9eef..df8f989 100644 --- a/src/command.rs +++ b/src/command.rs @@ -1,36 +1,123 @@ -use clap::{AppSettings, Args, Parser, ValueEnum}; - -#[derive(Parser)] -#[clap(name = "cargo")] -#[clap(bin_name = "cargo")] -pub enum Cargo { - #[clap(name = "3ds")] - Input(Input), +// TODO: docstrings for everything!!! + +use clap::{Args, Parser, Subcommand}; + +#[derive(Parser, Debug)] +#[command(name = "cargo")] +#[command(bin_name = "cargo")] +pub enum Command { + #[command(name = "3ds")] + Root(Root), } -#[derive(Args)] -#[clap(about)] -#[clap(global_setting(AppSettings::AllowLeadingHyphen))] -pub struct Input { - #[clap(value_enum)] +#[derive(Args, Debug)] +#[command(version, about)] +pub struct Root { + /// The cargo command to run. This command will be forwarded to the real + /// `cargo` with the appropriate arguments for a 3DS executable. + #[command(subcommand)] pub cmd: CargoCommand, - pub cargo_opts: Vec, + + /// Don't actually run any commands, just echo them to the console. + /// This is mostly intended for testing. + #[arg(hide = true)] + pub dry_run: bool, + + /// Pass additional options through to the `cargo` command. + /// + /// To pass flags that start with `-`, you must use `--` to separate `cargo 3ds` + /// options from cargo options. All args after `--` will be passed through + /// to cargo unmodified. + /// + /// If one of the arguments is itself `--`, the args following that will be + /// considered as args to pass to the executable, rather than to `cargo` + /// (only works for the `run` or `test` commands). For example, if you want + /// to pass some args to the executable directly it might look like this: + /// + /// > cargo 3ds run -- -- arg1 arg2 + #[arg(trailing_var_arg = true)] + #[arg(global = true)] + cargo_options: Vec, } -#[derive(ValueEnum, Copy, Clone, Ord, PartialOrd, Eq, PartialEq)] +#[derive(Subcommand, Debug)] pub enum CargoCommand { + /// Builds an executable suitable to run on a 3DS (3dsx). Build, - Run, - Test, + /// Equivalent to `cargo check`. Check, + /// Equivalent to `cargo clippy`. Clippy, + /// Equivalent to `cargo doc`. + Doc, + /// Builds an executable and sends it to a device with `3dslink`. + Run(Run), + /// Builds a test executable and sends it to a device with `3dslink`. + /// + /// This can be used with `--test` for integration tests, or `--lib` for + /// unit tests (which require a custom test runner). + Test(Test), + // TODO: this doesn't seem to work for some reason... + #[command(external_subcommand)] + Other(Vec), } -impl CargoCommand { - pub fn should_build_3dsx(&self) -> bool { - matches!( - self, - CargoCommand::Build | CargoCommand::Run | CargoCommand::Test - ) +#[derive(Args, Debug)] +pub struct Test { + /// If set, the built executable will not be sent to the device to run it. + #[arg(long)] + pub no_run: bool, + #[command(flatten)] + pub run_args: Run, +} + +#[derive(Args, Debug)] +pub struct Run { + /// Specify the IP address of the device to send the executable to. + /// + /// Corresponds to 3dslink's `--address` arg, which defaults to automatically + /// finding the device. + #[arg(long, short = 'a')] + pub address: Option, + + /// Set the 0th argument of the executable when running it. Corresponds to + /// 3dslink's `--argv0` argument. + #[arg(long, short = '0')] + pub argv0: Option, + + /// Start the 3dslink server after sending the executable. Corresponds to + /// 3dslink's `--server` argument. + #[arg(long, short = 's')] + pub server: bool, + + /// Set the number of tries when connecting to the device to send the executable. + /// Corresponds to 3dslink's `--retries` argument. + // Can't use `short = 'r'` because that would conflict with cargo's `--release/-r` + #[arg(long)] + pub retries: Option, +} + +impl Root { + /// Get the args to be passed to the executable itself (not `cargo`). + pub fn cargo_options(&self) -> &[String] { + self.split_args().0 + } + + /// Get the args to be passed to the executable itself (not `cargo`). + pub fn executable_args(&self) -> &[String] { + self.split_args().1 + } + + fn split_args(&self) -> (&[String], &[String]) { + if let Some(split) = self.cargo_options.iter().position(|arg| arg == "--") { + let split = if &self.cargo_options[split] == "--" { + split + 1 + } else { + split + }; + self.cargo_options.split_at(split) + } else { + (&self.cargo_options[..], &[]) + } } } diff --git a/src/main.rs b/src/main.rs index 3edd05a..614f1d6 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,3 +1,4 @@ +use cargo_3ds::cmd_clap4::Command; use cargo_3ds::command::Cargo; use cargo_3ds::{ build_3dsx, build_elf, build_smdh, check_rust_version, get_message_format, get_metadata, @@ -7,34 +8,40 @@ use clap::Parser; use std::process; fn main() { - check_rust_version(); + let Command::Root(cmd) = cargo_3ds::cmd_clap4::Command::parse(); - let Cargo::Input(mut input) = Cargo::parse(); + dbg!(&cmd); + dbg!(cmd.cargo_options()); + dbg!(cmd.executable_args()); - let should_link = get_should_link(&mut input); - let message_format = get_message_format(&mut input); + // check_rust_version(); - let (status, messages) = build_elf(input.cmd, &message_format, &input.cargo_opts); + // let Cargo::Input(mut input) = Cargo::parse(); - if !status.success() { - process::exit(status.code().unwrap_or(1)); - } + // let should_link = get_should_link(&mut input); + // let message_format = get_message_format(&mut input); - if !input.cmd.should_build_3dsx() { - return; - } + // let (status, messages) = build_elf(input.cmd, &message_format, &input.cargo_opts); - eprintln!("Getting metadata"); - let app_conf = get_metadata(&messages); + // if !status.success() { + // process::exit(status.code().unwrap_or(1)); + // } - eprintln!("Building smdh:{}", app_conf.path_smdh().display()); - build_smdh(&app_conf); + // if !input.cmd.should_build_3dsx() { + // return; + // } - eprintln!("Building 3dsx: {}", app_conf.path_3dsx().display()); - build_3dsx(&app_conf); + // eprintln!("Getting metadata"); + // let app_conf = get_metadata(&messages); - if should_link { - eprintln!("Running 3dslink"); - link(&app_conf); - } + // eprintln!("Building smdh:{}", app_conf.path_smdh().display()); + // build_smdh(&app_conf); + + // eprintln!("Building 3dsx: {}", app_conf.path_3dsx().display()); + // build_3dsx(&app_conf); + + // if should_link { + // eprintln!("Running 3dslink"); + // link(&app_conf); + // } }