From 935594b3090cd7869d184b7cd0a7403c02c1219c Mon Sep 17 00:00:00 2001 From: Ian Chamberlain Date: Fri, 8 Apr 2022 11:09:08 -0400 Subject: [PATCH 1/3] Allow passthrough when message-format is specified --- src/main.rs | 40 +++++++++++++++++++++++++++++++--------- 1 file changed, 31 insertions(+), 9 deletions(-) diff --git a/src/main.rs b/src/main.rs index 6e2e160..9776483 100644 --- a/src/main.rs +++ b/src/main.rs @@ -140,9 +140,25 @@ impl CargoCommand { let cargo = env::var("CARGO").unwrap_or_else(|_| "cargo".to_string()); - let mut command = Command::new(cargo) - .arg(&self.command) - .arg("--message-format=json-render-diagnostics") + let has_message_format = self + .args + .iter() + .any(|arg| arg.starts_with("--message-format")); + + let mut command = Command::new(cargo); + command.arg(&self.command); + + if has_message_format { + // The user presumably cares about the message format, so we should + // print to stdout like usual. + command.stdout(Stdio::inherit()) + } else { + command + .stdout(Stdio::piped()) + .arg("--message-format=json-render-diagnostics") + }; + + let mut command = command .arg("-Z") .arg("build-std") .arg("--target") @@ -150,16 +166,22 @@ impl CargoCommand { .args(&self.args) .env("RUSTFLAGS", rustflags) .stdin(Stdio::inherit()) - .stdout(Stdio::piped()) .stderr(Stdio::inherit()) .spawn() .unwrap(); - let stdout_reader = std::io::BufReader::new(command.stdout.take().unwrap()); - - let messages = Message::parse_stream(stdout_reader) - .collect::>>() - .unwrap(); + let messages = if has_message_format { + // if the user specified message format, we can't parse the messages + // for anything since we wrote them all to stdout. + // TODO: should we exit early in this case? We can't get the + // metadata about the built artifacts or anything in this case. + Vec::new() + } else { + let stdout_reader = std::io::BufReader::new(command.stdout.take().unwrap()); + Message::parse_stream(stdout_reader) + .collect::>>() + .unwrap() + }; (command.wait().unwrap(), messages) } From 8023bfb28c070a571ce795e9f36e913c42080e67 Mon Sep 17 00:00:00 2001 From: Ian Chamberlain Date: Wed, 11 May 2022 21:20:18 -0400 Subject: [PATCH 2/3] Parse message-format up front and use TeeReader We can still parse the JSON output, even if Also: - remove some unused deps. - make sure we use eprintln so it doesn't interfere with any JSON output the user might want --- Cargo.toml | 6 ++-- src/main.rs | 98 ++++++++++++++++++++++++++++++++++------------------- 2 files changed, 65 insertions(+), 39 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 63cf6f5..e6072cf 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,15 +4,13 @@ version = "0.1.0" description = "Cargo wrapper for developing Rust-based Nintendo 3DS homebrew apps" repository = "https://github.com/Meziu/cargo-3ds" license = "MIT" -authors = [ "Andrea Ciliberti " ] +authors = ["Andrea Ciliberti "] edition = "2018" [dependencies] -clap = "2.33.1" -goblin = "0.4.3" -scroll = "0.10.1" cargo_metadata = "0.14.0" rustc_version = "0.4.0" serde = "1.0.111" serde_derive = "1.0.111" +tee = "0.1.0" toml = "0.5.6" diff --git a/src/main.rs b/src/main.rs index 9776483..e9486ed 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,11 +1,13 @@ use cargo_metadata::{Message, MetadataCommand}; use rustc_version::{Channel, Version}; +use std::io::{BufRead, BufReader}; use std::path::{Path, PathBuf}; use std::process::ExitStatus; use std::{ env, fmt, io, process::{self, Command, Stdio}, }; +use tee::TeeReader; #[derive(serde_derive::Deserialize, Default)] struct CTRConfig { @@ -102,9 +104,12 @@ struct CargoCommand { command: String, should_link: bool, args: Vec, + message_format: String, } impl CargoCommand { + const DEFAULT_MESSAGE_FORMAT: &'static str = "json-render-diagnostics"; + fn from_args() -> Option { // Skip `cargo 3ds`. `cargo-3ds` isn't supported for now let mut args = env::args().skip(2); @@ -127,62 +132,85 @@ impl CargoCommand { _ => (command, false), }; + let message_format = match Self::extract_message_format(&mut remaining_args) { + Some(format) => { + if !format.starts_with("json") { + eprintln!("error: non-JSON `message-format` is not supported"); + std::process::exit(1); + } + format + } + None => Self::DEFAULT_MESSAGE_FORMAT.to_string(), + }; + Some(Self { command, should_link, args: remaining_args, + message_format, }) } + fn extract_message_format(args: &mut Vec) -> Option { + for (i, arg) in args.iter().enumerate() { + if arg.starts_with("--message-format") { + return { + let arg = args.remove(i); + + if let Some((_, format)) = arg.split_once('=') { + Some(format.to_string()) + } else { + Some(args.remove(i)) + } + }; + } + } + + None + } + fn build_elf(&self) -> (ExitStatus, Vec) { let rustflags = env::var("RUSTFLAGS").unwrap_or_default() + &format!(" -L{}/libctru/lib -lctru", env::var("DEVKITPRO").unwrap()); let cargo = env::var("CARGO").unwrap_or_else(|_| "cargo".to_string()); - let has_message_format = self - .args - .iter() - .any(|arg| arg.starts_with("--message-format")); - - let mut command = Command::new(cargo); - command.arg(&self.command); - - if has_message_format { - // The user presumably cares about the message format, so we should - // print to stdout like usual. - command.stdout(Stdio::inherit()) - } else { - command - .stdout(Stdio::piped()) - .arg("--message-format=json-render-diagnostics") - }; - - let mut command = command + let mut command = Command::new(cargo) + .env("RUSTFLAGS", rustflags) + .arg(&self.command) .arg("-Z") .arg("build-std") .arg("--target") .arg("armv6k-nintendo-3ds") + .arg("--message-format") + .arg(&self.message_format) .args(&self.args) - .env("RUSTFLAGS", rustflags) + .stdout(Stdio::piped()) .stdin(Stdio::inherit()) .stderr(Stdio::inherit()) .spawn() .unwrap(); - let messages = if has_message_format { - // if the user specified message format, we can't parse the messages - // for anything since we wrote them all to stdout. - // TODO: should we exit early in this case? We can't get the - // metadata about the built artifacts or anything in this case. - Vec::new() + let command_stdout = command.stdout.take().unwrap(); + + let mut tee_reader; + let mut stdout_reader; + + let buf_reader: &mut dyn BufRead = if self.message_format == Self::DEFAULT_MESSAGE_FORMAT { + stdout_reader = BufReader::new(command_stdout); + &mut stdout_reader } else { - let stdout_reader = std::io::BufReader::new(command.stdout.take().unwrap()); - Message::parse_stream(stdout_reader) - .collect::>>() - .unwrap() + // The user presumably cares about the message format, 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 }; + let messages = Message::parse_stream(buf_reader) + .collect::>() + .unwrap(); + (command.wait().unwrap(), messages) } @@ -242,8 +270,8 @@ fn check_rust_version() { let rustc_version = rustc_version::version_meta().unwrap(); if rustc_version.channel > Channel::Nightly { - println!("cargo-3ds requires a nightly rustc version."); - println!( + eprintln!("cargo-3ds requires a nightly rustc version."); + eprintln!( "Please run `rustup override set nightly` to use nightly in the \ current directory." ); @@ -261,11 +289,11 @@ fn check_rust_version() { }; if old_version || old_commit { - println!( + eprintln!( "cargo-3ds requires rustc nightly version >= {}", MINIMUM_COMMIT_DATE, ); - println!("Please run `rustup update nightly` to upgrade your nightly version"); + eprintln!("Please run `rustup update nightly` to upgrade your nightly version"); process::exit(1); } @@ -362,7 +390,7 @@ fn build_3dsx(config: &CTRConfig) { // If romfs directory exists, automatically include it let (romfs_path, is_default_romfs) = get_romfs_path(config); if romfs_path.is_dir() { - println!("Adding RomFS from {}", romfs_path.display()); + eprintln!("Adding RomFS from {}", romfs_path.display()); process = process.arg(format!("--romfs={}", romfs_path.to_string_lossy())); } else if !is_default_romfs { eprintln!( From 1ebde461d08cd2ba8b68dff990aa2b680697eab7 Mon Sep 17 00:00:00 2001 From: Ian Chamberlain Date: Sun, 15 May 2022 11:25:51 -0400 Subject: [PATCH 3/3] Update to 2021 edition --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index e6072cf..2d3d060 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,7 +5,7 @@ description = "Cargo wrapper for developing Rust-based Nintendo 3DS homebrew app repository = "https://github.com/Meziu/cargo-3ds" license = "MIT" authors = ["Andrea Ciliberti "] -edition = "2018" +edition = "2021" [dependencies] cargo_metadata = "0.14.0"