|
|
@ -1,5 +1,11 @@ |
|
|
|
|
|
|
|
use std::fs; |
|
|
|
|
|
|
|
use std::io::Read; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
use cargo_metadata::Message; |
|
|
|
use clap::{Args, Parser, Subcommand}; |
|
|
|
use clap::{Args, Parser, Subcommand}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
use crate::{build_3dsx, build_smdh, get_metadata, link, CTRConfig}; |
|
|
|
|
|
|
|
|
|
|
|
#[derive(Parser, Debug)] |
|
|
|
#[derive(Parser, Debug)] |
|
|
|
#[command(name = "cargo", bin_name = "cargo")] |
|
|
|
#[command(name = "cargo", bin_name = "cargo")] |
|
|
|
pub enum Cargo { |
|
|
|
pub enum Cargo { |
|
|
@ -23,7 +29,7 @@ pub struct Input { |
|
|
|
#[command(allow_external_subcommands = true)] |
|
|
|
#[command(allow_external_subcommands = true)] |
|
|
|
pub enum CargoCmd { |
|
|
|
pub enum CargoCmd { |
|
|
|
/// Builds an executable suitable to run on a 3DS (3dsx).
|
|
|
|
/// Builds an executable suitable to run on a 3DS (3dsx).
|
|
|
|
Build(RemainingArgs), |
|
|
|
Build(Build), |
|
|
|
|
|
|
|
|
|
|
|
/// Builds an executable and sends it to a device with `3dslink`.
|
|
|
|
/// Builds an executable and sends it to a device with `3dslink`.
|
|
|
|
Run(Run), |
|
|
|
Run(Run), |
|
|
@ -34,10 +40,13 @@ pub enum CargoCmd { |
|
|
|
/// unit tests (which require a custom test runner).
|
|
|
|
/// unit tests (which require a custom test runner).
|
|
|
|
Test(Test), |
|
|
|
Test(Test), |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// Sets up a new cargo project suitable to run on a 3DS.
|
|
|
|
|
|
|
|
New(New), |
|
|
|
|
|
|
|
|
|
|
|
// NOTE: it seems docstring + name for external subcommands are not rendered
|
|
|
|
// NOTE: it seems docstring + name for external subcommands are not rendered
|
|
|
|
// in help, but we might as well set them here in case a future version of clap
|
|
|
|
// in help, but we might as well set them here in case a future version of clap
|
|
|
|
// does include them in help text.
|
|
|
|
// does include them in help text.
|
|
|
|
/// Run any other `cargo` command with RUSTFLAGS set for the 3DS.
|
|
|
|
/// Run any other `cargo` command with custom building tailored for the 3DS.
|
|
|
|
#[command(external_subcommand, name = "COMMAND")] |
|
|
|
#[command(external_subcommand, name = "COMMAND")] |
|
|
|
Passthrough(Vec<String>), |
|
|
|
Passthrough(Vec<String>), |
|
|
|
} |
|
|
|
} |
|
|
@ -61,19 +70,10 @@ pub struct RemainingArgs { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
#[derive(Parser, Debug)] |
|
|
|
#[derive(Parser, Debug)] |
|
|
|
pub struct Test { |
|
|
|
pub struct Build { |
|
|
|
/// If set, the built executable will not be sent to the device to run it.
|
|
|
|
// Passthrough cargo options.
|
|
|
|
#[arg(long)] |
|
|
|
|
|
|
|
pub no_run: bool, |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// If set, documentation tests will be built instead of unit tests.
|
|
|
|
|
|
|
|
/// This implies `--no-run`.
|
|
|
|
|
|
|
|
#[arg(long)] |
|
|
|
|
|
|
|
pub doc: bool, |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// The test command uses a superset of the same arguments as Run.
|
|
|
|
|
|
|
|
#[command(flatten)] |
|
|
|
#[command(flatten)] |
|
|
|
pub run_args: Run, |
|
|
|
pub cargo_args: RemainingArgs, |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
#[derive(Parser, Debug)] |
|
|
|
#[derive(Parser, Debug)] |
|
|
@ -101,12 +101,99 @@ pub struct Run { |
|
|
|
#[arg(long)] |
|
|
|
#[arg(long)] |
|
|
|
pub retries: Option<usize>, |
|
|
|
pub retries: Option<usize>, |
|
|
|
|
|
|
|
|
|
|
|
// Passthrough cargo options.
|
|
|
|
// Passthrough `cargo build` options.
|
|
|
|
|
|
|
|
#[command(flatten)] |
|
|
|
|
|
|
|
pub build_args: Build, |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#[derive(Parser, 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, |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// If set, documentation tests will be built instead of unit tests.
|
|
|
|
|
|
|
|
/// This implies `--no-run`.
|
|
|
|
|
|
|
|
#[arg(long)] |
|
|
|
|
|
|
|
pub doc: bool, |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// The test command uses a superset of the same arguments as Run.
|
|
|
|
|
|
|
|
#[command(flatten)] |
|
|
|
|
|
|
|
pub run_args: Run, |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#[derive(Parser, Debug)] |
|
|
|
|
|
|
|
pub struct New { |
|
|
|
|
|
|
|
/// Path of the new project.
|
|
|
|
|
|
|
|
#[arg(required = true)] |
|
|
|
|
|
|
|
pub path: String, |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// The test command uses a superset of the same arguments as Run.
|
|
|
|
#[command(flatten)] |
|
|
|
#[command(flatten)] |
|
|
|
pub cargo_args: RemainingArgs, |
|
|
|
pub cargo_args: RemainingArgs, |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
impl CargoCmd { |
|
|
|
impl CargoCmd { |
|
|
|
|
|
|
|
/// Returns the additional arguments run by the "official" cargo subcommand.
|
|
|
|
|
|
|
|
pub fn cargo_args(&self) -> Vec<String> { |
|
|
|
|
|
|
|
match self { |
|
|
|
|
|
|
|
CargoCmd::Build(build) => build.cargo_args.cargo_args(), |
|
|
|
|
|
|
|
CargoCmd::Run(run) => run.build_args.cargo_args.cargo_args(), |
|
|
|
|
|
|
|
CargoCmd::Test(test) => { |
|
|
|
|
|
|
|
let mut cargo_args = test.run_args.build_args.cargo_args.cargo_args(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// We can't run 3DS executables on the host, so unconditionally pass
|
|
|
|
|
|
|
|
// --no-run here and send the executable with 3dslink later, if the
|
|
|
|
|
|
|
|
// user wants
|
|
|
|
|
|
|
|
if test.doc { |
|
|
|
|
|
|
|
eprintln!("Documentation tests requested, no 3dsx will be built or run"); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// https://github.com/rust-lang/cargo/issues/7040
|
|
|
|
|
|
|
|
cargo_args.append(&mut vec![ |
|
|
|
|
|
|
|
"--doc".to_string(), |
|
|
|
|
|
|
|
"-Z".to_string(), |
|
|
|
|
|
|
|
"doctest-xcompile".to_string(), |
|
|
|
|
|
|
|
]); |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
cargo_args.push("--no-run".to_string()); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
cargo_args |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
CargoCmd::New(new) => { |
|
|
|
|
|
|
|
// We push the original path in the new command (we captured it in [`New`] to learn about the context)
|
|
|
|
|
|
|
|
let mut cargo_args = new.cargo_args.cargo_args(); |
|
|
|
|
|
|
|
cargo_args.push(new.path.clone()); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
cargo_args |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
CargoCmd::Passthrough(other) => other.clone().split_off(1), |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// Returns the cargo subcommand run by `cargo-3ds` when handling a [`CargoCmd`].
|
|
|
|
|
|
|
|
///
|
|
|
|
|
|
|
|
/// # Notes
|
|
|
|
|
|
|
|
///
|
|
|
|
|
|
|
|
/// This is not equivalent to the lowercase name of the [`CargoCmd`] variant.
|
|
|
|
|
|
|
|
/// Commands may use different commands under the hood to function (e.g. [`CargoCmd::Run`] uses `build`).
|
|
|
|
|
|
|
|
pub fn subcommand_name(&self) -> &str { |
|
|
|
|
|
|
|
match self { |
|
|
|
|
|
|
|
CargoCmd::Build(_) | CargoCmd::Run(_) => "build", |
|
|
|
|
|
|
|
CargoCmd::Test(_) => "test", |
|
|
|
|
|
|
|
CargoCmd::New(_) => "new", |
|
|
|
|
|
|
|
CargoCmd::Passthrough(cmd) => &cmd[0], |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// Whether or not this command should compile any code, and thus needs import the custom environment configuration (e.g. target spec).
|
|
|
|
|
|
|
|
pub fn should_compile(&self) -> bool { |
|
|
|
|
|
|
|
matches!( |
|
|
|
|
|
|
|
self, |
|
|
|
|
|
|
|
Self::Build(_) | Self::Run(_) | Self::Test(_) | Self::Passthrough(_) |
|
|
|
|
|
|
|
) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/// Whether or not this command should build a 3DSX executable file.
|
|
|
|
/// Whether or not this command should build a 3DSX executable file.
|
|
|
|
pub fn should_build_3dsx(&self) -> bool { |
|
|
|
pub fn should_build_3dsx(&self) -> bool { |
|
|
|
matches!( |
|
|
|
matches!( |
|
|
@ -129,10 +216,11 @@ impl CargoCmd { |
|
|
|
|
|
|
|
|
|
|
|
pub fn extract_message_format(&mut self) -> Result<Option<String>, String> { |
|
|
|
pub fn extract_message_format(&mut self) -> Result<Option<String>, String> { |
|
|
|
let cargo_args = match self { |
|
|
|
let cargo_args = match self { |
|
|
|
Self::Build(args) => &mut args.args, |
|
|
|
Self::Build(build) => &mut build.cargo_args.args, |
|
|
|
Self::Run(run) => &mut run.cargo_args.args, |
|
|
|
Self::Run(run) => &mut run.build_args.cargo_args.args, |
|
|
|
|
|
|
|
Self::New(new) => &mut new.cargo_args.args, |
|
|
|
|
|
|
|
Self::Test(test) => &mut test.run_args.build_args.cargo_args.args, |
|
|
|
Self::Passthrough(args) => args, |
|
|
|
Self::Passthrough(args) => args, |
|
|
|
Self::Test(test) => &mut test.run_args.cargo_args.args, |
|
|
|
|
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
let format = Self::extract_message_format_from_args(cargo_args)?; |
|
|
|
let format = Self::extract_message_format_from_args(cargo_args)?; |
|
|
@ -183,28 +271,71 @@ impl CargoCmd { |
|
|
|
Ok(None) |
|
|
|
Ok(None) |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// Runs the custom callback *after* the cargo command, depending on the type of command launched.
|
|
|
|
|
|
|
|
///
|
|
|
|
|
|
|
|
/// # Examples
|
|
|
|
|
|
|
|
///
|
|
|
|
|
|
|
|
/// - `cargo 3ds build` and other "build" commands will use their callbacks to build the final `.3dsx` file and link it.
|
|
|
|
|
|
|
|
/// - `cargo 3ds new` and other generic commands will use their callbacks to make 3ds-specific changes to the environment.
|
|
|
|
|
|
|
|
pub fn run_callback(&self, messages: &[Message]) { |
|
|
|
|
|
|
|
// Process the metadata only for commands that have it/use it
|
|
|
|
|
|
|
|
let config = if self.should_build_3dsx() { |
|
|
|
|
|
|
|
eprintln!("Getting metadata"); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
get_metadata(messages) |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
CTRConfig::default() |
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Run callback only for commands that use it
|
|
|
|
|
|
|
|
match self { |
|
|
|
|
|
|
|
Self::Build(cmd) => cmd.callback(&config), |
|
|
|
|
|
|
|
Self::Run(cmd) => cmd.callback(&config), |
|
|
|
|
|
|
|
Self::Test(cmd) => cmd.callback(&config), |
|
|
|
|
|
|
|
Self::New(cmd) => cmd.callback(), |
|
|
|
|
|
|
|
_ => (), |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
impl RemainingArgs { |
|
|
|
impl RemainingArgs { |
|
|
|
/// Get the args to be passed to the executable itself (not `cargo`).
|
|
|
|
/// Get the args to be passed to the executable itself (not `cargo`).
|
|
|
|
pub fn cargo_args(&self) -> &[String] { |
|
|
|
pub fn cargo_args(&self) -> Vec<String> { |
|
|
|
self.split_args().0 |
|
|
|
self.split_args().0 |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/// Get the args to be passed to the executable itself (not `cargo`).
|
|
|
|
/// Get the args to be passed to the executable itself (not `cargo`).
|
|
|
|
pub fn exe_args(&self) -> &[String] { |
|
|
|
pub fn exe_args(&self) -> Vec<String> { |
|
|
|
self.split_args().1 |
|
|
|
self.split_args().1 |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
fn split_args(&self) -> (&[String], &[String]) { |
|
|
|
fn split_args(&self) -> (Vec<String>, Vec<String>) { |
|
|
|
if let Some(split) = self.args.iter().position(|s| s == "--") { |
|
|
|
let mut args = self.args.clone(); |
|
|
|
self.args.split_at(split + 1) |
|
|
|
|
|
|
|
|
|
|
|
if let Some(split) = args.iter().position(|s| s == "--") { |
|
|
|
|
|
|
|
let second_half = args.split_off(split + 1); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
(args, second_half) |
|
|
|
} else { |
|
|
|
} else { |
|
|
|
(&self.args[..], &[]) |
|
|
|
(args, Vec::new()) |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
impl Build { |
|
|
|
|
|
|
|
/// Callback for `cargo 3ds build`.
|
|
|
|
|
|
|
|
///
|
|
|
|
|
|
|
|
/// This callback handles building the application as a `.3dsx` file.
|
|
|
|
|
|
|
|
fn callback(&self, config: &CTRConfig) { |
|
|
|
|
|
|
|
eprintln!("Building smdh:{}", config.path_smdh().display()); |
|
|
|
|
|
|
|
build_smdh(config); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
eprintln!("Building 3dsx: {}", config.path_3dsx().display()); |
|
|
|
|
|
|
|
build_3dsx(config); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
impl Run { |
|
|
|
impl Run { |
|
|
|
/// Get the args to pass to `3dslink` based on these options.
|
|
|
|
/// Get the args to pass to `3dslink` based on these options.
|
|
|
|
pub fn get_3dslink_args(&self) -> Vec<String> { |
|
|
|
pub fn get_3dslink_args(&self) -> Vec<String> { |
|
|
@ -226,7 +357,7 @@ impl Run { |
|
|
|
args.push("--server".to_string()); |
|
|
|
args.push("--server".to_string()); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
let exe_args = self.cargo_args.exe_args(); |
|
|
|
let exe_args = self.build_args.cargo_args.exe_args(); |
|
|
|
if !exe_args.is_empty() { |
|
|
|
if !exe_args.is_empty() { |
|
|
|
// For some reason 3dslink seems to want 2 instances of `--`, one
|
|
|
|
// For some reason 3dslink seems to want 2 instances of `--`, one
|
|
|
|
// in front of all of the args like this...
|
|
|
|
// in front of all of the args like this...
|
|
|
@ -246,6 +377,97 @@ impl Run { |
|
|
|
|
|
|
|
|
|
|
|
args |
|
|
|
args |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// Callback for `cargo 3ds run`.
|
|
|
|
|
|
|
|
///
|
|
|
|
|
|
|
|
/// This callback handles launching the application via `3dslink`.
|
|
|
|
|
|
|
|
fn callback(&self, config: &CTRConfig) { |
|
|
|
|
|
|
|
// Run the normal "build" callback
|
|
|
|
|
|
|
|
self.build_args.callback(config); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
eprintln!("Running 3dslink"); |
|
|
|
|
|
|
|
link(config, self); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
impl Test { |
|
|
|
|
|
|
|
/// Callback for `cargo 3ds test`.
|
|
|
|
|
|
|
|
///
|
|
|
|
|
|
|
|
/// This callback handles launching the application via `3dslink`.
|
|
|
|
|
|
|
|
fn callback(&self, config: &CTRConfig) { |
|
|
|
|
|
|
|
if self.no_run { |
|
|
|
|
|
|
|
// If the tests don't have to run, use the "build" callback
|
|
|
|
|
|
|
|
self.run_args.build_args.callback(config) |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
// If the tests have to run, use the "run" callback
|
|
|
|
|
|
|
|
self.run_args.callback(config) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const TOML_CHANGES: &str = "ctru-rs = { git = \"https://github.com/rust3ds/ctru-rs\" }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
[package.metadata.cargo-3ds] |
|
|
|
|
|
|
|
romfs_dir = \"romfs\" |
|
|
|
|
|
|
|
"; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const CUSTOM_MAIN_RS: &str = "use ctru::prelude::*; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
fn main() { |
|
|
|
|
|
|
|
ctru::use_panic_handler(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let apt = Apt::new().unwrap(); |
|
|
|
|
|
|
|
let mut hid = Hid::new().unwrap(); |
|
|
|
|
|
|
|
let gfx = Gfx::new().unwrap(); |
|
|
|
|
|
|
|
let _console = Console::new(gfx.top_screen.borrow_mut()); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
println!(\"Hello, World!\"); |
|
|
|
|
|
|
|
println!(\"\\x1b[29;16HPress Start to exit\"); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
while apt.main_loop() { |
|
|
|
|
|
|
|
gfx.wait_for_vblank(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
hid.scan_input(); |
|
|
|
|
|
|
|
if hid.keys_down().contains(KeyPad::START) { |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
"; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
impl New { |
|
|
|
|
|
|
|
/// Callback for `cargo 3ds new`.
|
|
|
|
|
|
|
|
///
|
|
|
|
|
|
|
|
/// This callback handles the custom environment modifications when creating a new 3DS project.
|
|
|
|
|
|
|
|
fn callback(&self) { |
|
|
|
|
|
|
|
// Commmit changes to the project only if is meant to be a binary
|
|
|
|
|
|
|
|
if self.cargo_args.args.contains(&"--lib".to_string()) { |
|
|
|
|
|
|
|
return; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Attain a canonicalised path for the new project and it's TOML manifest
|
|
|
|
|
|
|
|
let project_path = fs::canonicalize(&self.path).unwrap(); |
|
|
|
|
|
|
|
let toml_path = project_path.join("Cargo.toml"); |
|
|
|
|
|
|
|
let romfs_path = project_path.join("romfs"); |
|
|
|
|
|
|
|
let main_rs_path = project_path.join("src/main.rs"); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Create the "romfs" directory
|
|
|
|
|
|
|
|
fs::create_dir(romfs_path).unwrap(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Read the contents of `Cargo.toml` to a string
|
|
|
|
|
|
|
|
let mut buf = String::new(); |
|
|
|
|
|
|
|
fs::File::open(&toml_path) |
|
|
|
|
|
|
|
.unwrap() |
|
|
|
|
|
|
|
.read_to_string(&mut buf) |
|
|
|
|
|
|
|
.unwrap(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Add the custom changes to the TOML
|
|
|
|
|
|
|
|
let buf = buf + TOML_CHANGES; |
|
|
|
|
|
|
|
fs::write(&toml_path, buf).unwrap(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Add the custom changes to the main.rs file
|
|
|
|
|
|
|
|
fs::write(main_rs_path, CUSTOM_MAIN_RS).unwrap(); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
#[cfg(test)] |
|
|
|
#[cfg(test)] |
|
|
@ -281,8 +503,10 @@ mod tests { |
|
|
|
]; |
|
|
|
]; |
|
|
|
|
|
|
|
|
|
|
|
for (args, expected) in CASES { |
|
|
|
for (args, expected) in CASES { |
|
|
|
let mut cmd = CargoCmd::Build(RemainingArgs { |
|
|
|
let mut cmd = CargoCmd::Build(Build { |
|
|
|
args: args.iter().map(ToString::to_string).collect(), |
|
|
|
cargo_args: RemainingArgs { |
|
|
|
|
|
|
|
args: args.iter().map(ToString::to_string).collect(), |
|
|
|
|
|
|
|
}, |
|
|
|
}); |
|
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
assert_eq!( |
|
|
|
assert_eq!( |
|
|
@ -290,8 +514,8 @@ mod tests { |
|
|
|
expected.map(ToString::to_string) |
|
|
|
expected.map(ToString::to_string) |
|
|
|
); |
|
|
|
); |
|
|
|
|
|
|
|
|
|
|
|
if let CargoCmd::Build(args) = cmd { |
|
|
|
if let CargoCmd::Build(build) = cmd { |
|
|
|
assert_eq!(args.args, vec!["--foo", "bar"]); |
|
|
|
assert_eq!(build.cargo_args.args, vec!["--foo", "bar"]); |
|
|
|
} else { |
|
|
|
} else { |
|
|
|
unreachable!(); |
|
|
|
unreachable!(); |
|
|
|
} |
|
|
|
} |
|
|
@ -301,8 +525,10 @@ mod tests { |
|
|
|
#[test] |
|
|
|
#[test] |
|
|
|
fn extract_format_err() { |
|
|
|
fn extract_format_err() { |
|
|
|
for args in [&["--message-format=foo"][..], &["--message-format", "foo"]] { |
|
|
|
for args in [&["--message-format=foo"][..], &["--message-format", "foo"]] { |
|
|
|
let mut cmd = CargoCmd::Build(RemainingArgs { |
|
|
|
let mut cmd = CargoCmd::Build(Build { |
|
|
|
args: args.iter().map(ToString::to_string).collect(), |
|
|
|
cargo_args: RemainingArgs { |
|
|
|
|
|
|
|
args: args.iter().map(ToString::to_string).collect(), |
|
|
|
|
|
|
|
}, |
|
|
|
}); |
|
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
assert!(cmd.extract_message_format().is_err()); |
|
|
|
assert!(cmd.extract_message_format().is_err()); |
|
|
@ -339,11 +565,11 @@ mod tests { |
|
|
|
expected_exe: &["bar"], |
|
|
|
expected_exe: &["bar"], |
|
|
|
}, |
|
|
|
}, |
|
|
|
] { |
|
|
|
] { |
|
|
|
let Run { cargo_args, .. } = |
|
|
|
let Run { build_args, .. } = |
|
|
|
Run::parse_from(std::iter::once(&"run").chain(param.input)); |
|
|
|
Run::parse_from(std::iter::once(&"run").chain(param.input)); |
|
|
|
|
|
|
|
|
|
|
|
assert_eq!(cargo_args.cargo_args(), param.expected_cargo); |
|
|
|
assert_eq!(build_args.cargo_args.cargo_args(), param.expected_cargo); |
|
|
|
assert_eq!(cargo_args.exe_args(), param.expected_exe); |
|
|
|
assert_eq!(build_args.cargo_args.exe_args(), param.expected_exe); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|