delete multiple files with selection

This commit is contained in:
2025-09-04 16:26:23 +02:00
parent 49b4162448
commit 8b2ed0e700
17 changed files with 250 additions and 137 deletions

View File

@@ -1,5 +1,5 @@
use anyhow::{Context as _, anyhow, bail};
use futures_util::TryStreamExt;
use futures_util::{TryStreamExt, future::join_all};
use rustix::fs::{Statx, statx};
use std::{
collections::HashSet,
@@ -182,10 +182,10 @@ impl FileSystem {
/// Actually removes a file or directory from the underlying file system
///
/// * `path`: The directory's absolute path (absolute not in relation to the root file system but `self.base_directory`)
/// * `path`: The file's absolute path (absolute not in relation to the root file system but `self.base_directory`)
/// * `force`: Whether to delete directories that are not empty
async fn rm(&self, path: &AbsoluteFilePath, force: bool) -> io::Result<()> {
let file_path = self.get_target_path(path);
let file_path = self.get_target_path(&path);
if fs::metadata(&file_path).await?.is_file() {
return fs::remove_file(&file_path).await;
@@ -412,14 +412,34 @@ impl FileSystemRepository for FileSystem {
})
}
async fn rm(&self, request: RmRequest) -> Result<(), RmError> {
self.rm(request.path(), request.force())
.await
.map_err(|e| match e.kind() {
std::io::ErrorKind::NotFound => RmError::NotFound,
std::io::ErrorKind::DirectoryNotEmpty => RmError::NotEmpty,
_ => anyhow!("Failed to delete file at {}: {e:?}", request.path()).into(),
})
async fn rm(&self, request: RmRequest) -> Vec<Result<AbsoluteFilePath, RmError>> {
let force = request.force();
let paths: Vec<AbsoluteFilePath> = request.into_paths().into();
async fn _rm(
fs: &FileSystem,
path: AbsoluteFilePath,
force: bool,
) -> Result<AbsoluteFilePath, RmError> {
fs.rm(&path, force)
.await
.map(|_| path.clone())
.map_err(|e| match e.kind() {
std::io::ErrorKind::NotFound => RmError::NotFound(path),
std::io::ErrorKind::DirectoryNotEmpty => RmError::NotEmpty(path),
_ => anyhow!("Failed to delete file at {}: {e:?}", path).into(),
})
}
let results: Vec<Result<AbsoluteFilePath, RmError>> = join_all(
paths
.into_iter()
.map(|path| _rm(&self, path, force))
.collect::<Vec<_>>(),
)
.await;
results
}
async fn mv(&self, request: MvRequest) -> Result<(), MvError> {

View File

@@ -87,11 +87,26 @@ impl WarrenNotifier for NotifierDebugLogger {
}
async fn warren_rm(&self, response: &WarrenRmResponse) {
tracing::debug!(
"[Notifier] Deleted file {} from warren {}",
response.path(),
response.warren().name(),
);
let span = tracing::debug_span!("warren_rm", "{}", response.warren().name()).entered();
let results = response.results();
for result in results {
match result.as_ref() {
Ok(path) => tracing::debug!("Deleted file: {path}"),
Err(e) => match e {
crate::domain::warren::models::file::RmError::NotFound(path) => {
tracing::debug!("File not found: {path}")
}
crate::domain::warren::models::file::RmError::NotEmpty(path) => {
tracing::debug!("Directory not empty: {path}")
}
crate::domain::warren::models::file::RmError::Unknown(_) => (),
},
}
}
span.exit();
}
async fn warren_mv(&self, response: &WarrenMvResponse) {
@@ -392,9 +407,11 @@ impl AuthNotifier for NotifierDebugLogger {
}
async fn auth_warren_rm(&self, user: &User, response: &WarrenRmResponse) {
let results = response.results();
let successes = results.iter().filter(|r| r.is_ok()).count();
tracing::debug!(
"[Notifier] Deleted file {} from warren {} for authenticated user {}",
response.path(),
"[Notifier] Deleted {successes} file(s) from warren {} for authenticated user {}",
response.warren().name(),
user.id(),
);