From e8535a130dab94a665e6ad09f0ae72a70c338d93 Mon Sep 17 00:00:00 2001 From: Ian Chamberlain Date: Mon, 3 Apr 2023 12:39:07 -0400 Subject: [PATCH 1/3] Add limited support for `cargo 3ds test --doc` --- README.md | 13 +++++++++++++ src/command.rs | 10 +++++++++- src/lib.rs | 52 +++++++++++++++++++++++++++++++++++--------------- 3 files changed, 59 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index 5ac5dab..d566bd5 100644 --- a/README.md +++ b/README.md @@ -95,3 +95,16 @@ executable arguments, *another* `--` can be used. For example: This works without two `--` instances because `--verbose` begins the set of `cargo` arguments and ends the set of 3DS-specific arguments. + + +### Caveats + +Due to the fact that only one executable at a time can be sent with `3dslink`, +by default only the "last" executable built will be used. If a `test` or `run` +command builds more than one binary, you may need to filter it in order to run +the executable you want. + +Doc tests sort of work, but `cargo-3ds` uses a number of unstable cargo and +rustdoc features to make them work, so the output won't be as pretty and will +require some manual workarounds to actually run the tests and see output from them. +For now, `cargo 3ds test --doc` will not build a 3dsx file or use `3dslink` at all. diff --git a/src/command.rs b/src/command.rs index a014b31..f3ddb55 100644 --- a/src/command.rs +++ b/src/command.rs @@ -66,6 +66,11 @@ pub struct Test { #[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, @@ -104,7 +109,10 @@ pub struct Run { impl CargoCmd { /// Whether or not this command should build a 3DSX executable file. pub fn should_build_3dsx(&self) -> bool { - matches!(self, Self::Build(_) | Self::Run(_) | Self::Test(_)) + matches!( + self, + Self::Build(_) | Self::Run(_) | Self::Test(Test { doc: false, .. }) + ) } /// Whether or not the resulting executable should be sent to the 3DS with diff --git a/src/lib.rs b/src/lib.rs index aeb1bfd..a88773e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -3,6 +3,7 @@ pub mod command; use crate::command::CargoCmd; use cargo_metadata::{Message, MetadataCommand}; +use command::Test; use rustc_version::Channel; use semver::Version; use serde::Deserialize; @@ -26,15 +27,23 @@ pub fn run_cargo(cmd: &CargoCmd, message_format: Option) -> (ExitStatus, let mut tee_reader; let mut stdout_reader; - let buf_reader: &mut dyn BufRead = if message_format.is_none() { - stdout_reader = BufReader::new(command_stdout); - &mut stdout_reader - } else { - // The user presumably cares about the message format, so we should + + let buf_reader: &mut dyn BufRead = match (message_format, cmd) { + // The user presumably cares about the message format if set, so we should // copy stuff to stdout like they expect. We can still extract the executable // information out of it that we need for 3dsxtool etc. - tee_reader = BufReader::new(TeeReader::new(command_stdout, io::stdout())); - &mut tee_reader + (Some(_), _) | + // Rustdoc unfortunately prints to stdout for compile errors, so + // we also use a tee when building doc tests too. + // Possibly related: https://github.com/rust-lang/rust/issues/75135 + (None, CargoCmd::Test(Test { doc: true, .. })) => { + tee_reader = BufReader::new(TeeReader::new(command_stdout, io::stdout())); + &mut tee_reader + } + _ => { + stdout_reader = BufReader::new(command_stdout); + &mut stdout_reader + } }; let messages = Message::parse_stream(buf_reader) @@ -75,7 +84,7 @@ pub fn make_cargo_build_command(cmd: &CargoCmd, message_format: &Option) ); if !sysroot.join("lib/rustlib/armv6k-nintendo-3ds").exists() { - eprintln!("No pre-build std found, using build-std"); + eprintln!("No pre-built std found, using build-std"); command.arg("-Z").arg("build-std"); } @@ -83,9 +92,25 @@ pub fn make_cargo_build_command(cmd: &CargoCmd, message_format: &Option) CargoCmd::Build(cargo_args) => cargo_args.cargo_args(), CargoCmd::Run(run) => run.cargo_args.cargo_args(), CargoCmd::Test(test) => { - // We can't run 3DS executables on the host, so pass --no-run here and - // send the executable with 3dslink later, if the user wants - command.arg("--no-run"); + // 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 { + // https://github.com/rust-lang/cargo/issues/7040 + command.args(["--doc", "-Z", "doctest-xcompile"]); + + // Cargo doesn't like --no-run for doctests: + // https://github.com/rust-lang/rust/issues/87022 + let rustdoc_flags = std::env::var("RUSTDOCFLAGS").unwrap_or_default() + // TODO: should we make this output directory depend on profile etc? + + " --no-run --persist-doctests target/doctests"; + + command.env("RUSTDOCFLAGS", rustdoc_flags); + } else { + command.arg("--no-run"); + } + test.run_args.cargo_args.cargo_args() } CargoCmd::Passthrough(other) => &other[1..], @@ -146,10 +171,7 @@ pub fn check_rust_version() { }; if old_version || old_commit { - eprintln!( - "cargo-3ds requires rustc nightly version >= {}", - MINIMUM_COMMIT_DATE, - ); + eprintln!("cargo-3ds requires rustc nightly version >= {MINIMUM_COMMIT_DATE}"); eprintln!("Please run `rustup update nightly` to upgrade your nightly version"); process::exit(1); From 5a06e64307499ffe681453e7d88d7ee986054eb7 Mon Sep 17 00:00:00 2001 From: Ian Chamberlain Date: Mon, 3 Apr 2023 12:42:27 -0400 Subject: [PATCH 2/3] Add default CODEOWNERS to auto-add reviews --- .github/CODEOWNERS | 1 + 1 file changed, 1 insertion(+) create mode 100644 .github/CODEOWNERS diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 0000000..0163641 --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1 @@ +* @rust3ds/active From 3e7665fb6305e7365871b386df63463d9c0891e7 Mon Sep 17 00:00:00 2001 From: Ian Chamberlain Date: Wed, 5 Apr 2023 13:11:35 -0400 Subject: [PATCH 3/3] Slightly improve doctest output Warn user that no 3dsx will be built in this case, and use "human" formatting so that we get colored rustc output (since we don't need to parse the JSON output in this case anyway). --- src/command.rs | 30 ++++++++++++++++++++++-------- src/lib.rs | 2 ++ 2 files changed, 24 insertions(+), 8 deletions(-) diff --git a/src/command.rs b/src/command.rs index f3ddb55..7877819 100644 --- a/src/command.rs +++ b/src/command.rs @@ -119,8 +119,8 @@ impl CargoCmd { /// `3dslink`. pub fn should_link_to_device(&self) -> bool { match self { - CargoCmd::Test(test) => !test.no_run, - CargoCmd::Run(_) => true, + Self::Test(test) => !test.no_run, + Self::Run(_) => true, _ => false, } } @@ -128,12 +128,26 @@ impl CargoCmd { pub const DEFAULT_MESSAGE_FORMAT: &str = "json-render-diagnostics"; pub fn extract_message_format(&mut self) -> Result, String> { - Self::extract_message_format_from_args(match self { - CargoCmd::Build(args) => &mut args.args, - CargoCmd::Run(run) => &mut run.cargo_args.args, - CargoCmd::Test(test) => &mut test.run_args.cargo_args.args, - CargoCmd::Passthrough(args) => args, - }) + let cargo_args = match self { + Self::Build(args) => &mut args.args, + Self::Run(run) => &mut run.cargo_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)?; + if format.is_some() { + return Ok(format); + } + + if let Self::Test(Test { doc: true, .. }) = self { + // We don't care about JSON output for doctests since we're not + // building any 3dsx etc. Just use the default output as it's more + // readable compared to DEFAULT_MESSAGE_FORMAT + Ok(Some(String::from("human"))) + } else { + Ok(None) + } } fn extract_message_format_from_args( diff --git a/src/lib.rs b/src/lib.rs index a88773e..8fde305 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -97,6 +97,8 @@ pub fn make_cargo_build_command(cmd: &CargoCmd, message_format: &Option) // user wants if test.doc { + eprintln!("Documentation tests requested, no 3dsx will be built or run"); + // https://github.com/rust-lang/cargo/issues/7040 command.args(["--doc", "-Z", "doctest-xcompile"]);