mirror of
https://github.com/FyroxEngine/Fyrox.git
synced 2026-10-12 02:02:20 +00:00
ability to move a folder with resource in the resource manager
This commit is contained in:
+8
-66
@@ -56,7 +56,6 @@ use crate::{
|
||||
wrap_panel::WrapPanelBuilder,
|
||||
HorizontalAlignment, Orientation, Thickness, UiNode, UserInterface, VerticalAlignment,
|
||||
},
|
||||
walkdir,
|
||||
},
|
||||
load_image,
|
||||
message::MessageSender,
|
||||
@@ -241,69 +240,6 @@ fn try_move_resource(
|
||||
}
|
||||
}
|
||||
|
||||
fn try_move_folder(src_dir: &Path, dest_dir: &Path, resource_manager: &ResourceManager) {
|
||||
if dest_dir.starts_with(src_dir) {
|
||||
// Trying to drop a folder into its own subfolder
|
||||
return;
|
||||
}
|
||||
|
||||
// Early validation to prevent error spam when trying to move a folder out of the
|
||||
// assets directory.
|
||||
if !is_path_in_registry(dest_dir, resource_manager) {
|
||||
return;
|
||||
}
|
||||
|
||||
// At this point we have a folder dropped on some other folder. In this case
|
||||
// we need to move all the assets from the dropped folder to a new subfolder (with the same
|
||||
// name as the dropped folder) of the other folder first. After that we can move the rest
|
||||
// of the files and finally delete the dropped folder.
|
||||
let mut what_where_stack = vec![(src_dir.to_path_buf(), dest_dir.to_path_buf())];
|
||||
let mut any_error = false;
|
||||
while let Some((src_dir, target_dir)) = what_where_stack.pop() {
|
||||
let src_dir_name = some_or_continue!(src_dir.file_name());
|
||||
|
||||
let target_sub_dir = target_dir.join(src_dir_name);
|
||||
if !target_sub_dir.exists() {
|
||||
if let Err(err) = std::fs::create_dir(&target_sub_dir) {
|
||||
err!(
|
||||
"Unable to create {} directory. Reason: {}",
|
||||
target_sub_dir.display(),
|
||||
err
|
||||
);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
let target_sub_dir_normalized = ok_or_continue!(make_relative_path(&target_sub_dir));
|
||||
|
||||
for entry in walkdir::WalkDir::new(&src_dir)
|
||||
.max_depth(1)
|
||||
.into_iter()
|
||||
.filter_map(|e| e.ok())
|
||||
{
|
||||
let path = entry.path();
|
||||
if path.is_file() {
|
||||
let ext = some_or_continue!(path.extension());
|
||||
let file_name = some_or_continue!(path.file_name());
|
||||
if is_supported_resource(ext, resource_manager) {
|
||||
let dest_path = target_sub_dir_normalized.join(file_name);
|
||||
if !try_move_resource(path, &dest_path, resource_manager) {
|
||||
any_error = true;
|
||||
}
|
||||
}
|
||||
} else if entry.path().is_dir() && entry.path() != src_dir {
|
||||
// Sub-folders will be processed after all assets from current dir
|
||||
// were moved.
|
||||
what_where_stack.push((entry.path().to_path_buf(), target_sub_dir.clone()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if !any_error {
|
||||
Log::verify(std::fs::remove_dir_all(src_dir));
|
||||
}
|
||||
}
|
||||
|
||||
impl AssetBrowser {
|
||||
pub const ADD_ASSET_NORMAL_BRUSH: &'static str = "AssetBrowser.AddAssetNormalBrush";
|
||||
pub const ADD_ASSET_HOVER_BRUSH: &'static str = "AssetBrowser.AddAssetHoverBrush";
|
||||
@@ -859,7 +795,11 @@ impl AssetBrowser {
|
||||
);
|
||||
self.schedule_refresh();
|
||||
} else if src_item_path.is_dir() {
|
||||
try_move_folder(src_item_path, dest_dir, &engine.resource_manager);
|
||||
Log::verify(block_on(engine.resource_manager.try_move_folder(
|
||||
src_item_path,
|
||||
dest_dir,
|
||||
true,
|
||||
)));
|
||||
self.schedule_refresh();
|
||||
}
|
||||
}
|
||||
@@ -1078,7 +1018,9 @@ impl AssetBrowser {
|
||||
try_move_resource(&item.path, &dest_dir.join(file_name), resource_manager);
|
||||
}
|
||||
} else if src_dir != Path::new("") {
|
||||
try_move_folder(src_dir, dest_dir, resource_manager);
|
||||
Log::verify(block_on(
|
||||
resource_manager.try_move_folder(src_dir, dest_dir, true),
|
||||
));
|
||||
self.schedule_refresh();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,6 +48,7 @@ use crate::{
|
||||
Resource, TypedResourceData, UntypedResource,
|
||||
};
|
||||
use fxhash::FxHashSet;
|
||||
use fyrox_core::{make_relative_path, some_or_continue, some_or_return};
|
||||
use std::{
|
||||
fmt::{Debug, Display, Formatter},
|
||||
io::Error,
|
||||
@@ -288,6 +289,79 @@ impl Display for ResourceMovementError {
|
||||
}
|
||||
}
|
||||
|
||||
/// A set of potential errors that may occur when moving a folder with resources.
|
||||
#[derive(Debug)]
|
||||
pub enum FolderMovementError {
|
||||
/// An IO error.
|
||||
Io(std::io::Error),
|
||||
/// A file error.
|
||||
FileError(FileError),
|
||||
/// A [`ResourceMovementError`].
|
||||
ResourceMovementError(ResourceMovementError),
|
||||
/// The folder is not in the registry.
|
||||
NotInRegistry {
|
||||
/// A path of the folder being moved.
|
||||
dest_dir: PathBuf,
|
||||
},
|
||||
/// Trying to move a folder into one of its own sub-folders.
|
||||
HierarchyError {
|
||||
/// Path of the folder being moved.
|
||||
src_dir: PathBuf,
|
||||
/// Destination directory.
|
||||
dest_dir: PathBuf,
|
||||
},
|
||||
}
|
||||
|
||||
impl From<FileError> for FolderMovementError {
|
||||
fn from(value: FileError) -> Self {
|
||||
Self::FileError(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<std::io::Error> for FolderMovementError {
|
||||
fn from(value: Error) -> Self {
|
||||
Self::Io(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ResourceMovementError> for FolderMovementError {
|
||||
fn from(value: ResourceMovementError) -> Self {
|
||||
Self::ResourceMovementError(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for FolderMovementError {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
FolderMovementError::Io(err) => {
|
||||
write!(f, "Io error: {err}")
|
||||
}
|
||||
FolderMovementError::FileError(err) => {
|
||||
write!(f, "File error: {err}")
|
||||
}
|
||||
FolderMovementError::ResourceMovementError(err) => {
|
||||
write!(f, "{err}")
|
||||
}
|
||||
FolderMovementError::NotInRegistry { dest_dir } => {
|
||||
write!(
|
||||
f,
|
||||
"Unable to move the {} folder, because it is not in the registry!",
|
||||
dest_dir.display()
|
||||
)
|
||||
}
|
||||
FolderMovementError::HierarchyError { src_dir, dest_dir } => {
|
||||
write!(
|
||||
f,
|
||||
"Trying to move a folder into one of its own sub-folders. \
|
||||
Source folder is {}, destination folder is {}",
|
||||
src_dir.display(),
|
||||
dest_dir.display()
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ResourceManager {
|
||||
/// Creates a resource manager with default settings and loaders.
|
||||
pub fn new(io: Arc<dyn ResourceIo>, task_pool: Arc<TaskPool>) -> Self {
|
||||
@@ -554,6 +628,29 @@ impl ResourceManager {
|
||||
let resources = self.state().reload_resources();
|
||||
join_all(resources).await;
|
||||
}
|
||||
|
||||
/// Checks if there's a loader for the given resource path.
|
||||
pub fn is_supported_resource(&self, path: &Path) -> bool {
|
||||
self.state().is_supported_resource(path)
|
||||
}
|
||||
|
||||
/// Checks if the given path is located inside the folder tracked by the resource registry.
|
||||
pub fn is_path_in_registry(&self, path: &Path) -> bool {
|
||||
self.state().is_path_in_registry(path)
|
||||
}
|
||||
|
||||
/// Tries to move a folder to some other folder.
|
||||
#[allow(clippy::await_holding_lock)]
|
||||
pub async fn try_move_folder(
|
||||
&self,
|
||||
src_dir: &Path,
|
||||
dest_dir: &Path,
|
||||
overwrite_existing: bool,
|
||||
) -> Result<(), FolderMovementError> {
|
||||
self.state()
|
||||
.try_move_folder(src_dir, dest_dir, overwrite_existing)
|
||||
.await
|
||||
}
|
||||
}
|
||||
|
||||
impl ResourceManagerState {
|
||||
@@ -1357,6 +1454,88 @@ impl ResourceManagerState {
|
||||
self.move_resource_by_path(resource_path, new_path, overwrite_existing)
|
||||
.await
|
||||
}
|
||||
|
||||
/// Checks if there's a loader for the given resource path.
|
||||
pub fn is_supported_resource(&self, path: &Path) -> bool {
|
||||
let ext = some_or_return!(path.extension(), false);
|
||||
let ext = some_or_return!(ext.to_str(), false);
|
||||
|
||||
self.loaders
|
||||
.lock()
|
||||
.iter()
|
||||
.any(|loader| loader.supports_extension(ext))
|
||||
}
|
||||
|
||||
/// Checks if the given path is located inside the folder tracked by the resource registry.
|
||||
pub fn is_path_in_registry(&self, path: &Path) -> bool {
|
||||
let registry = self.resource_registry.lock();
|
||||
if let Some(registry_directory) = registry.directory() {
|
||||
if let Ok(canonical_registry_path) = registry_directory.canonicalize() {
|
||||
if let Ok(canonical_path) = path.canonicalize() {
|
||||
return canonical_path.starts_with(canonical_registry_path);
|
||||
}
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
/// Tries to move a folder to some other folder.
|
||||
pub async fn try_move_folder(
|
||||
&self,
|
||||
src_dir: &Path,
|
||||
dest_dir: &Path,
|
||||
overwrite_existing: bool,
|
||||
) -> Result<(), FolderMovementError> {
|
||||
if dest_dir.starts_with(src_dir) {
|
||||
return Err(FolderMovementError::HierarchyError {
|
||||
src_dir: src_dir.to_path_buf(),
|
||||
dest_dir: dest_dir.to_path_buf(),
|
||||
});
|
||||
}
|
||||
|
||||
// Early validation to prevent error spam when trying to move a folder out of the
|
||||
// assets directory.
|
||||
if !self.is_path_in_registry(dest_dir) {
|
||||
return Err(FolderMovementError::NotInRegistry {
|
||||
dest_dir: dest_dir.to_path_buf(),
|
||||
});
|
||||
}
|
||||
|
||||
// At this point we have a folder dropped on some other folder. In this case
|
||||
// we need to move all the assets from the dropped folder to a new subfolder (with the same
|
||||
// name as the dropped folder) of the other folder first. After that we can move the rest
|
||||
// of the files and finally delete the dropped folder.
|
||||
let mut what_where_stack = vec![(src_dir.to_path_buf(), dest_dir.to_path_buf())];
|
||||
while let Some((src_dir, target_dir)) = what_where_stack.pop() {
|
||||
let src_dir_name = some_or_continue!(src_dir.file_name());
|
||||
|
||||
let target_sub_dir = target_dir.join(src_dir_name);
|
||||
if !self.resource_io.exists(&target_sub_dir).await {
|
||||
std::fs::create_dir(&target_sub_dir)?;
|
||||
}
|
||||
|
||||
let target_sub_dir_normalized = ok_or_continue!(make_relative_path(&target_sub_dir));
|
||||
|
||||
for path in self.resource_io.walk_directory(&src_dir, 1).await? {
|
||||
if path.is_file() {
|
||||
let file_name = some_or_continue!(path.file_name());
|
||||
if self.is_supported_resource(&path) {
|
||||
let dest_path = target_sub_dir_normalized.join(file_name);
|
||||
self.move_resource_by_path(path, &dest_path, overwrite_existing)
|
||||
.await?;
|
||||
}
|
||||
} else if path.is_dir() && path != src_dir {
|
||||
// Sub-folders will be processed after all assets from current dir
|
||||
// were moved.
|
||||
what_where_stack.push((path, target_sub_dir.clone()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::fs::remove_dir_all(src_dir)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
||||
Reference in New Issue
Block a user