Skip to main content

cssforge_core/
discovery.rs

1use anyhow::{Context, Result};
2use ignore::WalkBuilder;
3use std::{
4    path::{Path, PathBuf},
5    process::Command,
6};
7
8pub fn discover_css_files(root: &Path) -> Result<Vec<PathBuf>> {
9    if root.is_file() {
10        if root
11            .extension()
12            .and_then(|s| s.to_str())
13            .is_some_and(|ext| ext.eq_ignore_ascii_case("css"))
14        {
15            return Ok(vec![root.to_path_buf()]);
16        }
17        return Ok(Vec::new());
18    }
19
20    let mut files = Vec::new();
21    let walker = WalkBuilder::new(root)
22        .hidden(false)
23        .git_ignore(true)
24        .git_global(true)
25        .git_exclude(true)
26        .parents(true)
27        .build();
28
29    for entry in walker {
30        let entry = entry.with_context(|| format!("failed while walking {}", root.display()))?;
31        if !entry.file_type().is_some_and(|ft| ft.is_file()) {
32            continue;
33        }
34        let path = entry.into_path();
35        if path
36            .extension()
37            .and_then(|s| s.to_str())
38            .is_some_and(|ext| ext.eq_ignore_ascii_case("css"))
39        {
40            files.push(path);
41        }
42    }
43
44    files.sort();
45    Ok(files)
46}
47
48pub fn is_git_dirty(path: &Path) -> bool {
49    let cwd = if path.is_dir() {
50        path
51    } else {
52        path.parent().unwrap_or_else(|| Path::new("."))
53    };
54    Command::new("git")
55        .arg("status")
56        .arg("--porcelain")
57        .current_dir(cwd)
58        .output()
59        .ok()
60        .filter(|out| out.status.success())
61        .is_some_and(|out| !out.stdout.is_empty())
62}