thoughts_tool/utils/
git.rs1use std::fmt::Write;
2use std::fs;
3use std::path::Path;
4
5use anyhow::Result;
6use tracing::info;
7
8pub fn ensure_gitignore_entry(
10 repo_path: &Path,
11 entry: &str,
12 comment: Option<&str>,
13) -> Result<bool> {
14 let gitignore_path = repo_path.join(".gitignore");
15
16 if gitignore_path.exists() {
18 let content = fs::read_to_string(&gitignore_path)?;
19
20 let entry_no_slash = entry.trim_start_matches('/');
22 let has_entry = content.lines().any(|line| {
23 let trimmed = line.trim();
24 trimmed == entry || trimmed == entry_no_slash || trimmed == format!("{entry_no_slash}/")
25 });
26
27 if has_entry {
28 Ok(false)
29 } else {
30 let mut new_content = content;
32 if !new_content.ends_with('\n') {
33 new_content.push('\n');
34 }
35 if let Some(comment_text) = comment {
36 new_content.push('\n');
37 let _ = writeln!(new_content, "# {comment_text}");
38 }
39 new_content.push_str(entry);
40 new_content.push('\n');
41
42 fs::write(&gitignore_path, new_content)?;
43 info!("Added {} to .gitignore", entry);
44 Ok(true)
45 }
46 } else {
47 let mut content = String::new();
49 if let Some(comment_text) = comment {
50 let _ = writeln!(content, "# {comment_text}");
51 }
52 let _ = writeln!(content, "{entry}");
53
54 fs::write(&gitignore_path, content)?;
55 info!("Created .gitignore with {} entry", entry);
56 Ok(true)
57 }
58}