xtask: Split out cargo commands

This commit is contained in:
Henrik Tjäder 2023-03-01 00:25:05 +01:00
parent 512bab17cc
commit fae15db216
2 changed files with 274 additions and 248 deletions

267
xtask/src/cargo_commands.rs Normal file
View file

@ -0,0 +1,267 @@
use crate::{
argument_parsing::{Backends, BuildOrCheck, Package, PackageOpt, Sizearguments, TestMetadata},
command::{BuildMode, CargoCommand},
command_parser, package_feature_extractor, DEFAULT_FEATURES,
};
use log::error;
use rayon::prelude::*;
/// Cargo command to either build or check
pub fn cargo(
operation: BuildOrCheck,
cargoarg: &Option<&str>,
package: &PackageOpt,
backend: Backends,
) -> anyhow::Result<()> {
let features = package_feature_extractor(package, backend);
let command = match operation {
BuildOrCheck::Check => CargoCommand::Check {
cargoarg,
package: package.package,
target: backend.to_target(),
features,
mode: BuildMode::Release,
},
BuildOrCheck::Build => CargoCommand::Build {
cargoarg,
package: package.package,
target: backend.to_target(),
features,
mode: BuildMode::Release,
},
};
command_parser(&command, false)?;
Ok(())
}
/// Cargo command to either build or check all examples
///
/// The examples are in rtic/examples
pub fn cargo_example(
operation: BuildOrCheck,
cargoarg: &Option<&str>,
backend: Backends,
examples: &[String],
) -> anyhow::Result<()> {
examples.into_par_iter().for_each(|example| {
let features = Some(format!(
"{},{}",
DEFAULT_FEATURES,
backend.to_rtic_feature()
));
let command = match operation {
BuildOrCheck::Check => CargoCommand::ExampleCheck {
cargoarg,
example,
target: backend.to_target(),
features,
mode: BuildMode::Release,
},
BuildOrCheck::Build => CargoCommand::ExampleBuild {
cargoarg,
example,
target: backend.to_target(),
features,
mode: BuildMode::Release,
},
};
if let Err(err) = command_parser(&command, false) {
error!("{err}");
}
});
Ok(())
}
/// Run cargo clippy on selected package
pub fn cargo_clippy(
cargoarg: &Option<&str>,
package: &PackageOpt,
backend: Backends,
) -> anyhow::Result<()> {
let features = package_feature_extractor(package, backend);
command_parser(
&CargoCommand::Clippy {
cargoarg,
package: package.package,
target: backend.to_target(),
features,
},
false,
)?;
Ok(())
}
/// Run cargo fmt on selected package
pub fn cargo_format(
cargoarg: &Option<&str>,
package: &PackageOpt,
check_only: bool,
) -> anyhow::Result<()> {
command_parser(
&CargoCommand::Format {
cargoarg,
package: package.package,
check_only,
},
false,
)?;
Ok(())
}
/// Run cargo doc
pub fn cargo_doc(cargoarg: &Option<&str>, backend: Backends) -> anyhow::Result<()> {
let features = Some(format!(
"{},{}",
DEFAULT_FEATURES,
backend.to_rtic_feature()
));
command_parser(&CargoCommand::Doc { cargoarg, features }, false)?;
Ok(())
}
/// Run cargo test on the selcted package or all packages
///
/// If no package is specified, loop through all packages
pub fn cargo_test(package: &PackageOpt, backend: Backends) -> anyhow::Result<()> {
if let Some(package) = package.package {
let cmd = match package {
Package::Rtic => TestMetadata::match_package(package, backend),
Package::RticArbiter => TestMetadata::match_package(package, backend),
Package::RticChannel => TestMetadata::match_package(package, backend),
Package::RticCommon => TestMetadata::match_package(package, backend),
Package::RticMacros => TestMetadata::match_package(package, backend),
Package::RticMonotonics => TestMetadata::match_package(package, backend),
Package::RticTime => TestMetadata::match_package(package, backend),
};
command_parser(&cmd, false)?;
} else {
// Iterate over all workspace packages
for package in [
Package::Rtic,
Package::RticArbiter,
Package::RticChannel,
Package::RticCommon,
Package::RticMacros,
Package::RticMonotonics,
Package::RticTime,
] {
let mut error_messages = vec![];
let cmd = &TestMetadata::match_package(package, backend);
if let Err(err) = command_parser(&cmd, false) {
error_messages.push(err);
}
if !error_messages.is_empty() {
for err in error_messages {
error!("{err}");
}
}
}
}
Ok(())
}
/// Use mdbook to build the book
pub fn cargo_book(cargoarg: &Option<&str>) -> anyhow::Result<()> {
command_parser(
&CargoCommand::Book {
mdbookarg: cargoarg,
},
false,
)?;
Ok(())
}
/// Run examples
///
/// Supports updating the expected output via the overwrite argument
pub fn run_test(
cargoarg: &Option<&str>,
backend: Backends,
examples: &[String],
overwrite: bool,
) -> anyhow::Result<()> {
examples.into_par_iter().for_each(|example| {
let cmd = CargoCommand::ExampleBuild {
cargoarg: &Some("--quiet"),
example,
target: backend.to_target(),
features: Some(format!(
"{},{}",
DEFAULT_FEATURES,
backend.to_rtic_feature()
)),
mode: BuildMode::Release,
};
if let Err(err) = command_parser(&cmd, false) {
error!("{err}");
}
let cmd = CargoCommand::Qemu {
cargoarg,
example,
target: backend.to_target(),
features: Some(format!(
"{},{}",
DEFAULT_FEATURES,
backend.to_rtic_feature()
)),
mode: BuildMode::Release,
};
if let Err(err) = command_parser(&cmd, overwrite) {
error!("{err}");
}
});
Ok(())
}
/// Check the binary sizes of examples
pub fn build_and_check_size(
cargoarg: &Option<&str>,
backend: Backends,
examples: &[String],
size_arguments: &Option<Sizearguments>,
) -> anyhow::Result<()> {
examples.into_par_iter().for_each(|example| {
// Make sure the requested example(s) are built
let cmd = CargoCommand::ExampleBuild {
cargoarg: &Some("--quiet"),
example,
target: backend.to_target(),
features: Some(format!(
"{},{}",
DEFAULT_FEATURES,
backend.to_rtic_feature()
)),
mode: BuildMode::Release,
};
if let Err(err) = command_parser(&cmd, false) {
error!("{err}");
}
let cmd = CargoCommand::ExampleSize {
cargoarg,
example,
target: backend.to_target(),
features: Some(format!(
"{},{}",
DEFAULT_FEATURES,
backend.to_rtic_feature()
)),
mode: BuildMode::Release,
arguments: size_arguments.clone(),
};
if let Err(err) = command_parser(&cmd, false) {
error!("{err}");
}
});
Ok(())
}

