aboutsummaryrefslogtreecommitdiff
path: root/xtask/src/command.rs
diff options
context:
space:
mode:
Diffstat (limited to 'xtask/src/command.rs')
-rw-r--r--xtask/src/command.rs404
1 files changed, 353 insertions, 51 deletions
diff --git a/xtask/src/command.rs b/xtask/src/command.rs
index 100888c..6e91a52 100644
--- a/xtask/src/command.rs
+++ b/xtask/src/command.rs
@@ -1,4 +1,4 @@
-use crate::{RunResult, TestRunError};
+use crate::{debug, ExtraArguments, Package, RunResult, TestRunError};
use core::fmt;
use os_pipe::pipe;
use std::{fs::File, io::Read, process::Command};
@@ -12,64 +12,364 @@ pub enum BuildMode {
#[derive(Debug)]
pub enum CargoCommand<'a> {
+ // For future embedded-ci
+ #[allow(dead_code)]
Run {
+ cargoarg: &'a Option<&'a str>,
example: &'a str,
target: &'a str,
- features: Option<&'a str>,
+ features: Option<String>,
mode: BuildMode,
},
- BuildAll {
+ Qemu {
+ cargoarg: &'a Option<&'a str>,
+ example: &'a str,
+ target: &'a str,
+ features: Option<String>,
+ mode: BuildMode,
+ },
+ ExampleBuild {
+ cargoarg: &'a Option<&'a str>,
+ example: &'a str,
target: &'a str,
- features: Option<&'a str>,
+ features: Option<String>,
mode: BuildMode,
},
- // Size {
- // example_paths: Vec<&'a Path>,
- // },
- // Clean,
+ ExampleCheck {
+ cargoarg: &'a Option<&'a str>,
+ example: &'a str,
+ target: &'a str,
+ features: Option<String>,
+ mode: BuildMode,
+ },
+ Build {
+ cargoarg: &'a Option<&'a str>,
+ package: Option<Package>,
+ target: &'a str,
+ features: Option<String>,
+ mode: BuildMode,
+ },
+ Check {
+ cargoarg: &'a Option<&'a str>,
+ package: Option<Package>,
+ target: &'a str,
+ features: Option<String>,
+ mode: BuildMode,
+ },
+ Clippy {
+ cargoarg: &'a Option<&'a str>,
+ package: Option<Package>,
+ target: &'a str,
+ features: Option<String>,
+ },
+ Format {
+ cargoarg: &'a Option<&'a str>,
+ package: Option<Package>,
+ check_only: bool,
+ },
+ Doc {
+ cargoarg: &'a Option<&'a str>,
+ features: Option<String>,
+ arguments: Option<ExtraArguments>,
+ },
+ Test {
+ package: Option<Package>,
+ features: Option<String>,
+ test: Option<String>,
+ },
+ Book {
+ arguments: Option<ExtraArguments>,
+ },
+ ExampleSize {
+ cargoarg: &'a Option<&'a str>,
+ example: &'a str,
+ target: &'a str,
+ features: Option<String>,
+ mode: BuildMode,
+ arguments: Option<ExtraArguments>,
+ },
}
impl<'a> CargoCommand<'a> {
- fn name(&self) -> &str {
+ fn command(&self) -> &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) -> &str {
match self {
- CargoCommand::Run { .. } => "run",
- // CargoCommand::Size { example_paths: _ } => "rust-size",
- CargoCommand::BuildAll { .. } => "build",
+ 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",
}
}
pub fn args(&self) -> Vec<&str> {
match self {
+ // For future embedded-ci, for now the same as Qemu
CargoCommand::Run {
+ cargoarg,
example,
target,
features,
mode,
} => {
- let mut args = vec![
- self.name(),
- "--example",
- example,
- "--target",
- target,
- "--features",
- "test-critical-section",
- ];
+ 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]);
- if let Some(feature_name) = features {
- args.extend_from_slice(&["--features", feature_name]);
+ if let Some(feature) = features {
+ args.extend_from_slice(&["--features", feature]);
+ }
+ if let Some(flag) = mode.to_flag() {
+ args.push(flag);
+ }
+ args
+ }
+ CargoCommand::Qemu {
+ 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]);
+
+ if let Some(feature) = features {
+ args.extend_from_slice(&["--features", feature]);
}
if let Some(flag) = mode.to_flag() {
args.push(flag);
}
args
}
- CargoCommand::BuildAll {
+ CargoCommand::Build {
+ cargoarg,
+ package,
target,
features,
mode,
} => {
- let mut args = vec![self.name(), "--examples", "--target", target];
+ let mut args = vec!["+nightly"];
+ if let Some(cargoarg) = cargoarg {
+ args.extend_from_slice(&[cargoarg]);
+ }
+
+ args.extend_from_slice(&[self.command(), "--target", target]);
+
+ if let Some(package) = package {
+ args.extend_from_slice(&["--package", package.name()]);
+ }
+
+ if let Some(feature) = features {
+ args.extend_from_slice(&["--features", feature]);
+ }
+ if let Some(flag) = mode.to_flag() {
+ args.push(flag);
+ }
+ args
+ }
+ 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.name()]);
+ }
+
+ if let Some(feature) = features {
+ args.extend_from_slice(&["--features", feature]);
+ }
+ if let Some(flag) = mode.to_flag() {
+ args.push(flag);
+ }
+ args
+ }
+ 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.name()]);
+ }
+
+ if let Some(feature) = features {
+ args.extend_from_slice(&["--features", feature]);
+ }
+ args
+ }
+ 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
+ }
+ 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.name()]);
+ }
+
+ if let Some(feature) = features {
+ args.extend_from_slice(&["--features", feature]);
+ }
+ if let Some(test) = test {
+ args.extend_from_slice(&["--test", test]);
+ }
+ args
+ }
+ 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 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.name()]);
+ }
+ if *check_only {
+ args.extend_from_slice(&["--check"]);
+ }
+
+ args
+ }
+ CargoCommand::ExampleBuild {
+ 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]);
+
+ if let Some(feature) = features {
+ args.extend_from_slice(&["--features", feature]);
+ }
+ if let Some(flag) = mode.to_flag() {
+ args.push(flag);
+ }
+ args
+ }
+ 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]);
+
+ if let Some(feature) = features {
+ args.extend_from_slice(&["--features", feature]);
+ }
+ if let Some(flag) = mode.to_flag() {
+ args.push(flag);
+ }
+ args
+ }
+ CargoCommand::ExampleSize {
+ cargoarg,
+ example,
+ target,
+ features,
+ mode,
+ arguments,
+ } => {
+ 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]);
if let Some(feature_name) = features {
args.extend_from_slice(&["--features", feature_name]);
@@ -77,25 +377,21 @@ impl<'a> CargoCommand<'a> {
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::Size { example_paths } => {
- // example_paths.iter().map(|p| p.to_str().unwrap()).collect()
- // }
- }
- }
-
- pub fn command(&self) -> &str {
- match self {
- // we need to cheat a little here:
- // `cargo size` can't be ran on multiple files, so we're using `rust-size` instead –
- // which isn't a command that starts wizh `cargo`. So we're sneakily swapping them out :)
- // CargoCommand::Size { .. } => "rust-size",
- _ => "cargo",
+ }
}
}
}
impl BuildMode {
+ #[allow(clippy::wrong_self_convention)]
pub fn to_flag(&self) -> Option<&str> {
match self {
BuildMode::Release => Some("--release"),
@@ -111,49 +407,55 @@ impl fmt::Display for BuildMode {
BuildMode::Debug => "debug",
};
- write!(f, "{}", cmd)
+ write!(f, "{cmd}")
}
}
pub fn run_command(command: &CargoCommand) -> anyhow::Result<RunResult> {
let (mut reader, writer) = pipe()?;
- println!("👟 {} {}", command.command(), command.args().join(" "));
+ let (mut error_reader, error_writer) = pipe()?;
+ debug!("👟 {} {}", command.executable(), command.args().join(" "));
- let mut handle = Command::new(command.command())
+ let mut handle = Command::new(command.executable())
.args(command.args())
.stdout(writer)
+ .stderr(error_writer)
.spawn()?;
// retrieve output and clean up
- let mut output = String::new();
- reader.read_to_string(&mut output)?;
+ let mut stdout = String::new();
+ reader.read_to_string(&mut stdout)?;
let exit_status = handle.wait()?;
+ let mut stderr = String::new();
+ error_reader.read_to_string(&mut stderr)?;
+
Ok(RunResult {
exit_status,
- output,
+ stdout,
+ stderr,
})
}
-/// Check if `run` was sucessful.
+/// 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: String) -> Result<(), TestRunError> {
+pub fn run_successful(run: &RunResult, expected_output_file: &str) -> Result<(), TestRunError> {
let mut file_handle =
- File::open(expected_output_file.clone()).map_err(|_| TestRunError::FileError {
- file: expected_output_file.clone(),
+ 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.clone(),
+ file: expected_output_file.to_owned(),
})?;
- if expected_output != run.output {
+ if expected_output != run.stdout {
Err(TestRunError::FileCmpError {
expected: expected_output.clone(),
- got: run.output.clone(),
+ got: run.stdout.clone(),
})
} else if !run.exit_status.success() {
Err(TestRunError::CommandError(run.clone()))