Skip to content

Commit

Permalink
Add xtask crate (#4293)
Browse files Browse the repository at this point in the history
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 <#2887>
Closes <#4373>

---------

Co-authored-by: Emil Ernerfeldt <[email protected]>
  • Loading branch information
YgorSouza and emilk authored Apr 21, 2024
1 parent d68c8d7 commit 46b241e
Show file tree
Hide file tree
Showing 9 changed files with 176 additions and 19 deletions.
3 changes: 3 additions & 0 deletions .cargo/config.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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 changes: 4 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ members = [
"crates/epaint",

"examples/*",

"xtask",
]

[workspace.package]
Expand Down
20 changes: 1 addition & 19 deletions scripts/cargo_deny.sh
Original file line number Diff line number Diff line change
@@ -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 changes: 9 additions & 0 deletions xtask/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
[package]
name = "xtask"
edition.workspace = true
license.workspace = true
rust-version.workspace = true
version.workspace = true
publish = false

[dependencies]
12 changes: 12 additions & 0 deletions xtask/README.md
Original file line number Diff line number Diff line change
@@ -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 changes: 60 additions & 0 deletions xtask/src/deny.rs
Original file line number Diff line number Diff line change
@@ -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 changes: 40 additions & 0 deletions xtask/src/main.rs
Original file line number Diff line number Diff line change
@@ -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 changes: 45 additions & 0 deletions xtask/src/utils.rs
Original file line number Diff line number Diff line change
@@ -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(())
}

0 comments on commit 46b241e

Please sign in to comment.