use crate::Result;
use std::fs;
use std::path::PathBuf;
#[derive(Debug, clap::Args)]
pub struct CheckSymlinks {
#[clap(required = true)]
pub files: Vec<PathBuf>,
}
impl CheckSymlinks {
pub async fn run(&self) -> Result<()> {
let mut found_broken = false;
for file_path in &self.files {
if is_broken_symlink(file_path)? {
println!("{}", file_path.display());
found_broken = true;
}
}
if found_broken {
return Err(eyre::eyre!("Broken symlinks found"));
}
Ok(())
}
}
fn is_broken_symlink(path: &PathBuf) -> Result<bool> {
let metadata = match fs::symlink_metadata(path) {
Ok(m) => m,
Err(_) => return Ok(false), };
if !metadata.is_symlink() {
return Ok(false);
}
match fs::metadata(path) {
Ok(_) => Ok(false), Err(_) => Ok(true), }
}
#[cfg(test)]
mod tests {
use super::*;
use std::fs;
use tempfile::TempDir;
#[cfg(unix)]
use std::os::unix::fs::symlink;
#[test]
#[cfg(unix)]
fn test_valid_symlink() {
let dir = TempDir::new().unwrap();
let target = dir.path().join("target.txt");
let link = dir.path().join("link");
fs::write(&target, "content").unwrap();
symlink(&target, &link).unwrap();
let result = is_broken_symlink(&link).unwrap();
assert!(!result);
}
#[test]
#[cfg(unix)]
fn test_broken_symlink() {
let dir = TempDir::new().unwrap();
let target = dir.path().join("target.txt");
let link = dir.path().join("link");
symlink(&target, &link).unwrap();
let result = is_broken_symlink(&link).unwrap();
assert!(result);
}
#[test]
fn test_regular_file() {
let dir = TempDir::new().unwrap();
let file = dir.path().join("file.txt");
fs::write(&file, "content").unwrap();
let result = is_broken_symlink(&file).unwrap();
assert!(!result);
}
#[test]
fn test_nonexistent_file() {
let dir = TempDir::new().unwrap();
let file = dir.path().join("nonexistent");
let result = is_broken_symlink(&file).unwrap();
assert!(!result); }
#[test]
#[cfg(unix)]
fn test_symlink_to_directory() {
let dir = TempDir::new().unwrap();
let target_dir = dir.path().join("target_dir");
let link = dir.path().join("link");
fs::create_dir(&target_dir).unwrap();
symlink(&target_dir, &link).unwrap();
let result = is_broken_symlink(&link).unwrap();
assert!(!result);
}
#[test]
#[cfg(unix)]
fn test_broken_symlink_to_directory() {
let dir = TempDir::new().unwrap();
let target_dir = dir.path().join("nonexistent_dir");
let link = dir.path().join("link");
symlink(&target_dir, &link).unwrap();
let result = is_broken_symlink(&link).unwrap();
assert!(result);
}
}