From 63b7024cb98717dd785ae888f419002b9835c6b1 Mon Sep 17 00:00:00 2001 From: datdenkikniet Date: Fri, 14 Apr 2023 23:59:23 +0200 Subject: xtask: build usage examples and general improvements --- xtask/src/command.rs | 92 +++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 81 insertions(+), 11 deletions(-) (limited to 'xtask/src/command.rs') diff --git a/xtask/src/command.rs b/xtask/src/command.rs index b62724a..93de9cf 100644 --- a/xtask/src/command.rs +++ b/xtask/src/command.rs @@ -8,6 +8,7 @@ use core::fmt; use std::{ fs::File, io::Read, + path::PathBuf, process::{Command, Stdio}, }; @@ -111,6 +112,14 @@ pub enum CargoCommand<'a> { mode: BuildMode, arguments: Option, }, + CheckInDir { + mode: BuildMode, + dir: PathBuf, + }, + BuildInDir { + mode: BuildMode, + dir: PathBuf, + }, } impl core::fmt::Display for CargoCommand<'_> { @@ -211,6 +220,10 @@ impl core::fmt::Display for CargoCommand<'_> { details(target, mode, features, cargoarg) ) } + CargoCommand::BuildInDir { mode, dir } => { + let dir = dir.as_os_str().to_str().unwrap_or("Not displayable"); + write!(f, "Build {dir} ({mode})") + } CargoCommand::Check { cargoarg, package, @@ -225,6 +238,10 @@ impl core::fmt::Display for CargoCommand<'_> { details(target, mode, features, cargoarg) ) } + CargoCommand::CheckInDir { mode, dir } => { + let dir = dir.as_os_str().to_str().unwrap_or("Not displayable"); + write!(f, "Check {dir} ({mode})") + } CargoCommand::Clippy { cargoarg, package, @@ -316,11 +333,15 @@ impl<'a> CargoCommand<'a> { format!("{executable} {args}") } - fn command(&self) -> &str { + fn command(&self) -> &'static str { match self { CargoCommand::Run { .. } | CargoCommand::Qemu { .. } => "run", - CargoCommand::ExampleCheck { .. } | CargoCommand::Check { .. } => "check", - CargoCommand::ExampleBuild { .. } | CargoCommand::Build { .. } => "build", + CargoCommand::ExampleCheck { .. } + | CargoCommand::Check { .. } + | CargoCommand::CheckInDir { .. } => "check", + CargoCommand::ExampleBuild { .. } + | CargoCommand::Build { .. } + | CargoCommand::BuildInDir { .. } => "build", CargoCommand::ExampleSize { .. } => "size", CargoCommand::Clippy { .. } => "clippy", CargoCommand::Format { .. } => "fmt", @@ -329,7 +350,7 @@ impl<'a> CargoCommand<'a> { CargoCommand::Test { .. } => "test", } } - pub fn executable(&self) -> &str { + pub fn executable(&self) -> &'static str { match self { CargoCommand::Run { .. } | CargoCommand::Qemu { .. } @@ -341,7 +362,9 @@ impl<'a> CargoCommand<'a> { | CargoCommand::Clippy { .. } | CargoCommand::Format { .. } | CargoCommand::Test { .. } - | CargoCommand::Doc { .. } => "cargo", + | CargoCommand::Doc { .. } + | CargoCommand::CheckInDir { .. } + | CargoCommand::BuildInDir { .. } => "cargo", CargoCommand::Book { .. } => "mdbook", } } @@ -641,6 +664,34 @@ impl<'a> CargoCommand<'a> { } args } + CargoCommand::CheckInDir { mode, dir: _ } => { + let mut args = vec!["+nightly"]; + args.push(self.command()); + + if let Some(mode) = mode.to_flag() { + args.push(mode); + } + + args + } + CargoCommand::BuildInDir { mode, dir: _ } => { + let mut args = vec!["+nightly", self.command()]; + + if let Some(mode) = mode.to_flag() { + args.push(mode); + } + + args + } + } + } + + fn chdir(&self) -> Option<&PathBuf> { + match self { + CargoCommand::CheckInDir { dir, .. } | CargoCommand::BuildInDir { dir, .. } => { + Some(dir) + } + _ => None, } } } @@ -669,11 +720,18 @@ impl fmt::Display for BuildMode { pub fn run_command(command: &CargoCommand, stderr_mode: OutputMode) -> anyhow::Result { log::info!("👟 {command}"); - let result = Command::new(command.executable()) + let mut process = Command::new(command.executable()); + + process .args(command.args()) .stdout(Stdio::piped()) - .stderr(stderr_mode) - .output()?; + .stderr(stderr_mode); + + if let Some(dir) = command.chdir() { + process.current_dir(dir); + } + + let result = process.output()?; let exit_status = result.status; let stderr = String::from_utf8(result.stderr).unwrap_or("Not displayable".into()); @@ -759,15 +817,27 @@ pub fn handle_results(globals: &Globals, results: Vec) -> anyhow errors.clone().for_each(log_stdout_stderr(Level::Error)); successes.for_each(|(cmd, _)| { + let path = if let Some(dir) = cmd.chdir() { + let path = dir.as_os_str().to_str().unwrap_or("Not displayable"); + format!(" (in {path}") + } else { + format!("") + }; + if globals.verbose > 0 { - info!("✅ Success: {cmd}\n {}", cmd.as_cmd_string()); + info!("✅ Success:{path} {cmd}\n {}", cmd.as_cmd_string()); } else { - info!("✅ Success: {cmd}"); + info!("✅ Success:{path} {cmd}"); } }); errors.clone().for_each(|(cmd, _)| { - error!("❌ Failed: {cmd}\n {}", cmd.as_cmd_string()); + if let Some(dir) = cmd.chdir() { + let path = dir.as_os_str().to_str().unwrap_or("Not displayable"); + error!("❌ Failed: (in {path}) {cmd}\n {}", cmd.as_cmd_string()); + } else { + error!("❌ Failed: {cmd}\n {}", cmd.as_cmd_string()); + } }); let ecount = errors.count(); -- cgit v1.2.3 From fa8af4cbcffbedec1504ed464bd02b6ee6e3fb4b Mon Sep 17 00:00:00 2001 From: datdenkikniet Date: Sat, 15 Apr 2023 20:19:37 +0200 Subject: Add the most important message --- xtask/src/command.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'xtask/src/command.rs') diff --git a/xtask/src/command.rs b/xtask/src/command.rs index 93de9cf..186836b 100644 --- a/xtask/src/command.rs +++ b/xtask/src/command.rs @@ -771,7 +771,7 @@ pub fn run_successful(run: &RunResult, expected_output_file: &str) -> Result<(), } } -pub fn handle_results(globals: &Globals, results: Vec) -> anyhow::Result<()> { +pub fn handle_results(globals: &Globals, results: Vec) -> Result<(), ()> { let errors = results.iter().filter_map(|r| { if let FinalRunResult::Failed(c, r) = r { Some((c, r)) @@ -842,8 +842,10 @@ pub fn handle_results(globals: &Globals, results: Vec) -> anyhow let ecount = errors.count(); if ecount != 0 { - Err(anyhow::anyhow!("{ecount} commands failed.")) + log::error!("{ecount} commands failed."); + Err(()) } else { + info!("🚀🚀🚀 All tasks succeeded 🚀🚀🚀"); Ok(()) } } -- cgit v1.2.3 From 6517a4bec2e909b40eb9974e063f95e44e4d9a31 Mon Sep 17 00:00:00 2001 From: datdenkikniet Date: Sat, 15 Apr 2023 20:44:06 +0200 Subject: Also check for CommandErrors in error checking --- xtask/src/command.rs | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) (limited to 'xtask/src/command.rs') diff --git a/xtask/src/command.rs b/xtask/src/command.rs index 186836b..93ea824 100644 --- a/xtask/src/command.rs +++ b/xtask/src/command.rs @@ -774,7 +774,7 @@ pub fn run_successful(run: &RunResult, expected_output_file: &str) -> Result<(), pub fn handle_results(globals: &Globals, results: Vec) -> Result<(), ()> { let errors = results.iter().filter_map(|r| { if let FinalRunResult::Failed(c, r) = r { - Some((c, r)) + Some((c, &r.stdout, &r.stderr)) } else { None } @@ -782,16 +782,22 @@ pub fn handle_results(globals: &Globals, results: Vec) -> Result let successes = results.iter().filter_map(|r| { if let FinalRunResult::Success(c, r) = r { - Some((c, r)) + Some((c, &r.stdout, &r.stderr)) + } else { + None + } + }); + + let command_errors = results.iter().filter_map(|r| { + if let FinalRunResult::CommandError(c, e) = r { + Some((c, e)) } else { None } }); let log_stdout_stderr = |level: Level| { - move |(command, result): (&CargoCommand, &RunResult)| { - let stdout = &result.stdout; - let stderr = &result.stderr; + move |(command, stdout, stderr): (&CargoCommand, &String, &String)| { if !stdout.is_empty() && !stderr.is_empty() { log::log!( level, @@ -816,7 +822,7 @@ pub fn handle_results(globals: &Globals, results: Vec) -> Result successes.clone().for_each(log_stdout_stderr(Level::Debug)); errors.clone().for_each(log_stdout_stderr(Level::Error)); - successes.for_each(|(cmd, _)| { + successes.for_each(|(cmd, _, _)| { let path = if let Some(dir) = cmd.chdir() { let path = dir.as_os_str().to_str().unwrap_or("Not displayable"); format!(" (in {path}") @@ -831,7 +837,7 @@ pub fn handle_results(globals: &Globals, results: Vec) -> Result } }); - errors.clone().for_each(|(cmd, _)| { + errors.clone().for_each(|(cmd, _, _)| { if let Some(dir) = cmd.chdir() { let path = dir.as_os_str().to_str().unwrap_or("Not displayable"); error!("❌ Failed: (in {path}) {cmd}\n {}", cmd.as_cmd_string()); @@ -840,8 +846,13 @@ pub fn handle_results(globals: &Globals, results: Vec) -> Result } }); + command_errors + .clone() + .for_each(|(cmd, error)| error!("❌ Failed: {cmd}\n {}\n{error}", cmd.as_cmd_string())); + let ecount = errors.count(); - if ecount != 0 { + let cecount = command_errors.count(); + if ecount != 0 || cecount != 0 { log::error!("{ecount} commands failed."); Err(()) } else { -- cgit v1.2.3 From 859cd418f063590a9928b3e43caeea0b53dc0823 Mon Sep 17 00:00:00 2001 From: datdenkikniet Date: Sat, 15 Apr 2023 20:57:27 +0200 Subject: Rename some things --- xtask/src/command.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'xtask/src/command.rs') diff --git a/xtask/src/command.rs b/xtask/src/command.rs index 93ea824..a1c4d25 100644 --- a/xtask/src/command.rs +++ b/xtask/src/command.rs @@ -831,16 +831,16 @@ pub fn handle_results(globals: &Globals, results: Vec) -> Result }; if globals.verbose > 0 { - info!("✅ Success:{path} {cmd}\n {}", cmd.as_cmd_string()); + info!("✅ Success: {cmd}{path}\n {}", cmd.as_cmd_string()); } else { - info!("✅ Success:{path} {cmd}"); + info!("✅ Success:{cmd}{path}"); } }); errors.clone().for_each(|(cmd, _, _)| { if let Some(dir) = cmd.chdir() { let path = dir.as_os_str().to_str().unwrap_or("Not displayable"); - error!("❌ Failed: (in {path}) {cmd}\n {}", cmd.as_cmd_string()); + error!("❌ Failed: {cmd} (in {path}) \n {}", cmd.as_cmd_string()); } else { error!("❌ Failed: {cmd}\n {}", cmd.as_cmd_string()); } -- cgit v1.2.3 From d838286de679a1ac35ea79999816418cd02b7259 Mon Sep 17 00:00:00 2001 From: datdenkikniet Date: Sat, 15 Apr 2023 21:16:45 +0200 Subject: Fix config pickup behaviour so that both examples and usage-examples build correctly --- xtask/src/command.rs | 28 +++++++++++++++++++++++++--- 1 file changed, 25 insertions(+), 3 deletions(-) (limited to 'xtask/src/command.rs') diff --git a/xtask/src/command.rs b/xtask/src/command.rs index a1c4d25..a45cb8a 100644 --- a/xtask/src/command.rs +++ b/xtask/src/command.rs @@ -383,6 +383,7 @@ impl<'a> CargoCommand<'a> { if let Some(cargoarg) = cargoarg { args.extend_from_slice(&[cargoarg]); } + args.extend_from_slice(&[ self.command(), "--example", @@ -407,9 +408,15 @@ impl<'a> CargoCommand<'a> { mode, } => { let mut args = vec!["+nightly"]; + if let Some(cargoarg) = cargoarg { args.extend_from_slice(&[cargoarg]); } + + // We need to be in the `rtic` directory to pick up + // the correct .cargo/config.toml file + args.extend_from_slice(&["-Z", "unstable-options", "-C", "rtic"]); + args.extend_from_slice(&[ self.command(), "--example", @@ -641,6 +648,11 @@ impl<'a> CargoCommand<'a> { if let Some(cargoarg) = cargoarg { args.extend_from_slice(&[cargoarg]); } + + // We need to be in the `rtic` directory to pick up + // the correct .cargo/config.toml file + args.extend_from_slice(&["-Z", "unstable-options", "-C", "rtic"]); + args.extend_from_slice(&[ self.command(), "--example", @@ -694,6 +706,13 @@ impl<'a> CargoCommand<'a> { _ => None, } } + + pub fn print_stdout_intermediate(&self) -> bool { + match self { + Self::ExampleSize { .. } => true, + _ => false, + } + } } impl BuildMode { @@ -737,6 +756,10 @@ pub fn run_command(command: &CargoCommand, stderr_mode: OutputMode) -> anyhow::R let stderr = String::from_utf8(result.stderr).unwrap_or("Not displayable".into()); let stdout = String::from_utf8(result.stdout).unwrap_or("Not displayable".into()); + if command.print_stdout_intermediate() && exit_status.success() { + log::info!("\n{}", stdout); + } + Ok(RunResult { exit_status, stdout, @@ -850,9 +873,8 @@ pub fn handle_results(globals: &Globals, results: Vec) -> Result .clone() .for_each(|(cmd, error)| error!("❌ Failed: {cmd}\n {}\n{error}", cmd.as_cmd_string())); - let ecount = errors.count(); - let cecount = command_errors.count(); - if ecount != 0 || cecount != 0 { + let ecount = errors.count() + command_errors.count(); + if ecount != 0 { log::error!("{ecount} commands failed."); Err(()) } else { -- cgit v1.2.3 From 1c84ccf6e4169b4b45f0e22e709e4265a10324a5 Mon Sep 17 00:00:00 2001 From: datdenkikniet Date: Sat, 15 Apr 2023 22:19:13 +0200 Subject: Fix running of tests --- xtask/src/command.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'xtask/src/command.rs') diff --git a/xtask/src/command.rs b/xtask/src/command.rs index a45cb8a..187a3dd 100644 --- a/xtask/src/command.rs +++ b/xtask/src/command.rs @@ -593,6 +593,11 @@ impl<'a> CargoCommand<'a> { if let Some(cargoarg) = cargoarg { args.extend_from_slice(&[cargoarg]); } + + // We need to be in the `rtic` directory to pick up + // the correct .cargo/config.toml file + args.extend_from_slice(&["-Z", "unstable-options", "-C", "rtic"]); + args.extend_from_slice(&[ self.command(), "--example", @@ -856,7 +861,7 @@ pub fn handle_results(globals: &Globals, results: Vec) -> Result if globals.verbose > 0 { info!("✅ Success: {cmd}{path}\n {}", cmd.as_cmd_string()); } else { - info!("✅ Success:{cmd}{path}"); + info!("✅ Success: {cmd}{path}"); } }); -- cgit v1.2.3 From deeb3877f061fb71389ec7730c6c21e81e9e3050 Mon Sep 17 00:00:00 2001 From: datdenkikniet Date: Sat, 15 Apr 2023 22:40:25 +0200 Subject: Improve locality of error messages & ExampleBuild + Qemu commands, and indicate failure earlier --- xtask/src/command.rs | 34 ++++++++++++++-------------------- 1 file changed, 14 insertions(+), 20 deletions(-) (limited to 'xtask/src/command.rs') diff --git a/xtask/src/command.rs b/xtask/src/command.rs index 187a3dd..3596897 100644 --- a/xtask/src/command.rs +++ b/xtask/src/command.rs @@ -765,6 +765,10 @@ pub fn run_command(command: &CargoCommand, stderr_mode: OutputMode) -> anyhow::R log::info!("\n{}", stdout); } + if !exit_status.success() { + log::error!("❌ Command failed. Run to completion for the summary."); + } + Ok(RunResult { exit_status, stdout, @@ -825,32 +829,19 @@ pub fn handle_results(globals: &Globals, results: Vec) -> Result }); let log_stdout_stderr = |level: Level| { - move |(command, stdout, stderr): (&CargoCommand, &String, &String)| { + move |(cmd, stdout, stderr): (&CargoCommand, &String, &String)| { + let cmd = cmd.as_cmd_string(); if !stdout.is_empty() && !stderr.is_empty() { - log::log!( - level, - "Output for \"{command}\"\nStdout:\n{stdout}\nStderr:\n{stderr}" - ); + log::log!(level, "\n{cmd}\nStdout:\n{stdout}\nStderr:\n{stderr}"); } else if !stdout.is_empty() { - log::log!( - level, - "Output for \"{command}\":\nStdout:\n{}", - stdout.trim_end() - ); + log::log!(level, "\n{cmd}\nStdout:\n{}", stdout.trim_end()); } else if !stderr.is_empty() { - log::log!( - level, - "Output for \"{command}\"\nStderr:\n{}", - stderr.trim_end() - ); + log::log!(level, "\n{cmd}\nStderr:\n{}", stderr.trim_end()); } } }; - successes.clone().for_each(log_stdout_stderr(Level::Debug)); - errors.clone().for_each(log_stdout_stderr(Level::Error)); - - successes.for_each(|(cmd, _, _)| { + successes.for_each(|(cmd, stdout, stderr)| { let path = if let Some(dir) = cmd.chdir() { let path = dir.as_os_str().to_str().unwrap_or("Not displayable"); format!(" (in {path}") @@ -863,15 +854,18 @@ pub fn handle_results(globals: &Globals, results: Vec) -> Result } else { info!("✅ Success: {cmd}{path}"); } + + log_stdout_stderr(Level::Debug)((cmd, stdout, stderr)); }); - errors.clone().for_each(|(cmd, _, _)| { + errors.clone().for_each(|(cmd, stdout, stderr)| { if let Some(dir) = cmd.chdir() { let path = dir.as_os_str().to_str().unwrap_or("Not displayable"); error!("❌ Failed: {cmd} (in {path}) \n {}", cmd.as_cmd_string()); } else { error!("❌ Failed: {cmd}\n {}", cmd.as_cmd_string()); } + log_stdout_stderr(Level::Error)((cmd, stdout, stderr)); }); command_errors -- cgit v1.2.3 From 9dc9f492639daace5222562c124846fb0d3cb154 Mon Sep 17 00:00:00 2001 From: datdenkikniet Date: Sat, 15 Apr 2023 23:22:00 +0200 Subject: Use chdir() instead of unstable option, also confirm whenver a command succeeds because why not --- xtask/src/command.rs | 89 ++++++++++++++++++++++++++++++++-------------------- 1 file changed, 55 insertions(+), 34 deletions(-) (limited to 'xtask/src/command.rs') diff --git a/xtask/src/command.rs b/xtask/src/command.rs index 3596897..e06c89e 100644 --- a/xtask/src/command.rs +++ b/xtask/src/command.rs @@ -51,6 +51,7 @@ pub enum CargoCommand<'a> { target: Target<'a>, features: Option, mode: BuildMode, + dir: Option, }, ExampleBuild { cargoarg: &'a Option<&'a str>, @@ -58,6 +59,7 @@ pub enum CargoCommand<'a> { target: Target<'a>, features: Option, mode: BuildMode, + dir: Option, }, ExampleCheck { cargoarg: &'a Option<&'a str>, @@ -111,6 +113,7 @@ pub enum CargoCommand<'a> { features: Option, mode: BuildMode, arguments: Option, + dir: Option, }, CheckInDir { mode: BuildMode, @@ -179,22 +182,32 @@ impl core::fmt::Display for CargoCommand<'_> { target, features, mode, - } => write!( - f, - "Run example {example} in QEMU {}", - details(target, mode, features, cargoarg) - ), + dir, + } => { + let details = details(target, mode, features, cargoarg); + if let Some(dir) = dir { + let dir = dir.to_str().unwrap_or("Not displayable"); + write!(f, "Run example {example} in QEMU from {dir} {details}",) + } else { + write!(f, "Run example {example} in QEMU {details}",) + } + } CargoCommand::ExampleBuild { cargoarg, example, target, features, mode, - } => write!( - f, - "Build example {example} {}", - details(target, mode, features, cargoarg) - ), + dir, + } => { + let details = details(target, mode, features, cargoarg); + if let Some(dir) = dir { + let dir = dir.to_str().unwrap_or("Not displayable"); + write!(f, "Build example {example} in {dir} {details}") + } else { + write!(f, "Build example {example} {details}",) + } + } CargoCommand::ExampleCheck { cargoarg, example, @@ -221,7 +234,7 @@ impl core::fmt::Display for CargoCommand<'_> { ) } CargoCommand::BuildInDir { mode, dir } => { - let dir = dir.as_os_str().to_str().unwrap_or("Not displayable"); + let dir = dir.to_str().unwrap_or("Not displayable"); write!(f, "Build {dir} ({mode})") } CargoCommand::Check { @@ -239,7 +252,7 @@ impl core::fmt::Display for CargoCommand<'_> { ) } CargoCommand::CheckInDir { mode, dir } => { - let dir = dir.as_os_str().to_str().unwrap_or("Not displayable"); + let dir = dir.to_str().unwrap_or("Not displayable"); write!(f, "Check {dir} ({mode})") } CargoCommand::Clippy { @@ -315,12 +328,15 @@ impl core::fmt::Display for CargoCommand<'_> { features, mode, arguments: _, + dir, } => { - write!( - f, - "Compute size of example {example} {}", - details(target, mode, features, cargoarg) - ) + let details = details(target, mode, features, cargoarg); + if let Some(dir) = dir { + let dir = dir.to_str().unwrap_or("Not displayable"); + write!(f, "Compute size of example {example} from {dir} {details}",) + } else { + write!(f, "Compute size of example {example} {details}") + } } } } @@ -328,9 +344,15 @@ impl core::fmt::Display for CargoCommand<'_> { impl<'a> CargoCommand<'a> { pub fn as_cmd_string(&self) -> String { + let cd = if let Some(Some(chdir)) = self.chdir().map(|p| p.to_str()) { + format!("cd {chdir} && ") + } else { + format!("") + }; + let executable = self.executable(); let args = self.args().join(" "); - format!("{executable} {args}") + format!("{cd}{executable} {args}") } fn command(&self) -> &'static str { @@ -406,6 +428,8 @@ impl<'a> CargoCommand<'a> { target, features, mode, + // Dir is exposed through chdir instead + dir: _, } => { let mut args = vec!["+nightly"]; @@ -413,10 +437,6 @@ impl<'a> CargoCommand<'a> { args.extend_from_slice(&[cargoarg]); } - // We need to be in the `rtic` directory to pick up - // the correct .cargo/config.toml file - args.extend_from_slice(&["-Z", "unstable-options", "-C", "rtic"]); - args.extend_from_slice(&[ self.command(), "--example", @@ -588,16 +608,14 @@ impl<'a> CargoCommand<'a> { target, features, mode, + // Dir is exposed through chdir instead + dir: _, } => { let mut args = vec!["+nightly"]; if let Some(cargoarg) = cargoarg { args.extend_from_slice(&[cargoarg]); } - // We need to be in the `rtic` directory to pick up - // the correct .cargo/config.toml file - args.extend_from_slice(&["-Z", "unstable-options", "-C", "rtic"]); - args.extend_from_slice(&[ self.command(), "--example", @@ -648,16 +666,14 @@ impl<'a> CargoCommand<'a> { features, mode, arguments, + // Dir is exposed through chdir instead + dir: _, } => { let mut args = vec!["+nightly"]; if let Some(cargoarg) = cargoarg { args.extend_from_slice(&[cargoarg]); } - // We need to be in the `rtic` directory to pick up - // the correct .cargo/config.toml file - args.extend_from_slice(&["-Z", "unstable-options", "-C", "rtic"]); - args.extend_from_slice(&[ self.command(), "--example", @@ -708,6 +724,9 @@ impl<'a> CargoCommand<'a> { CargoCommand::CheckInDir { dir, .. } | CargoCommand::BuildInDir { dir, .. } => { Some(dir) } + CargoCommand::Qemu { dir, .. } + | CargoCommand::ExampleBuild { dir, .. } + | CargoCommand::ExampleSize { dir, .. } => dir.as_ref(), _ => None, } } @@ -752,7 +771,7 @@ pub fn run_command(command: &CargoCommand, stderr_mode: OutputMode) -> anyhow::R .stderr(stderr_mode); if let Some(dir) = command.chdir() { - process.current_dir(dir); + process.current_dir(dir.canonicalize()?); } let result = process.output()?; @@ -765,7 +784,9 @@ pub fn run_command(command: &CargoCommand, stderr_mode: OutputMode) -> anyhow::R log::info!("\n{}", stdout); } - if !exit_status.success() { + if exit_status.success() { + log::info!("✅ Success.") + } else { log::error!("❌ Command failed. Run to completion for the summary."); } @@ -843,7 +864,7 @@ pub fn handle_results(globals: &Globals, results: Vec) -> Result successes.for_each(|(cmd, stdout, stderr)| { let path = if let Some(dir) = cmd.chdir() { - let path = dir.as_os_str().to_str().unwrap_or("Not displayable"); + let path = dir.to_str().unwrap_or("Not displayable"); format!(" (in {path}") } else { format!("") @@ -860,7 +881,7 @@ pub fn handle_results(globals: &Globals, results: Vec) -> Result errors.clone().for_each(|(cmd, stdout, stderr)| { if let Some(dir) = cmd.chdir() { - let path = dir.as_os_str().to_str().unwrap_or("Not displayable"); + let path = dir.to_str().unwrap_or("Not displayable"); error!("❌ Failed: {cmd} (in {path}) \n {}", cmd.as_cmd_string()); } else { error!("❌ Failed: {cmd}\n {}", cmd.as_cmd_string()); -- cgit v1.2.3 From 404867cdf92990cb0aba415dfbee97c7fef78b60 Mon Sep 17 00:00:00 2001 From: datdenkikniet Date: Sun, 16 Apr 2023 09:44:30 +0200 Subject: CargoCommand can take any package --- xtask/src/command.rs | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) (limited to 'xtask/src/command.rs') diff --git a/xtask/src/command.rs b/xtask/src/command.rs index e06c89e..da6d907 100644 --- a/xtask/src/command.rs +++ b/xtask/src/command.rs @@ -1,8 +1,8 @@ use log::{error, info, Level}; use crate::{ - argument_parsing::Globals, cargo_commands::FinalRunResult, ExtraArguments, Package, RunResult, - Target, TestRunError, + argument_parsing::Globals, cargo_commands::FinalRunResult, ExtraArguments, RunResult, Target, + TestRunError, }; use core::fmt; use std::{ @@ -70,27 +70,27 @@ pub enum CargoCommand<'a> { }, Build { cargoarg: &'a Option<&'a str>, - package: Option, + package: Option, target: Target<'a>, features: Option, mode: BuildMode, }, Check { cargoarg: &'a Option<&'a str>, - package: Option, + package: Option, target: Target<'a>, features: Option, mode: BuildMode, }, Clippy { cargoarg: &'a Option<&'a str>, - package: Option, + package: Option, target: Target<'a>, features: Option, }, Format { cargoarg: &'a Option<&'a str>, - package: Option, + package: Option, check_only: bool, }, Doc { @@ -99,7 +99,7 @@ pub enum CargoCommand<'a> { arguments: Option, }, Test { - package: Option, + package: Option, features: Option, test: Option, }, @@ -127,7 +127,7 @@ pub enum CargoCommand<'a> { impl core::fmt::Display for CargoCommand<'_> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let p = |p: &Option| { + let p = |p: &Option| { if let Some(package) = p { format!("package {package}") } else { @@ -468,7 +468,7 @@ impl<'a> CargoCommand<'a> { args.extend_from_slice(&[self.command(), "--target", target.triple()]); if let Some(package) = package { - args.extend_from_slice(&["--package", package.name()]); + args.extend_from_slice(&["--package", package]); } if let Some(feature) = features { @@ -493,7 +493,7 @@ impl<'a> CargoCommand<'a> { args.extend_from_slice(&[self.command()]); if let Some(package) = package { - args.extend_from_slice(&["--package", package.name()]); + args.extend_from_slice(&["--package", package]); } if let Some(feature) = features { @@ -518,7 +518,7 @@ impl<'a> CargoCommand<'a> { args.extend_from_slice(&[self.command()]); if let Some(package) = package { - args.extend_from_slice(&["--package", package.name()]); + args.extend_from_slice(&["--package", package]); } if let Some(feature) = features { @@ -557,7 +557,7 @@ impl<'a> CargoCommand<'a> { args.extend_from_slice(&[self.command()]); if let Some(package) = package { - args.extend_from_slice(&["--package", package.name()]); + args.extend_from_slice(&["--package", package]); } if let Some(feature) = features { @@ -594,7 +594,7 @@ impl<'a> CargoCommand<'a> { } if let Some(package) = package { - args.extend_from_slice(&["--package", package.name()]); + args.extend_from_slice(&["--package", package]); } if *check_only { args.extend_from_slice(&["--check"]); -- cgit v1.2.3 From b59bf686c1e10bb8068d89e43779d7777f553c48 Mon Sep 17 00:00:00 2001 From: datdenkikniet Date: Sun, 16 Apr 2023 11:00:39 +0200 Subject: Redo command building so that we don't repeat as much, and to make it easier to add new ones --- xtask/src/command.rs | 583 +++++++++++++++++++++------------------------------ 1 file changed, 240 insertions(+), 343 deletions(-) (limited to 'xtask/src/command.rs') diff --git a/xtask/src/command.rs b/xtask/src/command.rs index da6d907..33d0703 100644 --- a/xtask/src/command.rs +++ b/xtask/src/command.rs @@ -41,14 +41,15 @@ pub enum CargoCommand<'a> { Run { cargoarg: &'a Option<&'a str>, example: &'a str, - target: Target<'a>, + target: Option>, features: Option, mode: BuildMode, + dir: Option, }, Qemu { cargoarg: &'a Option<&'a str>, example: &'a str, - target: Target<'a>, + target: Option>, features: Option, mode: BuildMode, dir: Option, @@ -56,7 +57,7 @@ pub enum CargoCommand<'a> { ExampleBuild { cargoarg: &'a Option<&'a str>, example: &'a str, - target: Target<'a>, + target: Option>, features: Option, mode: BuildMode, dir: Option, @@ -64,28 +65,30 @@ pub enum CargoCommand<'a> { ExampleCheck { cargoarg: &'a Option<&'a str>, example: &'a str, - target: Target<'a>, + target: Option>, features: Option, mode: BuildMode, }, Build { cargoarg: &'a Option<&'a str>, package: Option, - target: Target<'a>, + target: Option>, features: Option, mode: BuildMode, + dir: Option, }, Check { cargoarg: &'a Option<&'a str>, package: Option, - target: Target<'a>, + target: Option>, features: Option, mode: BuildMode, + dir: Option, }, Clippy { cargoarg: &'a Option<&'a str>, package: Option, - target: Target<'a>, + target: Option>, features: Option, }, Format { @@ -109,60 +112,78 @@ pub enum CargoCommand<'a> { ExampleSize { cargoarg: &'a Option<&'a str>, example: &'a str, - target: Target<'a>, + target: Option>, features: Option, mode: BuildMode, arguments: Option, dir: Option, }, - CheckInDir { - mode: BuildMode, - dir: PathBuf, - }, - BuildInDir { - mode: BuildMode, - dir: PathBuf, - }, } impl core::fmt::Display for CargoCommand<'_> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let p = |p: &Option| { + fn p(p: &Option) -> String { if let Some(package) = p { format!("package {package}") } else { format!("default package") } - }; + } - let feat = |f: &Option| { + fn feat(f: &Option) -> String { if let Some(features) = f { format!("\"{features}\"") } else { format!("no features") } - }; + } - let carg = |f: &&Option<&str>| { + fn carg(f: &&Option<&str>) -> String { if let Some(cargoarg) = f { format!("{cargoarg}") } else { format!("no cargo args") } - }; + } - let details = |target: &Target, - mode: &BuildMode, - features: &Option, - cargoarg: &&Option<&str>| { + fn details( + target: &Option, + mode: Option<&BuildMode>, + features: &Option, + cargoarg: &&Option<&str>, + path: Option<&PathBuf>, + ) -> String { let feat = feat(features); let carg = carg(cargoarg); - if cargoarg.is_some() { + let in_dir = if let Some(path) = path { + let path = path.to_str().unwrap_or(""); + format!("in {path}") + } else { + format!("") + }; + + let target = if let Some(target) = target { + format!("{target}") + } else { + format!("") + }; + + let mode = if let Some(mode) = mode { + format!("{mode}") + } else { + format!("debug") + }; + + if cargoarg.is_some() && path.is_some() { + format!("({target}, {mode}, {feat}, {carg}, {in_dir})") + } else if cargoarg.is_some() { format!("({target}, {mode}, {feat}, {carg})") + } else if path.is_some() { + format!("({target}, {mode}, {feat}, {in_dir})") } else { format!("({target}, {mode}, {feat})") } - }; + } match self { CargoCommand::Run { @@ -171,11 +192,14 @@ impl core::fmt::Display for CargoCommand<'_> { target, features, mode, - } => write!( - f, - "Run example {example} {}", - details(target, mode, features, cargoarg) - ), + dir, + } => { + write!( + f, + "Run example {example} {}", + details(target, Some(mode), features, cargoarg, dir.as_ref()) + ) + } CargoCommand::Qemu { cargoarg, example, @@ -184,13 +208,8 @@ impl core::fmt::Display for CargoCommand<'_> { mode, dir, } => { - let details = details(target, mode, features, cargoarg); - if let Some(dir) = dir { - let dir = dir.to_str().unwrap_or("Not displayable"); - write!(f, "Run example {example} in QEMU from {dir} {details}",) - } else { - write!(f, "Run example {example} in QEMU {details}",) - } + let details = details(target, Some(mode), features, cargoarg, dir.as_ref()); + write!(f, "Run example {example} in QEMU {details}",) } CargoCommand::ExampleBuild { cargoarg, @@ -200,13 +219,8 @@ impl core::fmt::Display for CargoCommand<'_> { mode, dir, } => { - let details = details(target, mode, features, cargoarg); - if let Some(dir) = dir { - let dir = dir.to_str().unwrap_or("Not displayable"); - write!(f, "Build example {example} in {dir} {details}") - } else { - write!(f, "Build example {example} {details}",) - } + let details = details(target, Some(mode), features, cargoarg, dir.as_ref()); + write!(f, "Build example {example} {details}",) } CargoCommand::ExampleCheck { cargoarg, @@ -217,7 +231,7 @@ impl core::fmt::Display for CargoCommand<'_> { } => write!( f, "Check example {example} {}", - details(target, mode, features, cargoarg) + details(target, Some(mode), features, cargoarg, None) ), CargoCommand::Build { cargoarg, @@ -225,50 +239,40 @@ impl core::fmt::Display for CargoCommand<'_> { target, features, mode, + dir, } => { let package = p(package); write!( f, "Build {package} {}", - details(target, mode, features, cargoarg) + details(target, Some(mode), features, cargoarg, dir.as_ref()) ) } - CargoCommand::BuildInDir { mode, dir } => { - let dir = dir.to_str().unwrap_or("Not displayable"); - write!(f, "Build {dir} ({mode})") - } + CargoCommand::Check { cargoarg, package, target, features, mode, + dir, } => { let package = p(package); write!( f, "Check {package} {}", - details(target, mode, features, cargoarg) + details(target, Some(mode), features, cargoarg, dir.as_ref()) ) } - CargoCommand::CheckInDir { mode, dir } => { - let dir = dir.to_str().unwrap_or("Not displayable"); - write!(f, "Check {dir} ({mode})") - } CargoCommand::Clippy { cargoarg, package, target, features, } => { + let details = details(target, None, features, cargoarg, None); let package = p(package); - let features = feat(features); - let carg = carg(cargoarg); - if cargoarg.is_some() { - write!(f, "Clippy {package} ({target}, {features}, {carg})") - } else { - write!(f, "Clippy {package} ({target}, {features})") - } + write!(f, "Clippy {package} {details}") } CargoCommand::Format { cargoarg, @@ -330,13 +334,8 @@ impl core::fmt::Display for CargoCommand<'_> { arguments: _, dir, } => { - let details = details(target, mode, features, cargoarg); - if let Some(dir) = dir { - let dir = dir.to_str().unwrap_or("Not displayable"); - write!(f, "Compute size of example {example} from {dir} {details}",) - } else { - write!(f, "Compute size of example {example} {details}") - } + let details = details(target, Some(mode), features, cargoarg, dir.as_ref()); + write!(f, "Compute size of example {example} {details}") } } } @@ -358,12 +357,8 @@ impl<'a> CargoCommand<'a> { fn command(&self) -> &'static str { match self { CargoCommand::Run { .. } | CargoCommand::Qemu { .. } => "run", - CargoCommand::ExampleCheck { .. } - | CargoCommand::Check { .. } - | CargoCommand::CheckInDir { .. } => "check", - CargoCommand::ExampleBuild { .. } - | CargoCommand::Build { .. } - | CargoCommand::BuildInDir { .. } => "build", + CargoCommand::ExampleCheck { .. } | CargoCommand::Check { .. } => "check", + CargoCommand::ExampleBuild { .. } | CargoCommand::Build { .. } => "build", CargoCommand::ExampleSize { .. } => "size", CargoCommand::Clippy { .. } => "clippy", CargoCommand::Format { .. } => "fmt", @@ -384,189 +379,159 @@ impl<'a> CargoCommand<'a> { | CargoCommand::Clippy { .. } | CargoCommand::Format { .. } | CargoCommand::Test { .. } - | CargoCommand::Doc { .. } - | CargoCommand::CheckInDir { .. } - | CargoCommand::BuildInDir { .. } => "cargo", + | CargoCommand::Doc { .. } => "cargo", CargoCommand::Book { .. } => "mdbook", } } + /// Build args using common arguments for all commands, and the + /// specific information provided + fn build_args<'i, T: Iterator>( + &'i self, + nightly: bool, + cargoarg: &'i Option<&'i str>, + features: &'i Option, + mode: Option<&'i BuildMode>, + extra: T, + ) -> Vec<&str> { + let mut args: Vec<&str> = Vec::new(); + + if nightly { + args.push("+nightly"); + } + + if let Some(cargoarg) = cargoarg.as_deref() { + args.push(cargoarg); + } + + args.push(self.command()); + + if let Some(target) = self.target() { + args.extend_from_slice(&["--target", target.triple()]) + } + + if let Some(features) = features.as_ref() { + args.extend_from_slice(&["--features", features]); + } + + if let Some(mode) = mode.map(|m| m.to_flag()).flatten() { + args.push(mode); + } + + args.extend(extra); + + args + } + + /// Turn the ExtraArguments into an interator that contains the separating dashes + /// and the rest of the arguments. + /// + /// NOTE: you _must_ chain this iterator at the _end_ of the extra arguments. + fn extra_args(args: Option<&ExtraArguments>) -> impl Iterator { + #[allow(irrefutable_let_patterns)] + let args = if let Some(ExtraArguments::Other(arguments)) = args { + // Extra arguments must be passed after "--" + ["--"] + .into_iter() + .chain(arguments.iter().map(String::as_str)) + .collect() + } else { + vec![] + }; + args.into_iter() + } + pub fn args(&self) -> Vec<&str> { + fn p(package: &Option) -> impl Iterator { + if let Some(package) = package { + vec!["--package", &package].into_iter() + } else { + vec![].into_iter() + } + } + match self { // For future embedded-ci, for now the same as Qemu CargoCommand::Run { cargoarg, example, - target, features, mode, - } => { - let mut args = vec!["+nightly"]; - if let Some(cargoarg) = cargoarg { - args.extend_from_slice(&[cargoarg]); - } - - args.extend_from_slice(&[ - self.command(), - "--example", - example, - "--target", - target.triple(), - ]); - - if let Some(feature) = features { - args.extend_from_slice(&["--features", feature]); - } - if let Some(flag) = mode.to_flag() { - args.push(flag); - } - args - } + // dir is exposed through `chdir` + dir: _, + // Target is added by build_args + target: _, + } => self.build_args( + true, + cargoarg, + features, + Some(mode), + ["--example", example].into_iter(), + ), CargoCommand::Qemu { cargoarg, example, - target, features, mode, - // Dir is exposed through chdir instead + // dir is exposed through `chdir` dir: _, - } => { - let mut args = vec!["+nightly"]; - - if let Some(cargoarg) = cargoarg { - args.extend_from_slice(&[cargoarg]); - } - - args.extend_from_slice(&[ - self.command(), - "--example", - example, - "--target", - target.triple(), - ]); - - if let Some(feature) = features { - args.extend_from_slice(&["--features", feature]); - } - if let Some(flag) = mode.to_flag() { - args.push(flag); - } - args - } + // Target is added by build_args + target: _, + } => self.build_args( + true, + cargoarg, + features, + Some(mode), + ["--example", example].into_iter(), + ), CargoCommand::Build { cargoarg, package, - target, features, mode, - } => { - let mut args = vec!["+nightly"]; - if let Some(cargoarg) = cargoarg { - args.extend_from_slice(&[cargoarg]); - } - - args.extend_from_slice(&[self.command(), "--target", target.triple()]); - - if let Some(package) = package { - args.extend_from_slice(&["--package", package]); - } - - if let Some(feature) = features { - args.extend_from_slice(&["--features", feature]); - } - if let Some(flag) = mode.to_flag() { - args.push(flag); - } - args - } + // Dir is exposed through `chdir` + dir: _, + // Target is added by build_args + target: _, + } => self.build_args(true, cargoarg, features, Some(mode), p(package)), CargoCommand::Check { cargoarg, package, - target: _, features, mode, - } => { - let mut args = vec!["+nightly"]; - if let Some(cargoarg) = cargoarg { - args.extend_from_slice(&[cargoarg]); - } - args.extend_from_slice(&[self.command()]); - - if let Some(package) = package { - args.extend_from_slice(&["--package", package]); - } - - if let Some(feature) = features { - args.extend_from_slice(&["--features", feature]); - } - if let Some(flag) = mode.to_flag() { - args.push(flag); - } - args - } + // Dir is exposed through `chdir` + dir: _, + // Target is added by build_args + target: _, + } => self.build_args(true, cargoarg, features, Some(mode), p(package)), CargoCommand::Clippy { cargoarg, package, - target: _, features, - } => { - let mut args = vec!["+nightly"]; - if let Some(cargoarg) = cargoarg { - args.extend_from_slice(&[cargoarg]); - } - - args.extend_from_slice(&[self.command()]); - - if let Some(package) = package { - args.extend_from_slice(&["--package", package]); - } - - if let Some(feature) = features { - args.extend_from_slice(&["--features", feature]); - } - args - } + // Target is added by build_args + target: _, + } => self.build_args(true, cargoarg, features, None, p(package)), CargoCommand::Doc { cargoarg, features, arguments, } => { - let mut args = vec!["+nightly"]; - if let Some(cargoarg) = cargoarg { - args.extend_from_slice(&[cargoarg]); - } - - args.extend_from_slice(&[self.command()]); - - if let Some(feature) = features { - args.extend_from_slice(&["--features", feature]); - } - if let Some(ExtraArguments::Other(arguments)) = arguments { - for arg in arguments { - args.extend_from_slice(&[arg.as_str()]); - } - } - args + let extra = Self::extra_args(arguments.as_ref()); + self.build_args(true, cargoarg, features, None, extra) } CargoCommand::Test { package, features, test, } => { - let mut args = vec!["+nightly"]; - args.extend_from_slice(&[self.command()]); - - if let Some(package) = package { - args.extend_from_slice(&["--package", package]); - } - - if let Some(feature) = features { - args.extend_from_slice(&["--features", feature]); - } - if let Some(test) = test { - args.extend_from_slice(&["--test", test]); - } - args + let extra = if let Some(test) = test { + vec!["--test", test] + } else { + vec![] + }; + let package = p(package); + let extra = extra.into_iter().chain(package); + self.build_args(true, &None, features, None, extra) } CargoCommand::Book { arguments } => { let mut args = vec![]; @@ -588,145 +553,89 @@ impl<'a> CargoCommand<'a> { package, check_only, } => { - let mut args = vec!["+nightly", self.command()]; - if let Some(cargoarg) = cargoarg { - args.extend_from_slice(&[cargoarg]); - } - - if let Some(package) = package { - args.extend_from_slice(&["--package", package]); - } - if *check_only { - args.extend_from_slice(&["--check"]); - } - - args + let extra = if *check_only { Some("--check") } else { None }; + let package = p(package); + self.build_args( + true, + cargoarg, + &None, + None, + extra.into_iter().chain(package), + ) } CargoCommand::ExampleBuild { cargoarg, example, - target, features, mode, - // Dir is exposed through chdir instead + // dir is exposed through `chdir` dir: _, - } => { - let mut args = vec!["+nightly"]; - if let Some(cargoarg) = cargoarg { - args.extend_from_slice(&[cargoarg]); - } - - args.extend_from_slice(&[ - self.command(), - "--example", - example, - "--target", - target.triple(), - ]); - - if let Some(feature) = features { - args.extend_from_slice(&["--features", feature]); - } - if let Some(flag) = mode.to_flag() { - args.push(flag); - } - args - } + // Target is added by build_args + target: _, + } => self.build_args( + true, + cargoarg, + features, + Some(mode), + ["--example", example].into_iter(), + ), CargoCommand::ExampleCheck { cargoarg, example, - target, features, mode, - } => { - let mut args = vec!["+nightly"]; - if let Some(cargoarg) = cargoarg { - args.extend_from_slice(&[cargoarg]); - } - args.extend_from_slice(&[ - self.command(), - "--example", - example, - "--target", - target.triple(), - ]); - - if let Some(feature) = features { - args.extend_from_slice(&["--features", feature]); - } - if let Some(flag) = mode.to_flag() { - args.push(flag); - } - args - } + // Target is added by build_args + target: _, + } => self.build_args( + true, + cargoarg, + features, + Some(mode), + ["--example", example].into_iter(), + ), CargoCommand::ExampleSize { cargoarg, example, - target, features, mode, arguments, - // Dir is exposed through chdir instead + // Target is added by build_args + target: _, + // dir is exposed through `chdir` dir: _, } => { - let mut args = vec!["+nightly"]; - if let Some(cargoarg) = cargoarg { - args.extend_from_slice(&[cargoarg]); - } - - args.extend_from_slice(&[ - self.command(), - "--example", - example, - "--target", - target.triple(), - ]); - - if let Some(feature_name) = features { - args.extend_from_slice(&["--features", feature_name]); - } - if let Some(flag) = mode.to_flag() { - args.push(flag); - } - if let Some(ExtraArguments::Other(arguments)) = arguments { - // Arguments to cargo size must be passed after "--" - args.extend_from_slice(&["--"]); - for arg in arguments { - args.extend_from_slice(&[arg.as_str()]); - } - } - args - } - CargoCommand::CheckInDir { mode, dir: _ } => { - let mut args = vec!["+nightly"]; - args.push(self.command()); + let extra = ["--example", example] + .into_iter() + .chain(Self::extra_args(arguments.as_ref())); - if let Some(mode) = mode.to_flag() { - args.push(mode); - } - - args - } - CargoCommand::BuildInDir { mode, dir: _ } => { - let mut args = vec!["+nightly", self.command()]; - - if let Some(mode) = mode.to_flag() { - args.push(mode); - } - - args + self.build_args(true, cargoarg, features, Some(mode), extra) } } } + /// TODO: integrate this into `args` once `-C` becomes stable. fn chdir(&self) -> Option<&PathBuf> { match self { - CargoCommand::CheckInDir { dir, .. } | CargoCommand::BuildInDir { dir, .. } => { - Some(dir) - } CargoCommand::Qemu { dir, .. } | CargoCommand::ExampleBuild { dir, .. } - | CargoCommand::ExampleSize { dir, .. } => dir.as_ref(), + | CargoCommand::ExampleSize { dir, .. } + | CargoCommand::Build { dir, .. } + | CargoCommand::Run { dir, .. } + | CargoCommand::Check { dir, .. } => dir.as_ref(), + _ => None, + } + } + + fn target(&self) -> Option<&Target> { + match self { + CargoCommand::Run { target, .. } + | CargoCommand::Qemu { target, .. } + | CargoCommand::ExampleBuild { target, .. } + | CargoCommand::ExampleCheck { target, .. } + | CargoCommand::Build { target, .. } + | CargoCommand::Check { target, .. } + | CargoCommand::Clippy { target, .. } + | CargoCommand::ExampleSize { target, .. } => target.as_ref(), _ => None, } } @@ -863,29 +772,17 @@ pub fn handle_results(globals: &Globals, results: Vec) -> Result }; successes.for_each(|(cmd, stdout, stderr)| { - let path = if let Some(dir) = cmd.chdir() { - let path = dir.to_str().unwrap_or("Not displayable"); - format!(" (in {path}") - } else { - format!("") - }; - if globals.verbose > 0 { - info!("✅ Success: {cmd}{path}\n {}", cmd.as_cmd_string()); + info!("✅ Success: {cmd}\n {}", cmd.as_cmd_string()); } else { - info!("✅ Success: {cmd}{path}"); + info!("✅ Success: {cmd}"); } log_stdout_stderr(Level::Debug)((cmd, stdout, stderr)); }); errors.clone().for_each(|(cmd, stdout, stderr)| { - if let Some(dir) = cmd.chdir() { - let path = dir.to_str().unwrap_or("Not displayable"); - error!("❌ Failed: {cmd} (in {path}) \n {}", cmd.as_cmd_string()); - } else { - error!("❌ Failed: {cmd}\n {}", cmd.as_cmd_string()); - } + error!("❌ Failed: {cmd}\n {}", cmd.as_cmd_string()); log_stdout_stderr(Level::Error)((cmd, stdout, stderr)); }); -- cgit v1.2.3 From 66a3d02b4585a76615d750c33a37edd5e8fd30e6 Mon Sep 17 00:00:00 2001 From: datdenkikniet Date: Sun, 16 Apr 2023 11:02:49 +0200 Subject: Rename cargo_commands -> run Rename command -> cargo_command --- xtask/src/command.rs | 801 --------------------------------------------------- 1 file changed, 801 deletions(-) delete mode 100644 xtask/src/command.rs (limited to 'xtask/src/command.rs') diff --git a/xtask/src/command.rs b/xtask/src/command.rs deleted file mode 100644 index 33d0703..0000000 --- a/xtask/src/command.rs +++ /dev/null @@ -1,801 +0,0 @@ -use log::{error, info, Level}; - -use crate::{ - argument_parsing::Globals, cargo_commands::FinalRunResult, ExtraArguments, RunResult, Target, - TestRunError, -}; -use core::fmt; -use std::{ - fs::File, - io::Read, - path::PathBuf, - process::{Command, Stdio}, -}; - -#[allow(dead_code)] -#[derive(Debug, Clone, Copy, PartialEq)] -pub enum BuildMode { - Release, - Debug, -} - -#[derive(Debug, Clone, Copy, PartialEq)] -pub enum OutputMode { - PipedAndCollected, - Inherited, -} - -impl From for Stdio { - fn from(value: OutputMode) -> Self { - match value { - OutputMode::PipedAndCollected => Stdio::piped(), - OutputMode::Inherited => Stdio::inherit(), - } - } -} - -#[derive(Debug)] -pub enum CargoCommand<'a> { - // For future embedded-ci - #[allow(dead_code)] - Run { - cargoarg: &'a Option<&'a str>, - example: &'a str, - target: Option>, - features: Option, - mode: BuildMode, - dir: Option, - }, - Qemu { - cargoarg: &'a Option<&'a str>, - example: &'a str, - target: Option>, - features: Option, - mode: BuildMode, - dir: Option, - }, - ExampleBuild { - cargoarg: &'a Option<&'a str>, - example: &'a str, - target: Option>, - features: Option, - mode: BuildMode, - dir: Option, - }, - ExampleCheck { - cargoarg: &'a Option<&'a str>, - example: &'a str, - target: Option>, - features: Option, - mode: BuildMode, - }, - Build { - cargoarg: &'a Option<&'a str>, - package: Option, - target: Option>, - features: Option, - mode: BuildMode, - dir: Option, - }, - Check { - cargoarg: &'a Option<&'a str>, - package: Option, - target: Option>, - features: Option, - mode: BuildMode, - dir: Option, - }, - Clippy { - cargoarg: &'a Option<&'a str>, - package: Option, - target: Option>, - features: Option, - }, - Format { - cargoarg: &'a Option<&'a str>, - package: Option, - check_only: bool, - }, - Doc { - cargoarg: &'a Option<&'a str>, - features: Option, - arguments: Option, - }, - Test { - package: Option, - features: Option, - test: Option, - }, - Book { - arguments: Option, - }, - ExampleSize { - cargoarg: &'a Option<&'a str>, - example: &'a str, - target: Option>, - features: Option, - mode: BuildMode, - arguments: Option, - dir: Option, - }, -} - -impl core::fmt::Display for CargoCommand<'_> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - fn p(p: &Option) -> String { - if let Some(package) = p { - format!("package {package}") - } else { - format!("default package") - } - } - - fn feat(f: &Option) -> String { - if let Some(features) = f { - format!("\"{features}\"") - } else { - format!("no features") - } - } - - fn carg(f: &&Option<&str>) -> String { - if let Some(cargoarg) = f { - format!("{cargoarg}") - } else { - format!("no cargo args") - } - } - - fn details( - target: &Option, - mode: Option<&BuildMode>, - features: &Option, - cargoarg: &&Option<&str>, - path: Option<&PathBuf>, - ) -> String { - let feat = feat(features); - let carg = carg(cargoarg); - let in_dir = if let Some(path) = path { - let path = path.to_str().unwrap_or(""); - format!("in {path}") - } else { - format!("") - }; - - let target = if let Some(target) = target { - format!("{target}") - } else { - format!("") - }; - - let mode = if let Some(mode) = mode { - format!("{mode}") - } else { - format!("debug") - }; - - if cargoarg.is_some() && path.is_some() { - format!("({target}, {mode}, {feat}, {carg}, {in_dir})") - } else if cargoarg.is_some() { - format!("({target}, {mode}, {feat}, {carg})") - } else if path.is_some() { - format!("({target}, {mode}, {feat}, {in_dir})") - } else { - format!("({target}, {mode}, {feat})") - } - } - - match self { - CargoCommand::Run { - cargoarg, - example, - target, - features, - mode, - dir, - } => { - write!( - f, - "Run example {example} {}", - details(target, Some(mode), features, cargoarg, dir.as_ref()) - ) - } - CargoCommand::Qemu { - cargoarg, - example, - target, - features, - mode, - dir, - } => { - let details = details(target, Some(mode), features, cargoarg, dir.as_ref()); - write!(f, "Run example {example} in QEMU {details}",) - } - CargoCommand::ExampleBuild { - cargoarg, - example, - target, - features, - mode, - dir, - } => { - let details = details(target, Some(mode), features, cargoarg, dir.as_ref()); - write!(f, "Build example {example} {details}",) - } - CargoCommand::ExampleCheck { - cargoarg, - example, - target, - features, - mode, - } => write!( - f, - "Check example {example} {}", - details(target, Some(mode), features, cargoarg, None) - ), - CargoCommand::Build { - cargoarg, - package, - target, - features, - mode, - dir, - } => { - let package = p(package); - write!( - f, - "Build {package} {}", - details(target, Some(mode), features, cargoarg, dir.as_ref()) - ) - } - - CargoCommand::Check { - cargoarg, - package, - target, - features, - mode, - dir, - } => { - let package = p(package); - write!( - f, - "Check {package} {}", - details(target, Some(mode), features, cargoarg, dir.as_ref()) - ) - } - CargoCommand::Clippy { - cargoarg, - package, - target, - features, - } => { - let details = details(target, None, features, cargoarg, None); - let package = p(package); - write!(f, "Clippy {package} {details}") - } - CargoCommand::Format { - cargoarg, - package, - check_only, - } => { - let package = p(package); - let carg = carg(cargoarg); - - let carg = if cargoarg.is_some() { - format!("(cargo args: {carg})") - } else { - format!("") - }; - - if *check_only { - write!(f, "Check format for {package} {carg}") - } else { - write!(f, "Format {package} {carg}") - } - } - CargoCommand::Doc { - cargoarg, - features, - arguments, - } => { - let feat = feat(features); - let carg = carg(cargoarg); - let arguments = arguments - .clone() - .map(|a| format!("{a}")) - .unwrap_or_else(|| "no extra arguments".into()); - if cargoarg.is_some() { - write!(f, "Document ({feat}, {carg}, {arguments})") - } else { - write!(f, "Document ({feat}, {arguments})") - } - } - CargoCommand::Test { - package, - features, - test, - } => { - let p = p(package); - let test = test - .clone() - .map(|t| format!("test {t}")) - .unwrap_or("all tests".into()); - let feat = feat(features); - write!(f, "Run {test} in {p} (features: {feat})") - } - CargoCommand::Book { arguments: _ } => write!(f, "Build the book"), - CargoCommand::ExampleSize { - cargoarg, - example, - target, - features, - mode, - arguments: _, - dir, - } => { - let details = details(target, Some(mode), features, cargoarg, dir.as_ref()); - write!(f, "Compute size of example {example} {details}") - } - } - } -} - -impl<'a> CargoCommand<'a> { - pub fn as_cmd_string(&self) -> String { - let cd = if let Some(Some(chdir)) = self.chdir().map(|p| p.to_str()) { - format!("cd {chdir} && ") - } else { - format!("") - }; - - let executable = self.executable(); - let args = self.args().join(" "); - format!("{cd}{executable} {args}") - } - - fn command(&self) -> &'static str { - match self { - CargoCommand::Run { .. } | CargoCommand::Qemu { .. } => "run", - CargoCommand::ExampleCheck { .. } | CargoCommand::Check { .. } => "check", - CargoCommand::ExampleBuild { .. } | CargoCommand::Build { .. } => "build", - CargoCommand::ExampleSize { .. } => "size", - CargoCommand::Clippy { .. } => "clippy", - CargoCommand::Format { .. } => "fmt", - CargoCommand::Doc { .. } => "doc", - CargoCommand::Book { .. } => "build", - CargoCommand::Test { .. } => "test", - } - } - pub fn executable(&self) -> &'static str { - match self { - CargoCommand::Run { .. } - | CargoCommand::Qemu { .. } - | CargoCommand::ExampleCheck { .. } - | CargoCommand::Check { .. } - | CargoCommand::ExampleBuild { .. } - | CargoCommand::Build { .. } - | CargoCommand::ExampleSize { .. } - | CargoCommand::Clippy { .. } - | CargoCommand::Format { .. } - | CargoCommand::Test { .. } - | CargoCommand::Doc { .. } => "cargo", - CargoCommand::Book { .. } => "mdbook", - } - } - - /// Build args using common arguments for all commands, and the - /// specific information provided - fn build_args<'i, T: Iterator>( - &'i self, - nightly: bool, - cargoarg: &'i Option<&'i str>, - features: &'i Option, - mode: Option<&'i BuildMode>, - extra: T, - ) -> Vec<&str> { - let mut args: Vec<&str> = Vec::new(); - - if nightly { - args.push("+nightly"); - } - - if let Some(cargoarg) = cargoarg.as_deref() { - args.push(cargoarg); - } - - args.push(self.command()); - - if let Some(target) = self.target() { - args.extend_from_slice(&["--target", target.triple()]) - } - - if let Some(features) = features.as_ref() { - args.extend_from_slice(&["--features", features]); - } - - if let Some(mode) = mode.map(|m| m.to_flag()).flatten() { - args.push(mode); - } - - args.extend(extra); - - args - } - - /// Turn the ExtraArguments into an interator that contains the separating dashes - /// and the rest of the arguments. - /// - /// NOTE: you _must_ chain this iterator at the _end_ of the extra arguments. - fn extra_args(args: Option<&ExtraArguments>) -> impl Iterator { - #[allow(irrefutable_let_patterns)] - let args = if let Some(ExtraArguments::Other(arguments)) = args { - // Extra arguments must be passed after "--" - ["--"] - .into_iter() - .chain(arguments.iter().map(String::as_str)) - .collect() - } else { - vec![] - }; - args.into_iter() - } - - pub fn args(&self) -> Vec<&str> { - fn p(package: &Option) -> impl Iterator { - if let Some(package) = package { - vec!["--package", &package].into_iter() - } else { - vec![].into_iter() - } - } - - match self { - // For future embedded-ci, for now the same as Qemu - CargoCommand::Run { - cargoarg, - example, - features, - mode, - // dir is exposed through `chdir` - dir: _, - // Target is added by build_args - target: _, - } => self.build_args( - true, - cargoarg, - features, - Some(mode), - ["--example", example].into_iter(), - ), - CargoCommand::Qemu { - cargoarg, - example, - features, - mode, - // dir is exposed through `chdir` - dir: _, - // Target is added by build_args - target: _, - } => self.build_args( - true, - cargoarg, - features, - Some(mode), - ["--example", example].into_iter(), - ), - CargoCommand::Build { - cargoarg, - package, - features, - mode, - // Dir is exposed through `chdir` - dir: _, - // Target is added by build_args - target: _, - } => self.build_args(true, cargoarg, features, Some(mode), p(package)), - CargoCommand::Check { - cargoarg, - package, - features, - mode, - // Dir is exposed through `chdir` - dir: _, - // Target is added by build_args - target: _, - } => self.build_args(true, cargoarg, features, Some(mode), p(package)), - CargoCommand::Clippy { - cargoarg, - package, - features, - // Target is added by build_args - target: _, - } => self.build_args(true, cargoarg, features, None, p(package)), - CargoCommand::Doc { - cargoarg, - features, - arguments, - } => { - let extra = Self::extra_args(arguments.as_ref()); - self.build_args(true, cargoarg, features, None, extra) - } - CargoCommand::Test { - package, - features, - test, - } => { - let extra = if let Some(test) = test { - vec!["--test", test] - } else { - vec![] - }; - let package = p(package); - let extra = extra.into_iter().chain(package); - self.build_args(true, &None, features, None, extra) - } - CargoCommand::Book { arguments } => { - let mut args = vec![]; - - if let Some(ExtraArguments::Other(arguments)) = arguments { - for arg in arguments { - args.extend_from_slice(&[arg.as_str()]); - } - } else { - // If no argument given, run mdbook build - // with default path to book - args.extend_from_slice(&[self.command()]); - args.extend_from_slice(&["book/en"]); - } - args - } - CargoCommand::Format { - cargoarg, - package, - check_only, - } => { - let extra = if *check_only { Some("--check") } else { None }; - let package = p(package); - self.build_args( - true, - cargoarg, - &None, - None, - extra.into_iter().chain(package), - ) - } - CargoCommand::ExampleBuild { - cargoarg, - example, - features, - mode, - // dir is exposed through `chdir` - dir: _, - // Target is added by build_args - target: _, - } => self.build_args( - true, - cargoarg, - features, - Some(mode), - ["--example", example].into_iter(), - ), - CargoCommand::ExampleCheck { - cargoarg, - example, - features, - mode, - // Target is added by build_args - target: _, - } => self.build_args( - true, - cargoarg, - features, - Some(mode), - ["--example", example].into_iter(), - ), - CargoCommand::ExampleSize { - cargoarg, - example, - features, - mode, - arguments, - // Target is added by build_args - target: _, - // dir is exposed through `chdir` - dir: _, - } => { - let extra = ["--example", example] - .into_iter() - .chain(Self::extra_args(arguments.as_ref())); - - self.build_args(true, cargoarg, features, Some(mode), extra) - } - } - } - - /// TODO: integrate this into `args` once `-C` becomes stable. - fn chdir(&self) -> Option<&PathBuf> { - match self { - CargoCommand::Qemu { dir, .. } - | CargoCommand::ExampleBuild { dir, .. } - | CargoCommand::ExampleSize { dir, .. } - | CargoCommand::Build { dir, .. } - | CargoCommand::Run { dir, .. } - | CargoCommand::Check { dir, .. } => dir.as_ref(), - _ => None, - } - } - - fn target(&self) -> Option<&Target> { - match self { - CargoCommand::Run { target, .. } - | CargoCommand::Qemu { target, .. } - | CargoCommand::ExampleBuild { target, .. } - | CargoCommand::ExampleCheck { target, .. } - | CargoCommand::Build { target, .. } - | CargoCommand::Check { target, .. } - | CargoCommand::Clippy { target, .. } - | CargoCommand::ExampleSize { target, .. } => target.as_ref(), - _ => None, - } - } - - pub fn print_stdout_intermediate(&self) -> bool { - match self { - Self::ExampleSize { .. } => true, - _ => false, - } - } -} - -impl BuildMode { - #[allow(clippy::wrong_self_convention)] - pub fn to_flag(&self) -> Option<&str> { - match self { - BuildMode::Release => Some("--release"), - BuildMode::Debug => None, - } - } -} - -impl fmt::Display for BuildMode { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let cmd = match self { - BuildMode::Release => "release", - BuildMode::Debug => "debug", - }; - - write!(f, "{cmd}") - } -} - -pub fn run_command(command: &CargoCommand, stderr_mode: OutputMode) -> anyhow::Result { - log::info!("👟 {command}"); - - let mut process = Command::new(command.executable()); - - process - .args(command.args()) - .stdout(Stdio::piped()) - .stderr(stderr_mode); - - if let Some(dir) = command.chdir() { - process.current_dir(dir.canonicalize()?); - } - - let result = process.output()?; - - let exit_status = result.status; - let stderr = String::from_utf8(result.stderr).unwrap_or("Not displayable".into()); - let stdout = String::from_utf8(result.stdout).unwrap_or("Not displayable".into()); - - if command.print_stdout_intermediate() && exit_status.success() { - log::info!("\n{}", stdout); - } - - if exit_status.success() { - log::info!("✅ Success.") - } else { - log::error!("❌ Command failed. Run to completion for the summary."); - } - - Ok(RunResult { - exit_status, - stdout, - stderr, - }) -} - -/// Check if `run` was successful. -/// returns Ok in case the run went as expected, -/// Err otherwise -pub fn run_successful(run: &RunResult, expected_output_file: &str) -> Result<(), TestRunError> { - let mut file_handle = - File::open(expected_output_file).map_err(|_| TestRunError::FileError { - file: expected_output_file.to_owned(), - })?; - let mut expected_output = String::new(); - file_handle - .read_to_string(&mut expected_output) - .map_err(|_| TestRunError::FileError { - file: expected_output_file.to_owned(), - })?; - - if expected_output != run.stdout { - Err(TestRunError::FileCmpError { - expected: expected_output.clone(), - got: run.stdout.clone(), - }) - } else if !run.exit_status.success() { - Err(TestRunError::CommandError(run.clone())) - } else { - Ok(()) - } -} - -pub fn handle_results(globals: &Globals, results: Vec) -> Result<(), ()> { - let errors = results.iter().filter_map(|r| { - if let FinalRunResult::Failed(c, r) = r { - Some((c, &r.stdout, &r.stderr)) - } else { - None - } - }); - - let successes = results.iter().filter_map(|r| { - if let FinalRunResult::Success(c, r) = r { - Some((c, &r.stdout, &r.stderr)) - } else { - None - } - }); - - let command_errors = results.iter().filter_map(|r| { - if let FinalRunResult::CommandError(c, e) = r { - Some((c, e)) - } else { - None - } - }); - - let log_stdout_stderr = |level: Level| { - move |(cmd, stdout, stderr): (&CargoCommand, &String, &String)| { - let cmd = cmd.as_cmd_string(); - if !stdout.is_empty() && !stderr.is_empty() { - log::log!(level, "\n{cmd}\nStdout:\n{stdout}\nStderr:\n{stderr}"); - } else if !stdout.is_empty() { - log::log!(level, "\n{cmd}\nStdout:\n{}", stdout.trim_end()); - } else if !stderr.is_empty() { - log::log!(level, "\n{cmd}\nStderr:\n{}", stderr.trim_end()); - } - } - }; - - successes.for_each(|(cmd, stdout, stderr)| { - if globals.verbose > 0 { - info!("✅ Success: {cmd}\n {}", cmd.as_cmd_string()); - } else { - info!("✅ Success: {cmd}"); - } - - log_stdout_stderr(Level::Debug)((cmd, stdout, stderr)); - }); - - errors.clone().for_each(|(cmd, stdout, stderr)| { - error!("❌ Failed: {cmd}\n {}", cmd.as_cmd_string()); - log_stdout_stderr(Level::Error)((cmd, stdout, stderr)); - }); - - command_errors - .clone() - .for_each(|(cmd, error)| error!("❌ Failed: {cmd}\n {}\n{error}", cmd.as_cmd_string())); - - let ecount = errors.count() + command_errors.count(); - if ecount != 0 { - log::error!("{ecount} commands failed."); - Err(()) - } else { - info!("🚀🚀🚀 All tasks succeeded 🚀🚀🚀"); - Ok(()) - } -} -- cgit v1.2.3