Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Upgrade to clap4, add extra args and help strings #26

Merged
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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"]}
clap = { version = "4.0.15", features = ["derive", "wrap_help"] }
126 changes: 107 additions & 19 deletions src/command.rs
Original file line number Diff line number Diff line change
@@ -1,36 +1,124 @@
use clap::{AppSettings, Args, Parser, ValueEnum};
// TODO: docstrings for everything!!!

#[derive(Parser)]
#[clap(name = "cargo")]
#[clap(bin_name = "cargo")]
use clap::{Args, Parser, Subcommand};

#[derive(Parser, Debug)]
#[command(name = "cargo")]
#[command(bin_name = "cargo")]
pub enum Cargo {
#[clap(name = "3ds")]
#[command(name = "3ds")]
Input(Input),
}

#[derive(Args)]
#[clap(about)]
#[clap(global_setting(AppSettings::AllowLeadingHyphen))]
#[derive(Args, Debug)]
#[command(version, about)]
pub struct Input {
#[clap(value_enum)]
/// 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<String>,

/// Don't actually run any commands, just echo them to the console.
/// This is mostly intended for testing.
#[arg(long, hide = true)]
pub dry_run: bool,
ian-h-chamberlain marked this conversation as resolved.
Show resolved Hide resolved

/// 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.
AzureMarker marked this conversation as resolved.
Show resolved Hide resolved
AzureMarker marked this conversation as resolved.
Show resolved Hide resolved
///
/// 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<String>,
}

#[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<String>),
}

#[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<String>,

/// Set the 0th argument of the executable when running it. Corresponds to
/// 3dslink's `--argv0` argument.
#[arg(long, short = '0')]
pub argv0: Option<String>,

/// 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<usize>,
}

impl CargoCommand {
pub fn should_build_3dsx(&self) -> bool {
matches!(
self,
CargoCommand::Build | CargoCommand::Run | CargoCommand::Test
)
impl Input {
/// Get the args to be passed to the executable itself (not `cargo`).
pub fn cargo_opts(&self) -> &[String] {
self.split_args().0
}

/// Get the args to be passed to the executable itself (not `cargo`).
pub fn exe_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[..], &[])
}
}
}
27 changes: 14 additions & 13 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,9 @@ pub fn get_should_link(input: &mut Input) -> bool {
// When running compile only commands, don't link the executable to the 3ds.
// Otherwise, link and run on the 3ds but do not run locally.
match input.cmd {
CargoCommand::Run => true,
CargoCommand::Test if !input.cargo_opts.contains(&"--no-run".to_string()) => {
input.cargo_opts.push("--no-run".to_string());
CargoCommand::Run(_) => true,
CargoCommand::Test(_) if !input.cargo_opts().contains(&"--no-run".to_string()) => {
// input.cargo_opts().push("--no-run".to_string());
true
}
_ => false,
Expand All @@ -36,28 +36,28 @@ pub fn get_should_link(input: &mut Input) -> bool {
pub fn get_message_format(input: &mut Input) -> String {
// Checks for a position within the args where '--message-format' is located
if let Some(pos) = input
.cargo_opts
.cargo_opts()
.iter()
.position(|s| s.starts_with("--message-format"))
{
// Remove the arg from list
let arg = input.cargo_opts.remove(pos);
let arg = input.cargo_opts()[pos].clone(); // TODO

// Allows for usage of '--message-format=<format>' and also using space separation.
// Check for a '=' delimiter and use the second half of the split as the format,
// otherwise remove next arg which is now at the same position as the original flag.
let format = if let Some((_, format)) = arg.split_once('=') {
format.to_string()
} else {
input.cargo_opts.remove(pos)
input.cargo_opts()[pos].clone() // TODO
};

// Non-json formats are not supported so the executable exits.
if !format.starts_with("json") {
if format.starts_with("json") {
format
} else {
eprintln!("error: non-JSON `message-format` is not supported");
process::exit(1);
} else {
format
}
} else {
// Default to 'json-render-diagnostics'
Expand Down Expand Up @@ -114,10 +114,11 @@ pub fn make_cargo_build_command(
let mut command = Command::new(cargo);

let cmd = match cmd {
CargoCommand::Build | CargoCommand::Run => "build",
CargoCommand::Test => "test",
CargoCommand::Build | CargoCommand::Run(_) => "build",
CargoCommand::Test(_) => "test",
CargoCommand::Check => "check",
CargoCommand::Clippy => "clippy",
CargoCommand::Doc => "doc",
};

command
Expand Down Expand Up @@ -200,7 +201,7 @@ pub fn check_rust_version() {

/// Parses messages returned by the executed cargo command from [`build_elf`].
/// The returned [`CTRConfig`] is then used for further building in and execution
/// in [`build_smdh`], ['build_3dsx'], and [`link`].
/// in [`build_smdh`], [`build_3dsx`], and [`link`].
pub fn get_metadata(messages: &[Message]) -> CTRConfig {
let metadata = MetadataCommand::new()
.exec()
Expand Down Expand Up @@ -249,7 +250,7 @@ pub fn get_metadata(messages: &[Message]) -> CTRConfig {
};

let author = match package.authors.as_slice() {
[name, ..] => name.to_owned(),
[name, ..] => name.clone(),
[] => String::from("Unspecified Author"), // as standard with the devkitPRO toolchain
};

Expand Down
42 changes: 23 additions & 19 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,30 +11,34 @@ fn main() {

let Cargo::Input(mut input) = Cargo::parse();

let should_link = get_should_link(&mut input);
let message_format = get_message_format(&mut input);
dbg!(&input);
dbg!(input.cargo_opts());
dbg!(input.exe_args());

let (status, messages) = build_elf(input.cmd, &message_format, &input.cargo_opts);
// let should_link = get_should_link(&mut input);
// let message_format = get_message_format(&mut input);

if !status.success() {
process::exit(status.code().unwrap_or(1));
}
// let (status, messages) = build_elf(input.cmd, &message_format, &input.cargo_opts);

if !input.cmd.should_build_3dsx() {
return;
}
// if !status.success() {
// process::exit(status.code().unwrap_or(1));
// }

eprintln!("Getting metadata");
let app_conf = get_metadata(&messages);
// if !input.cmd.should_build_3dsx() {
// return;
// }

eprintln!("Building smdh:{}", app_conf.path_smdh().display());
build_smdh(&app_conf);
// eprintln!("Getting metadata");
// let app_conf = get_metadata(&messages);

eprintln!("Building 3dsx: {}", app_conf.path_3dsx().display());
build_3dsx(&app_conf);
// eprintln!("Building smdh:{}", app_conf.path_smdh().display());
// build_smdh(&app_conf);

if should_link {
eprintln!("Running 3dslink");
link(&app_conf);
}
// eprintln!("Building 3dsx: {}", app_conf.path_3dsx().display());
// build_3dsx(&app_conf);

// if should_link {
// eprintln!("Running 3dslink");
// link(&app_conf);
// }
}