Skip to main content

xtask/
main.rs

1#![doc = include_str!("../README.md")]
2// A task runner's output is the point of running it: the child commands it
3// wraps inherit the terminal, and the progress it reports itself goes to
4// stdout and stderr. The workspace lints deny both everywhere else.
5#![expect(
6    clippy::print_stdout,
7    clippy::print_stderr,
8    reason = "reporting to the terminal is this binary's job"
9)]
10
11mod build_android;
12mod check;
13mod http;
14mod miri;
15mod print_gpu;
16mod publish;
17mod run_wasm;
18mod step;
19mod test;
20mod test_wasm;
21
22use argh::FromArgs;
23
24fn main() {
25    if let Err(error) = run() {
26        eprintln!("{error}");
27        std::process::exit(1);
28    }
29}
30
31fn run() -> Result<(), String> {
32    let args: Args = argh::from_env();
33    match args.task {
34        Task::Check(task) => check::run(task.release),
35        Task::Test(task) => test::run(task.release),
36        Task::TestWasm(task) => test_wasm::run(&task),
37        Task::Miri(task) => miri::run(&task),
38        Task::RunWasm(task) => run_wasm::run(&task),
39        Task::BuildAndroid(task) => build_android::run(&task),
40        Task::Publish(task) => publish::run(&task),
41        Task::PrintGpu(task) => print_gpu::run(&task),
42    }
43}
44
45/// The repository task runner.
46#[derive(FromArgs)]
47struct Args {
48    /// the task to run.
49    #[argh(subcommand)]
50    task: Task,
51}
52
53/// The tasks `cargo xtask` offers.
54///
55/// argh derives each variant's subcommand name from its payload struct, which
56/// must itself derive `FromArgs` and be declared as a subcommand.
57#[derive(FromArgs)]
58#[argh(subcommand)]
59enum Task {
60    /// Run the typo and TOML checks, then clippy and the doc build over the
61    /// whole workspace, then check formatting.
62    Check(CheckArgs),
63    /// Run the workspace's tests.
64    Test(TestArgs),
65    /// Run the GPU tests in a real browser, through wasm and WebGL2.
66    TestWasm(TestWasmArgs),
67    /// Run the ECS's tests under Miri, which is what checks its `unsafe`.
68    Miri(MiriArgs),
69    /// Build and serve the web examples.
70    RunWasm(RunWasmArgs),
71    /// Build the Android example's shared library and the APK around it.
72    BuildAndroid(BuildAndroidArgs),
73    /// Publish the workspace's crates to crates.io, in dependency order.
74    Publish(PublishArgs),
75    /// Print the GPU device the tests draw with, as JSON.
76    PrintGpu(PrintGpuArgs),
77}
78
79/// Arguments of `cargo xtask check`.
80#[derive(FromArgs)]
81#[argh(
82    subcommand,
83    name = "check",
84    description = "run the typo and TOML checks, clippy and the doc build over the whole workspace, then check formatting"
85)]
86struct CheckArgs {
87    /// build in release mode.
88    #[argh(switch)]
89    release: bool,
90}
91
92/// Arguments of `cargo xtask test`.
93#[derive(FromArgs)]
94#[argh(
95    subcommand,
96    name = "test",
97    description = "run the workspace's tests through nextest, then the doctests"
98)]
99struct TestArgs {
100    /// build in release mode.
101    #[argh(switch)]
102    release: bool,
103}
104
105/// Arguments of `cargo xtask test-wasm`.
106#[derive(FromArgs)]
107#[argh(
108    subcommand,
109    name = "test-wasm",
110    description = "run the GPU tests in a real browser through wasm and WebGL2"
111)]
112struct TestWasmArgs {
113    /// show the browser window, to watch a failure happen.
114    #[argh(switch)]
115    show: bool,
116}
117
118/// Arguments of `cargo xtask miri`.
119#[derive(FromArgs)]
120#[argh(
121    subcommand,
122    name = "miri",
123    description = "run the ECS's tests under Miri, which is what checks its unsafe"
124)]
125struct MiriArgs {}
126
127/// Arguments of `cargo xtask run-wasm`.
128#[derive(FromArgs)]
129#[argh(
130    subcommand,
131    name = "run-wasm",
132    description = "build the web examples and serve them for a browser"
133)]
134struct RunWasmArgs {
135    /// which examples to build and serve.
136    #[argh(option, default = "WebApp::All")]
137    app: WebApp,
138    /// build and bindgen only; do not serve.
139    #[argh(switch)]
140    no_serve: bool,
141    /// extra arguments for the cargo build.
142    #[argh(positional, greedy)]
143    cargo_args: Vec<String>,
144}
145
146/// Which web examples a wasm task covers.
147#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, argh::FromArgValue)]
148enum WebApp {
149    /// the unlit3d example alone.
150    Unlit3d,
151    /// the unlit3dx example alone.
152    Unlit3dx,
153    /// the landing page and both examples.
154    #[default]
155    All,
156}
157
158/// Arguments of `cargo xtask build-android`.
159#[derive(FromArgs)]
160#[argh(
161    subcommand,
162    name = "build-android",
163    description = "build the Android example's shared library and the APK around it"
164)]
165struct BuildAndroidArgs {
166    /// build a release APK instead of a debug one.
167    #[argh(switch)]
168    release: bool,
169}
170
171/// Arguments of `cargo xtask print-gpu`.
172#[derive(FromArgs)]
173#[argh(
174    subcommand,
175    name = "print-gpu",
176    description = "print the GPU device the tests draw with, as JSON"
177)]
178struct PrintGpuArgs {
179    /// report only this tier: webgpu, webgl2 or native. Omit to report every
180    /// tier `cargo xtask test` runs at.
181    #[argh(option)]
182    tier: Option<String>,
183}
184
185/// Arguments of `cargo xtask publish`.
186#[derive(FromArgs)]
187#[argh(
188    subcommand,
189    name = "publish",
190    description = "publish the workspace's crates to crates.io, in dependency order"
191)]
192struct PublishArgs {
193    /// extra arguments for every `cargo publish`; pass them after `--`.
194    #[argh(positional, greedy)]
195    cargo_args: Vec<String>,
196}