diff --git a/src/linker.rs b/src/linker.rs index 8811571..b5e37b0 100644 --- a/src/linker.rs +++ b/src/linker.rs @@ -8,28 +8,25 @@ use crate::fomod::FileTypeEnum; pub struct Linker { target: PathBuf, + game_dir: PathBuf, } impl Linker { - pub fn new(target_path: &Path) -> Self { + pub fn new(target_path: &Path, game_dir: &Path) -> Self { Self { target: target_path.to_owned(), + game_dir: game_dir.to_owned(), } } - #[inline] - fn install_path(&self) -> &Path { - &self.target - } - fn link_file(&self, from: &Path, to: &Path) -> Result<(), LinkerError> { - let target = self.install_path().join(path_to_lowercase(to)); + let target = self.target.join(path_to_lowercase(to)); if let Some(parent) = target.parent() { fs::create_dir_all(parent)?; } - unix::fs::symlink(from, target)?; + create_symlink_for_file(from, &target)?; Ok(()) } @@ -80,19 +77,44 @@ impl Linker { Ok(()) } + + pub fn link_install_to_target(&self) -> Result<(), LinkerError> { + fn symlink_tree(src: &Path, dst: &Path) -> Result<(), LinkerError> { + if !dst.exists() { + fs::create_dir_all(dst)?; + } + + for entry in fs::read_dir(src)? { + let entry = entry?; + let src_path = entry.path(); + let dst_path = dst.join(path_to_lowercase(&entry.path()).file_name().unwrap()); + + let meta = entry.metadata()?; + if meta.is_dir() { + symlink_tree(&src_path, &dst_path)?; + } else if meta.is_file() { + create_symlink_for_file(&src_path, &dst_path)?; + } + } + + Ok(()) + } + + symlink_tree(&self.game_dir, &self.target)?; + + Ok(()) + } } #[derive(Debug)] pub enum LinkerError { Io(io::Error), - NotASymlink(PathBuf), } impl std::fmt::Display for LinkerError { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { Self::Io(e) => write!(f, "IO error: {}", e), - Self::NotASymlink(path) => write!(f, "Tried to remove a non symlink: {:?}", path), } } } @@ -108,3 +130,15 @@ impl From for LinkerError { fn path_to_lowercase(path: &Path) -> PathBuf { PathBuf::from(path.to_string_lossy().to_lowercase()) } + +fn create_symlink_for_file(src: &Path, dst: &Path) -> io::Result<()> { + #[cfg(unix)] + { + unix::fs::symlink(src, dst) + } + + #[cfg(windows)] + { + std::os::windows::fs::symlink_file(src, dst) + } +}