View file

@ -1,13 +1,13 @@
mod argument_parsing;
mod build;
mod cargo_commands;
mod command;
use anyhow::bail;
use argument_parsing::{Package, Sizearguments, TestMetadata};
use argument_parsing::{Package, Sizearguments};
use clap::Parser;
use core::fmt;
use diffy::{create_patch, PatchFormatter};
use rayon::prelude::*;
use std::{
error::Error,
ffi::OsString,
@ -25,7 +25,11 @@ use log::{debug, error, info, log_enabled, trace, Level};
use crate::{
argument_parsing::{Backends, BuildOrCheck, Cli, Commands, PackageOpt},
build::init_build_dir,
command::{run_command, run_successful, BuildMode, CargoCommand},
cargo_commands::{
build_and_check_size, cargo, cargo_book, cargo_clippy, cargo_doc, cargo_example,
cargo_format, cargo_test, run_test,
},
command::{run_command, run_successful, CargoCommand},
};
// x86_64-unknown-linux-gnu
@ -260,251 +264,6 @@ fn main() -> anyhow::Result<()> {
Ok(())
}
fn cargo(
operation: BuildOrCheck,
cargoarg: &Option<&str>,
package: &PackageOpt,
backend: Backends,
) -> anyhow::Result<()> {
let features = package_feature_extractor(package, backend);
let command = match operation {
BuildOrCheck::Check => CargoCommand::Check {
cargoarg,
package: package.package,
target: backend.to_target(),
features,
mode: BuildMode::Release,
},
BuildOrCheck::Build => CargoCommand::Build {
cargoarg,
package: package.package,
target: backend.to_target(),
features,
mode: BuildMode::Release,
},
};
command_parser(&command, false)?;
Ok(())
}
fn cargo_example(
operation: BuildOrCheck,
cargoarg: &Option<&str>,
backend: Backends,
examples: &[String],
) -> anyhow::Result<()> {
examples.into_par_iter().for_each(|example| {
let features = Some(format!(
"{},{}",
DEFAULT_FEATURES,
backend.to_rtic_feature()
));
let command = match operation {
BuildOrCheck::Check => CargoCommand::ExampleCheck {
cargoarg,
example,
target: backend.to_target(),
features,
mode: BuildMode::Release,
},
BuildOrCheck::Build => CargoCommand::ExampleBuild {
cargoarg,
example,
target: backend.to_target(),
features,
mode: BuildMode::Release,
},
};
if let Err(err) = command_parser(&command, false) {
error!("{err}");
}
});
Ok(())
}
fn cargo_clippy(
cargoarg: &Option<&str>,
package: &PackageOpt,
backend: Backends,
) -> anyhow::Result<()> {
let features = package_feature_extractor(package, backend);
command_parser(
&CargoCommand::Clippy {
cargoarg,
package: package.package,
target: backend.to_target(),
features,
},
false,
)?;
Ok(())
}
fn cargo_format(
cargoarg: &Option<&str>,
package: &PackageOpt,
check_only: bool,
) -> anyhow::Result<()> {
command_parser(
&CargoCommand::Format {
cargoarg,
package: package.package,
check_only,
},
false,
)?;
Ok(())
}
fn cargo_doc(cargoarg: &Option<&str>, backend: Backends) -> anyhow::Result<()> {
let features = Some(format!(
"{},{}",
DEFAULT_FEATURES,
backend.to_rtic_feature()
));
command_parser(&CargoCommand::Doc { cargoarg, features }, false)?;
Ok(())
}
fn cargo_test(package: &PackageOpt, backend: Backends) -> anyhow::Result<()> {
if let Some(package) = package.package {
let cmd = match package {
Package::Rtic => TestMetadata::match_package(package, backend),
Package::RticArbiter => TestMetadata::match_package(package, backend),
Package::RticChannel => TestMetadata::match_package(package, backend),
Package::RticCommon => TestMetadata::match_package(package, backend),
Package::RticMacros => TestMetadata::match_package(package, backend),
Package::RticMonotonics => TestMetadata::match_package(package, backend),
Package::RticTime => TestMetadata::match_package(package, backend),
};
command_parser(&cmd, false)?;
} else {
// Iterate over all workspace packages
for package in [
Package::Rtic,
Package::RticArbiter,
Package::RticChannel,
Package::RticCommon,
Package::RticMacros,
Package::RticMonotonics,
Package::RticTime,
] {
let mut error_messages = vec![];
let cmd = &TestMetadata::match_package(package, backend);
if let Err(err) = command_parser(&cmd, false) {
error_messages.push(err);
}
if !error_messages.is_empty() {
for err in error_messages {
error!("{err}");
}
}
}
}
Ok(())
}
fn cargo_book(cargoarg: &Option<&str>) -> anyhow::Result<()> {
command_parser(
&CargoCommand::Book {
mdbookarg: cargoarg,
},
false,
)?;
Ok(())
}
fn run_test(
cargoarg: &Option<&str>,
backend: Backends,
examples: &[String],
overwrite: bool,
) -> anyhow::Result<()> {
examples.into_par_iter().for_each(|example| {
let cmd = CargoCommand::ExampleBuild {
cargoarg: &Some("--quiet"),
example,
target: backend.to_target(),
features: Some(format!(
"{},{}",
DEFAULT_FEATURES,
backend.to_rtic_feature()
)),
mode: BuildMode::Release,
};
if let Err(err) = command_parser(&cmd, false) {
error!("{err}");
}
let cmd = CargoCommand::Qemu {
cargoarg,
example,
target: backend.to_target(),
features: Some(format!(
"{},{}",
DEFAULT_FEATURES,
backend.to_rtic_feature()
)),
mode: BuildMode::Release,
};
if let Err(err) = command_parser(&cmd, overwrite) {
error!("{err}");
}
});
Ok(())
}
fn build_and_check_size(
cargoarg: &Option<&str>,
backend: Backends,
examples: &[String],
size_arguments: &Option<Sizearguments>,
) -> anyhow::Result<()> {
examples.into_par_iter().for_each(|example| {
// Make sure the requested example(s) are built
let cmd = CargoCommand::ExampleBuild {
cargoarg: &Some("--quiet"),
example,
target: backend.to_target(),
features: Some(format!(
"{},{}",
DEFAULT_FEATURES,
backend.to_rtic_feature()
)),
mode: BuildMode::Release,
};
if let Err(err) = command_parser(&cmd, false) {
error!("{err}");
}
let cmd = CargoCommand::ExampleSize {
cargoarg,
example,
target: backend.to_target(),
features: Some(format!(
"{},{}",
DEFAULT_FEATURES,
backend.to_rtic_feature()
)),
mode: BuildMode::Release,
arguments: size_arguments.clone(),
};
if let Err(err) = command_parser(&cmd, false) {
error!("{err}");
}
});
Ok(())
}
/// Get the features needed given the selected package
///
/// Without package specified the features for RTIC are required