diff --git a/.github/services/dropbox/dropbox/disable_action.yml b/.github/services/dropbox/dropbox/action.yml similarity index 100% rename from .github/services/dropbox/dropbox/disable_action.yml rename to .github/services/dropbox/dropbox/action.yml diff --git a/core/src/services/dropbox/backend.rs b/core/src/services/dropbox/backend.rs index 75d92fde717..6f7b9ccd6c6 100644 --- a/core/src/services/dropbox/backend.rs +++ b/core/src/services/dropbox/backend.rs @@ -192,35 +192,61 @@ impl Accessor for DropboxBackend { } async fn copy(&self, from: &str, to: &str, _: OpCopy) -> Result { - let resp = self.core.dropbox_copy(from, to).await?; + // Check if the from path exists. + let resp = self.core.dropbox_get_metadata(from).await?; + if StatusCode::OK != resp.status() { + let err = parse_error(resp).await?; + return Err(err); + } - let status = resp.status(); + // Check if the to path already exists. + // We need delete it fistly due to Dropbox doesn't support overwrite. + let resp = self.core.dropbox_get_metadata(to).await?; + if StatusCode::OK == resp.status() { + let resp = self.core.dropbox_delete(to).await?; + if StatusCode::OK != resp.status() { + let err = parse_error(resp).await?; + return Err(err); + } + } + let resp = self.core.dropbox_copy(from, to).await?; + let status = resp.status(); match status { StatusCode::OK => Ok(RpCopy::default()), _ => { let err = parse_error(resp).await?; - match err.kind() { - ErrorKind::NotFound => Ok(RpCopy::default()), - _ => Err(err), - } + Err(err) } } } async fn rename(&self, from: &str, to: &str, _: OpRename) -> Result { - let resp = self.core.dropbox_move(from, to).await?; + // Check if the from path exists. + let resp = self.core.dropbox_get_metadata(from).await?; + if StatusCode::OK != resp.status() { + let err = parse_error(resp).await?; + return Err(err); + } - let status = resp.status(); + // Check if the to path already exists. + // We need delete it fistly due to Dropbox doesn't support overwrite. + let resp = self.core.dropbox_get_metadata(to).await?; + if StatusCode::OK == resp.status() { + let resp = self.core.dropbox_delete(to).await?; + if StatusCode::OK != resp.status() { + let err = parse_error(resp).await?; + return Err(err); + } + } + let resp = self.core.dropbox_move(from, to).await?; + let status = resp.status(); match status { StatusCode::OK => Ok(RpRename::default()), _ => { let err = parse_error(resp).await?; - match err.kind() { - ErrorKind::NotFound => Ok(RpRename::default()), - _ => Err(err), - } + Err(err) } } } diff --git a/core/src/services/dropbox/lister.rs b/core/src/services/dropbox/lister.rs index 8b49e6b4ee2..ad1ee93aaf3 100644 --- a/core/src/services/dropbox/lister.rs +++ b/core/src/services/dropbox/lister.rs @@ -74,6 +74,17 @@ impl oio::PageList for DropboxLister { return result; } + // List "dir" should only return "dir/". + if !self.path.ends_with('/') { + let mut path = self.path.clone(); + path.push('/'); + ctx.entries + .push_back(oio::Entry::with(path, Metadata::new(EntryMode::DIR))); + + ctx.done = true; + return Ok(()); + } + let bytes = response.into_body(); let decoded_response: DropboxListResponse = serde_json::from_reader(bytes.reader()).map_err(new_json_deserialize_error)?; @@ -103,7 +114,9 @@ impl oio::PageList for DropboxLister { } } - ctx.entries.push_back(oio::Entry::with(name, meta)); + // Dropbox will return name without parent path, we need contact it. + let path = format!("{}{}", self.path, name); + ctx.entries.push_back(oio::Entry::with(path, meta)); } if decoded_response.has_more { diff --git a/core/tests/behavior/async_copy.rs b/core/tests/behavior/async_copy.rs index 56a372fe73d..19eff072e34 100644 --- a/core/tests/behavior/async_copy.rs +++ b/core/tests/behavior/async_copy.rs @@ -67,8 +67,8 @@ pub async fn test_copy_file_with_ascii_name(op: Operator) -> Result<()> { /// Copy a file with non ascii name and test contents. pub async fn test_copy_file_with_non_ascii_name(op: Operator) -> Result<()> { - // Koofr does not support non-ascii name.(https://github.com/apache/opendal/issues/4051) - if op.info().scheme() == Scheme::Koofr { + // Koofr (https://github.com/apache/opendal/issues/4051) and Dropbox does not support non-ascii name. + if op.info().scheme() == Scheme::Koofr || op.info().scheme() == Scheme::Dropbox { return Ok(()); } diff --git a/core/tests/behavior/async_list.rs b/core/tests/behavior/async_list.rs index b526e39e064..bd98f90f549 100644 --- a/core/tests/behavior/async_list.rs +++ b/core/tests/behavior/async_list.rs @@ -182,6 +182,11 @@ pub async fn test_list_dir_with_metakey_complete(op: Operator) -> Result<()> { /// List prefix should return newly created file. pub async fn test_list_prefix(op: Operator) -> Result<()> { + // Dropbox does not support list prefix. + if op.info().scheme() == Scheme::Dropbox { + return Ok(()); + } + let path = uuid::Uuid::new_v4().to_string(); debug!("Generate a random file: {}", &path); let (content, _) = gen_bytes(op.info().full_capability()); @@ -558,6 +563,11 @@ pub async fn test_list_dir_with_recursive_no_trailing_slash(op: Operator) -> Res } pub async fn test_list_file_with_recursive(op: Operator) -> Result<()> { + // Dropbox does not support list file with recursive. + if op.info().scheme() == Scheme::Dropbox { + return Ok(()); + } + let parent = uuid::Uuid::new_v4().to_string(); let paths = ["y", "yy"]; diff --git a/core/tests/behavior/blocking_list.rs b/core/tests/behavior/blocking_list.rs index c6bbd25f60b..a9835014dfd 100644 --- a/core/tests/behavior/blocking_list.rs +++ b/core/tests/behavior/blocking_list.rs @@ -280,6 +280,11 @@ pub fn test_blocking_list_dir_with_recursive_no_trailing_slash(op: BlockingOpera // Walk top down should output as expected // same as test_list_dir_with_recursive except listing 'x' instead of 'x/' pub fn test_blocking_list_file_with_recursive(op: BlockingOperator) -> Result<()> { + // Dropbox does not support list file with recursive. + if op.info().scheme() == Scheme::Dropbox { + return Ok(()); + } + let parent = uuid::Uuid::new_v4().to_string(); let paths = ["y", "yy"];