mirror of
https://github.com/esp-rs/esp-hal.git
synced 2025-10-01 14:20:44 +00:00
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:
parent
78bd99e653
commit
e5ea7e35cd
@ -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"
|
||||||
|
9
.github/workflows/documentation.yml
vendored
9
.github/workflows/documentation.yml
vendored
@ -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
|
||||||
|
6
.github/workflows/hil.yml
vendored
6
.github/workflows/hil.yml
vendored
@ -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()
|
||||||
|
@ -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
199
xtask/src/commands/build.rs
Normal 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
147
xtask/src/commands/mod.rs
Normal 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
228
xtask/src/commands/run.rs
Normal 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(())
|
||||||
|
}
|
@ -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(())
|
||||||
|
@ -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();
|
||||||
|
|
||||||
|
@ -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();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user