Files
wgpu/xtask/src/process.rs
Erich Gubler 91d48b2923 build: move from make to cargo xtask workflows
Re-implement `naga` development workflows using [`cargo xtask`]. Convert
`make` logic and shader test configuration as file with Bash variables
into an `xtask` crate and YAML files, respectively.

Pros:

* We now have a _portable_ workflow everywhere, which means Windows
  folks and people who don't install `make` don't have to suffer.
  😮‍💨
* Workflow logic is now relatively easy to inspect and change. Whew!
  💁🏻‍♂️💦
* Contributors can use their existing Rust knowledge to contribute to
  developer experience. 🎉
* `cargo xtask` is a relatively well-known convention for workflows in
  the ecosystem.
* We can do fancy things like allow folks to run at different log levels
  for workflows, depending on their tastes.

Cons:

* There's now a non-trivial compile step to project workflow.
  Incremental rebuilds seem to be pretty short, though!
* Code is much more verbose than the (very) terse `make` implementation.

[`cargo xtask`]: https://github.com/matklad/cargo-xtask
2023-06-08 16:56:57 +02:00

79 lines
1.9 KiB
Rust

use std::{
ffi::{OsStr, OsString},
fmt::{self, Display},
iter::once,
ops::{Deref, DerefMut},
process::Command,
};
use anyhow::{ensure, Context};
#[derive(Debug)]
pub(crate) struct EasyCommand {
inner: Command,
}
impl EasyCommand {
pub fn new<C>(cmd: C, config: impl FnOnce(&mut Command) -> &mut Command) -> Self
where
C: AsRef<OsStr>,
{
let mut inner = Command::new(cmd);
config(&mut inner);
Self { inner }
}
pub fn simple<C, A, I>(cmd: C, args: I) -> Self
where
C: AsRef<OsStr>,
A: AsRef<OsStr>,
I: IntoIterator<Item = A>,
{
Self::new(cmd, |cmd| cmd.args(args))
}
pub fn success(&mut self) -> anyhow::Result<()> {
let Self { inner } = self;
log::debug!("running {inner:?}");
let status = inner
.status()
.with_context(|| format!("failed to run {self}"))?;
ensure!(
status.success(),
"{self} failed to run; exit code: {:?}",
status.code()
);
Ok(())
}
}
impl Deref for EasyCommand {
type Target = Command;
fn deref(&self) -> &Self::Target {
&self.inner
}
}
impl DerefMut for EasyCommand {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.inner
}
}
pub(crate) fn which(binary_name: &str) -> anyhow::Result<OsString> {
::which::which(binary_name)
.with_context(|| format!("unable to find `{binary_name}` binary"))
.map(|buf| buf.file_name().unwrap().to_owned())
}
impl Display for EasyCommand {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let Self { inner } = self;
let prog = inner.get_program().to_string_lossy();
let args = inner.get_args().map(|a| a.to_string_lossy());
let shell_words = shell_words::join(once(prog).chain(args));
write!(f, "`{shell_words}`")
}
}