summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYgorSouza <43298013+YgorSouza@users.noreply.github.com>2024-04-21 19:26:16 +0200
committerGitHub <noreply@github.com>2024-04-21 19:26:16 +0200
commit46b241eb94f6bc9234c20d69159c5b4c5f784add (patch)
tree5e8d58c913fadab50f774e0507f3b45b3adfb939
parentd68c8d70aa1dd5c44bd1a83a9f6aa8247e7c5c3b (diff)
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>
-rw-r--r--.cargo/config.toml3
-rw-r--r--Cargo.lock4
-rw-r--r--Cargo.toml2
-rwxr-xr-xscripts/cargo_deny.sh20
-rw-r--r--xtask/Cargo.toml9
-rw-r--r--xtask/README.md12
-rw-r--r--xtask/src/deny.rs60
-rw-r--r--xtask/src/main.rs40
-rw-r--r--xtask/src/utils.rs45
9 files changed, 176 insertions, 19 deletions
diff --git a/.cargo/config.toml b/.cargo/config.toml
index be614b00..b18b6ce7 100644
--- a/.cargo/config.toml
+++ b/.cargo/config.toml
@@ -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 --"
diff --git a/Cargo.lock b/Cargo.lock
index 112c7d78..8698db26 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -4763,6 +4763,10 @@ 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"
source = "registry+https://github.com/rust-lang/crates.io-index"
diff --git a/Cargo.toml b/Cargo.toml
index 598eae08..425eb8de 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -14,6 +14,8 @@ members = [
"crates/epaint",
"examples/*",
+
+ "xtask",
]
[workspace.package]
diff --git a/scripts/cargo_deny.sh b/scripts/cargo_deny.sh
index 560b8efd..bf811e85 100755
--- a/scripts/cargo_deny.sh
+++ b/scripts/cargo_deny.sh
@@ -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
diff --git a/xtask/Cargo.toml b/xtask/Cargo.toml
new file mode 100644
index 00000000..ba5b9382
--- /dev/null
+++ b/xtask/Cargo.toml
@@ -0,0 +1,9 @@
+[package]
+name = "xtask"
+edition.workspace = true
+license.workspace = true
+rust-version.workspace = true
+version.workspace = true
+publish = false
+
+[dependencies]
diff --git a/xtask/README.md b/xtask/README.md
new file mode 100644
index 00000000..bb5e9277
--- /dev/null
+++ b/xtask/README.md
@@ -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>.
diff --git a/xtask/src/deny.rs b/xtask/src/deny.rs
new file mode 100644
index 00000000..5c24949b
--- /dev/null
+++ b/xtask/src/deny.rs
@@ -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)
+}
diff --git a/xtask/src/main.rs b/xtask/src/main.rs
new file mode 100644
index 00000000..b1946292
--- /dev/null
+++ b/xtask/src/main.rs
@@ -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}");
+}
diff --git a/xtask/src/utils.rs b/xtask/src/utils.rs
new file mode 100644
index 00000000..760c27f8
--- /dev/null
+++ b/xtask/src/utils.rs
@@ -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(())
+}