This is an automated email from the ASF dual-hosted git repository.
xuanwo pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/opendal.git
The following commit(s) were added to refs/heads/main by this push:
new 06235da7f refactor: Deprecate remove_all API in favor of RFC-3911:
Deleter API (#6785)
06235da7f is described below
commit 06235da7f01062b21515144018208a519cca8d28
Author: KUAN-HAO HUANG <[email protected]>
AuthorDate: Tue Dec 16 21:29:59 2025 +0800
refactor: Deprecate remove_all API in favor of RFC-3911: Deleter API (#6785)
* try 3922
* decrease explanation
* allow
* fix fmt error
* update
* fix bindings
* fix errors
* fix format error
* allow
* update
* fix import
* fmt error
* fix error from behavior test local_fs
* remove redundant part
* modify ci error toml-format
* remove redundant part
* Format code
---------
Co-authored-by: rich <[email protected]>
Co-authored-by: Xuanwo <[email protected]>
---
bindings/dart/rust/src/frb_generated.rs | 6 ++---
bindings/haskell/src/lib.rs | 15 ++++++++---
bindings/java/src/async_operator.rs | 3 ++-
bindings/java/src/operator.rs | 9 ++++++-
bindings/nodejs/src/lib.rs | 12 +++++++--
bindings/ocaml/src/operator/mod.rs | 9 ++++++-
bindings/python/src/operator.rs | 16 ++++++++++--
bindings/ruby/src/operator.rs | 9 ++++++-
core/core/src/blocking/operator.rs | 37 +++++++++++++++++++++++++--
core/core/src/types/operator/operator.rs | 43 ++++++++++++++++----------------
core/tests/behavior/async_delete.rs | 2 +-
core/tests/behavior/async_list.rs | 12 +++++----
integrations/unftp-sbe/src/lib.rs | 3 ++-
13 files changed, 132 insertions(+), 44 deletions(-)
diff --git a/bindings/dart/rust/src/frb_generated.rs
b/bindings/dart/rust/src/frb_generated.rs
index 04c6604be..f867fb21d 100644
--- a/bindings/dart/rust/src/frb_generated.rs
+++ b/bindings/dart/rust/src/frb_generated.rs
@@ -27,7 +27,7 @@
use crate::api::opendal_api::*;
use flutter_rust_bridge::for_generated::byteorder::{NativeEndian,
ReadBytesExt, WriteBytesExt};
-use flutter_rust_bridge::for_generated::{Lifetimeable, Lockable,
transform_result_dco};
+use flutter_rust_bridge::for_generated::{transform_result_dco, Lifetimeable,
Lockable};
use flutter_rust_bridge::{Handler, IntoIntoDart};
// Section: boilerplate
@@ -1491,7 +1491,7 @@ mod io {
use flutter_rust_bridge::for_generated::byteorder::{
NativeEndian, ReadBytesExt, WriteBytesExt,
};
- use flutter_rust_bridge::for_generated::{Lifetimeable, Lockable,
transform_result_dco};
+ use flutter_rust_bridge::for_generated::{transform_result_dco,
Lifetimeable, Lockable};
use flutter_rust_bridge::{Handler, IntoIntoDart};
// Section: boilerplate
@@ -1544,7 +1544,7 @@ mod web {
};
use flutter_rust_bridge::for_generated::wasm_bindgen;
use flutter_rust_bridge::for_generated::wasm_bindgen::prelude::*;
- use flutter_rust_bridge::for_generated::{Lifetimeable, Lockable,
transform_result_dco};
+ use flutter_rust_bridge::for_generated::{transform_result_dco,
Lifetimeable, Lockable};
use flutter_rust_bridge::{Handler, IntoIntoDart};
// Section: boilerplate
diff --git a/bindings/haskell/src/lib.rs b/bindings/haskell/src/lib.rs
index a142fe603..f196002a0 100644
--- a/bindings/haskell/src/lib.rs
+++ b/bindings/haskell/src/lib.rs
@@ -706,9 +706,18 @@ pub unsafe extern "C" fn blocking_remove_all(
}
};
- let res = match op.remove_all(path_str) {
- Ok(()) => FFIResult::ok(()),
- Err(e) => FFIResult::err_with_source("Failed to remove all", e),
+ let res = {
+ use od::options::DeleteOptions;
+ match op.delete_options(
+ path_str,
+ DeleteOptions {
+ recursive: true,
+ ..Default::default()
+ },
+ ) {
+ Ok(()) => FFIResult::ok(()),
+ Err(e) => FFIResult::err_with_source("Failed to remove all",
e),
+ }
};
*result = res;
diff --git a/bindings/java/src/async_operator.rs
b/bindings/java/src/async_operator.rs
index 0494e7895..8e3852439 100644
--- a/bindings/java/src/async_operator.rs
+++ b/bindings/java/src/async_operator.rs
@@ -469,7 +469,8 @@ fn intern_remove_all(
executor_or_default(env, executor)?.spawn(async move {
let result = op
- .remove_all(&path)
+ .delete_with(&path)
+ .recursive(true)
.await
.map(|_| JValueOwned::Void)
.map_err(Into::into);
diff --git a/bindings/java/src/operator.rs b/bindings/java/src/operator.rs
index 146177512..08922dfdf 100644
--- a/bindings/java/src/operator.rs
+++ b/bindings/java/src/operator.rs
@@ -283,9 +283,16 @@ pub unsafe extern "system" fn
Java_org_apache_opendal_Operator_removeAll(
}
fn intern_remove_all(env: &mut JNIEnv, op: &mut blocking::Operator, path:
JString) -> Result<()> {
+ use opendal::options::DeleteOptions;
let path = jstring_to_string(env, &path)?;
- Ok(op.remove_all(&path)?)
+ Ok(op.delete_options(
+ &path,
+ DeleteOptions {
+ recursive: true,
+ ..Default::default()
+ },
+ )?)
}
/// # Safety
diff --git a/bindings/nodejs/src/lib.rs b/bindings/nodejs/src/lib.rs
index 510b425eb..e56380e0a 100644
--- a/bindings/nodejs/src/lib.rs
+++ b/bindings/nodejs/src/lib.rs
@@ -516,7 +516,8 @@ impl Operator {
#[napi]
pub async fn remove_all(&self, path: String) -> Result<()> {
self.async_op
- .remove_all(&path)
+ .delete_with(&path)
+ .recursive(true)
.await
.map_err(format_napi_error)
}
@@ -532,8 +533,15 @@ impl Operator {
/// ```
#[napi]
pub fn remove_all_sync(&self, path: String) -> Result<()> {
+ use opendal::options::DeleteOptions;
self.blocking_op
- .remove_all(&path)
+ .delete_options(
+ &path,
+ DeleteOptions {
+ recursive: true,
+ ..Default::default()
+ },
+ )
.map_err(format_napi_error)
}
diff --git a/bindings/ocaml/src/operator/mod.rs
b/bindings/ocaml/src/operator/mod.rs
index 420709966..ded6da0d2 100644
--- a/bindings/ocaml/src/operator/mod.rs
+++ b/bindings/ocaml/src/operator/mod.rs
@@ -148,7 +148,14 @@ pub fn blocking_remove(operator: &mut Operator, path:
Vec<String>) -> Result<(),
#[ocaml::func]
#[ocaml::sig("operator -> string -> (unit, string) Result.t ")]
pub fn blocking_remove_all(operator: &mut Operator, path: String) ->
Result<(), String> {
- map_res_error(operator.0.remove_all(path.as_str()))
+ use opendal::options::DeleteOptions;
+ map_res_error(operator.0.delete_options(
+ path.as_str(),
+ DeleteOptions {
+ recursive: true,
+ ..Default::default()
+ },
+ ))
}
#[ocaml::func]
diff --git a/bindings/python/src/operator.rs b/bindings/python/src/operator.rs
index 90015d41b..9f85f0ad3 100644
--- a/bindings/python/src/operator.rs
+++ b/bindings/python/src/operator.rs
@@ -484,8 +484,17 @@ impl Operator {
/// path : str
/// The path to remove.
pub fn remove_all(&self, path: PathBuf) -> PyResult<()> {
+ use ocore::options::DeleteOptions;
let path = path.to_string_lossy().to_string();
- self.core.remove_all(&path).map_err(format_pyerr)
+ self.core
+ .delete_options(
+ &path,
+ DeleteOptions {
+ recursive: true,
+ ..Default::default()
+ },
+ )
+ .map_err(format_pyerr)
}
/// Create a directory at the given path.
@@ -1219,7 +1228,10 @@ impl AsyncOperator {
let this = self.core.clone();
let path = path.to_string_lossy().to_string();
future_into_py(py, async move {
- this.remove_all(&path).await.map_err(format_pyerr)
+ this.delete_with(&path)
+ .recursive(true)
+ .await
+ .map_err(format_pyerr)
})
}
diff --git a/bindings/ruby/src/operator.rs b/bindings/ruby/src/operator.rs
index bb92a7b4b..c9ae692c9 100644
--- a/bindings/ruby/src/operator.rs
+++ b/bindings/ruby/src/operator.rs
@@ -200,9 +200,16 @@ impl Operator {
/// @param path [String]
/// @return [nil]
fn remove_all(ruby: &Ruby, rb_self: &Self, path: String) -> Result<(),
Error> {
+ use ocore::options::DeleteOptions;
rb_self
.blocking_op
- .remove_all(&path)
+ .delete_options(
+ &path,
+ DeleteOptions {
+ recursive: true,
+ ..Default::default()
+ },
+ )
.map_err(|err| Error::new(ruby.exception_runtime_error(),
err.to_string()))
}
diff --git a/core/core/src/blocking/operator.rs
b/core/core/src/blocking/operator.rs
index 0f6fa89cb..740fec949 100644
--- a/core/core/src/blocking/operator.rs
+++ b/core/core/src/blocking/operator.rs
@@ -555,9 +555,31 @@ impl Operator {
/// Remove the path and all nested dirs and files recursively.
///
+ /// # Deprecated
+ ///
+ /// This method is deprecated since v0.55.0. Use
[`blocking::Operator::delete_options`] with
+ /// `recursive: true` instead.
+ ///
+ /// ## Migration Example
+ ///
+ /// Instead of:
+ /// ```ignore
+ /// op.remove_all("path/to/dir")?;
+ /// ```
+ ///
+ /// Use:
+ /// ```ignore
+ /// use opendal_core::options::DeleteOptions;
+ /// op.delete_options("path/to/dir", DeleteOptions {
+ /// recursive: true,
+ /// ..Default::default()
+ /// })?;
+ /// ```
+ ///
/// # Notes
///
- /// We don't support batch delete now.
+ /// If underlying services support delete in batch, we will use batch
+ /// delete instead.
///
/// # Examples
///
@@ -571,8 +593,19 @@ impl Operator {
/// # Ok(())
/// # }
/// ```
+ #[deprecated(
+ since = "0.55.0",
+ note = "Use `delete_options` with `recursive: true` instead"
+ )]
+ #[allow(deprecated)]
pub fn remove_all(&self, path: &str) -> Result<()> {
- self.handle.block_on(self.op.remove_all(path))
+ self.delete_options(
+ path,
+ options::DeleteOptions {
+ recursive: true,
+ ..Default::default()
+ },
+ )
}
/// List entries whose paths start with the given prefix `path`.
diff --git a/core/core/src/types/operator/operator.rs
b/core/core/src/types/operator/operator.rs
index 15d6df711..caf895e57 100644
--- a/core/core/src/types/operator/operator.rs
+++ b/core/core/src/types/operator/operator.rs
@@ -1375,6 +1375,23 @@ impl Operator {
/// Remove the path and all nested dirs and files recursively.
///
+ /// # Deprecated
+ ///
+ /// This method is deprecated since v0.55.0. Use [`Operator::delete_with`]
with
+ /// `recursive(true)` instead.
+ ///
+ /// ## Migration Example
+ ///
+ /// Instead of:
+ /// ```ignore
+ /// op.remove_all("path/to/dir").await?;
+ /// ```
+ ///
+ /// Use:
+ /// ```ignore
+ /// op.delete_with("path/to/dir").recursive(true).await?;
+ /// ```
+ ///
/// # Notes
///
/// If underlying services support delete in batch, we will use batch
@@ -1392,28 +1409,12 @@ impl Operator {
/// # Ok(())
/// # }
/// ```
+ #[deprecated(
+ since = "0.55.0",
+ note = "Use `delete_with` with `recursive(true)` instead"
+ )]
pub async fn remove_all(&self, path: &str) -> Result<()> {
- match self.stat(path).await {
- // If object exists.
- Ok(metadata) => {
- // If the object is a file, we can delete it.
- if metadata.mode() != EntryMode::DIR {
- self.delete(path).await?;
- // There may still be objects prefixed with the path in
some backend, so we can't return here.
- }
- }
-
- // If dir not found, it may be a prefix in object store like S3,
- // and we still need to delete objects under the prefix.
- Err(e) if e.kind() == ErrorKind::NotFound => {}
-
- // Pass on any other error.
- Err(e) => return Err(e),
- };
-
- let lister = self.lister_with(path).recursive(true).await?;
- self.delete_try_stream(lister).await?;
- Ok(())
+ self.delete_with(path).recursive(true).await
}
/// List entries whose paths start with the given prefix `path`.
diff --git a/core/tests/behavior/async_delete.rs
b/core/tests/behavior/async_delete.rs
index 625496075..b1584badd 100644
--- a/core/tests/behavior/async_delete.rs
+++ b/core/tests/behavior/async_delete.rs
@@ -179,7 +179,7 @@ async fn test_blocking_remove_all_with_objects(
op.write(&path, content).await.expect("write must succeed");
}
- op.remove_all(&parent).await?;
+ op.delete_with(&parent).recursive(true).await?;
let found = op
.lister_with(&format!("{parent}/"))
diff --git a/core/tests/behavior/async_list.rs
b/core/tests/behavior/async_list.rs
index 8aecb7d92..2be5f0d0d 100644
--- a/core/tests/behavior/async_list.rs
+++ b/core/tests/behavior/async_list.rs
@@ -140,7 +140,7 @@ pub async fn test_list_rich_dir(op: Operator) -> Result<()>
{
assert_eq!(actual, expected);
- op.remove_all(parent).await?;
+ op.delete_with(parent).recursive(true).await?;
Ok(())
}
@@ -399,7 +399,7 @@ pub async fn test_list_with_start_after(op: Operator) ->
Result<()> {
assert_eq!(expected, actual);
- op.remove_all(dir).await?;
+ op.delete_with(dir).recursive(true).await?;
Ok(())
}
@@ -556,7 +556,9 @@ pub async fn test_remove_all(op: Operator) -> Result<()> {
}
}
- op.remove_all(&format!("{parent}/x/")).await?;
+ op.delete_with(&format!("{parent}/x/"))
+ .recursive(true)
+ .await?;
for path in expected.iter() {
if path.ends_with('/') {
@@ -688,7 +690,7 @@ pub async fn test_list_with_versions_and_limit(op:
Operator) -> Result<()> {
assert_eq!(actual, expected);
- op.remove_all(parent).await?;
+ op.delete_with(parent).recursive(true).await?;
Ok(())
}
@@ -735,7 +737,7 @@ pub async fn test_list_with_versions_and_start_after(op:
Operator) -> Result<()>
actual.sort_unstable();
assert_eq!(expected, actual);
- op.remove_all(dir).await?;
+ op.delete_with(dir).recursive(true).await?;
Ok(())
}
diff --git a/integrations/unftp-sbe/src/lib.rs
b/integrations/unftp-sbe/src/lib.rs
index ba75050a5..80c443e55 100644
--- a/integrations/unftp-sbe/src/lib.rs
+++ b/integrations/unftp-sbe/src/lib.rs
@@ -263,7 +263,8 @@ impl<User: UserDetail> StorageBackend<User> for
OpendalStorage {
async fn rmd<P: AsRef<Path> + Send + Debug>(&self, _: &User, path: P) ->
storage::Result<()> {
self.op
- .remove_all(convert_path(path.as_ref())?)
+ .delete_with(convert_path(path.as_ref())?)
+ .recursive(true)
.await
.map_err(convert_err)
}