Refactor xtask subcommands to be group by common functionality (#3457)

* Create `command` submodule, extract build-related args/actions

* Extract run-related args/actions

* Fix clippy warnings

* Update `README.md` for xtask package

* Fix order of positional arguments for examples

* Update workflows and cargo aliases

* Inline function which is only called in one place

* Update HIL workflow
This commit is contained in:
Jesse Braham 2025-05-07 11:32:51 +02:00 committed by GitHub
parent 78bd99e653
commit e5ea7e35cd
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
10 changed files with 675 additions and 648 deletions

View File

@ -2,4 +2,4 @@
xtask = "run --package xtask --" xtask = "run --package xtask --"
xdoc = "run --package xtask --features=deploy-docs,preview-docs --" xdoc = "run --package xtask --features=deploy-docs,preview-docs --"
xfmt = "xtask fmt-packages" xfmt = "xtask fmt-packages"
qa = "xtask run-example qa-test" qa = "xtask run example qa-test"

View File

@ -25,7 +25,7 @@ jobs:
setup: setup:
runs-on: ubuntu-latest runs-on: ubuntu-latest
outputs: outputs:
packages: '${{ github.event.inputs.packages }}' packages: "${{ github.event.inputs.packages }}"
steps: steps:
- run: echo "Setup complete!" - run: echo "Setup complete!"
build: build:
@ -71,7 +71,7 @@ jobs:
ref: ${{ matrix.packages.tag }} ref: ${{ matrix.packages.tag }}
- name: Build documentation - name: Build documentation
run: hal-xtask build-documentation --packages=${{ matrix.packages.name }} --base-url /projects/rust/ run: hal-xtask build documentation --packages=${{ matrix.packages.name }} --base-url /projects/rust/
# https://github.com/actions/deploy-pages/issues/303#issuecomment-1951207879 # https://github.com/actions/deploy-pages/issues/303#issuecomment-1951207879
- name: Remove problematic '.lock' files - name: Remove problematic '.lock' files
@ -98,11 +98,6 @@ jobs:
with: with:
path: "docs/" path: "docs/"
# Create an index for _all_ packages.
- name: Create index.html
run: cargo xtask build-documentation-index
- if: ${{ github.event.inputs.server == 'preview' }} - if: ${{ github.event.inputs.server == 'preview' }}
name: Deploy to preview server name: Deploy to preview server
uses: appleboy/scp-action@v0.1.7 uses: appleboy/scp-action@v0.1.7

View File

@ -9,7 +9,7 @@ on:
repository: repository:
description: "Owner and repository to test" description: "Owner and repository to test"
required: true required: true
default: 'esp-rs/esp-hal' default: "esp-rs/esp-hal"
branch: branch:
description: "Branch, tag or SHA to checkout." description: "Branch, tag or SHA to checkout."
required: true required: true
@ -118,7 +118,7 @@ jobs:
version: 1.85.0.0 version: 1.85.0.0
- name: Build tests - name: Build tests
run: cargo xtask build-tests ${{ matrix.target.soc }} run: cargo xtask build tests ${{ matrix.target.soc }}
- uses: actions/upload-artifact@v4 - uses: actions/upload-artifact@v4
with: with:
@ -176,7 +176,7 @@ jobs:
export PATH=$PATH:/home/espressif/.cargo/bin export PATH=$PATH:/home/espressif/.cargo/bin
chmod +x xtask chmod +x xtask
./xtask run-elfs ${{ matrix.target.soc }} tests-${{ matrix.target.soc }} ./xtask run elfs ${{ matrix.target.soc }} tests-${{ matrix.target.soc }}
- name: Clean up - name: Clean up
if: always() if: always()

View File

@ -8,20 +8,13 @@ Automation using [cargo-xtask](https://github.com/matklad/cargo-xtask).
Usage: xtask <COMMAND> Usage: xtask <COMMAND>
Commands: Commands:
build-documentation Build documentation for the specified chip build Build-related subcommands
build-documentation-index Build documentation index including the specified packages run Run-related subcommands
build-examples Build all examples for the specified chip
build-package Build the specified package with the given options
build-tests Build all applicable tests or the specified test for a specified chip
bump-version Bump the version of the specified package(s) bump-version Bump the version of the specified package(s)
ci Perform (parts of) the checks done in CI
fmt-packages Format all packages in the workspace with rustfmt fmt-packages Format all packages in the workspace with rustfmt
lint-packages Lint all packages in the workspace with clippy lint-packages Lint all packages in the workspace with clippy
publish Attempt to publish the specified package publish Attempt to publish the specified package
run-doc-tests Run doctests for specified chip and package
run-example Run the given example for the specified chip
run-tests Run all applicable tests or the specified test for a specified chip
run-elfs Run all ELFs in a folder
ci Perform (parts of) the checks done in CI
tag-releases Generate git tags for all new package releases tag-releases Generate git tags for all new package releases
help Print this message or the help of the given subcommand(s) help Print this message or the help of the given subcommand(s)
@ -32,14 +25,15 @@ Options:
You can get help for subcommands, too! You can get help for subcommands, too!
```text ```text
cargo xtask build-examples --help cargo xtask build examples --help
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.21s Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.11s
Running `target\debug\xtask.exe build-examples --help` Running `[...]/target/debug/xtask build examples --help`
Build all examples for the specified chip Build all examples for the specified chip
Usage: xtask.exe build-examples [OPTIONS] <PACKAGE> <CHIP> [EXAMPLE] Usage: xtask build examples [OPTIONS] <CHIP> <PACKAGE>
... [...]
``` ```
## Test/example metadata use ## Test/example metadata use

199
xtask/src/commands/build.rs Normal file
View File

@ -0,0 +1,199 @@
use std::path::Path;
use anyhow::{Result, bail};
use clap::{Args, Subcommand};
use esp_metadata::Chip;
use strum::IntoEnumIterator as _;
use super::{ExamplesArgs, TestsArgs};
use crate::{
Package,
cargo::{self, CargoAction, CargoArgsBuilder},
firmware::Metadata,
};
// ----------------------------------------------------------------------------
// Subcommands
#[derive(Debug, Subcommand)]
pub enum Build {
/// Build documentation for the specified chip.
Documentation(BuildDocumentationArgs),
/// Build all examples for the specified chip.
Examples(ExamplesArgs),
/// Build the specified package with the given options.
Package(BuildPackageArgs),
/// Build all applicable tests or the specified test for a specified chip.
Tests(TestsArgs),
}
// ----------------------------------------------------------------------------
// Subcommand Arguments
#[derive(Debug, Default, Args)]
pub struct BuildDocumentationArgs {
/// Package(s) to document.
#[arg(long, value_enum, value_delimiter = ',', default_values_t = Package::iter())]
pub packages: Vec<Package>,
/// Chip(s) to build documentation for.
#[arg(long, value_enum, value_delimiter = ',', default_values_t = Chip::iter())]
pub chips: Vec<Chip>,
/// Base URL of the deployed documentation.
#[arg(long)]
pub base_url: Option<String>,
#[cfg(feature = "preview-docs")]
#[arg(long)]
pub serve: bool,
}
#[derive(Debug, Args)]
pub struct BuildPackageArgs {
/// Package to build.
#[arg(value_enum)]
pub package: Package,
/// Target to build for.
#[arg(long)]
pub target: Option<String>,
/// Features to build with.
#[arg(long, value_delimiter = ',')]
pub features: Vec<String>,
/// Toolchain to build with.
#[arg(long)]
pub toolchain: Option<String>,
/// Don't enabled the default features.
#[arg(long)]
pub no_default_features: bool,
}
// ----------------------------------------------------------------------------
// Subcommand Actions
pub fn build_documentation(workspace: &Path, mut args: BuildDocumentationArgs) -> Result<()> {
crate::documentation::build_documentation(
workspace,
&mut args.packages,
&mut args.chips,
args.base_url,
)?;
crate::documentation::build_documentation_index(workspace, &mut args.packages)?;
#[cfg(feature = "preview-docs")]
if args.serve {
use std::{
thread::{sleep, spawn},
time::Duration,
};
use rocket::fs::{FileServer, Options};
spawn(|| {
sleep(Duration::from_millis(1000));
opener::open_browser("http://127.0.0.1:8000/").ok();
});
rocket::async_main(
{
rocket::build().mount(
"/",
FileServer::new(
"docs",
Options::Index | Options::IndexFile | Options::DotFiles,
),
)
}
.launch(),
)?;
}
Ok(())
}
pub fn build_examples(
args: ExamplesArgs,
examples: Vec<Metadata>,
package_path: &Path,
out_path: &Path,
) -> Result<()> {
// Determine the appropriate build target for the given package and chip:
let target = args.package.target_triple(&args.chip)?;
if examples.iter().any(|ex| ex.matches(&args.example)) {
// Attempt to build only the specified example:
for example in examples.iter().filter(|ex| ex.matches(&args.example)) {
crate::execute_app(
package_path,
args.chip,
target,
example,
CargoAction::Build(out_path.to_path_buf()),
1,
args.debug,
)?;
}
Ok(())
} else if args.example.is_some() {
// An invalid argument was provided:
bail!("Example not found or unsupported for the given chip")
} else {
// Attempt to build each supported example, with all required features enabled:
examples.iter().try_for_each(|example| {
crate::execute_app(
package_path,
args.chip,
target,
example,
CargoAction::Build(out_path.to_path_buf()),
1,
args.debug,
)
})
}
}
pub fn build_package(workspace: &Path, args: BuildPackageArgs) -> Result<()> {
// Absolute path of the package's root:
let package_path = crate::windows_safe_path(&workspace.join(args.package.to_string()));
// Build the package using the provided features and/or target, if any:
log::info!("Building package '{}'", package_path.display());
if !args.features.is_empty() {
log::info!(" Features: {}", args.features.join(","));
}
if let Some(ref target) = args.target {
log::info!(" Target: {}", target);
}
let mut builder = CargoArgsBuilder::default()
.subcommand("build")
.arg("--release");
if let Some(toolchain) = args.toolchain {
builder = builder.toolchain(toolchain);
}
if let Some(target) = args.target {
// If targeting an Xtensa device, we must use the '+esp' toolchain modifier:
if target.starts_with("xtensa") {
builder = builder.toolchain("esp");
builder = builder.arg("-Zbuild-std=core,alloc")
}
builder = builder.target(target);
}
if !args.features.is_empty() {
builder = builder.features(&args.features);
}
if args.no_default_features {
builder = builder.arg("--no-default-features");
}
let args = builder.build();
log::debug!("{args:#?}");
cargo::run(&args, &package_path)?;
Ok(())
}

147
xtask/src/commands/mod.rs Normal file
View File

@ -0,0 +1,147 @@
use std::path::Path;
use anyhow::{Result, bail};
use clap::Args;
use esp_metadata::Chip;
pub use self::{build::*, run::*};
use crate::{Package, cargo::CargoAction};
mod build;
mod run;
// ----------------------------------------------------------------------------
// Subcommand Arguments
#[derive(Debug, Args)]
pub struct ExamplesArgs {
/// Package whose examples we which to act on.
#[arg(value_enum)]
pub package: Package,
/// Chip to target.
#[arg(value_enum)]
pub chip: Chip,
/// Build examples in debug mode only
#[arg(long)]
pub debug: bool,
/// Optional example to act on (all examples used if omitted)
#[arg(long)]
pub example: Option<String>,
}
#[derive(Debug, Args)]
pub struct TestsArgs {
/// Chip to target.
#[arg(value_enum)]
pub chip: Chip,
/// Repeat the tests for a specific number of times.
#[arg(long, default_value_t = 1)]
pub repeat: usize,
/// Optional test to act on (all tests used if omitted)
#[arg(long, short = 't')]
pub test: Option<String>,
}
// ----------------------------------------------------------------------------
// Subcommand Actions
pub fn examples(workspace: &Path, mut args: ExamplesArgs, action: CargoAction) -> Result<()> {
// Ensure that the package/chip combination provided are valid:
args.package.validate_package_chip(&args.chip)?;
// If the 'esp-hal' package is specified, what we *really* want is the
// 'examples' package instead:
if args.package == Package::EspHal {
log::warn!(
"Package '{}' specified, using '{}' instead",
Package::EspHal,
Package::Examples
);
args.package = Package::Examples;
}
// Absolute path of the package's root:
let package_path = crate::windows_safe_path(&workspace.join(args.package.to_string()));
let example_path = match args.package {
Package::Examples | Package::QaTest => package_path.join("src").join("bin"),
Package::HilTest => package_path.join("tests"),
_ => package_path.join("examples"),
};
// Load all examples which support the specified chip and parse their metadata:
let mut examples = crate::firmware::load(&example_path)?
.into_iter()
.filter(|example| example.supports_chip(args.chip))
.collect::<Vec<_>>();
// Sort all examples by name:
examples.sort_by_key(|a| a.binary_name());
// Execute the specified action:
match action {
CargoAction::Build(out_path) => build_examples(args, examples, &package_path, &out_path),
CargoAction::Run if args.example.is_some() => run_example(args, examples, &package_path),
CargoAction::Run => run_examples(args, examples, &package_path),
}
}
pub fn tests(workspace: &Path, args: TestsArgs, action: CargoAction) -> Result<()> {
// Absolute path of the 'hil-test' package's root:
let package_path = crate::windows_safe_path(&workspace.join("hil-test"));
// Determine the appropriate build target for the given package and chip:
let target = Package::HilTest.target_triple(&args.chip)?;
// Load all tests which support the specified chip and parse their metadata:
let mut tests = crate::firmware::load(&package_path.join("tests"))?
.into_iter()
.filter(|example| example.supports_chip(args.chip))
.collect::<Vec<_>>();
// Sort all tests by name:
tests.sort_by_key(|a| a.binary_name());
// Execute the specified action:
if tests.iter().any(|test| test.matches(&args.test)) {
for test in tests.iter().filter(|test| test.matches(&args.test)) {
crate::execute_app(
&package_path,
args.chip,
target,
test,
action.clone(),
args.repeat,
false,
)?;
}
Ok(())
} else if args.test.is_some() {
bail!("Test not found or unsupported for the given chip")
} else {
let mut failed = Vec::new();
for test in tests {
if crate::execute_app(
&package_path,
args.chip,
target,
&test,
action.clone(),
args.repeat,
false,
)
.is_err()
{
failed.push(test.name_with_configuration());
}
}
if !failed.is_empty() {
bail!("Failed tests: {:#?}", failed);
}
Ok(())
}
}

228
xtask/src/commands/run.rs Normal file
View File

@ -0,0 +1,228 @@
use std::{
fs,
path::{Path, PathBuf},
process::Command,
};
use anyhow::{Context as _, Result, bail, ensure};
use clap::{Args, Subcommand};
use esp_metadata::Chip;
use super::{ExamplesArgs, TestsArgs};
use crate::{
cargo::{CargoAction, CargoArgsBuilder},
firmware::Metadata,
};
// ----------------------------------------------------------------------------
// Subcommands
#[derive(Debug, Subcommand)]
pub enum Run {
/// Run doctests for specified chip and package.
DocTests(ExamplesArgs),
/// Run all ELFs in a folder.
Elfs(RunElfsArgs),
/// Run the given example for the specified chip.
Example(ExamplesArgs),
/// Run all applicable tests or the specified test for a specified chip.
Tests(TestsArgs),
}
// ----------------------------------------------------------------------------
// Subcommand Arguments
#[derive(Debug, Args)]
pub struct RunElfsArgs {
/// Which chip to run the tests for.
#[arg(value_enum)]
pub chip: Chip,
/// Path to the ELFs.
pub path: PathBuf,
}
// ----------------------------------------------------------------------------
// Subcommand Actions
pub fn run_doc_tests(workspace: &Path, args: ExamplesArgs) -> Result<()> {
let chip = args.chip;
let package_name = args.package.to_string();
let package_path = crate::windows_safe_path(&workspace.join(&package_name));
// Determine the appropriate build target, and cargo features for the given
// package and chip:
let target = args.package.target_triple(&chip)?;
let features = vec![chip.to_string(), "unstable".to_string()];
// We need `nightly` for building the doc tests, unfortunately:
let toolchain = if chip.is_xtensa() { "esp" } else { "nightly" };
// Build up an array of command-line arguments to pass to `cargo`:
let builder = CargoArgsBuilder::default()
.toolchain(toolchain)
.subcommand("test")
.arg("--doc")
.arg("-Zdoctest-xcompile")
.arg("-Zbuild-std=core,panic_abort")
.target(target)
.features(&features)
.arg("--release");
let args = builder.build();
log::debug!("{args:#?}");
// Execute `cargo doc` from the package root:
crate::cargo::run(&args, &package_path)?;
Ok(())
}
pub fn run_elfs(args: RunElfsArgs) -> Result<()> {
let mut failed: Vec<String> = Vec::new();
for elf in fs::read_dir(&args.path)? {
let entry = elf?;
let elf_path = entry.path();
let elf_name = elf_path
.with_extension("")
.file_name()
.unwrap()
.to_string_lossy()
.to_string();
log::info!("Running test '{}' for '{}'", elf_name, args.chip);
let mut command = Command::new("probe-rs");
command.arg("run").arg(elf_path);
if args.chip == Chip::Esp32c2 {
command.arg("--speed").arg("15000");
};
command.arg("--verify");
let mut command = command.spawn().context("Failed to execute probe-rs")?;
let status = command
.wait()
.context("Error while waiting for probe-rs to exit")?;
log::info!("'{elf_name}' done");
if !status.success() {
failed.push(elf_name);
}
}
if !failed.is_empty() {
bail!("Failed tests: {:?}", failed);
}
Ok(())
}
pub fn run_example(args: ExamplesArgs, examples: Vec<Metadata>, package_path: &Path) -> Result<()> {
// Determine the appropriate build target for the given package and chip:
let target = args.package.target_triple(&args.chip)?;
// Filter the examples down to only the binary we're interested in, assuming it
// actually supports the specified chip:
let mut found_one = false;
for example in examples.iter().filter(|ex| ex.matches(&args.example)) {
found_one = true;
crate::execute_app(
package_path,
args.chip,
target,
example,
CargoAction::Run,
1,
args.debug,
)?;
}
ensure!(
found_one,
"Example not found or unsupported for {}",
args.chip
);
Ok(())
}
pub fn run_examples(
args: ExamplesArgs,
examples: Vec<Metadata>,
package_path: &Path,
) -> Result<()> {
// Determine the appropriate build target for the given package and chip:
let target = args.package.target_triple(&args.chip)?;
// Filter the examples down to only the binaries we're interested in
let mut examples: Vec<Metadata> = examples
.iter()
.filter(|ex| ex.supports_chip(args.chip))
.cloned()
.collect();
examples.sort_by_key(|ex| ex.tag());
let console = console::Term::stdout();
for example in examples {
let mut skip = false;
log::info!("Running example '{}'", example.output_file_name());
if let Some(description) = example.description() {
log::info!(
"\n\n{}\n\nPress ENTER to run example, `s` to skip",
description.trim()
);
} else {
log::info!("\n\nPress ENTER to run example, `s` to skip");
}
loop {
let key = console.read_key();
match key {
Ok(console::Key::Enter) => break,
Ok(console::Key::Char('s')) => {
skip = true;
break;
}
_ => (),
}
}
if !skip {
while !skip
&& crate::execute_app(
package_path,
args.chip,
target,
&example,
CargoAction::Run,
1,
args.debug,
)
.is_err()
{
log::info!("Failed to run example. Retry or skip? (r/s)");
loop {
let key = console.read_key();
match key {
Ok(console::Key::Char('r')) => break,
Ok(console::Key::Char('s')) => {
skip = true;
break;
}
_ => (),
}
}
}
}
}
Ok(())
}

View File

@ -5,7 +5,7 @@ use std::{
path::{Path, PathBuf}, path::{Path, PathBuf},
}; };
use anyhow::{ensure, Context as _, Result}; use anyhow::{Context as _, Result, ensure};
use clap::ValueEnum; use clap::ValueEnum;
use esp_metadata::Config; use esp_metadata::Config;
use kuchikiki::traits::*; use kuchikiki::traits::*;
@ -13,7 +13,7 @@ use minijinja::Value;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use strum::IntoEnumIterator; use strum::IntoEnumIterator;
use crate::{cargo::CargoArgsBuilder, Chip, Package}; use crate::{Chip, Package, cargo::CargoArgsBuilder};
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// Build Documentation // Build Documentation
@ -159,11 +159,7 @@ fn build_documentation_for_package(
if package.chip_features_matter() { if package.chip_features_matter() {
version.to_string() version.to_string()
} else { } else {
format!( format!("{}/{}", version, package.to_string().replace('-', "_"))
"{}/{}",
version.to_string(),
package.to_string().replace('-', "_")
)
} }
) )
.as_bytes(), .as_bytes(),
@ -200,7 +196,7 @@ fn cargo_doc(workspace: &Path, package: Package, chip: Option<Chip>) -> Result<P
let mut features = vec![]; let mut features = vec![];
if let Some(chip) = &chip { if let Some(chip) = &chip {
features.push(chip.to_string()); features.push(chip.to_string());
features.extend(package.feature_rules(Config::for_chip(&chip))); features.extend(package.feature_rules(Config::for_chip(chip)));
} else { } else {
features.extend(package.feature_rules(&Config::empty())); features.extend(package.feature_rules(&Config::empty()));
} }
@ -319,7 +315,9 @@ pub fn build_documentation_index(workspace: &Path, packages: &mut [Package]) ->
// If the chip features are not relevant, then there is no need to generate an // If the chip features are not relevant, then there is no need to generate an
// index for the given package's documentation: // index for the given package's documentation:
if !package.chip_features_matter() { if !package.chip_features_matter() {
log::warn!("Package '{package}' does not have device-specific documentation, no need to generate an index"); log::warn!(
"Package '{package}' does not have device-specific documentation, no need to generate an index"
);
continue; continue;
} }
@ -354,14 +352,12 @@ pub fn build_documentation_index(workspace: &Path, packages: &mut [Package]) ->
.map(|path| { .map(|path| {
let chip = path let chip = path
.components() .components()
.last() .next_back()
.unwrap() .unwrap()
.as_os_str() .as_os_str()
.to_string_lossy(); .to_string_lossy();
let chip = Chip::from_str(&chip, true).unwrap(); Chip::from_str(&chip, true).unwrap()
chip
}) })
.collect::<Vec<_>>(); .collect::<Vec<_>>();
@ -376,7 +372,7 @@ pub fn build_documentation_index(workspace: &Path, packages: &mut [Package]) ->
minijinja::context! { metadata => meta }, minijinja::context! { metadata => meta },
)?; )?;
let path = version_path.join("index.html"); let path = version_path.join("index.html");
fs::write(&path, html).context(format!("Failed to write index.html"))?; fs::write(&path, html).context("Failed to write index.html")?;
log::info!("Created {}", path.display()); log::info!("Created {}", path.display());
} }
} }
@ -388,7 +384,7 @@ pub fn build_documentation_index(workspace: &Path, packages: &mut [Package]) ->
) )
.context("Failed to copy esp-rs.svg")?; .context("Failed to copy esp-rs.svg")?;
let meta = generate_documentation_meta_for_index(&workspace)?; let meta = generate_documentation_meta_for_index(workspace)?;
// Render the template to HTML and write it out to the desired path: // Render the template to HTML and write it out to the desired path:
let html = render_template( let html = render_template(
@ -397,7 +393,7 @@ pub fn build_documentation_index(workspace: &Path, packages: &mut [Package]) ->
minijinja::context! { metadata => meta }, minijinja::context! { metadata => meta },
)?; )?;
let path = docs_path.join("index.html"); let path = docs_path.join("index.html");
fs::write(&path, html).context(format!("Failed to write index.html"))?; fs::write(&path, html).context("Failed to write index.html")?;
log::info!("Created {}", path.display()); log::info!("Created {}", path.display());
Ok(()) Ok(())

