Browse Source

Merge pull request #42 from rust3ds/feature/verbose-flag

pull/46/head
Ian Chamberlain 1 year ago committed by GitHub
parent
commit
cda49e09b6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 1
      Cargo.toml
  2. 43
      src/command.rs
  3. 69
      src/lib.rs
  4. 4
      src/main.rs

1
Cargo.toml

@ -18,3 +18,4 @@ serde = { version = "1.0.139", features = ["derive"] }
tee = "0.1.0" tee = "0.1.0"
toml = "0.5.6" toml = "0.5.6"
clap = { version = "4.0.15", features = ["derive", "wrap_help"] } clap = { version = "4.0.15", features = ["derive", "wrap_help"] }
shlex = "1.1.0"

43
src/command.rs

@ -18,6 +18,11 @@ pub enum Cargo {
pub struct Input { pub struct Input {
#[command(subcommand)] #[command(subcommand)]
pub cmd: CargoCmd, pub cmd: CargoCmd,
/// Print the exact commands `cargo-3ds` is running. Note that this does not
/// set the verbose flag for cargo itself.
#[arg(long, short = 'v')]
pub verbose: bool,
} }
/// Run a cargo command. COMMAND will be forwarded to the real /// Run a cargo command. COMMAND will be forwarded to the real
@ -153,6 +158,10 @@ impl CargoCmd {
"--doc".to_string(), "--doc".to_string(),
"-Z".to_string(), "-Z".to_string(),
"doctest-xcompile".to_string(), "doctest-xcompile".to_string(),
// doctests don't automatically build the `test` crate,
// so we manually specify it on the command line
"-Z".to_string(),
"build-std=std,test".to_string(),
]); ]);
} else { } else {
cargo_args.push("--no-run".to_string()); cargo_args.push("--no-run".to_string());
@ -278,21 +287,21 @@ impl CargoCmd {
/// ///
/// - `cargo 3ds build` and other "build" commands will use their callbacks to build the final `.3dsx` file and link it. /// - `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. /// - `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]) { pub fn run_callback(&self, messages: &[Message], verbose: bool) {
// Process the metadata only for commands that have it/use it // Process the metadata only for commands that have it/use it
let config = if self.should_build_3dsx() { let config = if self.should_build_3dsx() {
eprintln!("Getting metadata"); eprintln!("Getting metadata");
get_metadata(messages) Some(get_metadata(messages))
} else { } else {
CTRConfig::default() None
}; };
// Run callback only for commands that use it // Run callback only for commands that use it
match self { match self {
Self::Build(cmd) => cmd.callback(&config), Self::Build(cmd) => cmd.callback(&config, verbose),
Self::Run(cmd) => cmd.callback(&config), Self::Run(cmd) => cmd.callback(&config, verbose),
Self::Test(cmd) => cmd.callback(&config), Self::Test(cmd) => cmd.callback(&config, verbose),
Self::New(cmd) => cmd.callback(), Self::New(cmd) => cmd.callback(),
_ => (), _ => (),
} }
@ -327,12 +336,14 @@ impl Build {
/// Callback for `cargo 3ds build`. /// Callback for `cargo 3ds build`.
/// ///
/// This callback handles building the application as a `.3dsx` file. /// This callback handles building the application as a `.3dsx` file.
fn callback(&self, config: &CTRConfig) { fn callback(&self, config: &Option<CTRConfig>, verbose: bool) {
if let Some(config) = config {
eprintln!("Building smdh: {}", config.path_smdh().display()); eprintln!("Building smdh: {}", config.path_smdh().display());
build_smdh(config); build_smdh(config, verbose);
eprintln!("Building 3dsx: {}", config.path_3dsx().display()); eprintln!("Building 3dsx: {}", config.path_3dsx().display());
build_3dsx(config); build_3dsx(config, verbose);
}
} }
} }
@ -381,12 +392,14 @@ impl Run {
/// Callback for `cargo 3ds run`. /// Callback for `cargo 3ds run`.
/// ///
/// This callback handles launching the application via `3dslink`. /// This callback handles launching the application via `3dslink`.
fn callback(&self, config: &CTRConfig) { fn callback(&self, config: &Option<CTRConfig>, verbose: bool) {
// Run the normal "build" callback // Run the normal "build" callback
self.build_args.callback(config); self.build_args.callback(config, verbose);
if let Some(cfg) = config {
eprintln!("Running 3dslink"); eprintln!("Running 3dslink");
link(config, self); link(cfg, self, verbose);
}
} }
} }
@ -394,13 +407,13 @@ impl Test {
/// Callback for `cargo 3ds test`. /// Callback for `cargo 3ds test`.
/// ///
/// This callback handles launching the application via `3dslink`. /// This callback handles launching the application via `3dslink`.
fn callback(&self, config: &CTRConfig) { fn callback(&self, config: &Option<CTRConfig>, verbose: bool) {
if self.no_run { if self.no_run {
// If the tests don't have to run, use the "build" callback // If the tests don't have to run, use the "build" callback
self.run_args.build_args.callback(config) self.run_args.build_args.callback(config, verbose);
} else { } else {
// If the tests have to run, use the "run" callback // If the tests have to run, use the "run" callback
self.run_args.callback(config) self.run_args.callback(config, verbose);
} }
} }
} }

