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/incubator-opendal.git


The following commit(s) were added to refs/heads/main by this push:
     new 97974f4f5 fix(services/gdrive): fix return value of 
`get_file_id_by_path` (#3801)
97974f4f5 is described below

commit 97974f4f5e85886e8e511150bd5add490f2b921c
Author: G-XD <[email protected]>
AuthorDate: Sat Dec 23 02:09:27 2023 +0800

    fix(services/gdrive): fix return value of `get_file_id_by_path` (#3801)
---
 core/src/services/gdrive/backend.rs | 30 +++++++++++----
 core/src/services/gdrive/core.rs    | 73 +++++++++++++------------------------
 core/src/services/gdrive/lister.rs  | 15 +++++++-
 3 files changed, 63 insertions(+), 55 deletions(-)

diff --git a/core/src/services/gdrive/backend.rs 
b/core/src/services/gdrive/backend.rs
index eb38e75d5..fd83d96fa 100644
--- a/core/src/services/gdrive/backend.rs
+++ b/core/src/services/gdrive/backend.rs
@@ -212,7 +212,11 @@ impl Accessor for GdriveBackend {
     }
 
     async fn copy(&self, from: &str, to: &str, _args: OpCopy) -> 
Result<RpCopy> {
-        let from_file_id = self.core.get_file_id_by_path(from).await?;
+        let from_file_id = self
+            .core
+            .get_file_id_by_path(from)
+            .await?
+            .ok_or(Error::new(ErrorKind::NotFound, "invalid 'from' path"))?;
 
         // split `to` into parent and name according to the last `/`
         let mut to_path_items: Vec<&str> = to.split('/').filter(|&x| 
!x.is_empty()).collect();
@@ -225,14 +229,26 @@ impl Accessor for GdriveBackend {
 
         let to_parent = to_path_items.join("/") + "/";
 
-        if to_parent != "/" {
-            self.create_dir(&to_parent, OpCreateDir::new()).await?;
-        }
-
-        let to_parent_id = 
self.core.get_file_id_by_path(to_parent.as_str()).await?;
+        let to_parent_id =
+            if let Some(id) = 
self.core.get_file_id_by_path(to_parent.as_str()).await? {
+                id
+            } else {
+                self.create_dir(&to_parent, OpCreateDir::new()).await?;
+                self.core
+                    .get_file_id_by_path(to_parent.as_str())
+                    .await?
+                    .ok_or_else(|| {
+                        Error::new(ErrorKind::Unexpected, "create to's parent 
folder failed")
+                    })?
+            };
 
         // copy will overwrite `to`, delete it if exist
-        if self.core.get_file_id_by_path(to).await.is_ok() {
+        if self
+            .core
+            .get_file_id_by_path(to)
+            .await
+            .is_ok_and(|id| id.is_some())
+        {
             self.delete(to, OpDelete::new()).await?;
         }
 
diff --git a/core/src/services/gdrive/core.rs b/core/src/services/gdrive/core.rs
index f6517419d..f43e80acd 100644
--- a/core/src/services/gdrive/core.rs
+++ b/core/src/services/gdrive/core.rs
@@ -24,7 +24,6 @@ use bytes;
 use bytes::Bytes;
 use chrono::DateTime;
 use chrono::Utc;
-use futures::stream;
 use http::header;
 use http::Request;
 use http::Response;
@@ -77,13 +76,13 @@ impl GdriveCore {
     /// - A path is a sequence of file names separated by slashes.
     /// - A file only knows its parent id, but not its name.
     /// - To find the file id of a file, we need to traverse the path from the 
root to the file.
-    pub(crate) async fn get_file_id_by_path(&self, file_path: &str) -> 
Result<String> {
+    pub(crate) async fn get_file_id_by_path(&self, file_path: &str) -> 
Result<Option<String>> {
         let path = build_abs_path(&self.root, file_path);
 
         let mut cache = self.path_cache.lock().await;
 
         if let Some(id) = cache.get(&path) {
-            return Ok(id.to_owned());
+            return Ok(Some(id.to_owned()));
         }
 
         let mut parent_id = "root".to_owned();
@@ -108,15 +107,11 @@ impl GdriveCore {
                 parent_id = id;
                 cache.insert(path_part, parent_id.clone());
             } else {
-                // TODO: return None instead of error.
-                return Err(Error::new(
-                    ErrorKind::NotFound,
-                    &format!("path not found: {}", item),
-                ));
+                return Ok(None);
             };
         }
 
-        Ok(parent_id)
+        Ok(Some(parent_id))
     }
 
     /// Ensure the parent path exists.
@@ -277,13 +272,16 @@ impl GdriveCore {
     }
 
     pub async fn gdrive_stat(&self, path: &str) -> 
Result<Response<IncomingAsyncBody>> {
-        let path_id = self.get_file_id_by_path(path).await?;
+        let path_id = self.get_file_id_by_path(path).await?.ok_or(Error::new(
+            ErrorKind::NotFound,
+            &format!("path not found: {}", path),
+        ))?;
 
         // The file metadata in the Google Drive API is very complex.
         // For now, we only need the file id, name, mime type and modified 
time.
         let mut req = Request::get(&format!(
             
"https://www.googleapis.com/drive/v3/files/{}?fields=id,name,mimeType,size,modifiedTime";,
-            path_id.as_str()
+            path_id
         ))
             .body(AsyncBody::Empty)
             .map_err(new_request_build_error)?;
@@ -293,9 +291,14 @@ impl GdriveCore {
     }
 
     pub async fn gdrive_get(&self, path: &str) -> 
Result<Response<IncomingAsyncBody>> {
+        let path_id = self.get_file_id_by_path(path).await?.ok_or(Error::new(
+            ErrorKind::NotFound,
+            &format!("path not found: {}", path),
+        ))?;
+
         let url: String = format!(
             "https://www.googleapis.com/drive/v3/files/{}?alt=media";,
-            self.get_file_id_by_path(path).await?
+            path_id
         );
 
         let mut req = Request::get(&url)
@@ -308,39 +311,11 @@ impl GdriveCore {
 
     pub async fn gdrive_list(
         &self,
-        path: &str,
+        file_id: &str,
         page_size: i32,
         next_page_token: &str,
     ) -> Result<Response<IncomingAsyncBody>> {
-        let file_id = self.get_file_id_by_path(path).await;
-
-        // when list over a no exist dir, `get_file_id_by_path` will return a 
NotFound Error, we should return a empty list in this case.
-        let q = match file_id {
-            Ok(file_id) => {
-                format!("'{}' in parents and trashed = false", file_id)
-            }
-            Err(e) => match e.kind() {
-                ErrorKind::NotFound => {
-                    return Response::builder()
-                        .status(StatusCode::OK)
-                        .body(IncomingAsyncBody::new(
-                            Box::new(oio::into_stream(stream::empty())),
-                            Some(0),
-                        ))
-                        .map_err(|e| {
-                            Error::new(
-                                ErrorKind::Unexpected,
-                                &format!("failed to create a empty response 
for list: {}", e),
-                            )
-                            .set_source(e)
-                        });
-                }
-                _ => {
-                    return Err(e);
-                }
-            },
-        };
-
+        let q = format!("'{}' in parents and trashed = false", file_id);
         let mut url = format!(
             "https://www.googleapis.com/drive/v3/files?pageSize={}&q={}";,
             page_size,
@@ -364,7 +339,10 @@ impl GdriveCore {
         source: &str,
         target: &str,
     ) -> Result<Response<IncomingAsyncBody>> {
-        let file_id = self.get_file_id_by_path(source).await?;
+        let file_id = self.get_file_id_by_path(source).await?.ok_or(Error::new(
+            ErrorKind::NotFound,
+            &format!("source path not found: {}", source),
+        ))?;
 
         let parent = self.ensure_parent_path(target).await?;
 
@@ -402,10 +380,11 @@ impl GdriveCore {
     }
 
     pub async fn gdrive_delete(&self, path: &str) -> 
Result<Response<IncomingAsyncBody>> {
-        let url = format!(
-            "https://www.googleapis.com/drive/v3/files/{}";,
-            self.get_file_id_by_path(path).await?
-        );
+        let file_id = self.get_file_id_by_path(path).await?.ok_or(Error::new(
+            ErrorKind::NotFound,
+            &format!("path not found: {}", path),
+        ))?;
+        let url = format!("https://www.googleapis.com/drive/v3/files/{}";, 
file_id);
 
         let mut req = Request::delete(&url)
             .body(AsyncBody::Empty)
diff --git a/core/src/services/gdrive/lister.rs 
b/core/src/services/gdrive/lister.rs
index d3ae48633..b8cf78a8e 100644
--- a/core/src/services/gdrive/lister.rs
+++ b/core/src/services/gdrive/lister.rs
@@ -40,7 +40,20 @@ impl GdriveLister {
 #[async_trait]
 impl oio::PageList for GdriveLister {
     async fn next_page(&self, ctx: &mut oio::PageContext) -> Result<()> {
-        let resp = self.core.gdrive_list(&self.path, 100, &ctx.token).await?;
+        let file_id = self.core.get_file_id_by_path(&self.path).await?;
+
+        let file_id = match file_id {
+            Some(file_id) => file_id,
+            None => {
+                ctx.done = true;
+                return Ok(());
+            }
+        };
+
+        let resp = self
+            .core
+            .gdrive_list(file_id.as_str(), 100, &ctx.token)
+            .await?;
 
         let bytes = match resp.status() {
             StatusCode::OK => resp.into_body().bytes().await?,

Reply via email to