use log::debug;
use std::path::{Path, PathBuf};
pub fn symlink_dir<P: AsRef<Path>, U: AsRef<Path>>(src: P, dst: U) -> std::io::Result<()> {
let src = src.as_ref();
let dst = dst.as_ref();
debug!("Creating symlink: {} -> {}", dst.display(), src.display());
#[cfg(unix)]
{
std::os::unix::fs::symlink(src, dst)?;
}
#[cfg(windows)]
{
junction::create(src, dst)?;
}
debug!("Successfully created symlink: {} -> {}", dst.display(), src.display());
Ok(())
}
pub fn remove_symlink_dir<P: AsRef<Path>>(path: P) -> std::io::Result<()> {
let path = path.as_ref();
debug!("Removing symlink: {}", path.display());
#[cfg(windows)]
{
std::fs::remove_dir(path)?;
}
#[cfg(unix)]
{
std::fs::remove_file(path)?;
}
debug!("Successfully removed symlink: {}", path.display());
Ok(())
}
pub fn read_symlink<P: AsRef<Path>>(path: P) -> std::io::Result<PathBuf> {
let path = path.as_ref();
#[cfg(windows)]
{
junction::get_target(path)
}
#[cfg(unix)]
{
std::fs::read_link(path)
}
}
pub fn is_symlink<P: AsRef<Path>>(path: P) -> bool {
let path = path.as_ref();
#[cfg(windows)]
{
junction::exists(path).unwrap_or(false)
}
#[cfg(unix)]
{
path.is_symlink()
}
}
pub fn get_symlink_target<P: AsRef<Path>>(path: P) -> Option<PathBuf> {
let path = path.as_ref();
if !path.exists() {
return None;
}
#[cfg(windows)]
{
if junction::exists(path).unwrap_or(false) {
junction::get_target(path).ok()
} else {
None
}
}
#[cfg(unix)]
{
if path.is_symlink() {
std::fs::read_link(path).ok()
} else {
None
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use tempfile::TempDir;
#[test]
fn test_create_and_remove_symlink() {
let temp_dir = TempDir::new().unwrap();
let target_path = temp_dir.path().join("target");
std::fs::create_dir_all(&target_path).unwrap();
std::fs::write(target_path.join("test.txt"), "Hello, World!").unwrap();
let link_path = temp_dir.path().join("link");
if link_path.exists() {
if is_symlink(&link_path) {
let _ = remove_symlink_dir(&link_path);
} else if link_path.is_dir() {
let _ = std::fs::remove_dir_all(&link_path);
} else {
let _ = std::fs::remove_file(&link_path);
}
}
symlink_dir(&target_path, &link_path).unwrap();
assert!(link_path.exists());
assert!(is_symlink(&link_path));
let test_file = link_path.join("test.txt");
assert!(test_file.exists());
let content = std::fs::read_to_string(test_file).unwrap();
assert_eq!(content, "Hello, World!");
let target = get_symlink_target(&link_path).unwrap();
assert_eq!(target, target_path);
remove_symlink_dir(&link_path).unwrap();
assert!(!link_path.exists());
assert!(target_path.exists()); }
#[test]
fn test_nonexistent_path() {
let temp_dir = TempDir::new().unwrap();
let nonexistent = temp_dir.path().join("nonexistent");
assert!(remove_symlink_dir(&nonexistent).is_err());
assert!(get_symlink_target(&nonexistent).is_none());
assert!(!is_symlink(&nonexistent));
}
}