diff --git a/packages/app-lib/src/state/dirs.rs b/packages/app-lib/src/state/dirs.rs index 6a7c3ae7b..cf07ba2cf 100644 --- a/packages/app-lib/src/state/dirs.rs +++ b/packages/app-lib/src/state/dirs.rs @@ -209,34 +209,6 @@ impl DirectoryInfo { } } - fn is_same_disk( - old_dir: &Path, - new_dir: &Path, - ) -> crate::Result { - #[cfg(unix)] - { - use std::os::unix::fs::MetadataExt; - Ok(old_dir.metadata()?.dev() == new_dir.metadata()?.dev()) - } - - #[cfg(windows)] - { - let old_dir = crate::util::io::canonicalize(old_dir)?; - let new_dir = crate::util::io::canonicalize(new_dir)?; - - let old_component = old_dir.components().next(); - let new_component = new_dir.components().next(); - - match (old_component, new_component) { - ( - Some(std::path::Component::Prefix(old)), - Some(std::path::Component::Prefix(new)), - ) => Ok(old.as_os_str() == new.as_os_str()), - _ => Ok(false), - } - } - } - fn get_disk_usage(path: &Path) -> crate::Result> { let path = crate::util::io::canonicalize(path)?; @@ -335,7 +307,9 @@ impl DirectoryInfo { let paths_len = paths.len(); - if is_same_disk(&prev_dir, &move_dir).unwrap_or(false) { + if crate::util::io::is_same_disk(&prev_dir, &move_dir) + .unwrap_or(false) + { let success_idxs = Arc::new(DashSet::new()); let loader_bar_id = Arc::new(&loader_bar_id); @@ -359,7 +333,7 @@ impl DirectoryInfo { })?; } - crate::util::io::rename( + crate::util::io::rename_or_move( &x.old, &x.new, ) diff --git a/packages/app-lib/src/state/profiles.rs b/packages/app-lib/src/state/profiles.rs index 4cebf4c06..97b92cf8d 100644 --- a/packages/app-lib/src/state/profiles.rs +++ b/packages/app-lib/src/state/profiles.rs @@ -928,7 +928,8 @@ impl Profile { format!("{project_path}.disabled") }; - io::rename(&path.join(project_path), &path.join(&new_path)).await?; + io::rename_or_move(&path.join(project_path), &path.join(&new_path)) + .await?; Ok(new_path) } diff --git a/packages/app-lib/src/util/io.rs b/packages/app-lib/src/util/io.rs index f66af2cef..539c0003c 100644 --- a/packages/app-lib/src/util/io.rs +++ b/packages/app-lib/src/util/io.rs @@ -59,6 +59,19 @@ pub async fn read_dir( }) } +// create_dir +pub async fn create_dir( + path: impl AsRef, +) -> Result<(), IOError> { + let path = path.as_ref(); + tokio::fs::create_dir(path) + .await + .map_err(|e| IOError::IOPathError { + source: e, + path: path.to_string_lossy().to_string(), + }) +} + // create_dir_all pub async fn create_dir_all( path: impl AsRef, @@ -150,19 +163,72 @@ fn sync_write( tmp_path.persist(path)?; std::io::Result::Ok(()) } + +pub fn is_same_disk(old_dir: &Path, new_dir: &Path) -> Result { + #[cfg(unix)] + { + use std::os::unix::fs::MetadataExt; + Ok(old_dir.metadata()?.dev() == new_dir.metadata()?.dev()) + } + + #[cfg(windows)] + { + let old_dir = canonicalize(old_dir)?; + let new_dir = canonicalize(new_dir)?; + + let old_component = old_dir.components().next(); + let new_component = new_dir.components().next(); + + match (old_component, new_component) { + ( + Some(std::path::Component::Prefix(old)), + Some(std::path::Component::Prefix(new)), + ) => Ok(old.as_os_str() == new.as_os_str()), + _ => Ok(false), + } + } +} + // rename -pub async fn rename( +pub async fn rename_or_move( from: impl AsRef, to: impl AsRef, ) -> Result<(), IOError> { let from = from.as_ref(); let to = to.as_ref(); - tokio::fs::rename(from, to) - .await - .map_err(|e| IOError::IOPathError { - source: e, - path: from.to_string_lossy().to_string(), - }) + + if to + .parent() + .map_or(Ok(false), |to_dir| is_same_disk(from, to_dir))? + { + tokio::fs::rename(from, to) + .await + .map_err(|e| IOError::IOPathError { + source: e, + path: from.to_string_lossy().to_string(), + }) + } else { + move_recursive(from, to).await + } +} + +#[async_recursion::async_recursion] +async fn move_recursive(from: &Path, to: &Path) -> Result<(), IOError> { + if from.is_file() { + copy(from, to).await?; + remove_file(from).await?; + return Ok(()); + } + + create_dir(to).await?; + + let mut dir = read_dir(from).await?; + while let Some(entry) = dir.next_entry().await? { + let new_path = to.join(entry.file_name()); + move_recursive(&entry.path(), &new_path).await?; + } + + Ok(()) } // copy