use std::{fs::OpenOptions, io::Write, path::Path};
use crate::config::AppConfig;
pub fn ensure_stakpak_in_gitignore(config: &AppConfig) -> Result<bool, String> {
if !config.auto_append_gitignore.unwrap_or(true) {
return Ok(false);
}
let current_dir =
std::env::current_dir().map_err(|e| format!("Failed to get current directory: {}", e))?;
let git_info = crate::utils::local_context::get_git_info(¤t_dir.to_string_lossy());
if !git_info.is_git_repo {
return Ok(false);
}
let gitignore_path = current_dir.join(".gitignore");
if gitignore_path.exists() {
let status = check_and_update_gitignore(&gitignore_path)?;
Ok(status)
} else {
append_stakpak_to_gitignore(&gitignore_path)?;
Ok(true)
}
}
fn check_and_update_gitignore(gitignore_path: &Path) -> Result<bool, String> {
let content = std::fs::read_to_string(gitignore_path)
.map_err(|e| format!("Failed to read .gitignore: {}", e))?;
let lines: Vec<&str> = content.lines().collect();
let mut has_session_pattern = false;
let mut has_old_pattern = false;
let mut old_pattern_index = None;
for (i, line) in lines.iter().enumerate() {
let trimmed = line.trim();
if trimmed == ".stakpak/session*" {
has_session_pattern = true;
break;
} else if trimmed == ".stakpak" || trimmed == ".stakpak/" {
has_old_pattern = true;
old_pattern_index = Some(i);
}
}
if has_session_pattern {
return Ok(false);
}
if has_old_pattern && let Some(index) = old_pattern_index {
let mut new_lines = lines.clone();
new_lines[index] = ".stakpak/session*";
let new_content = new_lines.join("\n");
let new_content = if content.ends_with('\n') {
format!("{}\n", new_content)
} else {
new_content
};
std::fs::write(gitignore_path, new_content)
.map_err(|e| format!("Failed to update .gitignore: {}", e))?;
return Ok(true);
}
append_stakpak_to_gitignore(gitignore_path)?;
Ok(true)
}
fn append_stakpak_to_gitignore(gitignore_path: &Path) -> Result<(), String> {
let mut file = OpenOptions::new()
.create(true)
.append(true)
.open(gitignore_path)
.map_err(|e| format!("Failed to open/create .gitignore: {}", e))?;
let needs_newline = if gitignore_path.exists() {
let metadata = std::fs::metadata(gitignore_path)
.map_err(|e| format!("Failed to get .gitignore metadata: {}", e))?;
if metadata.len() > 0 {
let content = std::fs::read(gitignore_path)
.map_err(|e| format!("Failed to read .gitignore: {}", e))?;
!content.ends_with(b"\n")
} else {
false
}
} else {
false
};
if needs_newline {
writeln!(file).map_err(|e| format!("Failed to write newline to .gitignore: {}", e))?;
}
if gitignore_path.exists()
&& let Ok(metadata) = std::fs::metadata(gitignore_path)
&& metadata.len() > 0
{
writeln!(file).map_err(|e| format!("Failed to write blank line to .gitignore: {}", e))?;
}
writeln!(file, "# Stakpak session files")
.map_err(|e| format!("Failed to write comment to .gitignore: {}", e))?;
writeln!(file, ".stakpak/session*")
.map_err(|e| format!("Failed to write .stakpak/session* to .gitignore: {}", e))?;
Ok(())
}
pub fn is_git_repo() -> bool {
let current_dir = std::env::current_dir().unwrap_or_default();
let git_info = crate::utils::local_context::get_git_info(¤t_dir.to_string_lossy());
git_info.is_git_repo
}