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/cargo_command.rs | 801 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 801 insertions(+) create mode 100644 xtask/src/cargo_command.rs (limited to 'xtask/src/cargo_command.rs') diff --git a/xtask/src/cargo_command.rs b/xtask/src/cargo_command.rs new file mode 100644 index 0000000..cd38566 --- /dev/null +++ b/xtask/src/cargo_command.rs @@ -0,0 +1,801 @@ +use log::{error, info, Level}; + +use crate::{ + argument_parsing::Globals, xtasks::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 From c6b43800d2a368d7948639899b8dca50cc97712f Mon Sep 17 00:00:00 2001 From: datdenkikniet Date: Sun, 16 Apr 2023 11:05:41 +0200 Subject: Move all run-related stuff into `run` --- xtask/src/cargo_command.rs | 162 +-------------------------------------------- 1 file changed, 3 insertions(+), 159 deletions(-) (limited to 'xtask/src/cargo_command.rs') diff --git a/xtask/src/cargo_command.rs b/xtask/src/cargo_command.rs index cd38566..f399b87 100644 --- a/xtask/src/cargo_command.rs +++ b/xtask/src/cargo_command.rs @@ -1,16 +1,6 @@ -use log::{error, info, Level}; - -use crate::{ - argument_parsing::Globals, xtasks::FinalRunResult, ExtraArguments, RunResult, Target, - TestRunError, -}; +use crate::{ExtraArguments, Target}; use core::fmt; -use std::{ - fs::File, - io::Read, - path::PathBuf, - process::{Command, Stdio}, -}; +use std::path::PathBuf; #[allow(dead_code)] #[derive(Debug, Clone, Copy, PartialEq)] @@ -19,21 +9,6 @@ pub enum BuildMode { 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 @@ -614,7 +589,7 @@ impl<'a> CargoCommand<'a> { } /// TODO: integrate this into `args` once `-C` becomes stable. - fn chdir(&self) -> Option<&PathBuf> { + pub fn chdir(&self) -> Option<&PathBuf> { match self { CargoCommand::Qemu { dir, .. } | CargoCommand::ExampleBuild { dir, .. } @@ -668,134 +643,3 @@ impl fmt::Display for BuildMode { 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 From 4d3361658b2487154d8140b06b140e72c0227441 Mon Sep 17 00:00:00 2001 From: datdenkikniet Date: Sun, 16 Apr 2023 11:51:28 +0200 Subject: Unconditionally deny warnings for clippy --- xtask/src/cargo_command.rs | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) (limited to 'xtask/src/cargo_command.rs') diff --git a/xtask/src/cargo_command.rs b/xtask/src/cargo_command.rs index f399b87..9cf4f65 100644 --- a/xtask/src/cargo_command.rs +++ b/xtask/src/cargo_command.rs @@ -65,6 +65,7 @@ pub enum CargoCommand<'a> { package: Option, target: Option>, features: Option, + deny_warnings: bool, }, Format { cargoarg: &'a Option<&'a str>, @@ -244,10 +245,16 @@ impl core::fmt::Display for CargoCommand<'_> { package, target, features, + deny_warnings, } => { let details = details(target, None, features, cargoarg, None); let package = p(package); - write!(f, "Clippy {package} {details}") + let deny_warns = if *deny_warnings { + format!(" (deny warnings)") + } else { + format!("") + }; + write!(f, "Clippy{deny_warns} {package} {details}") } CargoCommand::Format { cargoarg, @@ -483,9 +490,19 @@ impl<'a> CargoCommand<'a> { cargoarg, package, features, + deny_warnings, // Target is added by build_args target: _, - } => self.build_args(true, cargoarg, features, None, p(package)), + } => { + let package = p(package); + let extra = if *deny_warnings { + vec!["--", "-D", "warnings"].into_iter() + } else { + vec![].into_iter() + }; + + self.build_args(true, cargoarg, features, None, package.chain(extra)) + } CargoCommand::Doc { cargoarg, features, -- cgit v1.2.3 From 2db26c1015f0a32fe43e71d60f5fd75dbb25f40c Mon Sep 17 00:00:00 2001 From: datdenkikniet Date: Sun, 16 Apr 2023 12:51:11 +0200 Subject: Deny on warnings in xtasks --- xtask/src/cargo_command.rs | 110 ++++++++++++++++++++++++++++++++++----------- 1 file changed, 83 insertions(+), 27 deletions(-) (limited to 'xtask/src/cargo_command.rs') diff --git a/xtask/src/cargo_command.rs b/xtask/src/cargo_command.rs index 9cf4f65..09487cb 100644 --- a/xtask/src/cargo_command.rs +++ b/xtask/src/cargo_command.rs @@ -28,6 +28,7 @@ pub enum CargoCommand<'a> { features: Option, mode: BuildMode, dir: Option, + deny_warnings: bool, }, ExampleBuild { cargoarg: &'a Option<&'a str>, @@ -36,6 +37,7 @@ pub enum CargoCommand<'a> { features: Option, mode: BuildMode, dir: Option, + deny_warnings: bool, }, ExampleCheck { cargoarg: &'a Option<&'a str>, @@ -43,6 +45,7 @@ pub enum CargoCommand<'a> { target: Option>, features: Option, mode: BuildMode, + deny_warnings: bool, }, Build { cargoarg: &'a Option<&'a str>, @@ -51,6 +54,7 @@ pub enum CargoCommand<'a> { features: Option, mode: BuildMode, dir: Option, + deny_warnings: bool, }, Check { cargoarg: &'a Option<&'a str>, @@ -59,6 +63,7 @@ pub enum CargoCommand<'a> { features: Option, mode: BuildMode, dir: Option, + deny_warnings: bool, }, Clippy { cargoarg: &'a Option<&'a str>, @@ -81,6 +86,7 @@ pub enum CargoCommand<'a> { package: Option, features: Option, test: Option, + deny_warnings: bool, }, Book { arguments: Option, @@ -123,6 +129,7 @@ impl core::fmt::Display for CargoCommand<'_> { } fn details( + deny_warnings: bool, target: &Option, mode: Option<&BuildMode>, features: &Option, @@ -150,14 +157,20 @@ impl core::fmt::Display for CargoCommand<'_> { format!("debug") }; + let deny_warnings = if deny_warnings { + format!("deny warnings, ") + } else { + format!("") + }; + if cargoarg.is_some() && path.is_some() { - format!("({target}, {mode}, {feat}, {carg}, {in_dir})") + format!("({deny_warnings}{target}, {mode}, {feat}, {carg}, {in_dir})") } else if cargoarg.is_some() { - format!("({target}, {mode}, {feat}, {carg})") + format!("({deny_warnings}{target}, {mode}, {feat}, {carg})") } else if path.is_some() { - format!("({target}, {mode}, {feat}, {in_dir})") + format!("({deny_warnings}{target}, {mode}, {feat}, {in_dir})") } else { - format!("({target}, {mode}, {feat})") + format!("({deny_warnings}{target}, {mode}, {feat})") } } @@ -173,7 +186,7 @@ impl core::fmt::Display for CargoCommand<'_> { write!( f, "Run example {example} {}", - details(target, Some(mode), features, cargoarg, dir.as_ref()) + details(false, target, Some(mode), features, cargoarg, dir.as_ref()) ) } CargoCommand::Qemu { @@ -183,8 +196,10 @@ impl core::fmt::Display for CargoCommand<'_> { features, mode, dir, + deny_warnings, } => { - let details = details(target, Some(mode), features, cargoarg, dir.as_ref()); + let warns = *deny_warnings; + let details = details(warns, target, Some(mode), features, cargoarg, dir.as_ref()); write!(f, "Run example {example} in QEMU {details}",) } CargoCommand::ExampleBuild { @@ -194,8 +209,10 @@ impl core::fmt::Display for CargoCommand<'_> { features, mode, dir, + deny_warnings, } => { - let details = details(target, Some(mode), features, cargoarg, dir.as_ref()); + let warns = *deny_warnings; + let details = details(warns, target, Some(mode), features, cargoarg, dir.as_ref()); write!(f, "Build example {example} {details}",) } CargoCommand::ExampleCheck { @@ -204,10 +221,11 @@ impl core::fmt::Display for CargoCommand<'_> { target, features, mode, + deny_warnings, } => write!( f, "Check example {example} {}", - details(target, Some(mode), features, cargoarg, None) + details(*deny_warnings, target, Some(mode), features, cargoarg, None) ), CargoCommand::Build { cargoarg, @@ -216,12 +234,14 @@ impl core::fmt::Display for CargoCommand<'_> { features, mode, dir, + deny_warnings, } => { let package = p(package); + let warns = *deny_warnings; write!( f, "Build {package} {}", - details(target, Some(mode), features, cargoarg, dir.as_ref()) + details(warns, target, Some(mode), features, cargoarg, dir.as_ref()) ) } @@ -232,12 +252,14 @@ impl core::fmt::Display for CargoCommand<'_> { features, mode, dir, + deny_warnings, } => { let package = p(package); + let warns = *deny_warnings; write!( f, "Check {package} {}", - details(target, Some(mode), features, cargoarg, dir.as_ref()) + details(warns, target, Some(mode), features, cargoarg, dir.as_ref()) ) } CargoCommand::Clippy { @@ -247,14 +269,9 @@ impl core::fmt::Display for CargoCommand<'_> { features, deny_warnings, } => { - let details = details(target, None, features, cargoarg, None); + let details = details(*deny_warnings, target, None, features, cargoarg, None); let package = p(package); - let deny_warns = if *deny_warnings { - format!(" (deny warnings)") - } else { - format!("") - }; - write!(f, "Clippy{deny_warns} {package} {details}") + write!(f, "Clippy {package} {details}") } CargoCommand::Format { cargoarg, @@ -297,14 +314,20 @@ impl core::fmt::Display for CargoCommand<'_> { package, features, test, + deny_warnings, } => { let p = p(package); let test = test .clone() .map(|t| format!("test {t}")) .unwrap_or("all tests".into()); + let deny_warnings = if *deny_warnings { + format!("deny warnings, ") + } else { + format!("") + }; let feat = feat(features); - write!(f, "Run {test} in {p} (features: {feat})") + write!(f, "Run {test} in {p} ({deny_warnings}features: {feat})") } CargoCommand::Book { arguments: _ } => write!(f, "Build the book"), CargoCommand::ExampleSize { @@ -316,7 +339,7 @@ impl core::fmt::Display for CargoCommand<'_> { arguments: _, dir, } => { - let details = details(target, Some(mode), features, cargoarg, dir.as_ref()); + let details = details(false, target, Some(mode), features, cargoarg, dir.as_ref()); write!(f, "Compute size of example {example} {details}") } } @@ -459,6 +482,8 @@ impl<'a> CargoCommand<'a> { dir: _, // Target is added by build_args target: _, + // deny_warnings is exposed through `rustflags` + deny_warnings: _, } => self.build_args( true, cargoarg, @@ -471,10 +496,12 @@ impl<'a> CargoCommand<'a> { package, features, mode, - // Dir is exposed through `chdir` - dir: _, // Target is added by build_args target: _, + // Dir is exposed through `chdir` + dir: _, + // deny_warnings is exposed through `rustflags` + deny_warnings: _, } => self.build_args(true, cargoarg, features, Some(mode), p(package)), CargoCommand::Check { cargoarg, @@ -485,23 +512,25 @@ impl<'a> CargoCommand<'a> { dir: _, // Target is added by build_args target: _, + // deny_warnings is exposed through `rustflags` + deny_warnings: _, } => self.build_args(true, cargoarg, features, Some(mode), p(package)), CargoCommand::Clippy { cargoarg, package, features, - deny_warnings, // Target is added by build_args target: _, + deny_warnings, } => { - let package = p(package); - let extra = if *deny_warnings { - vec!["--", "-D", "warnings"].into_iter() + let deny_warnings = if *deny_warnings { + vec!["--", "-D", "warnings"] } else { - vec![].into_iter() + vec![] }; - self.build_args(true, cargoarg, features, None, package.chain(extra)) + let extra = p(package).chain(deny_warnings); + self.build_args(true, cargoarg, features, None, extra) } CargoCommand::Doc { cargoarg, @@ -515,6 +544,8 @@ impl<'a> CargoCommand<'a> { package, features, test, + // deny_warnings is exposed through `rustflags` + deny_warnings: _, } => { let extra = if let Some(test) = test { vec!["--test", test] @@ -564,6 +595,8 @@ impl<'a> CargoCommand<'a> { dir: _, // Target is added by build_args target: _, + // deny_warnings is exposed through `rustflags` + deny_warnings: _, } => self.build_args( true, cargoarg, @@ -578,6 +611,8 @@ impl<'a> CargoCommand<'a> { mode, // Target is added by build_args target: _, + // deny_warnings is exposed through `rustflags` + deny_warnings: _, } => self.build_args( true, cargoarg, @@ -632,6 +667,27 @@ impl<'a> CargoCommand<'a> { } } + pub fn rustflags(&self) -> Option<&str> { + match self { + // Clippy is a special case: it sets deny warnings + // through an argument to rustc. + CargoCommand::Clippy { .. } => None, + CargoCommand::Check { deny_warnings, .. } + | CargoCommand::ExampleCheck { deny_warnings, .. } + | CargoCommand::Build { deny_warnings, .. } + | CargoCommand::ExampleBuild { deny_warnings, .. } + | CargoCommand::Test { deny_warnings, .. } + | CargoCommand::Qemu { deny_warnings, .. } => { + if *deny_warnings { + Some("-D warnings") + } else { + None + } + } + _ => None, + } + } + pub fn print_stdout_intermediate(&self) -> bool { match self { Self::ExampleSize { .. } => true, -- cgit v1.2.3 From 85e2cd6d4b1ac801dbbce2295a6617a56f9ea5a0 Mon Sep 17 00:00:00 2001 From: datdenkikniet Date: Sun, 16 Apr 2023 13:16:28 +0200 Subject: Also always deny warnings for doc --- xtask/src/cargo_command.rs | 30 ++++++++++++++++++++---------- 1 file changed, 20 insertions(+), 10 deletions(-) (limited to 'xtask/src/cargo_command.rs') diff --git a/xtask/src/cargo_command.rs b/xtask/src/cargo_command.rs index 09487cb..ef14a38 100644 --- a/xtask/src/cargo_command.rs +++ b/xtask/src/cargo_command.rs @@ -81,6 +81,7 @@ pub enum CargoCommand<'a> { cargoarg: &'a Option<&'a str>, features: Option, arguments: Option, + deny_warnings: bool, }, Test { package: Option, @@ -297,6 +298,7 @@ impl core::fmt::Display for CargoCommand<'_> { cargoarg, features, arguments, + deny_warnings, } => { let feat = feat(features); let carg = carg(cargoarg); @@ -304,10 +306,15 @@ impl core::fmt::Display for CargoCommand<'_> { .clone() .map(|a| format!("{a}")) .unwrap_or_else(|| "no extra arguments".into()); + let deny_warnings = if *deny_warnings { + format!("deny warnings, ") + } else { + format!("") + }; if cargoarg.is_some() { - write!(f, "Document ({feat}, {carg}, {arguments})") + write!(f, "Document ({deny_warnings}{feat}, {carg}, {arguments})") } else { - write!(f, "Document ({feat}, {arguments})") + write!(f, "Document ({deny_warnings}{feat}, {arguments})") } } CargoCommand::Test { @@ -482,7 +489,7 @@ impl<'a> CargoCommand<'a> { dir: _, // Target is added by build_args target: _, - // deny_warnings is exposed through `rustflags` + // deny_warnings is exposed through `extra_env` deny_warnings: _, } => self.build_args( true, @@ -500,7 +507,7 @@ impl<'a> CargoCommand<'a> { target: _, // Dir is exposed through `chdir` dir: _, - // deny_warnings is exposed through `rustflags` + // deny_warnings is exposed through `extra_env` deny_warnings: _, } => self.build_args(true, cargoarg, features, Some(mode), p(package)), CargoCommand::Check { @@ -512,7 +519,7 @@ impl<'a> CargoCommand<'a> { dir: _, // Target is added by build_args target: _, - // deny_warnings is exposed through `rustflags` + // deny_warnings is exposed through `extra_env` deny_warnings: _, } => self.build_args(true, cargoarg, features, Some(mode), p(package)), CargoCommand::Clippy { @@ -536,6 +543,8 @@ impl<'a> CargoCommand<'a> { cargoarg, features, arguments, + // deny_warnings is exposed through `extra_env` + deny_warnings: _, } => { let extra = Self::extra_args(arguments.as_ref()); self.build_args(true, cargoarg, features, None, extra) @@ -544,7 +553,7 @@ impl<'a> CargoCommand<'a> { package, features, test, - // deny_warnings is exposed through `rustflags` + // deny_warnings is exposed through `extra_env` deny_warnings: _, } => { let extra = if let Some(test) = test { @@ -595,7 +604,7 @@ impl<'a> CargoCommand<'a> { dir: _, // Target is added by build_args target: _, - // deny_warnings is exposed through `rustflags` + // deny_warnings is exposed through `extra_env` deny_warnings: _, } => self.build_args( true, @@ -611,7 +620,7 @@ impl<'a> CargoCommand<'a> { mode, // Target is added by build_args target: _, - // deny_warnings is exposed through `rustflags` + // deny_warnings is exposed through `extra_env` deny_warnings: _, } => self.build_args( true, @@ -667,11 +676,12 @@ impl<'a> CargoCommand<'a> { } } - pub fn rustflags(&self) -> Option<&str> { + pub fn extra_env(&self) -> Option<(&str, &str)> { match self { // Clippy is a special case: it sets deny warnings // through an argument to rustc. CargoCommand::Clippy { .. } => None, + CargoCommand::Doc { .. } => Some(("RUSTDOCFLAGS", "-D warnings")), CargoCommand::Check { deny_warnings, .. } | CargoCommand::ExampleCheck { deny_warnings, .. } | CargoCommand::Build { deny_warnings, .. } @@ -679,7 +689,7 @@ impl<'a> CargoCommand<'a> { | CargoCommand::Test { deny_warnings, .. } | CargoCommand::Qemu { deny_warnings, .. } => { if *deny_warnings { - Some("-D warnings") + Some(("RUSTFLAGS", "-D warnings")) } else { None } -- cgit v1.2.3 From bc92e43b113dae2a34db6b10812d84227ac5a6d6 Mon Sep 17 00:00:00 2001 From: datdenkikniet Date: Sun, 16 Apr 2023 13:22:10 +0200 Subject: Rename + better printout --- xtask/src/cargo_command.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'xtask/src/cargo_command.rs') diff --git a/xtask/src/cargo_command.rs b/xtask/src/cargo_command.rs index ef14a38..b0102ce 100644 --- a/xtask/src/cargo_command.rs +++ b/xtask/src/cargo_command.rs @@ -149,7 +149,7 @@ impl core::fmt::Display for CargoCommand<'_> { let target = if let Some(target) = target { format!("{target}") } else { - format!("") + format!("") }; let mode = if let Some(mode) = mode { -- cgit v1.2.3 From 319c2263f3cebd5d990ba5fee277ec9cf1b1d2f9 Mon Sep 17 00:00:00 2001 From: datdenkikniet Date: Sun, 16 Apr 2023 13:27:46 +0200 Subject: Also print extra env variables as cmd_str --- xtask/src/cargo_command.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'xtask/src/cargo_command.rs') diff --git a/xtask/src/cargo_command.rs b/xtask/src/cargo_command.rs index b0102ce..401bab4 100644 --- a/xtask/src/cargo_command.rs +++ b/xtask/src/cargo_command.rs @@ -355,6 +355,12 @@ impl core::fmt::Display for CargoCommand<'_> { impl<'a> CargoCommand<'a> { pub fn as_cmd_string(&self) -> String { + let env = if let Some((key, value)) = self.extra_env() { + format!("{key}=\"{value}\" ") + } else { + format!("") + }; + let cd = if let Some(Some(chdir)) = self.chdir().map(|p| p.to_str()) { format!("cd {chdir} && ") } else { @@ -363,7 +369,7 @@ impl<'a> CargoCommand<'a> { let executable = self.executable(); let args = self.args().join(" "); - format!("{cd}{executable} {args}") + format!("{env}{cd}{executable} {args}") } fn command(&self) -> &'static str { -- cgit v1.2.3 From b7e4498a7136041d89541bdc7725c8c023fa5c9c Mon Sep 17 00:00:00 2001 From: datdenkikniet Date: Sun, 16 Apr 2023 14:14:49 +0200 Subject: Also allow denying for QEMU, and fix the link-arg problem caused by overriding RUSTFLAGS --- xtask/src/cargo_command.rs | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) (limited to 'xtask/src/cargo_command.rs') diff --git a/xtask/src/cargo_command.rs b/xtask/src/cargo_command.rs index 401bab4..1d5f3c5 100644 --- a/xtask/src/cargo_command.rs +++ b/xtask/src/cargo_command.rs @@ -100,6 +100,7 @@ pub enum CargoCommand<'a> { mode: BuildMode, arguments: Option, dir: Option, + deny_warnings: bool, }, } @@ -345,8 +346,10 @@ impl core::fmt::Display for CargoCommand<'_> { mode, arguments: _, dir, + deny_warnings, } => { - let details = details(false, target, Some(mode), features, cargoarg, dir.as_ref()); + let warns = *deny_warnings; + let details = details(warns, target, Some(mode), features, cargoarg, dir.as_ref()); write!(f, "Compute size of example {example} {details}") } } @@ -645,6 +648,8 @@ impl<'a> CargoCommand<'a> { target: _, // dir is exposed through `chdir` dir: _, + // deny_warnings is exposed through `extra_env` + deny_warnings: _, } => { let extra = ["--example", example] .into_iter() @@ -688,12 +693,23 @@ impl<'a> CargoCommand<'a> { // through an argument to rustc. CargoCommand::Clippy { .. } => None, CargoCommand::Doc { .. } => Some(("RUSTDOCFLAGS", "-D warnings")), + + CargoCommand::Qemu { deny_warnings, .. } + | CargoCommand::ExampleBuild { deny_warnings, .. } + | CargoCommand::ExampleSize { deny_warnings, .. } => { + if *deny_warnings { + // NOTE: this also needs the link-arg because .cargo/config.toml + // is ignored if you set the RUSTFLAGS env variable. + Some(("RUSTFLAGS", "-D warnings -C link-arg=-Tlink.x")) + } else { + None + } + } + CargoCommand::Check { deny_warnings, .. } | CargoCommand::ExampleCheck { deny_warnings, .. } | CargoCommand::Build { deny_warnings, .. } - | CargoCommand::ExampleBuild { deny_warnings, .. } - | CargoCommand::Test { deny_warnings, .. } - | CargoCommand::Qemu { deny_warnings, .. } => { + | CargoCommand::Test { deny_warnings, .. } => { if *deny_warnings { Some(("RUSTFLAGS", "-D warnings")) } else { -- cgit v1.2.3