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 1ae7a401 feat(oli): implement `oli cp -r` (#1787)
1ae7a401 is described below

commit 1ae7a40134f16e4e128bf94d975f2fbc51a05fe4
Author: Jian Zeng <[email protected]>
AuthorDate: Tue Mar 28 17:20:06 2023 +0800

    feat(oli): implement `oli cp -r` (#1787)
    
    Signed-off-by: Jian Zeng <[email protected]>
---
 bin/oli/src/commands/cp.rs | 53 +++++++++++++++++++++++++++++++++++-----------
 1 file changed, 41 insertions(+), 12 deletions(-)

diff --git a/bin/oli/src/commands/cp.rs b/bin/oli/src/commands/cp.rs
index b26c46c9..90aa7403 100644
--- a/bin/oli/src/commands/cp.rs
+++ b/bin/oli/src/commands/cp.rs
@@ -15,13 +15,12 @@
 // specific language governing permissions and limitations
 // under the License.
 
-use std::path::PathBuf;
+use std::path::{Path, PathBuf};
 
-use anyhow::anyhow;
-use anyhow::Result;
-use clap::Arg;
-use clap::ArgMatches;
-use clap::Command;
+use anyhow::{anyhow, Result};
+use clap::{Arg, ArgAction, ArgMatches, Command};
+use futures::TryStreamExt;
+use opendal::Metakey;
 
 use crate::config::Config;
 
@@ -30,6 +29,7 @@ pub async fn main(args: &ArgMatches) -> Result<()> {
         .get_one::<PathBuf>("config")
         .ok_or_else(|| anyhow!("missing config path"))?;
     let cfg = Config::load(config_path)?;
+    let recursive = args.get_flag("recursive");
 
     let src = args
         .get_one::<String>("source")
@@ -41,13 +41,34 @@ pub async fn main(args: &ArgMatches) -> Result<()> {
         .ok_or_else(|| anyhow!("missing target"))?;
     let (dst_op, dst_path) = cfg.parse_location(dst)?;
 
-    let mut dst_w = dst_op.writer(&dst_path).await?;
+    if !recursive {
+        let mut dst_w = dst_op.writer(&dst_path).await?;
+        let reader = src_op.reader(&src_path).await?;
+        let buf_reader = futures::io::BufReader::with_capacity(8 * 1024 * 
1024, reader);
+        futures::io::copy_buf(buf_reader, &mut dst_w).await?;
+        // flush data
+        dst_w.close().await?;
+        return Ok(());
+    }
 
-    let reader = src_op.reader(&src_path).await?;
-    let buf_reader = futures::io::BufReader::with_capacity(8 * 1024 * 1024, 
reader);
-    futures::io::copy_buf(buf_reader, &mut dst_w).await?;
-    // flush data
-    dst_w.close().await?;
+    let dst_root = Path::new(&dst_path);
+    let mut ds = src_op.scan(&src_path).await?;
+    while let Some(de) = ds.try_next().await? {
+        let meta = src_op.metadata(&de, Metakey::Mode).await?;
+        if meta.mode().is_dir() {
+            continue;
+        }
+
+        let fp = de.path().strip_prefix(&src_path).expect("invalid path");
+        let reader = src_op.reader(de.path()).await?;
+        let buf_reader = futures::io::BufReader::with_capacity(8 * 1024 * 
1024, reader);
+
+        let mut writer = 
dst_op.writer(&dst_root.join(fp).to_string_lossy()).await?;
+
+        println!("Copying {}", de.path());
+        futures::io::copy_buf(buf_reader, &mut writer).await?;
+        writer.close().await?;
+    }
     Ok(())
 }
 
@@ -55,4 +76,12 @@ pub fn cli(cmd: Command) -> Command {
     cmd.about("copy")
         .arg(Arg::new("source").required(true))
         .arg(Arg::new("destination").required(true))
+        .arg(
+            Arg::new("recursive")
+                .required(false)
+                .long("recursive")
+                .short('r')
+                .help("Copy files under source recursively to destination")
+                .action(ArgAction::SetTrue),
+        )
 }

Reply via email to