xtask runner for CI types of things and other utilities.

This commit is contained in:
Bob McWhirter 2021-08-17 12:15:24 -04:00
parent bc57d6839f
commit 61e6b52870
3 changed files with 245 additions and 0 deletions

6
xtask/.cargo/config Normal file
View File

@ -0,0 +1,6 @@
[alias]
xtask = "run --package xtask --"
ci = "run --package xtask -- ci"
core = "run --package xtask -- core"
examples = "run --package xtask -- examples"
fmt = "run --package xtask -- fmt"

14
xtask/Cargo.toml Normal file
View File

@ -0,0 +1,14 @@
[package]
authors = [
"Ulf Lilleengen <lulf@redhat.com>",
"Bob McWhirter <bmcwhirt@redhat.com>"
]
edition = "2018"
name = "xtask"
version = "0.1.0"
[dependencies]
anyhow = "1.0"
xshell = "0.1"
yaml-rust = "0.4"
walkdir = "2.3.2"

225
xtask/src/main.rs Normal file
View File

@ -0,0 +1,225 @@
#![allow(dead_code)]
#![deny(unused_must_use)]
use std::format;
use std::{env, fs, path::PathBuf};
use std::path::Path;
use walkdir::WalkDir;
use xshell::{cmd, Cmd};
use yaml_rust::YamlLoader;
extern crate yaml_rust;
fn main() -> Result<(), anyhow::Error> {
let args = env::args().skip(1).collect::<Vec<_>>();
let args = args.iter().map(|s| &**s).collect::<Vec<_>>();
match &args[..] {
["ci"] => task_ci()?,
["core"] => task_check(Realm::Core)?,
["metapac"] => task_metapac_gen()?,
["examples"] => task_check(Realm::Examples)?,
["fmt-check"] => task_cargo_fmt_check()?,
["fmt"] => task_cargo_fmt()?,
_ => {
println!("");
println!("USAGE: cargo xtask [command]");
println!("");
println!("Commands:");
println!(" ci :: Runs entire CI");
println!(" core :: Builds the core");
println!(" metapac :: Builds the metapac");
println!(" examples :: Builds the examples");
println!(" fmt-check :: Checks rustfmt");
println!(" fmt :: Performs rustfmt");
println!("");
}
}
Ok(())
}
fn task_ci() -> Result<(), anyhow::Error> {
task_check(Realm::Core)?;
task_check(Realm::Examples)?;
task_metapac_gen()?;
task_cargo_fmt_check()?;
Ok(())
}
#[derive(Copy, Clone)]
enum Realm {
All,
Core,
Examples,
}
impl Realm {
fn accepts(&self, package: &str) -> bool {
match self {
Realm::All => true,
Realm::Core => !package.contains("examples"),
Realm::Examples => package.contains("examples"),
}
}
}
fn task_check(realm: Realm) -> Result<(), anyhow::Error> {
let _e = xshell::pushenv("CI", "true");
let matrix_yaml = root_dir()
.join(".github")
.join("workflows")
.join("rust.yml");
let matrix = YamlLoader::load_from_str(&*fs::read_to_string(matrix_yaml).unwrap()).unwrap();
let matrix = &matrix.get(0).unwrap()["jobs"]["ci"]["strategy"]["matrix"]["include"];
let entries = matrix.as_vec().unwrap();
for entry in entries {
let package = entry["package"].as_str().unwrap();
if !realm.accepts(package) {
continue;
}
let target = entry["target"].as_str().unwrap();
let features = entry["features"].as_str();
let package_dir = root_dir().join(entry["package"].as_str().unwrap());
let _p = xshell::pushd(package_dir)?;
banner(&*format!(
"Building {} [target={}] [features={}]",
package,
target,
features.unwrap_or("default-features")
));
let root_cargo_dir = root_dir().join(".cargo");
fs::create_dir_all(root_cargo_dir.clone()).unwrap();
fs::write(
root_cargo_dir.join("config"),
"[target.\"cfg(all())\"]\nrustflags = [\"-D\", \"warnings\"]",
)
.unwrap();
let mut args = Vec::new();
args.push("check");
args.push("--target");
args.push(target);
if let Some(features) = features {
args.push("--features");
args.push(features);
}
let command = Cmd::new(PathBuf::from("cargo"));
let command = command.args(args);
let result = command.run();
fs::remove_file(root_cargo_dir.join("config")).unwrap();
result?;
}
Ok(())
}
fn task_metapac_gen() -> Result<(), anyhow::Error> {
banner("Building metapac");
let _p = xshell::pushd(root_dir().join("stm32-metapac-gen"));
cmd!("cargo run").run()?;
Ok(())
}
fn task_cargo_fmt() -> Result<(), anyhow::Error> {
for entry in WalkDir::new(root_dir())
.follow_links(false)
.into_iter()
.filter_map(|e| e.ok())
{
let f_name = entry.file_name().to_string_lossy();
if f_name.ends_with(".rs") {
if !is_primary_source(entry.path()) {
continue;
}
let mut args = Vec::new();
args.push("--skip-children");
args.push("--unstable-features");
args.push("--edition=2018");
args.push(&*entry.path().to_str().unwrap());
let command = Cmd::new("rustfmt");
command.args(args).run()?;
}
}
Ok(())
}
fn task_cargo_fmt_check() -> Result<(), anyhow::Error> {
let mut actual_result = Ok(());
for entry in WalkDir::new(root_dir())
.follow_links(false)
.into_iter()
.filter_map(|e| e.ok())
{
let f_name = entry.file_name().to_string_lossy();
if f_name.ends_with(".rs") {
if !is_primary_source(entry.path()) {
continue;
}
let mut args = Vec::new();
args.push("--check");
args.push("--skip-children");
args.push("--unstable-features");
args.push("--edition=2018");
args.push(&*entry.path().to_str().unwrap());
let command = Cmd::new("rustfmt");
if let Err(result) = command.args(args).run() {
actual_result = Err(result.into());
}
}
}
actual_result
}
fn root_dir() -> PathBuf {
let mut xtask_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
xtask_dir.pop();
xtask_dir
}
fn examples_dir() -> PathBuf {
root_dir().join("examples")
}
fn is_primary_source(path: &Path) -> bool {
let mut current = path;
loop {
let current_file_name = current.file_name().unwrap().to_str().unwrap();
if current_file_name == "target"
|| current_file_name == "stm32-metapac-gen"
|| current_file_name == "stm32-data"
{
return false;
}
if let Some(path) = current.parent() {
current = path.into();
if current == root_dir() {
return true;
}
} else {
return false;
}
}
}
fn banner(text: &str) {
println!("------------------------------------------------------------------------------------------------------------------------------------------------");
println!("== {}", text);
println!("------------------------------------------------------------------------------------------------------------------------------------------------");
}