View File

@ -12,6 +12,7 @@ use strum::{Display, EnumIter, IntoEnumIterator as _};
use crate::{cargo::CargoArgsBuilder, firmware::Metadata}; use crate::{cargo::CargoArgsBuilder, firmware::Metadata};
pub mod cargo; pub mod cargo;
pub mod commands;
pub mod documentation; pub mod documentation;
pub mod firmware; pub mod firmware;
@ -172,16 +173,13 @@ impl Package {
pub fn lint_feature_rules(&self, _config: &Config) -> Vec<Vec<String>> { pub fn lint_feature_rules(&self, _config: &Config) -> Vec<Vec<String>> {
let mut cases = Vec::new(); let mut cases = Vec::new();
match self { if self == &Package::EspWifi {
Package::EspWifi => { // Minimal set of features that when enabled _should_ still compile:
// minimal set of features that when enabled _should_ still compile
cases.push(vec![ cases.push(vec![
"esp-hal/unstable".to_owned(), "esp-hal/unstable".to_owned(),
"builtin-scheduler".to_owned(), "builtin-scheduler".to_owned(),
]); ]);
} }
_ => {}
}
cases cases
} }
@ -307,7 +305,7 @@ pub fn execute_app(
let output = cargo::run_with_env(&args, package_path, env_vars, true)?; let output = cargo::run_with_env(&args, package_path, env_vars, true)?;
for line in output.lines() { for line in output.lines() {
if let Ok(artifact) = serde_json::from_str::<cargo::Artifact>(line) { if let Ok(artifact) = serde_json::from_str::<cargo::Artifact>(line) {
let out_dir = out_dir.join(&chip.to_string()); let out_dir = out_dir.join(chip.to_string());
std::fs::create_dir_all(&out_dir)?; std::fs::create_dir_all(&out_dir)?;
let output_file = out_dir.join(app.output_file_name()); let output_file = out_dir.join(app.output_file_name());
@ -327,56 +325,6 @@ pub fn execute_app(
Ok(()) Ok(())
} }
/// Build the specified package, using the given toolchain/target/features if
/// provided.
pub fn build_package(
package_path: &Path,
features: Vec<String>,
no_default_features: bool,
toolchain: Option<String>,
target: Option<String>,
) -> Result<()> {
log::info!("Building package '{}'", package_path.display());
if !features.is_empty() {
log::info!(" Features: {}", features.join(","));
}
if let Some(ref target) = target {
log::info!(" Target: {}", target);
}
let mut builder = CargoArgsBuilder::default()
.subcommand("build")
.arg("--release");
if let Some(toolchain) = toolchain {
builder = builder.toolchain(toolchain);
}
if let Some(target) = target {
// If targeting an Xtensa device, we must use the '+esp' toolchain modifier:
if target.starts_with("xtensa") {
builder = builder.toolchain("esp");
builder = builder.arg("-Zbuild-std=core,alloc")
}
builder = builder.target(target);
}
if !features.is_empty() {
builder = builder.features(&features);
}
if no_default_features {
builder = builder.arg("--no-default-features");
}
let args = builder.build();
log::debug!("{args:#?}");
cargo::run(&args, package_path)?;
Ok(())
}
/// Bump the version of the specified package by the specified amount. /// Bump the version of the specified package by the specified amount.
pub fn bump_version(workspace: &Path, package: Package, amount: Version) -> Result<()> { pub fn bump_version(workspace: &Path, package: Package, amount: Version) -> Result<()> {
let manifest_path = workspace.join(package.to_string()).join("Cargo.toml"); let manifest_path = workspace.join(package.to_string()).join("Cargo.toml");
@ -431,9 +379,9 @@ pub fn bump_version(workspace: &Path, package: Package, amount: Version) -> Resu
" Bumping {package} version for package {pkg}: ({prev_version} -> {version})" " Bumping {package} version for package {pkg}: ({prev_version} -> {version})"
); );
manifest["dependencies"].as_table_mut().map(|table| { if let Some(table) = manifest["dependencies"].as_table_mut() {
table[&package.to_string()]["version"] = toml_edit::value(version.to_string()) table[&package.to_string()]["version"] = toml_edit::value(version.to_string());
}); }
fs::write(&manifest_path, manifest.to_string()) fs::write(&manifest_path, manifest.to_string())
.with_context(|| format!("Could not write {}", manifest_path.display()))?; .with_context(|| format!("Could not write {}", manifest_path.display()))?;
@ -471,12 +419,10 @@ pub fn package_paths(workspace: &Path) -> Result<Vec<PathBuf>> {
let mut paths = Vec::new(); let mut paths = Vec::new();
for entry in fs::read_dir(workspace)? { for entry in fs::read_dir(workspace)? {
let entry = entry?; let entry = entry?;
if entry.file_type()?.is_dir() { if entry.file_type()?.is_dir() && entry.path().join("Cargo.toml").exists() {
if entry.path().join("Cargo.toml").exists() {
paths.push(entry.path()); paths.push(entry.path());
} }
} }
}
paths.sort(); paths.sort();

View File

@ -5,7 +5,7 @@ use std::{
time::Instant, time::Instant,
}; };
use anyhow::{Context as _, Result, bail, ensure}; use anyhow::{Result, bail};
use clap::{Args, Parser}; use clap::{Args, Parser};
use esp_metadata::{Chip, Config}; use esp_metadata::{Chip, Config};
use strum::IntoEnumIterator; use strum::IntoEnumIterator;
@ -13,7 +13,7 @@ use xtask::{
Package, Package,
Version, Version,
cargo::{CargoAction, CargoArgsBuilder}, cargo::{CargoAction, CargoArgsBuilder},
firmware::Metadata, commands::*,
}; };
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
@ -21,18 +21,17 @@ use xtask::{
#[derive(Debug, Parser)] #[derive(Debug, Parser)]
enum Cli { enum Cli {
/// Build documentation for the specified chip. /// Build-related subcommands
BuildDocumentation(BuildDocumentationArgs), #[clap(subcommand)]
/// Build documentation index including the specified packages. Build(Build),
BuildDocumentationIndex(BuildDocumentationIndexArgs), /// Run-related subcommands
/// Build all examples for the specified chip. #[clap(subcommand)]
BuildExamples(ExampleArgs), Run(Run),
/// Build the specified package with the given options.
BuildPackage(BuildPackageArgs),
/// Build all applicable tests or the specified test for a specified chip.
BuildTests(TestArgs),
/// Bump the version of the specified package(s). /// Bump the version of the specified package(s).
BumpVersion(BumpVersionArgs), BumpVersion(BumpVersionArgs),
/// Perform (parts of) the checks done in CI
Ci(CiArgs),
/// Format all packages in the workspace with rustfmt /// Format all packages in the workspace with rustfmt
#[clap(alias = "format-packages")] #[clap(alias = "format-packages")]
FmtPackages(FmtPackagesArgs), FmtPackages(FmtPackagesArgs),
@ -40,91 +39,10 @@ enum Cli {
LintPackages(LintPackagesArgs), LintPackages(LintPackagesArgs),
/// Attempt to publish the specified package. /// Attempt to publish the specified package.
Publish(PublishArgs), Publish(PublishArgs),
/// Run doctests for specified chip and package.
#[clap(alias = "run-doc-test")]
RunDocTests(ExampleArgs),
/// Run the given example for the specified chip.
RunExample(ExampleArgs),
/// Run all applicable tests or the specified test for a specified chip.
RunTests(TestArgs),
/// Run all ELFs in a folder.
RunElfs(RunElfArgs),
/// Perform (parts of) the checks done in CI
Ci(CiArgs),
/// Generate git tags for all new package releases. /// Generate git tags for all new package releases.
TagReleases(TagReleasesArgs), TagReleases(TagReleasesArgs),
} }
#[derive(Debug, Args)]
struct ExampleArgs {
/// Package whose examples we which to act on.
#[arg(value_enum)]
package: Package,
/// Chip to target.
#[arg(value_enum)]
chip: Chip,
/// Optional example to act on (all examples used if omitted)
example: Option<String>,
/// Build examples in debug mode only
#[arg(long)]
debug: bool,
}
#[derive(Debug, Args)]
struct TestArgs {
/// Chip to target.
#[arg(value_enum)]
chip: Chip,
/// Optional test to act on (all tests used if omitted)
#[arg(short = 't', long)]
test: Option<String>,
/// Repeat the tests for a specific number of times.
#[arg(long)]
repeat: Option<usize>,
}
#[derive(Debug, Args)]
struct BuildDocumentationArgs {
/// Package(s) to document.
#[arg(long, value_enum, value_delimiter = ',', default_values_t = Package::iter())]
packages: Vec<Package>,
/// Chip(s) to build documentation for.
#[arg(long, value_enum, value_delimiter = ',', default_values_t = Chip::iter())]
chips: Vec<Chip>,
/// Base URL of the deployed documentation.
#[arg(long)]
base_url: Option<String>,
}
#[derive(Debug, Args)]
struct BuildDocumentationIndexArgs {
/// Package(s) to build documentation index for.
#[arg(long, value_enum, value_delimiter = ',', default_values_t = Package::iter())]
packages: Vec<Package>,
#[cfg(feature = "preview-docs")]
#[arg(long)]
serve: bool,
}
#[derive(Debug, Args)]
struct BuildPackageArgs {
/// Package to build.
#[arg(value_enum)]
package: Package,
/// Target to build for.
#[arg(long)]
target: Option<String>,
/// Features to build with.
#[arg(long, value_delimiter = ',')]
features: Vec<String>,
/// Toolchain to build with.
#[arg(long)]
toolchain: Option<String>,
/// Don't enabled the default features.
#[arg(long)]
no_default_features: bool,
}
#[derive(Debug, Args)] #[derive(Debug, Args)]
struct BumpVersionArgs { struct BumpVersionArgs {
/// How much to bump the version by. /// How much to bump the version by.
@ -135,6 +53,13 @@ struct BumpVersionArgs {
packages: Vec<Package>, packages: Vec<Package>,
} }
#[derive(Debug, Args)]
struct CiArgs {
/// Chip to target.
#[arg(value_enum)]
chip: Chip,
}
#[derive(Debug, Args)] #[derive(Debug, Args)]
struct FmtPackagesArgs { struct FmtPackagesArgs {
/// Run in 'check' mode; exists with 0 if formatted correctly, 1 otherwise /// Run in 'check' mode; exists with 0 if formatted correctly, 1 otherwise
@ -146,15 +71,6 @@ struct FmtPackagesArgs {
packages: Vec<Package>, packages: Vec<Package>,
} }
#[derive(Debug, Args)]
struct GenerateEfuseFieldsArgs {
/// Path to the local ESP-IDF repository.
idf_path: PathBuf,
/// Chip to build eFuse fields table for.
#[arg(value_enum)]
chip: Chip,
}
#[derive(Debug, Args)] #[derive(Debug, Args)]
struct LintPackagesArgs { struct LintPackagesArgs {
/// Package(s) to target. /// Package(s) to target.
@ -181,22 +97,6 @@ struct PublishArgs {
no_dry_run: bool, no_dry_run: bool,
} }
#[derive(Debug, Args)]
struct RunElfArgs {
/// Which chip to run the tests for.
#[arg(value_enum)]
chip: Chip,
/// Path to the ELFs.
path: PathBuf,
}
#[derive(Debug, Args)]
struct CiArgs {
/// Chip to target.
#[arg(value_enum)]
chip: Chip,
}
#[derive(Debug, Args)] #[derive(Debug, Args)]
struct TagReleasesArgs { struct TagReleasesArgs {
/// Package(s) to tag. /// Package(s) to tag.
@ -218,28 +118,35 @@ fn main() -> Result<()> {
let target_path = Path::new("target"); let target_path = Path::new("target");
match Cli::parse() { match Cli::parse() {
Cli::BuildDocumentation(args) => build_documentation(&workspace, args), // Build-related subcommands:
Cli::BuildDocumentationIndex(args) => build_documentation_index(&workspace, args), Cli::Build(build) => match build {
Cli::BuildExamples(args) => examples( Build::Documentation(args) => build_documentation(&workspace, args),
Build::Examples(args) => examples(
&workspace, &workspace,
args, args,
CargoAction::Build(target_path.join("examples")), CargoAction::Build(target_path.join("examples")),
), ),
Cli::BuildPackage(args) => build_package(&workspace, args), Build::Package(args) => build_package(&workspace, args),
Cli::BuildTests(args) => tests( Build::Tests(args) => tests(
&workspace, &workspace,
args, args,
CargoAction::Build(target_path.join("tests")), CargoAction::Build(target_path.join("tests")),
), ),
},
// Run-related subcommands:
Cli::Run(run) => match run {
Run::DocTests(args) => run_doc_tests(&workspace, args),
Run::Elfs(args) => run_elfs(args),
Run::Example(args) => examples(&workspace, args, CargoAction::Run),
Run::Tests(args) => tests(&workspace, args, CargoAction::Run),
},
Cli::BumpVersion(args) => bump_version(&workspace, args), Cli::BumpVersion(args) => bump_version(&workspace, args),
Cli::Ci(args) => run_ci_checks(&workspace, args),
Cli::FmtPackages(args) => fmt_packages(&workspace, args), Cli::FmtPackages(args) => fmt_packages(&workspace, args),
Cli::LintPackages(args) => lint_packages(&workspace, args), Cli::LintPackages(args) => lint_packages(&workspace, args),
Cli::Publish(args) => publish(&workspace, args), Cli::Publish(args) => publish(&workspace, args),
Cli::RunDocTests(args) => run_doc_tests(&workspace, args),
Cli::RunElfs(args) => run_elfs(args),
Cli::RunExample(args) => examples(&workspace, args, CargoAction::Run),
Cli::RunTests(args) => tests(&workspace, args, CargoAction::Run),
Cli::Ci(args) => run_ci_checks(&workspace, args),
Cli::TagReleases(args) => tag_releases(&workspace, args), Cli::TagReleases(args) => tag_releases(&workspace, args),
} }
} }
@ -247,314 +154,6 @@ fn main() -> Result<()> {
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// Subcommands // Subcommands
fn examples(workspace: &Path, mut args: ExampleArgs, action: CargoAction) -> Result<()> {
// Ensure that the package/chip combination provided are valid:
args.package.validate_package_chip(&args.chip)?;
// If the 'esp-hal' package is specified, what we *really* want is the
// 'examples' package instead:
if args.package == Package::EspHal {
log::warn!(
"Package '{}' specified, using '{}' instead",
Package::EspHal,
Package::Examples
);
args.package = Package::Examples;
}
// Absolute path of the package's root:
let package_path = xtask::windows_safe_path(&workspace.join(args.package.to_string()));
let example_path = match args.package {
Package::Examples | Package::QaTest => package_path.join("src").join("bin"),
Package::HilTest => package_path.join("tests"),
_ => package_path.join("examples"),
};
// Load all examples which support the specified chip and parse their metadata:
let mut examples = xtask::firmware::load(&example_path)?
.iter()
.filter_map(|example| {
if example.supports_chip(args.chip) {
Some(example.clone())
} else {
None
}
})
.collect::<Vec<_>>();
// Sort all examples by name:
examples.sort_by_key(|a| a.binary_name());
// Execute the specified action:
match action {
CargoAction::Build(out_path) => build_examples(args, examples, &package_path, out_path),
CargoAction::Run if args.example.is_some() => run_example(args, examples, &package_path),
CargoAction::Run => run_examples(args, examples, &package_path),
}
}
fn build_examples(
args: ExampleArgs,
examples: Vec<Metadata>,
package_path: &Path,
out_path: PathBuf,
) -> Result<()> {
// Determine the appropriate build target for the given package and chip:
let target = args.package.target_triple(&args.chip)?;
if examples
.iter()
.find(|ex| ex.matches(&args.example))
.is_some()
{
// Attempt to build only the specified example:
for example in examples.iter().filter(|ex| ex.matches(&args.example)) {
xtask::execute_app(
package_path,
args.chip,
target,
example,
CargoAction::Build(out_path.clone()),
1,
args.debug,
)?;
}
Ok(())
} else if args.example.is_some() {
// An invalid argument was provided:
bail!("Example not found or unsupported for the given chip")
} else {
// Attempt to build each supported example, with all required features enabled:
examples.iter().try_for_each(|example| {
xtask::execute_app(
package_path,
args.chip,
target,
example,
CargoAction::Build(out_path.clone()),
1,
args.debug,
)
})
}
}
fn run_example(args: ExampleArgs, examples: Vec<Metadata>, package_path: &Path) -> Result<()> {
// Determine the appropriate build target for the given package and chip:
let target = args.package.target_triple(&args.chip)?;
// Filter the examples down to only the binary we're interested in, assuming it
// actually supports the specified chip:
let mut found_one = false;
for example in examples.iter().filter(|ex| ex.matches(&args.example)) {
found_one = true;
xtask::execute_app(
package_path,
args.chip,
target,
example,
CargoAction::Run,
1,
args.debug,
)?;
}
ensure!(
found_one,
"Example not found or unsupported for {}",
args.chip
);
Ok(())
}
fn run_examples(args: ExampleArgs, examples: Vec<Metadata>, package_path: &Path) -> Result<()> {
// Determine the appropriate build target for the given package and chip:
let target = args.package.target_triple(&args.chip)?;
// Filter the examples down to only the binaries we're interested in
let mut examples: Vec<Metadata> = examples
.iter()
.filter(|ex| ex.supports_chip(args.chip))
.cloned()
.collect();
examples.sort_by_key(|ex| ex.tag());
let console = console::Term::stdout();
for example in examples {
let mut skip = false;
log::info!("Running example '{}'", example.output_file_name());
if let Some(description) = example.description() {
log::info!(
"\n\n{}\n\nPress ENTER to run example, `s` to skip",
description.trim()
);
} else {
log::info!("\n\nPress ENTER to run example, `s` to skip");
}
loop {
let key = console.read_key();
match key {
Ok(console::Key::Enter) => break,
Ok(console::Key::Char('s')) => {
skip = true;
break;
}
_ => (),
}
}
if !skip {
while !skip
&& xtask::execute_app(
package_path,
args.chip,
target,
&example,
CargoAction::Run,
1,
args.debug,
)
.is_err()
{
log::info!("Failed to run example. Retry or skip? (r/s)");
loop {
let key = console.read_key();
match key {
Ok(console::Key::Char('r')) => break,
Ok(console::Key::Char('s')) => {
skip = true;
break;
}
_ => (),
}
}
}
}
}
Ok(())
}
fn tests(workspace: &Path, args: TestArgs, action: CargoAction) -> Result<()> {
// Absolute path of the 'hil-test' package's root:
let package_path = xtask::windows_safe_path(&workspace.join("hil-test"));
// Determine the appropriate build target for the given package and chip:
let target = Package::HilTest.target_triple(&args.chip)?;
// Load all tests which support the specified chip and parse their metadata:
let mut tests = xtask::firmware::load(&package_path.join("tests"))?
.into_iter()
.filter(|example| example.supports_chip(args.chip))
.collect::<Vec<_>>();
// Sort all tests by name:
tests.sort_by_key(|a| a.binary_name());
// Execute the specified action:
if tests.iter().find(|test| test.matches(&args.test)).is_some() {
for test in tests.iter().filter(|test| test.matches(&args.test)) {
xtask::execute_app(
&package_path,
args.chip,
target,
test,
action.clone(),
args.repeat.unwrap_or(1),
false,
)?;
}
Ok(())
} else if args.test.is_some() {
bail!("Test not found or unsupported for the given chip")
} else {
let mut failed = Vec::new();
for test in tests {
if xtask::execute_app(
&package_path,
args.chip,
target,
&test,
action.clone(),
args.repeat.unwrap_or(1),
false,
)
.is_err()
{
failed.push(test.name_with_configuration());
}
}
if !failed.is_empty() {
bail!("Failed tests: {:#?}", failed);
}
Ok(())
}
}
fn build_documentation(workspace: &Path, mut args: BuildDocumentationArgs) -> Result<()> {
xtask::documentation::build_documentation(
workspace,
&mut args.packages,
&mut args.chips,
args.base_url,
)
}
fn build_documentation_index(
workspace: &Path,
mut args: BuildDocumentationIndexArgs,
) -> Result<()> {
xtask::documentation::build_documentation_index(workspace, &mut args.packages)?;
#[cfg(feature = "preview-docs")]
if args.serve {
std::thread::spawn(|| {
std::thread::sleep(std::time::Duration::from_millis(1000));
opener::open_browser("http://127.0.0.1:8000/").ok();
});
rocket::async_main(
{
rocket::build().mount(
"/",
rocket::fs::FileServer::new(
"docs",
rocket::fs::Options::Index
| rocket::fs::Options::IndexFile
| rocket::fs::Options::DotFiles,
),
)
}
.launch(),
)?;
}
Ok(())
}
fn build_package(workspace: &Path, args: BuildPackageArgs) -> Result<()> {
// Absolute path of the package's root:
let package_path = xtask::windows_safe_path(&workspace.join(args.package.to_string()));
// Build the package using the provided features and/or target, if any:
xtask::build_package(
&package_path,
args.features,
args.no_default_features,
args.toolchain,
args.target,
)
}
fn bump_version(workspace: &Path, args: BumpVersionArgs) -> Result<()> { fn bump_version(workspace: &Path, args: BumpVersionArgs) -> Result<()> {
// Bump the version by the specified amount for each given package: // Bump the version by the specified amount for each given package:
for package in args.packages { for package in args.packages {
@ -617,7 +216,7 @@ fn lint_packages(workspace: &Path, args: LintPackagesArgs) -> Result<()> {
for chip in &args.chips { for chip in &args.chips {
let device = Config::for_chip(chip); let device = Config::for_chip(chip);
if let Err(_) = package.validate_package_chip(chip) { if package.validate_package_chip(chip).is_err() {
continue; continue;
} }
@ -734,83 +333,6 @@ fn publish(workspace: &Path, args: PublishArgs) -> Result<()> {
Ok(()) Ok(())
} }
fn run_elfs(args: RunElfArgs) -> Result<()> {
let mut failed: Vec<String> = Vec::new();
for elf in fs::read_dir(&args.path)? {
let entry = elf?;
let elf_path = entry.path();
let elf_name = elf_path
.with_extension("")
.file_name()
.unwrap()
.to_string_lossy()
.to_string();
log::info!("Running test '{}' for '{}'", elf_name, args.chip);
let mut command = Command::new("probe-rs");
command.arg("run").arg(elf_path);
if args.chip == Chip::Esp32c2 {
command.arg("--speed").arg("15000");
};
command.arg("--verify");
let mut command = command.spawn().context("Failed to execute probe-rs")?;
let status = command
.wait()
.context("Error while waiting for probe-rs to exit")?;
log::info!("'{elf_name}' done");
if !status.success() {
failed.push(elf_name);
}
}
if !failed.is_empty() {
bail!("Failed tests: {:?}", failed);
}
Ok(())
}
fn run_doc_tests(workspace: &Path, args: ExampleArgs) -> Result<()> {
let chip = args.chip;
let package_name = args.package.to_string();
let package_path = xtask::windows_safe_path(&workspace.join(&package_name));
// Determine the appropriate build target, and cargo features for the given
// package and chip:
let target = args.package.target_triple(&chip)?;
let features = vec![chip.to_string(), "unstable".to_string()];
// We need `nightly` for building the doc tests, unfortunately:
let toolchain = if chip.is_xtensa() { "esp" } else { "nightly" };
// Build up an array of command-line arguments to pass to `cargo`:
let builder = CargoArgsBuilder::default()
.toolchain(toolchain)
.subcommand("test")
.arg("--doc")
.arg("-Zdoctest-xcompile")
.arg("-Zbuild-std=core,panic_abort")
.target(target)
.features(&features)
.arg("--release");
let args = builder.build();
log::debug!("{args:#?}");
// Execute `cargo doc` from the package root:
xtask::cargo::run(&args, &package_path)?;
Ok(())
}
fn run_ci_checks(workspace: &Path, args: CiArgs) -> Result<()> { fn run_ci_checks(workspace: &Path, args: CiArgs) -> Result<()> {
let mut failure = false; let mut failure = false;
let started_at = Instant::now(); let started_at = Instant::now();
@ -832,7 +354,7 @@ fn run_ci_checks(workspace: &Path, args: CiArgs) -> Result<()> {
// Check doc-tests // Check doc-tests
run_doc_tests( run_doc_tests(
workspace, workspace,
ExampleArgs { ExamplesArgs {
package: Package::EspHal, package: Package::EspHal,
chip: args.chip, chip: args.chip,
example: None, example: None,
@ -848,7 +370,7 @@ fn run_ci_checks(workspace: &Path, args: CiArgs) -> Result<()> {
BuildDocumentationArgs { BuildDocumentationArgs {
packages: vec![Package::EspHal, Package::EspWifi, Package::EspHalEmbassy], packages: vec![Package::EspHal, Package::EspWifi, Package::EspHalEmbassy],
chips: vec![args.chip], chips: vec![args.chip],
base_url: None, ..Default::default()
}, },
) )
.inspect_err(|_| failure = true) .inspect_err(|_| failure = true)
@ -863,7 +385,7 @@ fn run_ci_checks(workspace: &Path, args: CiArgs) -> Result<()> {
// expects it // expects it
examples( examples(
workspace, workspace,
ExampleArgs { ExamplesArgs {
package: Package::EspLpHal, package: Package::EspLpHal,
chip: args.chip, chip: args.chip,
example: None, example: None,
@ -879,7 +401,7 @@ fn run_ci_checks(workspace: &Path, args: CiArgs) -> Result<()> {
let from_dir = PathBuf::from(format!( let from_dir = PathBuf::from(format!(
"./esp-lp-hal/target/{}/release/examples/{}", "./esp-lp-hal/target/{}/release/examples/{}",
args.chip.target(), args.chip.target(),
args.chip.to_string() args.chip
)); ));
let to_dir = PathBuf::from(format!( let to_dir = PathBuf::from(format!(
"./esp-lp-hal/target/{}/release/examples", "./esp-lp-hal/target/{}/release/examples",
@ -901,7 +423,7 @@ fn run_ci_checks(workspace: &Path, args: CiArgs) -> Result<()> {
BuildDocumentationArgs { BuildDocumentationArgs {
packages: vec![Package::EspLpHal], packages: vec![Package::EspLpHal],
chips: vec![args.chip], chips: vec![args.chip],
base_url: None, ..Default::default()
}, },
) )
.inspect_err(|_| failure = true) .inspect_err(|_| failure = true)
@ -925,13 +447,13 @@ fn run_ci_checks(workspace: &Path, args: CiArgs) -> Result<()> {
// Build (examples) // Build (examples)
examples( examples(
workspace, workspace,
ExampleArgs { ExamplesArgs {
package: Package::Examples, package: Package::Examples,
chip: args.chip, chip: args.chip,
example: None, example: None,
debug: true, debug: true,
}, },
CargoAction::Build(PathBuf::from(format!("./examples/target/"))), CargoAction::Build(PathBuf::from("./examples/target/")),
) )
.inspect_err(|_| failure = true) .inspect_err(|_| failure = true)
.ok(); .ok();
@ -939,13 +461,13 @@ fn run_ci_checks(workspace: &Path, args: CiArgs) -> Result<()> {
// Build (qa-test) // Build (qa-test)
examples( examples(
workspace, workspace,
ExampleArgs { ExamplesArgs {
package: Package::QaTest, package: Package::QaTest,
chip: args.chip, chip: args.chip,
example: None, example: None,
debug: true, debug: true,
}, },
CargoAction::Build(PathBuf::from(format!("./qa-test/target/"))), CargoAction::Build(PathBuf::from("./qa-test/target/")),
) )
.inspect_err(|_| failure = true) .inspect_err(|_| failure = true)
.ok(); .ok();