Skip to content
Draft
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,13 @@ jobs:
target: riscv32imc-unknown-none-elf,riscv32imac-unknown-none-elf
components: clippy,rustfmt,rust-src

# Prepare cargo-batch
- name: Setup cargo-batch
run: |
if ! command -v cargo-batch &> /dev/null; then
cargo install --git https://github.com/embassy-rs/cargo-batch cargo --bin cargo-batch --locked --force
fi
Comment on lines +86 to +88
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We shouldn't do this on the normal runners, the xtask should detect if cargo-batch is present and fall back to individual cargo commands otherwise, just like we do for esp-hal. forcing cargo-batch is not the best idea (what if you simply don't want it on your PC, or what if your antivirus decides to remove it suddenly?), we have the code to somewhat smartly generate the commands.


# //Define a new environment variable called toolchain
- if: ${{ contains(fromJson('["esp32", "esp32s2", "esp32s3"]'), matrix.chip) }}
run: echo "TOOLCHAIN=+esp" >> $GITHUB_ENV
Expand Down
6 changes: 1 addition & 5 deletions template/.cargo/config.toml
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,4 @@ rustflags = [
target = "riscv32imac-unknown-none-elf"

[unstable]
#IF option("alloc")
build-std = ["alloc", "core"]
#ELSE
#+build-std = ["core"]
#ENDIF
build-std = ["alloc", "core"] # TODO: experimental for `cargo-batch`
140 changes: 99 additions & 41 deletions xtask/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use esp_generate::{
template::{GeneratorOptionCategory, GeneratorOptionItem, Template},
};
use esp_metadata::Chip;
use log::info;
use log::{info, warn};

// Unfortunate hard-coded list of non-codegen options
const IGNORED_CATEGORIES: &[&str] = &["editor", "optional"];
Expand Down Expand Up @@ -85,10 +85,12 @@ fn check(
}

if dry_run {
info!("Dry run — no commands executed.");
return Ok(());
}

const PROJECT_NAME: &str = "test";

for options in to_check {
log::info!("WITH OPTIONS: {options:?}");

Expand All @@ -102,54 +104,27 @@ fn check(
// specified generation options:
generate(workspace, &project_path, PROJECT_NAME, chip, &options)?;

let project_root = project_path.join(PROJECT_NAME);
let mut batch = CargoBatch::new(&project_root, dry_run);

// Add commands to the batch
// Ensure that the generated project builds without errors:
let output = Command::new("cargo")
.args([if build { "build" } else { "check" }])
.env_remove("RUSTUP_TOOLCHAIN")
.current_dir(project_path.join(PROJECT_NAME))
.stdout(Stdio::inherit())
.stderr(Stdio::inherit())
.output()?;
if !output.status.success() {
bail!("Failed to execute cargo check subcommand")
}
batch.check_or_build(build);

// Ensure that the generated test project builds also:
if options.iter().any(|o| o == "embedded-test") {
let output = Command::new("cargo")
.args(["test", "--no-run"])
.env_remove("RUSTUP_TOOLCHAIN")
.current_dir(project_path.join(PROJECT_NAME))
.stdout(Stdio::inherit())
.stderr(Stdio::inherit())
.output()?;
if !output.status.success() {
bail!("Failed to execute cargo test subcommand")
}
batch.test();
}

// Run clippy against the generated project to check for lint errors:
let output = Command::new("cargo")
.args(["clippy", "--no-deps", "--", "-Dwarnings"])
.env_remove("RUSTUP_TOOLCHAIN")
.current_dir(project_path.join(PROJECT_NAME))
.stdout(Stdio::inherit())
.stderr(Stdio::inherit())
.output()?;
if !output.status.success() {
bail!("Failed to execute cargo clippy subcommand")
}

batch.clippy();
// Ensure that the generated project is correctly formatted:
let output = Command::new("cargo")
.args(["fmt", "--", "--check"])
.env_remove("RUSTUP_TOOLCHAIN")
.current_dir(project_path.join(PROJECT_NAME))
.stdout(Stdio::inherit())
.stderr(Stdio::inherit())
.output()?;
if !output.status.success() {
bail!("Failed to execute cargo fmt subcommand")
batch.fmt_check();

// Run all cargo commands in sequence
if let Err(e) = batch.run() {
warn!("Build failed for options {options:?}: {e}");
return Err(e);
}
}

Expand Down Expand Up @@ -338,3 +313,86 @@ fn generate(

Ok(())
}

/// Represents a single cargo command to be executed.
pub struct CargoCommand {
pub args: Vec<String>,
pub description: String,
}

impl CargoCommand {
pub fn new(description: impl Into<String>, args: impl IntoIterator<Item = impl Into<String>>) -> Self {
Self {
description: description.into(),
args: args.into_iter().map(|a| a.into()).collect(),
}
}
}

/// Helper to batch multiple cargo commands for a project directory.
pub struct CargoBatch<'a> {
project_dir: &'a Path,
commands: Vec<CargoCommand>,
dry_run: bool,
}

impl<'a> CargoBatch<'a> {
pub fn new(project_dir: &'a Path, dry_run: bool) -> Self {
Self {
project_dir,
commands: vec![],
dry_run,
}
}

/// Add a cargo command to the batch.
pub fn add(&mut self, cmd: CargoCommand) {
self.commands.push(cmd);
}

/// Convenience: cargo check or build.
pub fn check_or_build(&mut self, build: bool) {
let verb = if build { "build" } else { "check" };
self.add(CargoCommand::new(format!("cargo {verb}"), [verb]));
}

/// Convenience: cargo test --no-run
pub fn test(&mut self) {
self.add(CargoCommand::new("cargo test", ["test", "--no-run"]));
}

/// Convenience: cargo clippy -- -D warnings
pub fn clippy(&mut self) {
self.add(CargoCommand::new("cargo clippy", ["clippy", "--no-deps", "--", "-Dwarnings"]));
}

/// Convenience: cargo fmt --check
pub fn fmt_check(&mut self) {
self.add(CargoCommand::new("cargo fmt", ["fmt", "--", "--check"]));
}

/// Executes all queued commands in sequence.
pub fn run(&self) -> Result<()> {
for cmd in &self.commands {
info!("→ Running: {}", cmd.description);

if self.dry_run {
continue;
}

let output = Command::new("cargo")
.args(&cmd.args)
.env_remove("RUSTUP_TOOLCHAIN")
.current_dir(self.project_dir)
.stdout(Stdio::inherit())
.stderr(Stdio::inherit())
.output()?;

if !output.status.success() {
bail!("Failed to execute {}", cmd.description);
}
}

Ok(())
}
}
Loading