Add `xtask` crate (#4293)

Replaces only the cargo_deny.sh script for now. Can be expanded over
time to replace the other shell and python scripts, so only Rust is
needed to work with the repository.

Closes <https://github.com/emilk/egui/issues/2887>
Closes <https://github.com/emilk/egui/issues/4373>

---------

Co-authored-by: Emil Ernerfeldt <emil.ernerfeldt@gmail.com>
This commit is contained in:
YgorSouza 2024-04-21 19:26:16 +02:00 committed by GitHub
parent d68c8d70aa
commit 46b241eb94
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 176 additions and 19 deletions

View File

@ -4,3 +4,6 @@
# we don't use `[build]` because of rust analyzer's build cache invalidation https://github.com/emilk/eframe_template/issues/93
[target.wasm32-unknown-unknown]
rustflags = ["--cfg=web_sys_unstable_apis"]
[alias]
xtask = "run --quiet --package xtask --"

4
Cargo.lock generated
View File

@ -4762,6 +4762,10 @@ version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec7a2a501ed189703dba8b08142f057e887dfc4b2cc4db2d343ac6376ba3e0b9"
[[package]]
name = "xtask"
version = "0.27.2"
[[package]]
name = "yaml-rust"
version = "0.4.5"

View File

@ -14,6 +14,8 @@ members = [
"crates/epaint",
"examples/*",
"xtask",
]
[workspace.package]

View File

@ -1,21 +1,3 @@
#!/usr/bin/env bash
set -eu
script_path=$( cd "$(dirname "${BASH_SOURCE[0]}")" ; pwd -P )
cd "$script_path/.."
set -x
cargo install --quiet cargo-deny
cargo deny --all-features --log-level error --target aarch64-apple-darwin check
cargo deny --all-features --log-level error --target aarch64-linux-android check
cargo deny --all-features --log-level error --target i686-pc-windows-gnu check
cargo deny --all-features --log-level error --target i686-pc-windows-msvc check
cargo deny --all-features --log-level error --target i686-unknown-linux-gnu check
cargo deny --all-features --log-level error --target wasm32-unknown-unknown check
cargo deny --all-features --log-level error --target x86_64-apple-darwin check
cargo deny --all-features --log-level error --target x86_64-pc-windows-gnu check
cargo deny --all-features --log-level error --target x86_64-pc-windows-msvc check
cargo deny --all-features --log-level error --target x86_64-unknown-linux-gnu check
cargo deny --all-features --log-level error --target x86_64-unknown-linux-musl check
cargo deny --all-features --log-level error --target x86_64-unknown-redox check
cargo xtask deny

9
xtask/Cargo.toml Normal file
View File

@ -0,0 +1,9 @@
[package]
name = "xtask"
edition.workspace = true
license.workspace = true
rust-version.workspace = true
version.workspace = true
publish = false
[dependencies]

12
xtask/README.md Normal file
View File

@ -0,0 +1,12 @@
## xtask - Task automation
This crate is meant to automate common tasks on the repository. It serves as a
replacement for shell scripts that is more portable across host operating
systems (namely Windows) and hopefully also easier to work with for
contributors who are already familiar with Rust (and not necessarily with shell
scripting).
The executable can be invoked via the subcommand `cargo xtask`, thanks to an
alias defined in `.cargo/config.toml`.
For more information, see <https://github.com/matklad/cargo-xtask>.

60
xtask/src/deny.rs Normal file
View File

@ -0,0 +1,60 @@
//! Run `cargo deny`
//!
//! Also installs the subcommand if it is not already installed.
use std::process::Command;
use super::DynError;
pub fn deny(args: &[&str]) -> Result<(), DynError> {
if !args.is_empty() {
return Err(format!("Invalid arguments: {args:?}").into());
}
install_cargo_deny()?;
let targets = [
"aarch64-apple-darwin",
"aarch64-linux-android",
"i686-pc-windows-gnu",
"i686-pc-windows-msvc",
"i686-unknown-linux-gnu",
"wasm32-unknown-unknown",
"x86_64-apple-darwin",
"x86_64-pc-windows-gnu",
"x86_64-pc-windows-msvc",
"x86_64-unknown-linux-gnu",
"x86_64-unknown-linux-musl",
"x86_64-unknown-redox",
];
for target in targets {
let mut cmd = Command::new("cargo");
cmd.args([
"deny",
"--all-features",
"--log-level",
"error",
"--target",
target,
"check",
]);
super::utils::print_cmd(&cmd);
let status = cmd.status()?;
if !status.success() {
return Err(status.to_string().into());
}
}
Ok(())
}
fn install_cargo_deny() -> Result<(), DynError> {
let already_installed = Command::new("cargo")
.args(["deny", "--version"])
.output()
.is_ok_and(|out| out.status.success());
if already_installed {
return Ok(());
}
let mut cmd = Command::new("cargo");
cmd.args(["+stable", "install", "--quiet", "--locked", "cargo-deny"]);
let reason = "install cargo-deny";
super::utils::ask_to_run(cmd, true, reason)
}

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

@ -0,0 +1,40 @@
#![allow(clippy::print_stdout)]
#![allow(clippy::print_stderr)]
#![allow(clippy::exit)]
mod deny;
pub(crate) mod utils;
type DynError = Box<dyn std::error::Error>;
fn main() {
if let Err(e) = try_main() {
eprintln!("{e}");
std::process::exit(-1);
}
}
fn try_main() -> Result<(), DynError> {
let arg_strings: Vec<_> = std::env::args().skip(1).collect();
let args: Vec<_> = arg_strings.iter().map(String::as_str).collect();
match args.as_slice() {
&[] | &["-h"] | &["--help"] => print_help(),
&["deny", ..] => deny::deny(&args[1..])?,
c => Err(format!("Invalid arguments {c:?}"))?,
}
Ok(())
}
fn print_help() {
let help = "
xtask help
Subcommands
deny: Run cargo-deny for all targets
Options
-h, --help: print help and exit
";
println!("{help}");
}

45
xtask/src/utils.rs Normal file
View File

@ -0,0 +1,45 @@
use std::{
env,
io::{self, Write as _},
process::Command,
};
use super::DynError;
/// Print the command and its arguments as if the user had typed them
pub fn print_cmd(cmd: &Command) {
print!("{} ", cmd.get_program().to_string_lossy());
for arg in cmd.get_args() {
print!("{} ", arg.to_string_lossy());
}
println!();
}
/// Prompt user before running a command
///
/// Adapted from [miri](https://github.com/rust-lang/miri/blob/dba35d2be72f4b78343d1a0f0b4737306f310672/cargo-miri/src/util.rs#L181-L204)
pub fn ask_to_run(mut cmd: Command, ask: bool, reason: &str) -> Result<(), DynError> {
// Disable interactive prompts in CI (GitHub Actions, Travis, AppVeyor, etc).
// Azure doesn't set `CI` though (nothing to see here, just Microsoft being Microsoft),
// so we also check their `TF_BUILD`.
let is_ci = env::var_os("CI").is_some() || env::var_os("TF_BUILD").is_some();
if ask && !is_ci {
let mut buf = String::new();
print!("The script is going to run: \n\n`{cmd:?}`\n\n To {reason}.\nProceed? [Y/n] ",);
io::stdout().flush().unwrap();
io::stdin().read_line(&mut buf).unwrap();
match buf.trim().to_lowercase().as_ref() {
"" | "y" | "yes" => {}
"n" | "no" => return Err("Aborting as per your request".into()),
a => return Err(format!("Invalid answer `{a}`").into()),
};
} else {
eprintln!("Running `{cmd:?}` to {reason}.");
}
let status = cmd.status()?;
if !status.success() {
return Err(format!("failed to {reason}: {status}").into());
}
Ok(())
}