Skip to main content

harness_glob/
engine.rs

1use anyhow::Result;
2use ignore::WalkBuilder;
3use std::path::PathBuf;
4
5/// Pluggable engine — default enumerates files via `ignore::WalkBuilder`
6/// (the same machinery ripgrep uses for its ignore-aware walk). The
7/// pattern filter happens OUTSIDE this engine in the orchestrator,
8/// matching the TS design where the engine is pure enumeration.
9pub trait GlobEngine: Send + Sync {
10    fn list(&self, input: &GlobEngineInput) -> Result<Vec<String>>;
11}
12
13#[derive(Debug, Clone)]
14pub struct GlobEngineInput {
15    pub root: PathBuf,
16    pub max_filesize: u64,
17}
18
19pub fn default_engine() -> Box<dyn GlobEngine> {
20    Box::new(IgnoreWalkEngine)
21}
22
23pub struct IgnoreWalkEngine;
24
25impl GlobEngine for IgnoreWalkEngine {
26    fn list(&self, input: &GlobEngineInput) -> Result<Vec<String>> {
27        let mut wb = WalkBuilder::new(&input.root);
28        wb.hidden(true)
29            .git_ignore(true)
30            .git_global(true)
31            .git_exclude(true)
32            .ignore(true)
33            .parents(true)
34            .follow_links(false)
35            .max_filesize(Some(input.max_filesize))
36            .require_git(false)
37            .add_custom_ignore_filename(".rgignore");
38        let walker = wb.build();
39        let mut out: Vec<String> = Vec::new();
40        for entry in walker.flatten() {
41            let path = entry.path();
42            if !path.is_file() {
43                continue;
44            }
45            out.push(path.to_string_lossy().into_owned());
46        }
47        Ok(out)
48    }
49}