Compare commits
2 Commits
1f40e59519
...
9fe7340530
| Author | SHA1 | Date | |
|---|---|---|---|
|
9fe7340530
|
|||
|
bf04d48af4
|
@@ -8,40 +8,25 @@ use crate::fomod::FileTypeEnum;
|
|||||||
|
|
||||||
pub struct Linker {
|
pub struct Linker {
|
||||||
target: PathBuf,
|
target: PathBuf,
|
||||||
|
game_dir: PathBuf,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Linker {
|
impl Linker {
|
||||||
pub fn new(target_path: &Path) -> Self {
|
pub fn new(target_path: &Path, game_dir: &Path) -> Self {
|
||||||
Self {
|
Self {
|
||||||
target: target_path.to_owned(),
|
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> {
|
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() {
|
if let Some(parent) = target.parent() {
|
||||||
fs::create_dir_all(parent)?;
|
fs::create_dir_all(parent)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
unix::fs::symlink(from, target)?;
|
create_symlink_for_file(from, &target)?;
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn remove_link(&self, to: &Path) -> Result<(), LinkerError> {
|
|
||||||
let file = self.install_path().join(path_to_lowercase(to));
|
|
||||||
let metadata = fs::symlink_metadata(&file)?;
|
|
||||||
|
|
||||||
if !metadata.file_type().is_symlink() {
|
|
||||||
return Err(LinkerError::NotASymlink(file));
|
|
||||||
}
|
|
||||||
|
|
||||||
fs::remove_file(&file)?;
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -64,30 +49,6 @@ impl Linker {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn unlink_recursive(&self, from: &Path, to: &Path) -> Result<(), LinkerError> {
|
|
||||||
for entry in fs::read_dir(from)? {
|
|
||||||
let entry = entry?;
|
|
||||||
let entry_path = entry.path();
|
|
||||||
let relative = entry_path
|
|
||||||
.strip_prefix(from)
|
|
||||||
.map_err(|e| io::Error::new(io::ErrorKind::InvalidInput, e))?;
|
|
||||||
let target_path = to.join(relative);
|
|
||||||
|
|
||||||
if entry_path.is_dir() {
|
|
||||||
self.unlink_recursive(&entry_path, &target_path)?;
|
|
||||||
|
|
||||||
let install_target = self.install_path().join(&target_path);
|
|
||||||
if install_target.exists() && fs::read_dir(&install_target)?.next().is_none() {
|
|
||||||
fs::remove_dir(&install_target)?;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
self.remove_link(&target_path)?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn link_plugin_files(
|
pub fn link_plugin_files(
|
||||||
&self,
|
&self,
|
||||||
entries: &[FileTypeEnum],
|
entries: &[FileTypeEnum],
|
||||||
@@ -116,19 +77,44 @@ impl Linker {
|
|||||||
|
|
||||||
Ok(())
|
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)]
|
#[derive(Debug)]
|
||||||
pub enum LinkerError {
|
pub enum LinkerError {
|
||||||
Io(io::Error),
|
Io(io::Error),
|
||||||
NotASymlink(PathBuf),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::fmt::Display for LinkerError {
|
impl std::fmt::Display for LinkerError {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
Self::Io(e) => write!(f, "IO error: {}", e),
|
Self::Io(e) => write!(f, "IO error: {}", e),
|
||||||
Self::NotASymlink(path) => write!(f, "Tried to remove a non symlink: {:?}", path),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -144,3 +130,15 @@ impl From<io::Error> for LinkerError {
|
|||||||
fn path_to_lowercase(path: &Path) -> PathBuf {
|
fn path_to_lowercase(path: &Path) -> PathBuf {
|
||||||
PathBuf::from(path.to_string_lossy().to_lowercase())
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user