use anyhow::{Context, Result};
use regex::Regex;
use std::path::Path;
use std::process::{Command, Stdio};
use crate::log_debug;
pub fn is_inside_work_tree() -> Result<bool> {
let status = Command::new("git")
.args(["rev-parse", "--is-inside-work-tree"])
.stdout(Stdio::null())
.stderr(Stdio::null())
.status();
match status {
Ok(exit) => Ok(exit.success()),
Err(_) => Ok(false),
}
}
#[must_use]
pub fn is_binary_diff(diff: &str) -> bool {
diff.contains("Binary files")
|| diff.contains("GIT binary patch")
|| diff.contains("[Binary file changed]")
}
pub fn run_git_command(args: &[&str]) -> Result<String> {
let output = Command::new("git")
.args(args)
.output()
.context("Failed to execute git command")?;
if !output.status.success() {
return Err(anyhow::anyhow!(
"Git command failed: {}",
String::from_utf8_lossy(&output.stderr)
));
}
let stdout =
String::from_utf8(output.stdout).context("Invalid UTF-8 output from git command")?;
Ok(stdout.trim().to_string())
}
#[must_use]
pub fn should_exclude_file(path: &str) -> bool {
log_debug!("Checking if file should be excluded: {}", path);
let exclude_patterns = vec![
(String::from(r"(^|/)\.git(/|$)"), false), (String::from(r"(^|/)\.svn(/|$)"), false),
(String::from(r"(^|/)\.hg(/|$)"), false),
(String::from(r"(^|/)\.DS_Store$"), false),
(String::from(r"(^|/)node_modules(/|$)"), false),
(String::from(r"(^|/)target(/|$)"), false),
(String::from(r"(^|/)build(/|$)"), false),
(String::from(r"(^|/)dist(/|$)"), false),
(String::from(r"(^|/)\.vscode(/|$)"), false),
(String::from(r"(^|/)\.idea(/|$)"), false),
(String::from(r"(^|/)\.vs(/|$)"), false),
(String::from(r"package-lock\.json$"), true),
(String::from(r"\.lock$"), true),
(String::from(r"\.log$"), true),
(String::from(r"\.tmp$"), true),
(String::from(r"\.temp$"), true),
(String::from(r"\.swp$"), true),
(String::from(r"\.min\.js$"), true),
];
let path = Path::new(path);
for (pattern, is_extension) in exclude_patterns {
let re = match Regex::new(&pattern) {
Ok(re) => re,
Err(e) => {
log_debug!("Failed to compile regex '{}': {}", pattern, e);
continue;
}
};
if is_extension {
if let Some(file_name) = path.file_name()
&& let Some(file_name_str) = file_name.to_str()
&& re.is_match(file_name_str)
{
log_debug!("File excluded: {}", path.display());
return true;
}
} else if let Some(path_str) = path.to_str()
&& re.is_match(path_str)
{
log_debug!("File excluded: {}", path.display());
return true;
}
}
log_debug!("File not excluded: {}", path.display());
false
}