diff --git a/xtask/Cargo.toml b/xtask/Cargo.toml index 675f279..638d1d9 100644 --- a/xtask/Cargo.toml +++ b/xtask/Cargo.toml @@ -8,5 +8,6 @@ publish = false [dependencies] anyhow = "1" -pico-args = "0.3" smoljson = "0.1" +xshell = "0.1" +xflags = "0.1" diff --git a/xtask/src/bindgen.rs b/xtask/src/bindgen.rs index bdbf060..6bcc693 100644 --- a/xtask/src/bindgen.rs +++ b/xtask/src/bindgen.rs @@ -1,17 +1,12 @@ +use crate::flags::Bindgen; use anyhow::{anyhow, Context, Result}; use std::path::{Path, PathBuf}; -pub struct GenBindings { - pub bindings_path: Option, - pub output_path: Option, - pub wasm_import_name: Option, -} - -impl GenBindings { +impl Bindgen { pub fn run(self) -> Result<()> { let root = crate::project_root(); let bindings = self - .bindings_path + .cimgui_path .map(PathBuf::from) .unwrap_or_else(|| root.join("imgui-sys/third-party")); @@ -24,6 +19,7 @@ impl GenBindings { .wasm_import_name .or_else(|| std::env::var("IMGUI_RS_WASM_IMPORT_NAME").ok()) .unwrap_or_else(|| "imgui-sys-v0".to_string()); + let types = get_types(&bindings.join("structs_and_enums.json"))?; let funcs = get_definitions(&bindings.join("definitions.json"))?; let header = bindings.join("cimgui.h"); @@ -147,15 +143,3 @@ fn generate_binding_file( Ok(()) } - -// impl Deref for CountingCommand { -// type Target = std::process::Command; -// fn deref(&self) -> &Self::Target { -// &self.c -// } -// } -// impl std::ops::DerefMut for CountingCommand { -// fn deref_mut(&mut self) -> &mut Self::Target { -// &mut self.c -// } -// } diff --git a/xtask/src/flags.rs b/xtask/src/flags.rs new file mode 100644 index 0000000..636b727 --- /dev/null +++ b/xtask/src/flags.rs @@ -0,0 +1,88 @@ +//! xflags is a bit jank still, but pretty nice compared to pico_args, and +//! compiles a billion times faster than clap/structopt. +//! +//! When you modify stuff in the args_parser block, you'll get compile errors. +//! to fix these: +//! 1. run `env XFLAGS_DUMP= cargo build` in the shell. +//! 2. this will error, but should spit out a block of code delimited by +//! "generated start" and "generated end" comments. (if not, you probably +//! have an error message about your usage of the macro, fix and retry) +//! 3. Copy the generated code, and replace the bottom of this file with it. +//! +//! Also, rust-analyzer says this file has a "unresolved macro call". I don't +//! know why, just ignore it — it goes away if you close this file. + +#![allow(dead_code)] + +xflags::args_parser! { + /// Run custom build command. + cmd xtask { + optional -v, --verbose + + default cmd help { + /// Print help information. + optional -h, --help + } + /// Run lints the way we'd run it in CI + cmd lint {} + /// Run tests the way we'd run them in CI + cmd test {} + + /// produce bindings using bindgen (must have bindgen installed) + cmd bindgen { + optional --cimgui-path cimgui_path: String + optional --output-path output_path: String + optional --wasm-import-name wasm_import_name: String + } + } +} + +// generated start +// The following code is generated by `xflags` macro. +// Run `env XFLAGS_DUMP= cargo build` to regenerate. +#[derive(Debug)] +pub struct Xtask { + pub verbose: bool, + pub subcommand: XtaskCmd, +} + +#[derive(Debug)] +pub enum XtaskCmd { + Help(Help), + Lint(Lint), + Test(Test), + Bindgen(Bindgen), +} + +#[derive(Debug)] +pub struct Help { + pub help: bool, +} + +#[derive(Debug)] +pub struct Lint {} + +#[derive(Debug)] +pub struct Test {} + +#[derive(Debug)] +pub struct Bindgen { + pub cimgui_path: Option, + pub output_path: Option, + pub wasm_import_name: Option, +} + +impl Xtask { + pub const HELP: &'static str = Self::_HELP; + + pub fn from_env() -> xflags::Result { + let mut p = xflags::rt::Parser::new_from_env(); + Self::_parse(&mut p) + } + + pub fn from_vec(args: Vec) -> xflags::Result { + let mut p = xflags::rt::Parser::new(args); + Self::_parse(&mut p) + } +} +// generated end diff --git a/xtask/src/lib.rs b/xtask/src/lib.rs deleted file mode 100644 index cb0d688..0000000 --- a/xtask/src/lib.rs +++ /dev/null @@ -1,30 +0,0 @@ -use std::{ - env, - path::{Path, PathBuf}, -}; - -pub mod bindgen; - -pub fn project_root() -> PathBuf { - Path::new( - &env::var("CARGO_MANIFEST_DIR").unwrap_or_else(|_| env!("CARGO_MANIFEST_DIR").to_owned()), - ) - .ancestors() - .nth(1) - .unwrap() - .to_path_buf() -} - -pub fn pushd(p: impl AsRef) -> std::io::Result { - let cwd = std::env::current_dir()?; - std::env::set_current_dir(p.as_ref())?; - Ok(Pushd(cwd)) -} -pub struct Pushd(PathBuf); -impl Drop for Pushd { - fn drop(&mut self) { - if let Err(e) = std::env::set_current_dir(&self.0) { - eprintln!("warning: popd failed: {:?}", e); - } - } -} diff --git a/xtask/src/main.rs b/xtask/src/main.rs index e6aa30f..4ab8e9e 100644 --- a/xtask/src/main.rs +++ b/xtask/src/main.rs @@ -1,7 +1,9 @@ +mod bindgen; +mod flags; + use anyhow::Result; -use pico_args::Arguments; -use xtask::bindgen::GenBindings; -use xtask::{project_root, pushd}; +use flags::XtaskCmd; +use std::path::{Path, PathBuf}; fn main() { if let Err(e) = try_main() { @@ -13,47 +15,59 @@ fn main() { } } -const HELP: &str = "\ -cargo xtask -Run custom build command. - -USAGE: - cargo xtask - -SUBCOMMANDS: - bindgen - produce bindings using bindgen \ - must have bindgen installed, may require unix \ - as we pass `bindgen` very many CLI args -TODO: - run - run or list examples - lint-all - run clippy as we would in CI - test-all - run the tests we'd run in CI -"; - fn try_main() -> Result<()> { - let _g = pushd(project_root())?; - - let mut args = Arguments::from_env(); - let subcommand = args.subcommand()?.unwrap_or_default(); - - match subcommand.as_str() { - "bindgen" => { - // none of these are required. - let cmd = GenBindings { - // defaults to /imgui-sys/third-party - bindings_path: args.opt_value_from_str("--cimgui-dir")?, - // defaults to /imgui-sys/src - output_path: args.opt_value_from_str("--output-dir")?, - // defaults to "imgui-sys-v0", but can be set in - // env("IMGUI_RS_WASM_IMPORT_NAME") - wasm_import_name: args.opt_value_from_str("--wasm-import-name")?, - }; - args.finish()?; - cmd.run()?; - } - _ => { - eprintln!("{}", HELP); - } + let root = project_root(); + let _d = xshell::pushd(&root)?; + let flags = flags::Xtask::from_env()?; + if flags.verbose { + VERBOSE.store(true, std::sync::atomic::Ordering::Relaxed); + } + match flags.subcommand { + XtaskCmd::Help(_) => eprintln!("{}", flags::Xtask::HELP), + XtaskCmd::Lint(_) => lint_all()?, + XtaskCmd::Test(_) => test_all()?, + XtaskCmd::Bindgen(cmd) => cmd.run()?, } Ok(()) } + +fn lint_all() -> Result<()> { + xshell::cmd!("cargo clippy --workspace --all-targets").run()?; + xshell::cmd!( + "cargo clippy --manifest-path imgui-winit-support/Cargo.toml --all-features --all-targets" + ) + .run()?; + let winits = &["winit-19", "winit-20", "winit-22", "winit-23", "winit-24"]; + for &winit in winits { + xshell::cmd!("cargo clippy --manifest-path imgui-winit-support/Cargo.toml --no-default-features --features {winit} --all-targets").run()?; + } + xshell::cmd!("cargo fmt --all -- --check").run()?; + Ok(()) +} + +fn test_all() -> Result<()> { + xshell::cmd!("cargo test --workspace --all-targets").run()?; + xshell::cmd!("cargo test --workspace --doc").run()?; + let winits = &["winit-19", "winit-20", "winit-22", "winit-23", "winit-24"]; + for &winit in winits { + xshell::cmd!("cargo test --manifest-path imgui-winit-support/Cargo.toml --no-default-features --features {winit} --all-targets").run()?; + } + xshell::cmd!("cargo test -p imgui --release -- --ignored").run()?; + Ok(()) +} + +static VERBOSE: std::sync::atomic::AtomicBool = std::sync::atomic::AtomicBool::new(false); +pub fn verbose() -> bool { + VERBOSE.load(std::sync::atomic::Ordering::Relaxed) +} + +pub fn project_root() -> PathBuf { + Path::new( + &std::env::var("CARGO_MANIFEST_DIR") + .unwrap_or_else(|_| env!("CARGO_MANIFEST_DIR").to_owned()), + ) + .ancestors() + .nth(1) + .unwrap() + .to_path_buf() +}