feat(xtask): add --watch option for build-wasm and

`check-wasm-exports` xtask commands
This commit is contained in:
WillLillis 2025-01-06 22:36:16 -05:00 committed by Amaan Qureshi
parent 207ef9796e
commit 2c6f70cc57
5 changed files with 252 additions and 20 deletions

148
Cargo.lock generated
View file

@ -108,7 +108,7 @@ version = "0.71.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5f58bf3d7db68cfbac37cfc485a8d711e87e064c3d0fe0435b92f7a407f9d6b3"
dependencies = [
"bitflags",
"bitflags 2.6.0",
"cexpr",
"clang-sys",
"itertools 0.13.0",
@ -122,6 +122,12 @@ dependencies = [
"syn",
]
[[package]]
name = "bitflags"
version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
name = "bitflags"
version = "2.6.0"
@ -570,6 +576,15 @@ version = "2.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be"
[[package]]
name = "file-id"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6bc904b9bbefcadbd8e3a9fb0d464a9b979de6324c03b3c663e8994f46a5be36"
dependencies = [
"windows-sys 0.52.0",
]
[[package]]
name = "filetime"
version = "0.2.25"
@ -617,6 +632,15 @@ dependencies = [
"windows-sys 0.52.0",
]
[[package]]
name = "fsevent-sys"
version = "4.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "76ee7a02da4d231650c7cea31349b889be2f45ddb3ef3032d2ec8185f6313fd2"
dependencies = [
"libc",
]
[[package]]
name = "fuzzy-matcher"
version = "0.3.7"
@ -654,7 +678,7 @@ version = "0.19.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b903b73e45dc0c6c596f2d37eccece7c1c8bb6e4407b001096387c63d0d93724"
dependencies = [
"bitflags",
"bitflags 2.6.0",
"libc",
"libgit2-sys",
"log",
@ -881,6 +905,35 @@ version = "2.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b248f5224d1d606005e02c97f5aa4e88eeb230488bcc03bc9ca4d7991399f2b5"
[[package]]
name = "inotify"
version = "0.10.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fdd168d97690d0b8c412d6b6c10360277f4d7ee495c5d0d5d5fe0854923255cc"
dependencies = [
"bitflags 1.3.2",
"inotify-sys",
"libc",
]
[[package]]
name = "inotify-sys"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e05c02b5e89bff3b946cedeca278abc628fe811e604f027c45a8aa3cf793d0eb"
dependencies = [
"libc",
]
[[package]]
name = "instant"
version = "0.1.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e0242819d153cba4b4b05a5a8f2a7e9bbf97b6055b2a002b395c96b5ff3c0222"
dependencies = [
"cfg-if",
]
[[package]]
name = "is_terminal_polyfill"
version = "1.70.1"
@ -952,6 +1005,26 @@ dependencies = [
"wasm-bindgen",
]
[[package]]
name = "kqueue"
version = "1.0.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7447f1ca1b7b563588a205fe93dea8df60fd981423a768bc1c0ded35ed147d0c"
dependencies = [
"kqueue-sys",
"libc",
]
[[package]]
name = "kqueue-sys"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ed9625ffda8729b85e45cf04090035ac368927b8cebc34898e7c120f52e4838b"
dependencies = [
"bitflags 1.3.2",
"libc",
]
[[package]]
name = "lazy_static"
version = "1.5.0"
@ -1006,7 +1079,7 @@ version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d"
dependencies = [
"bitflags",
"bitflags 2.6.0",
"libc",
"redox_syscall",
]
@ -1094,6 +1167,18 @@ dependencies = [
"adler2",
]
[[package]]
name = "mio"
version = "1.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd"
dependencies = [
"libc",
"log",
"wasi",
"windows-sys 0.52.0",
]
[[package]]
name = "ndk-context"
version = "0.1.1"
@ -1106,7 +1191,7 @@ version = "0.29.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46"
dependencies = [
"bitflags",
"bitflags 2.6.0",
"cfg-if",
"cfg_aliases",
"libc",
@ -1122,6 +1207,47 @@ dependencies = [
"minimal-lexical",
]
[[package]]
name = "notify"
version = "7.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c533b4c39709f9ba5005d8002048266593c1cfaf3c5f0739d5b8ab0c6c504009"
dependencies = [
"bitflags 2.6.0",
"filetime",
"fsevent-sys",
"inotify",
"kqueue",
"libc",
"log",
"mio",
"notify-types",
"walkdir",
"windows-sys 0.52.0",
]
[[package]]
name = "notify-debouncer-full"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9dcf855483228259b2353f89e99df35fc639b2b2510d1166e4858e3f67ec1afb"
dependencies = [
"file-id",
"log",
"notify",
"notify-types",
"walkdir",
]
[[package]]
name = "notify-types"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "585d3cb5e12e01aed9e8a1f70d5c6b5e86fe2a6e48fc8cd0b3e0b8df6f6eb174"
dependencies = [
"instant",
]
[[package]]
name = "objc-sys"
version = "0.3.5"
@ -1150,7 +1276,7 @@ version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0ee638a5da3799329310ad4cfa62fbf045d5f56e3ef5ba4149e7452dcf89d5a8"
dependencies = [
"bitflags",
"bitflags 2.6.0",
"block2",
"libc",
"objc2",
@ -1337,7 +1463,7 @@ version = "0.5.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "03a862b389f93e68874fbf580b9de08dd02facb9a788ebadaf4a3fd33cf58834"
dependencies = [
"bitflags",
"bitflags 2.6.0",
]
[[package]]
@ -1409,7 +1535,7 @@ version = "0.38.42"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f93dc38ecbab2eb790ff964bb77fa94faf256fd3e73285fd7ba0903b76bedb85"
dependencies = [
"bitflags",
"bitflags 2.6.0",
"errno",
"libc",
"linux-raw-sys",
@ -2116,7 +2242,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c771866898879073c53b565a6c7b49953795159836714ac56a5befb581227c5"
dependencies = [
"ahash",
"bitflags",
"bitflags 2.6.0",
"hashbrown 0.14.5",
"indexmap",
"semver",
@ -2129,7 +2255,7 @@ version = "0.221.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9845c470a2e10b61dd42c385839cdd6496363ed63b5c9e420b5488b77bd22083"
dependencies = [
"bitflags",
"bitflags 2.6.0",
"hashbrown 0.15.2",
"indexmap",
"semver",
@ -2154,7 +2280,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5b79302e3e084713249cc5622e8608e7410afdeeea8c8026d04f491d1fab0b4b"
dependencies = [
"anyhow",
"bitflags",
"bitflags 2.6.0",
"bumpalo",
"cc",
"cfg-if",
@ -2646,6 +2772,8 @@ dependencies = [
"clap",
"git2",
"indoc",
"notify",
"notify-debouncer-full",
"regex",
"semver",
"serde",

View file

@ -28,3 +28,5 @@ semver.workspace = true
serde.workspace = true
serde_json.workspace = true
ureq = "2.12.1"
notify = "7.0.0"
notify-debouncer-full = "0.4.0"

View file

@ -1,13 +1,21 @@
use std::{
collections::HashSet,
ffi::{OsStr, OsString},
fmt::Write,
fs,
path::PathBuf,
process::Command,
time::Duration,
};
use anyhow::{anyhow, Result};
use notify::{
event::{AccessKind, AccessMode},
EventKind, RecursiveMode,
};
use notify_debouncer_full::new_debouncer;
use crate::{bail_on_err, BuildWasm, EMSCRIPTEN_TAG};
use crate::{bail_on_err, watch_wasm, BuildWasm, EMSCRIPTEN_TAG};
#[derive(PartialEq, Eq)]
enum EmccSource {
@ -95,9 +103,10 @@ pub fn run_wasm(args: &BuildWasm) -> Result<()> {
fs::create_dir_all("target/scratch").unwrap();
let exported_functions = concat!(
include_str!("../../lib/src/wasm/stdlib-symbols.txt"),
include_str!("../../lib/binding_web/exports.txt")
let exported_functions = format!(
"{}{}",
fs::read_to_string("lib/src/wasm/stdlib-symbols.txt")?,
fs::read_to_string("lib/binding_web/exports.txt")?
)
.replace('"', "")
.lines()
@ -159,9 +168,20 @@ pub fn run_wasm(args: &BuildWasm) -> Result<()> {
"-o",
"target/scratch/tree-sitter.js",
]);
let command = command.args(&emscripten_flags);
if args.watch {
watch_wasm!(|| build_wasm(command));
} else {
build_wasm(command)?;
}
Ok(())
}
fn build_wasm(cmd: &mut Command) -> Result<()> {
bail_on_err(
&command.args(emscripten_flags).spawn()?.wait_with_output()?,
&cmd.spawn()?.wait_with_output()?,
"Failed to compile the Tree-sitter WASM library",
)?;

View file

@ -1,12 +1,19 @@
use std::{
collections::HashSet,
io::BufRead,
path::PathBuf,
process::{Command, Stdio},
time::Duration,
};
use anyhow::{anyhow, Result};
use notify::{
event::{AccessKind, AccessMode},
EventKind, RecursiveMode,
};
use notify_debouncer_full::new_debouncer;
use crate::{bail_on_err, build_wasm::run_wasm, BuildWasm};
use crate::{bail_on_err, build_wasm::run_wasm, watch_wasm, BuildWasm, CheckWasmExports};
const EXCLUDES: [&str; 28] = [
// Unneeded because the JS side has its own way of implementing it
@ -44,15 +51,26 @@ const EXCLUDES: [&str; 28] = [
"ts_query_cursor_timeout_micros",
];
pub fn run() -> Result<()> {
pub fn run(args: &CheckWasmExports) -> Result<()> {
if args.watch {
watch_wasm!(check_wasm_exports);
} else {
check_wasm_exports()?;
}
Ok(())
}
fn check_wasm_exports() -> Result<()> {
// Build the wasm module with debug symbols for wasm-objdump
run_wasm(&BuildWasm {
debug: true,
verbose: false,
docker: false,
watch: false,
})?;
let mut wasm_exports = include_str!("../../lib/binding_web/exports.txt")
let mut wasm_exports = std::fs::read_to_string("lib/binding_web/exports.txt")?
.lines()
.map(|s| s.replace("_wasm", "").replace("byte", "index"))
// remove leading and trailing quotes, trailing comma

View file

@ -30,7 +30,7 @@ enum Commands {
/// Bumps the version of the workspace.
BumpVersion(BumpVersion),
/// Checks that WASM exports are synced.
CheckWasmExports,
CheckWasmExports(CheckWasmExports),
/// Runs `cargo clippy`.
Clippy(Clippy),
/// Fetches emscripten.
@ -82,6 +82,9 @@ struct BuildWasm {
/// Run emscripten with verbose output.
#[arg(long, short)]
verbose: bool,
/// Rebuild when relevant files are changed.
#[arg(long, short)]
watch: bool,
}
#[derive(Args)]
@ -91,6 +94,13 @@ struct BumpVersion {
version: Option<Version>,
}
#[derive(Args)]
struct CheckWasmExports {
/// Recheck when relevant files are changed.
#[arg(long, short)]
watch: bool,
}
#[derive(Args)]
struct Clippy {
/// Automatically apply lint suggestions (`clippy --fix`).
@ -207,7 +217,7 @@ fn run() -> Result<()> {
Commands::BuildWasm(build_wasm_options) => build_wasm::run_wasm(&build_wasm_options)?,
Commands::BuildWasmStdlib => build_wasm::run_wasm_stdlib()?,
Commands::BumpVersion(bump_options) => bump::run(bump_options)?,
Commands::CheckWasmExports => check_wasm_exports::run()?,
Commands::CheckWasmExports(check_options) => check_wasm_exports::run(&check_options)?,
Commands::Clippy(clippy_options) => clippy::run(&clippy_options)?,
Commands::FetchEmscripten => fetch::run_emscripten()?,
Commands::FetchFixtures => fetch::run_fixtures()?,
@ -289,3 +299,57 @@ pub fn create_commit(repo: &Repository, msg: &str, paths: &[&str]) -> Result<Oid
&[&parent_commit],
)?)
}
#[macro_export]
macro_rules! watch_wasm {
($watch_fn:expr) => {
if let Err(e) = $watch_fn() {
eprintln!("{e}");
}
let watch_files = [
"binding.c",
"binding.js",
"exports.txt",
"imports.js",
"prefix.js",
"suffix.js",
]
.iter()
.map(PathBuf::from)
.collect::<HashSet<PathBuf>>();
let (tx, rx) = std::sync::mpsc::channel();
let mut debouncer = new_debouncer(Duration::from_secs(1), None, tx)?;
debouncer.watch("lib/binding_web", RecursiveMode::NonRecursive)?;
for result in rx {
match result {
Ok(events) => {
for event in events {
if event.kind == EventKind::Access(AccessKind::Close(AccessMode::Write))
&& event
.paths
.iter()
.filter_map(|p| p.file_name())
.any(|p| watch_files.contains(&PathBuf::from(p)))
{
if let Err(e) = $watch_fn() {
eprintln!("{e}");
}
}
}
}
Err(errors) => {
return Err(anyhow!(
"{}",
errors
.into_iter()
.map(|e| e.to_string())
.collect::<Vec<_>>()
.join("\n")
));
}
}
}
};
}