69
src/lib.rs

@ -3,7 +3,7 @@ pub mod command;
use crate::command::{CargoCmd, Run}; use crate::command::{CargoCmd, Run};
use cargo_metadata::{Message, MetadataCommand}; use cargo_metadata::{Message, MetadataCommand};
use command::Test; use command::{Input, Test};
use rustc_version::Channel; use rustc_version::Channel;
use semver::Version; use semver::Version;
use serde::Deserialize; use serde::Deserialize;
@ -20,8 +20,12 @@ use std::{env, io, process};
/// ///
/// For commands that produce an executable output, this function will build the /// For commands that produce an executable output, this function will build the
/// `.elf` binary that can be used to create other 3ds files. /// `.elf` binary that can be used to create other 3ds files.
pub fn run_cargo(cmd: &CargoCmd, message_format: Option<String>) -> (ExitStatus, Vec<Message>) { pub fn run_cargo(input: &Input, message_format: Option<String>) -> (ExitStatus, Vec<Message>) {
let mut command = make_cargo_command(cmd, &message_format); let mut command = make_cargo_command(&input.cmd, &message_format);
if input.verbose {
print_command(&command);
}
let mut process = command.spawn().unwrap(); let mut process = command.spawn().unwrap();
let command_stdout = process.stdout.take().unwrap(); let command_stdout = process.stdout.take().unwrap();
@ -29,7 +33,7 @@ pub fn run_cargo(cmd: &CargoCmd, message_format: Option<String>) -> (ExitStatus,
let mut tee_reader; let mut tee_reader;
let mut stdout_reader; let mut stdout_reader;
let buf_reader: &mut dyn BufRead = match (message_format, cmd) { let buf_reader: &mut dyn BufRead = match (message_format, &input.cmd) {
// The user presumably cares about the message format if set, so we should // 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 // copy stuff to stdout like they expect. We can still extract the executable
// information out of it that we need for 3dsxtool etc. // information out of it that we need for 3dsxtool etc.
@ -112,6 +116,23 @@ pub fn make_cargo_command(cmd: &CargoCmd, message_format: &Option<String>) -> Co
command command
} }
fn print_command(command: &Command) {
let mut cmd_str = vec![command.get_program().to_string_lossy().to_string()];
cmd_str.extend(command.get_args().map(|s| s.to_string_lossy().to_string()));
eprintln!("Running command:");
for (k, v) in command.get_envs() {
let v = v.map(|v| v.to_string_lossy().to_string());
eprintln!(
" {}={} \\",
k.to_string_lossy(),
v.map_or_else(String::new, |s| shlex::quote(&s).to_string())
);
}
eprintln!(" {}", shlex::join(cmd_str.iter().map(String::as_str)));
eprintln!();
}
/// Finds the sysroot path of the current toolchain /// Finds the sysroot path of the current toolchain
pub fn find_sysroot() -> PathBuf { pub fn find_sysroot() -> PathBuf {
let sysroot = env::var("SYSROOT").ok().unwrap_or_else(|| { let sysroot = env::var("SYSROOT").ok().unwrap_or_else(|| {
@ -235,8 +256,9 @@ pub fn get_metadata(messages: &[Message]) -> CTRConfig {
/// Builds the smdh using `smdhtool`. /// Builds the smdh using `smdhtool`.
/// This will fail if `smdhtool` is not within the running directory or in a directory found in $PATH /// This will fail if `smdhtool` is not within the running directory or in a directory found in $PATH
pub fn build_smdh(config: &CTRConfig) { pub fn build_smdh(config: &CTRConfig, verbose: bool) {
let mut process = Command::new("smdhtool") let mut command = Command::new("smdhtool");
command
.arg("--create") .arg("--create")
.arg(&config.name) .arg(&config.name)
.arg(&config.description) .arg(&config.description)
@ -245,7 +267,13 @@ pub fn build_smdh(config: &CTRConfig) {
.arg(config.path_smdh()) .arg(config.path_smdh())
.stdin(Stdio::inherit()) .stdin(Stdio::inherit())
.stdout(Stdio::inherit()) .stdout(Stdio::inherit())
.stderr(Stdio::inherit()) .stderr(Stdio::inherit());
if verbose {
print_command(&command);
}
let mut process = command
.spawn() .spawn()
.expect("smdhtool command failed, most likely due to 'smdhtool' not being in $PATH"); .expect("smdhtool command failed, most likely due to 'smdhtool' not being in $PATH");
@ -258,9 +286,9 @@ pub fn build_smdh(config: &CTRConfig) {
/// Builds the 3dsx using `3dsxtool`. /// Builds the 3dsx using `3dsxtool`.
/// This will fail if `3dsxtool` is not within the running directory or in a directory found in $PATH /// This will fail if `3dsxtool` is not within the running directory or in a directory found in $PATH
pub fn build_3dsx(config: &CTRConfig) { pub fn build_3dsx(config: &CTRConfig, verbose: bool) {
let mut command = Command::new("3dsxtool"); let mut command = Command::new("3dsxtool");
let mut process = command command
.arg(&config.target_path) .arg(&config.target_path)
.arg(config.path_3dsx()) .arg(config.path_3dsx())
.arg(format!("--smdh={}", config.path_smdh().to_string_lossy())); .arg(format!("--smdh={}", config.path_smdh().to_string_lossy()));
@ -269,7 +297,7 @@ pub fn build_3dsx(config: &CTRConfig) {
let (romfs_path, is_default_romfs) = get_romfs_path(config); let (romfs_path, is_default_romfs) = get_romfs_path(config);
if romfs_path.is_dir() { if romfs_path.is_dir() {
eprintln!("Adding RomFS from {}", romfs_path.display()); eprintln!("Adding RomFS from {}", romfs_path.display());
process = process.arg(format!("--romfs={}", romfs_path.to_string_lossy())); command.arg(format!("--romfs={}", romfs_path.to_string_lossy()));
} else if !is_default_romfs { } else if !is_default_romfs {
eprintln!( eprintln!(
"Could not find configured RomFS dir: {}", "Could not find configured RomFS dir: {}",
@ -278,7 +306,11 @@ pub fn build_3dsx(config: &CTRConfig) {
process::exit(1); process::exit(1);
} }
let mut process = process if verbose {
print_command(&command);
}
let mut process = command
.stdin(Stdio::inherit()) .stdin(Stdio::inherit())
.stdout(Stdio::inherit()) .stdout(Stdio::inherit())
.stderr(Stdio::inherit()) .stderr(Stdio::inherit())
@ -294,17 +326,20 @@ pub fn build_3dsx(config: &CTRConfig) {
/// Link the generated 3dsx to a 3ds to execute and test using `3dslink`. /// Link the generated 3dsx to a 3ds to execute and test using `3dslink`.
/// This will fail if `3dslink` is not within the running directory or in a directory found in $PATH /// This will fail if `3dslink` is not within the running directory or in a directory found in $PATH
pub fn link(config: &CTRConfig, run_args: &Run) { pub fn link(config: &CTRConfig, run_args: &Run, verbose: bool) {
let mut process = Command::new("3dslink") let mut command = Command::new("3dslink");
command
.arg(config.path_3dsx()) .arg(config.path_3dsx())
.args(run_args.get_3dslink_args()) .args(run_args.get_3dslink_args())
.stdin(Stdio::inherit()) .stdin(Stdio::inherit())
.stdout(Stdio::inherit()) .stdout(Stdio::inherit())
.stderr(Stdio::inherit()) .stderr(Stdio::inherit());
.spawn()
.unwrap();
let status = process.wait().unwrap(); if verbose {
print_command(&command);
}
let status = command.spawn().unwrap().wait().unwrap();
if !status.success() { if !status.success() {
process::exit(status.code().unwrap_or(1)); process::exit(status.code().unwrap_or(1));

4
src/main.rs

@ -18,11 +18,11 @@ fn main() {
} }
}; };
let (status, messages) = run_cargo(&input.cmd, message_format); let (status, messages) = run_cargo(&input, message_format);
if !status.success() { if !status.success() {
process::exit(status.code().unwrap_or(1)); process::exit(status.code().unwrap_or(1));
} }
input.cmd.run_callback(&messages); input.cmd.run_callback(&messages, input.verbose);
} }

Loading…
Cancel
Save