mirror of
https://github.com/esp-rs/esp-hal.git
synced 2025-09-28 04:40:52 +00:00
Add build-package
and bump-version
subcommands to xtask
package (#1172)
* Implement builder pattern for cargo command-line args, refactoring * Add an `xtask` subcommand to build a package (not its examples) * Add an `xtask` subcommand to bump the versions of packages
This commit is contained in:
parent
2a5996f408
commit
0483b47e77
@ -9,4 +9,6 @@ anyhow = "1.0.79"
|
||||
clap = { version = "4.5.0", features = ["derive"] }
|
||||
env_logger = "0.11.1"
|
||||
log = "0.4.20"
|
||||
semver = "1.0.21"
|
||||
strum = { version = "0.26.1", features = ["derive"] }
|
||||
toml_edit = "0.22.5"
|
||||
|
@ -10,6 +10,8 @@ Usage: xtask <COMMAND>
|
||||
Commands:
|
||||
build-documentation Build documentation for the specified chip
|
||||
build-examples Build all examples for the specified chip
|
||||
build-package Build the specified package with the given options
|
||||
bump-version Bump the version of the specified package(s)
|
||||
help Print this message or the help of the given subcommand(s)
|
||||
|
||||
Options:
|
||||
|
108
xtask/src/cargo.rs
Normal file
108
xtask/src/cargo.rs
Normal file
@ -0,0 +1,108 @@
|
||||
//! Tools for working with Cargo.
|
||||
|
||||
use std::{
|
||||
path::Path,
|
||||
process::{Command, Stdio},
|
||||
};
|
||||
|
||||
use anyhow::{bail, Result};
|
||||
|
||||
/// Execute cargo with the given arguments and from the specified directory.
|
||||
pub fn run(args: &[String], cwd: &Path) -> Result<()> {
|
||||
if !cwd.is_dir() {
|
||||
bail!("The `cwd` argument MUST be a directory");
|
||||
}
|
||||
|
||||
let status = Command::new("cargo")
|
||||
.args(args)
|
||||
.current_dir(cwd)
|
||||
.stdout(Stdio::piped())
|
||||
.stderr(Stdio::inherit())
|
||||
.status()?;
|
||||
|
||||
// Make sure that we return an appropriate exit code here, as Github Actions
|
||||
// requires this in order to function correctly:
|
||||
if status.success() {
|
||||
Ok(())
|
||||
} else {
|
||||
bail!("Failed to execute cargo subcommand")
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
pub struct CargoArgsBuilder {
|
||||
toolchain: Option<String>,
|
||||
subcommand: String,
|
||||
target: Option<String>,
|
||||
features: Vec<String>,
|
||||
args: Vec<String>,
|
||||
}
|
||||
|
||||
impl CargoArgsBuilder {
|
||||
#[must_use]
|
||||
pub fn toolchain<S>(mut self, toolchain: S) -> Self
|
||||
where
|
||||
S: Into<String>,
|
||||
{
|
||||
self.toolchain = Some(toolchain.into());
|
||||
self
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn subcommand<S>(mut self, subcommand: S) -> Self
|
||||
where
|
||||
S: Into<String>,
|
||||
{
|
||||
self.subcommand = subcommand.into();
|
||||
self
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn target<S>(mut self, target: S) -> Self
|
||||
where
|
||||
S: Into<String>,
|
||||
{
|
||||
self.target = Some(target.into());
|
||||
self
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn features(mut self, features: &[String]) -> Self {
|
||||
self.features = features.to_vec();
|
||||
self
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn arg<S>(mut self, arg: S) -> Self
|
||||
where
|
||||
S: Into<String>,
|
||||
{
|
||||
self.args.push(arg.into());
|
||||
self
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn build(self) -> Vec<String> {
|
||||
let mut args = vec![];
|
||||
|
||||
if let Some(toolchain) = self.toolchain {
|
||||
args.push(format!("+{toolchain}"));
|
||||
}
|
||||
|
||||
args.push(self.subcommand);
|
||||
|
||||
if let Some(target) = self.target {
|
||||
args.push(format!("--target={target}"));
|
||||
}
|
||||
|
||||
if !self.features.is_empty() {
|
||||
args.push(format!("--features={}", self.features.join(",")));
|
||||
}
|
||||
|
||||
for arg in self.args {
|
||||
args.push(arg);
|
||||
}
|
||||
|
||||
args
|
||||
}
|
||||
}
|
152
xtask/src/lib.rs
152
xtask/src/lib.rs
@ -2,14 +2,17 @@ use std::{
|
||||
collections::VecDeque,
|
||||
fs,
|
||||
path::{Path, PathBuf},
|
||||
process::{Command, Stdio},
|
||||
};
|
||||
|
||||
use anyhow::{anyhow, bail, Result};
|
||||
use anyhow::{bail, Result};
|
||||
use clap::ValueEnum;
|
||||
use strum::{Display, EnumIter, IntoEnumIterator};
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Display, ValueEnum)]
|
||||
use self::cargo::CargoArgsBuilder;
|
||||
|
||||
mod cargo;
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Display, EnumIter, ValueEnum)]
|
||||
#[strum(serialize_all = "kebab-case")]
|
||||
pub enum Package {
|
||||
EspHal,
|
||||
@ -111,6 +114,14 @@ impl Metadata {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, Display, ValueEnum)]
|
||||
#[strum(serialize_all = "lowercase")]
|
||||
pub enum Version {
|
||||
Major,
|
||||
Minor,
|
||||
Patch,
|
||||
}
|
||||
|
||||
/// Build the documentation for the specified package and device.
|
||||
pub fn build_documentation(
|
||||
workspace: &Path,
|
||||
@ -124,20 +135,22 @@ pub fn build_documentation(
|
||||
|
||||
log::info!("Building '{package_name}' documentation targeting '{chip}'");
|
||||
|
||||
// Build up an array of command-line arguments to pass to `cargo doc`:
|
||||
let mut args = vec![
|
||||
"doc".into(),
|
||||
"-Zbuild-std=core".into(), // Required for Xtensa, for some reason
|
||||
format!("--target={target}"),
|
||||
format!("--features={}", chip.to_string()),
|
||||
];
|
||||
// Build up an array of command-line arguments to pass to `cargo`:
|
||||
let mut builder = CargoArgsBuilder::default()
|
||||
.subcommand("doc")
|
||||
.arg("-Zbuild-std=core") // Required for Xtensa, for some reason
|
||||
.target(target)
|
||||
.features(&[chip.to_string()]);
|
||||
|
||||
if open {
|
||||
args.push("--open".into());
|
||||
builder = builder.arg("--open");
|
||||
}
|
||||
|
||||
let args = builder.build();
|
||||
log::debug!("{args:#?}");
|
||||
|
||||
// Execute `cargo doc` from the package root:
|
||||
cargo(&args, &package_path)?;
|
||||
cargo::run(&args, &package_path)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@ -217,40 +230,105 @@ pub fn build_example(
|
||||
format!("--example={}", example.name())
|
||||
};
|
||||
|
||||
let mut features = example.features().to_vec();
|
||||
features.push(chip.to_string());
|
||||
|
||||
let mut builder = CargoArgsBuilder::default()
|
||||
.subcommand("build")
|
||||
.arg("-Zbuild-std=alloc,core")
|
||||
.arg("--release")
|
||||
.target(target)
|
||||
.features(&features)
|
||||
.arg(bin);
|
||||
|
||||
// If targeting an Xtensa device, we must use the '+esp' toolchain modifier:
|
||||
let mut args = vec![];
|
||||
if target.starts_with("xtensa") {
|
||||
args.push("+esp".into());
|
||||
builder = builder.toolchain("esp");
|
||||
}
|
||||
|
||||
args.extend(vec![
|
||||
"build".into(),
|
||||
"-Zbuild-std=alloc,core".into(),
|
||||
"--release".into(),
|
||||
format!("--target={target}"),
|
||||
format!("--features={},{}", chip, example.features().join(",")),
|
||||
bin,
|
||||
]);
|
||||
let args = builder.build();
|
||||
log::debug!("{args:#?}");
|
||||
|
||||
cargo(&args, package_path)?;
|
||||
cargo::run(&args, package_path)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn cargo(args: &[String], cwd: &Path) -> Result<()> {
|
||||
let status = Command::new("cargo")
|
||||
.args(args)
|
||||
.current_dir(cwd)
|
||||
.stdout(Stdio::piped())
|
||||
.stderr(Stdio::inherit())
|
||||
.status()?;
|
||||
|
||||
// Make sure that we return an appropriate exit code here, as Github Actions
|
||||
// requires this in order to function correctly:
|
||||
if status.success() {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(anyhow!("Failed to execute cargo subcommand"))
|
||||
/// Build the specified package, using the given toolchain/target/features if
|
||||
/// provided.
|
||||
pub fn build_package(
|
||||
package_path: &Path,
|
||||
features: Vec<String>,
|
||||
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("-Zbuild-std=core")
|
||||
.arg("--release");
|
||||
|
||||
if let Some(toolchain) = toolchain {
|
||||
builder = builder.toolchain(toolchain);
|
||||
}
|
||||
|
||||
if let Some(target) = target {
|
||||
builder = builder.target(target);
|
||||
}
|
||||
|
||||
if !features.is_empty() {
|
||||
builder = builder.features(&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.
|
||||
pub fn bump_version(workspace: &Path, package: Package, amount: Version) -> Result<()> {
|
||||
let manifest_path = workspace.join(package.to_string()).join("Cargo.toml");
|
||||
let manifest = fs::read_to_string(&manifest_path)?;
|
||||
|
||||
let mut manifest = manifest.parse::<toml_edit::Document>()?;
|
||||
|
||||
let version = manifest["package"]["version"]
|
||||
.to_string()
|
||||
.trim()
|
||||
.trim_matches('"')
|
||||
.to_string();
|
||||
let prev_version = &version;
|
||||
|
||||
let mut version = semver::Version::parse(&version)?;
|
||||
match amount {
|
||||
Version::Major => {
|
||||
version.major += 1;
|
||||
version.minor = 0;
|
||||
version.patch = 0;
|
||||
}
|
||||
Version::Minor => {
|
||||
version.minor += 1;
|
||||
version.patch = 0;
|
||||
}
|
||||
Version::Patch => {
|
||||
version.patch += 1;
|
||||
}
|
||||
}
|
||||
|
||||
log::info!("Bumping version for package: {package} ({prev_version} -> {version})");
|
||||
|
||||
manifest["package"]["version"] = toml_edit::value(version.to_string());
|
||||
fs::write(manifest_path, manifest.to_string())?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
@ -2,7 +2,8 @@ use std::path::{Path, PathBuf};
|
||||
|
||||
use anyhow::{bail, Result};
|
||||
use clap::{Args, Parser};
|
||||
use xtask::{Chip, Package};
|
||||
use strum::IntoEnumIterator;
|
||||
use xtask::{Chip, Package, Version};
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Command-line Interface
|
||||
@ -13,6 +14,10 @@ enum Cli {
|
||||
BuildDocumentation(BuildDocumentationArgs),
|
||||
/// Build all examples for the specified chip.
|
||||
BuildExamples(BuildExamplesArgs),
|
||||
/// Build the specified package with the given options.
|
||||
BuildPackage(BuildPackageArgs),
|
||||
/// Bump the version of the specified package(s)
|
||||
BumpVersion(BumpVersionArgs),
|
||||
}
|
||||
|
||||
#[derive(Debug, Args)]
|
||||
@ -38,6 +43,32 @@ struct BuildExamplesArgs {
|
||||
chip: Chip,
|
||||
}
|
||||
|
||||
#[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>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Args)]
|
||||
struct BumpVersionArgs {
|
||||
/// How much to bump the version by.
|
||||
#[arg(value_enum)]
|
||||
amount: Version,
|
||||
/// Package(s) to target.
|
||||
#[arg(value_enum, default_values_t = Package::iter())]
|
||||
packages: Vec<Package>,
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Application
|
||||
|
||||
@ -52,6 +83,8 @@ fn main() -> Result<()> {
|
||||
match Cli::parse() {
|
||||
Cli::BuildDocumentation(args) => build_documentation(&workspace, args),
|
||||
Cli::BuildExamples(args) => build_examples(&workspace, args),
|
||||
Cli::BuildPackage(args) => build_package(&workspace, args),
|
||||
Cli::BumpVersion(args) => bump_version(&workspace, args),
|
||||
}
|
||||
}
|
||||
|
||||
@ -107,6 +140,23 @@ fn build_examples(workspace: &Path, mut args: BuildExamplesArgs) -> Result<()> {
|
||||
.try_for_each(|example| xtask::build_example(&package_path, args.chip, target, example))
|
||||
}
|
||||
|
||||
fn build_package(workspace: &Path, args: BuildPackageArgs) -> Result<()> {
|
||||
// Absolute path of the package's root:
|
||||
let package_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.toolchain, args.target)
|
||||
}
|
||||
|
||||
fn bump_version(workspace: &Path, args: BumpVersionArgs) -> Result<()> {
|
||||
// Bump the version by the specified amount for each given package:
|
||||
for package in args.packages {
|
||||
xtask::bump_version(workspace, package, args.amount)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Helper Functions
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user