From 29281b1f9320b739ea1aa47a4eb31b226de88be2 Mon Sep 17 00:00:00 2001 From: Will Lillis Date: Mon, 19 Jan 2026 22:48:30 -0500 Subject: [PATCH] feat(xtask): allow alternate branch for fixture grammars Set tree-sitter-php fixture to `upstream_test_fixture` branch. Also remove the `--update` flag, as it does nothing. --- crates/xtask/src/fetch.rs | 183 +++++++++++++++++++++++++++--------- crates/xtask/src/main.rs | 13 +-- test/fixtures/fixtures.json | 32 +++---- 3 files changed, 155 insertions(+), 73 deletions(-) diff --git a/crates/xtask/src/fetch.rs b/crates/xtask/src/fetch.rs index 6fa431c6..66a5862e 100644 --- a/crates/xtask/src/fetch.rs +++ b/crates/xtask/src/fetch.rs @@ -1,19 +1,74 @@ -use crate::{bail_on_err, root_dir, FetchFixtures, EMSCRIPTEN_VERSION}; +use crate::{bail_on_err, root_dir, EMSCRIPTEN_VERSION}; use anyhow::Result; -use std::{fs, process::Command}; +use std::{fs, path::Path, process::Command}; -pub fn run_fixtures(args: &FetchFixtures) -> Result<()> { +enum FixtureRef<'a> { + Tag(&'a str), + Branch(&'a str), +} + +impl<'a> FixtureRef<'a> { + #[allow(clippy::use_self)] + const fn new(tag: &'a str, branch: Option<&'a str>) -> FixtureRef<'a> { + if let Some(b) = branch { + Self::Branch(b) + } else { + Self::Tag(tag) + } + } + + const fn ref_type(&self) -> &'static str { + match self { + FixtureRef::Tag(_) => "tag", + FixtureRef::Branch(_) => "branch", + } + } +} + +impl std::fmt::Display for FixtureRef<'_> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + FixtureRef::Tag(tag) => write!(f, "{tag}"), + FixtureRef::Branch(branch) => write!(f, "{branch}"), + } + } +} + +fn current_ref_name(grammar_dir: &Path) -> Result<(String, Option<&'static str>)> { + let tag_args = ["describe", "--tags", "--exact-match", "HEAD"]; + let branch_args = ["rev-parse", "--abbrev-ref", "HEAD"]; + + for (args, ref_type) in [tag_args.as_ref(), branch_args.as_ref()] + .iter() + .zip(&["tag", "branch"]) + { + let name_cmd = Command::new("git") + .current_dir(grammar_dir) + .args(*args) + .output()?; + let name = String::from_utf8_lossy(&name_cmd.stdout); + let name = name.trim(); + if !name.is_empty() { + return Ok((name.to_string(), Some(ref_type))); + } + } + + Ok(("".to_string(), None)) +} + +pub fn run_fixtures() -> Result<()> { let fixtures_dir = root_dir().join("test").join("fixtures"); let grammars_dir = fixtures_dir.join("grammars"); let fixtures_path = fixtures_dir.join("fixtures.json"); - // grammar name, tag - let mut fixtures: Vec<(String, String)> = + // grammar name, tag, [branch] + let fixtures: Vec<(String, String, Option)> = serde_json::from_str(&fs::read_to_string(&fixtures_path)?)?; - for (grammar, tag) in &mut fixtures { - let grammar_dir = grammars_dir.join(&grammar); + for (grammar, tag, branch) in &fixtures { + let grammar_dir = grammars_dir.join(grammar); let grammar_url = format!("https://github.com/tree-sitter/tree-sitter-{grammar}"); + let target_ref = FixtureRef::new(tag, branch.as_deref()); println!("Fetching the {grammar} grammar..."); @@ -24,7 +79,7 @@ pub fn run_fixtures(args: &FetchFixtures) -> Result<()> { "--depth", "1", "--branch", - tag, + &target_ref.to_string(), &grammar_url, &grammar_dir.to_string_lossy(), ]); @@ -33,31 +88,71 @@ pub fn run_fixtures(args: &FetchFixtures) -> Result<()> { &format!("Failed to clone the {grammar} grammar"), )?; } else { - let mut describe_command = Command::new("git"); - describe_command.current_dir(&grammar_dir).args([ - "describe", - "--tags", - "--exact-match", - "HEAD", - ]); + let (current_ref, current_ref_type) = current_ref_name(&grammar_dir)?; + if current_ref != target_ref.to_string() { + println!( + "Updating {grammar} grammar from {} {current_ref} to {} {target_ref}...", + current_ref_type.unwrap_or(""), + target_ref.ref_type(), + ); - let output = describe_command.output()?; - let current_tag = String::from_utf8_lossy(&output.stdout); - let current_tag = current_tag.trim(); - - if current_tag != tag { - println!("Updating {grammar} grammar from {current_tag} to {tag}..."); - - let mut fetch_command = Command::new("git"); - fetch_command.current_dir(&grammar_dir).args([ - "fetch", - "origin", - &format!("refs/tags/{tag}:refs/tags/{tag}"), - ]); - bail_on_err( - &fetch_command.spawn()?.wait_with_output()?, - &format!("Failed to fetch tag {tag} for {grammar} grammar"), - )?; + match target_ref { + FixtureRef::Branch(branch) => { + let mut fetch_cmd = Command::new("git"); + fetch_cmd.current_dir(&grammar_dir).args([ + "fetch", + "--update-shallow", + "origin", + &format!("+refs/heads/{branch}:refs/remotes/origin/{branch}"), + ]); + bail_on_err( + &fetch_cmd.spawn()?.wait_with_output()?, + &format!("Failed to fetch branch {branch}"), + )?; + let mut switch_cmd = Command::new("git"); + switch_cmd + .current_dir(&grammar_dir) + .args(["switch", branch]); + bail_on_err( + &switch_cmd.spawn()?.wait_with_output()?, + &format!("Failed to checkout branch {branch}"), + )?; + let mut set_upstream_cmd = Command::new("git"); + set_upstream_cmd.current_dir(&grammar_dir).args([ + "branch", + "--set-upstream-to", + &format!("origin/{branch}"), + branch, + ]); + bail_on_err( + &set_upstream_cmd.spawn()?.wait_with_output()?, + &format!("Failed to set upstream for branch {branch}"), + )?; + let mut pull_cmd = Command::new("git"); + pull_cmd + .current_dir(&grammar_dir) + .args(["pull", "origin", branch]); + bail_on_err( + &pull_cmd.spawn()?.wait_with_output()?, + &format!("Failed to pull latest from branch {branch}"), + )?; + } + FixtureRef::Tag(tag) => { + let mut fetch_command = Command::new("git"); + fetch_command.current_dir(&grammar_dir).args([ + "fetch", + "origin", + &format!("refs/tags/{tag}:refs/tags/{tag}"), + ]); + bail_on_err( + &fetch_command.spawn()?.wait_with_output()?, + &format!( + "Failed to fetch {} {target_ref} for {grammar} grammar", + target_ref.ref_type() + ), + )?; + } + } let mut reset_command = Command::new("git"); reset_command @@ -71,29 +166,23 @@ pub fn run_fixtures(args: &FetchFixtures) -> Result<()> { let mut checkout_command = Command::new("git"); checkout_command .current_dir(&grammar_dir) - .args(["checkout", tag]); + .args(["checkout", &target_ref.to_string()]); bail_on_err( &checkout_command.spawn()?.wait_with_output()?, - &format!("Failed to checkout tag {tag} for {grammar} grammar"), + &format!( + "Failed to checkout {} {target_ref} for {grammar} grammar", + target_ref.ref_type() + ), )?; } else { - println!("{grammar} grammar is already at tag {tag}"); + println!( + "{grammar} grammar is already at {} {target_ref}", + target_ref.ref_type() + ); } } } - if args.update { - println!("Updating the fixtures lock file"); - fs::write( - &fixtures_path, - // format the JSON without extra newlines - serde_json::to_string(&fixtures)? - .replace("[[", "[\n [") - .replace("],", "],\n ") - .replace("]]", "]\n]"), - )?; - } - Ok(()) } diff --git a/crates/xtask/src/main.rs b/crates/xtask/src/main.rs index 3814cf66..28ebd86a 100644 --- a/crates/xtask/src/main.rs +++ b/crates/xtask/src/main.rs @@ -36,7 +36,7 @@ enum Commands { /// Fetches emscripten. FetchEmscripten, /// Fetches the fixtures for testing tree-sitter. - FetchFixtures(FetchFixtures), + FetchFixtures, /// Generate the Rust bindings from the C library. GenerateBindings, /// Generates the fixtures for testing tree-sitter. @@ -118,13 +118,6 @@ struct Clippy { package: Option, } -#[derive(Args)] -struct FetchFixtures { - /// Update all fixtures to the latest tag - #[arg(long, short)] - update: bool, -} - #[derive(Args)] struct GenerateFixtures { /// Generates the parser to Wasm @@ -232,8 +225,8 @@ fn run() -> Result<()> { 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_fixture_options) => { - fetch::run_fixtures(&fetch_fixture_options)?; + Commands::FetchFixtures => { + fetch::run_fixtures()?; } Commands::GenerateBindings => generate::run_bindings()?, Commands::GenerateFixtures(generate_fixtures_options) => { diff --git a/test/fixtures/fixtures.json b/test/fixtures/fixtures.json index c1e2b167..1e1596df 100644 --- a/test/fixtures/fixtures.json +++ b/test/fixtures/fixtures.json @@ -1,17 +1,17 @@ [ - ["bash","v0.25.0"], - ["c","v0.24.1"], - ["cpp","v0.23.4"], - ["embedded-template","v0.25.0"], - ["go","v0.25.0"], - ["html","v0.23.2"], - ["java","v0.23.5"], - ["javascript","v0.25.0"], - ["jsdoc","v0.23.2"], - ["json","v0.24.8"], - ["php","v0.24.2"], - ["python","v0.23.6"], - ["ruby","v0.23.1"], - ["rust","v0.24.0"], - ["typescript","v0.23.2"] -] \ No newline at end of file + ["bash","v0.25.0", null], + ["c","v0.24.1", null], + ["cpp","v0.23.4", null], + ["embedded-template","v0.25.0", null], + ["go","v0.25.0", null], + ["html","v0.23.2", null], + ["java","v0.23.5", null], + ["javascript","v0.25.0", null], + ["jsdoc","v0.23.2", null], + ["json","v0.24.8", null], + ["php","v0.24.2", "upstream_test_fixture"], + ["python","v0.23.6", null], + ["ruby","v0.23.1", null], + ["rust","v0.24.0", null], + ["typescript","v0.23.2", null] +]