cssforge_core/
discovery.rs1use 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}