From 100f4858c3960aef34fd4c9d495144559f4b076a Mon Sep 17 00:00:00 2001 From: Julio Biason Date: Tue, 5 Sep 2023 14:56:33 -0300 Subject: [PATCH] Playing with tokio, copy, and wildcards --- globtest/Cargo.lock | 211 +++++++++++++++++++++++++++++++++++++++++++ globtest/Cargo.toml | 11 +++ globtest/README.md | 3 + globtest/src/main.rs | 100 ++++++++++++++++++++ 4 files changed, 325 insertions(+) create mode 100644 globtest/Cargo.lock create mode 100644 globtest/Cargo.toml create mode 100644 globtest/README.md create mode 100644 globtest/src/main.rs diff --git a/globtest/Cargo.lock b/globtest/Cargo.lock new file mode 100644 index 0000000..0ebc9b0 --- /dev/null +++ b/globtest/Cargo.lock @@ -0,0 +1,211 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "addr2line" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" +dependencies = [ + "gimli", +] + +[[package]] +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + +[[package]] +name = "aho-corasick" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c378d78423fdad8089616f827526ee33c19f2fddbd5de1629152c9593ba4783" +dependencies = [ + "memchr", +] + +[[package]] +name = "async-recursion" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5fd55a5ba1179988837d24ab4c7cc8ed6efdeff578ede0416b4225a5fca35bd0" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "backtrace" +version = "0.3.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837" +dependencies = [ + "addr2line", + "cc", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", +] + +[[package]] +name = "cc" +version = "1.0.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" +dependencies = [ + "libc", +] + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "gimli" +version = "0.28.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fb8d784f27acf97159b40fc4db5ecd8aa23b9ad5ef69cdd136d3bc80665f0c0" + +[[package]] +name = "globtest" +version = "0.1.0" +dependencies = [ + "async-recursion", + "regex", + "tokio", +] + +[[package]] +name = "libc" +version = "0.2.147" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" + +[[package]] +name = "memchr" +version = "2.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f232d6ef707e1956a43342693d2a31e72989554d58299d7a88738cc95b0d35c" + +[[package]] +name = "miniz_oxide" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7" +dependencies = [ + "adler", +] + +[[package]] +name = "object" +version = "0.32.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9cf5f9dd3933bd50a9e1f149ec995f39ae2c496d31fd772c1fd45ebc27e902b0" +dependencies = [ + "memchr", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" + +[[package]] +name = "proc-macro2" +version = "1.0.66" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18fb31db3f9bddb2ea821cde30a9f70117e3f119938b5ee630b7403aa6e2ead9" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "regex" +version = "1.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "697061221ea1b4a94a624f67d0ae2bfe4e22b8a17b6a192afb11046542cc8c47" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2f401f4955220693b56f8ec66ee9c78abffd8d1c4f23dc41a23839eb88f0795" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbb5fb1acd8a1a18b3dd5be62d25485eb770e05afb408a9627d14d451bae12da" + +[[package]] +name = "rustc-demangle" +version = "0.1.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" + +[[package]] +name = "syn" +version = "2.0.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "718fa2415bcb8d8bd775917a1bf12a7931b6dfa890753378538118181e0cb398" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "tokio" +version = "1.32.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17ed6077ed6cd6c74735e21f37eb16dc3935f96878b1fe961074089cc80893f9" +dependencies = [ + "backtrace", + "pin-project-lite", + "tokio-macros", +] + +[[package]] +name = "tokio-macros" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "unicode-ident" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "301abaae475aa91687eb82514b328ab47a211a533026cb25fc3e519b86adfc3c" diff --git a/globtest/Cargo.toml b/globtest/Cargo.toml new file mode 100644 index 0000000..043e6bc --- /dev/null +++ b/globtest/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "globtest" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +async-recursion = "1.0.5" +regex = "1.9.5" +tokio = { version = "1.32.0", features = ["rt", "macros", "fs"] } diff --git a/globtest/README.md b/globtest/README.md new file mode 100644 index 0000000..842d522 --- /dev/null +++ b/globtest/README.md @@ -0,0 +1,3 @@ +# GlobTest + +Testing making some simple `cp` using Tokio, with wildcard expansion (not actual globs, but close). diff --git a/globtest/src/main.rs b/globtest/src/main.rs new file mode 100644 index 0000000..582058b --- /dev/null +++ b/globtest/src/main.rs @@ -0,0 +1,100 @@ +use std::path::{Path, PathBuf}; + +use regex::Regex; + +#[tokio::main(flavor = "current_thread")] +async fn main() { + let mut args = std::env::args(); + args.next(); // jump the command name. + + let source = PathBuf::from(args.next().expect("I want a place to copy from!")); + let target = PathBuf::from(args.next().expect("I want a place to copy to!")); + + println!("From {source:?} to {target:?}"); + + match (source.is_file(), source.is_dir()) { + (true, true) => { + println!("NO, WAIT! HOW THE THING IS A FILE AND DIR AT THE SAME TIME?!?!"); + } + (true, false) => { + println!("Source is file"); + copy_file(&source, &target).await; + } + (false, true) => { + println!("Source is a whole directory"); + copy_dir(&source, &target).await; + } + (false, false) => { + println!("Source is not a file or a directory"); + copy_magic(&source, &target).await + } + } +} + +/// Magical copy +async fn copy_magic(source: &Path, target: &Path) { + if let Some(name) = source.file_name() { + if name.to_str().unwrap().contains('*') { + copy_mask(source, target).await; + } else { + println!("Source is not a file, not a dir and it doesn't have a mask."); + println!("I think you're nuts"); + } + } +} + +async fn copy_mask(source: &Path, target: &Path) { + let mask = source.file_name().unwrap(); + let source = source.parent().unwrap(); + let re = Regex::new(&mask.to_str().unwrap().replace("*", ".*")).unwrap(); + + let mut reader = tokio::fs::read_dir(&source).await.unwrap(); + while let Ok(Some(entry)) = reader.next_entry().await { + let entry = entry.path(); + if entry.is_file() { + if let Some(name) = entry.file_name() { + // does the name match the mask? + if re.is_match(name.to_str().unwrap()) { + copy_file(&source.join(name), target).await; + } + } + } + } +} + +/// Make a copy of a directory +#[async_recursion::async_recursion] +async fn copy_dir(source: &Path, target: &Path) { + if !target.is_dir() { + println!("Can't copy a whole directory to something that it is NOT a directory!"); + return; + } + + let mut reader = tokio::fs::read_dir(&source).await.unwrap(); + while let Ok(Some(entry)) = reader.next_entry().await { + let entry = entry.path(); + if entry.is_file() { + copy_file(&entry, &target).await; + } else { + let name = entry.file_name().unwrap(); + let target = target.join(name); + tokio::fs::create_dir_all(&target).await.unwrap(); + copy_dir(&entry, &target).await; + } + } +} + +/// Make a copy of a file. +async fn copy_file(source: &Path, target: &Path) { + if target.is_dir() { + println!("Copying to a directory"); + let filename = source.file_name().unwrap(); // after all, it IS a file + let target = target.join(filename); + println!("Copying from {:?} to {:?}", source, target); + tokio::fs::copy(source, target).await.unwrap(); + } else { + println!("Assuming the destination is already the filename"); + println!("Copying from {:?} to {:?}", source, target); + tokio::fs::copy(source, target).await.unwrap(); + } +}