find method for FileTransfer trait

This commit is contained in:
ChristianVisintin
2021-03-08 10:53:35 +01:00
committed by veeso
parent 3a1c6cac95
commit b9d801e8bc
6 changed files with 166 additions and 14 deletions

7
Cargo.lock generated
View File

@@ -1409,6 +1409,7 @@ dependencies = [
"ureq",
"users",
"whoami",
"wildmatch",
]
[[package]]
@@ -1703,6 +1704,12 @@ dependencies = [
"web-sys",
]
[[package]]
name = "wildmatch"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7f44b95f62d34113cf558c93511ac93027e03e9c29a60dd0fd70e6e025c7270a"
[[package]]
name = "winapi"
version = "0.3.9"

View File

@@ -39,6 +39,7 @@ toml = "0.5.8"
tui = { version = "0.14.0", features = ["crossterm"], default-features = false }
ureq = { version = "2.0.2", features = ["json"] }
whoami = "1.1.0"
wildmatch = "1.0.13"
[target.'cfg(any(target_os = "unix", target_os = "macos", target_os = "linux"))'.dependencies]
users = "0.11.0"

View File

@@ -976,7 +976,7 @@ mod tests {
}
#[test]
fn test_filetransfer_sftp_copy() {
fn test_filetransfer_ftp_copy() {
let mut ftp: FtpFileTransfer = FtpFileTransfer::new(false);
// Connect
assert!(ftp
@@ -1090,6 +1090,32 @@ mod tests {
assert!(ftp.disconnect().is_ok());
}
#[test]
fn test_filetransfer_ftp_find() {
let mut client: FtpFileTransfer = FtpFileTransfer::new(false);
// Connect
assert!(client
.connect(
String::from("test.rebex.net"),
21,
Some(String::from("demo")),
Some(String::from("password"))
)
.is_ok());
// Pwd
assert_eq!(client.pwd().ok().unwrap(), PathBuf::from("/"));
// Search for file (let's search for pop3-*.png); there should be 2
let search_res: Vec<FsFile> = client.find("pop3-*.png").ok().unwrap();
assert_eq!(search_res.len(), 2);
// verify names
assert_eq!(search_res[0].name.as_str(), "pop3-browser.png");
assert_eq!(search_res[1].name.as_str(), "pop3-console-client.png");
// Disconnect
assert!(client.disconnect().is_ok());
// Verify err
assert!(client.find("pippo").is_err());
}
#[test]
fn test_filetransfer_ftp_uninitialized() {
let file: FsFile = FsFile {

View File

@@ -23,12 +23,15 @@
*
*/
// dependencies
extern crate wildmatch;
// locals
use crate::fs::{FsEntry, FsFile};
// ext
use std::io::{Read, Write};
use std::path::{Path, PathBuf};
use crate::fs::{FsEntry, FsFile};
// Transfers
use wildmatch::WildMatch;
// exports
pub mod ftp_transfer;
pub mod scp_transfer;
pub mod sftp_transfer;
@@ -229,6 +232,66 @@ pub trait FileTransfer {
/// This mighe be necessary for some protocols.
/// You must call this method each time you want to finalize the read of the remote file.
fn on_recv(&mut self, readable: Box<dyn Read>) -> Result<(), FileTransferError>;
/// ### find
///
/// Find files from current directory (in all subdirectories) whose name matches the provided search
/// Search supports wildcards ('?', '*')
fn find(&mut self, search: &str) -> Result<Vec<FsFile>, FileTransferError> {
match self.is_connected() {
true => {
// Starting from current directory, iter dir
match self.pwd() {
Ok(p) => self.iter_search(p.as_path(), &WildMatch::new(search)),
Err(err) => Err(err),
}
}
false => Err(FileTransferError::new(
FileTransferErrorType::UninitializedSession,
)),
}
}
/// ### iter_search
///
/// Search recursively in `dir` for file matching the wildcard.
/// NOTE: DON'T RE-IMPLEMENT THIS FUNCTION, unless the file transfer provides a faster way to do so
/// NOTE: don't call this method from outside; consider it as private
fn iter_search(
&mut self,
dir: &Path,
filter: &WildMatch,
) -> Result<Vec<FsFile>, FileTransferError> {
let mut drained: Vec<FsFile> = Vec::new();
// Scan directory
match self.list_dir(dir) {
Ok(entries) => {
/* For each entry:
- if is dir: call iter_search with `dir`
- push `iter_search` result to `drained`
- if is file: check if it matches `filter`
- if it matches `filter`: push to to filter
*/
for entry in entries.iter() {
match entry {
FsEntry::Directory(dir) => {
match self.iter_search(dir.abs_path.as_path(), filter) {
Ok(mut filtered) => drained.append(&mut filtered),
Err(err) => return Err(err),
}
}
FsEntry::File(file) => {
if filter.is_match(file.name.as_str()) {
drained.push(file.clone());
}
}
}
}
Ok(drained)
}
Err(err) => Err(err),
}
}
}
// Traits

View File

@@ -1056,6 +1056,31 @@ mod tests {
assert!(client.disconnect().is_ok());
}
#[test]
fn test_filetransfer_scp_find() {
let mut client: ScpFileTransfer = ScpFileTransfer::new(SshKeyStorage::empty());
assert!(client
.connect(
String::from("test.rebex.net"),
22,
Some(String::from("demo")),
Some(String::from("password"))
)
.is_ok());
// Check session and scp
assert!(client.session.is_some());
// Search for file (let's search for pop3-*.png); there should be 2
let search_res: Vec<FsFile> = client.find("pop3-*.png").ok().unwrap();
assert_eq!(search_res.len(), 2);
// verify names
assert_eq!(search_res[0].name.as_str(), "pop3-browser.png");
assert_eq!(search_res[1].name.as_str(), "pop3-console-client.png");
// Disconnect
assert!(client.disconnect().is_ok());
// Verify err
assert!(client.find("pippo").is_err());
}
#[test]
fn test_filetransfer_scp_recv() {
let mut client: ScpFileTransfer = ScpFileTransfer::new(SshKeyStorage::empty());

View File

@@ -603,15 +603,13 @@ impl FileTransfer for SftpFileTransfer {
/// Execute a command on remote host
fn exec(&mut self, cmd: &str) -> Result<String, FileTransferError> {
match self.is_connected() {
true => {
match self.perform_shell_cmd_with_path(cmd) {
true => match self.perform_shell_cmd_with_path(cmd) {
Ok(output) => Ok(output),
Err(err) => Err(FileTransferError::new_ex(
FileTransferErrorType::ProtocolError,
format!("{}", err),
)),
}
}
},
false => Err(FileTransferError::new(
FileTransferErrorType::UninitializedSession,
)),
@@ -876,6 +874,9 @@ mod tests {
.is_err());
// Disconnect
assert!(client.disconnect().is_ok());
assert!(client
.change_dir(PathBuf::from("gomar/pett").as_path())
.is_err());
}
#[test]
@@ -899,6 +900,8 @@ mod tests {
assert_eq!(files.len(), 3); // There are 3 files
// Disconnect
assert!(client.disconnect().is_ok());
// Verify err
assert!(client.list_dir(pwd.as_path()).is_err());
}
#[test]
@@ -944,6 +947,33 @@ mod tests {
assert_eq!(client.exec("echo 5").ok().unwrap().as_str(), "5\n");
// Disconnect
assert!(client.disconnect().is_ok());
// Verify err
assert!(client.exec("echo 1").is_err());
}
#[test]
fn test_filetransfer_sftp_find() {
let mut client: SftpFileTransfer = SftpFileTransfer::new(SshKeyStorage::empty());
assert!(client
.connect(
String::from("test.rebex.net"),
22,
Some(String::from("demo")),
Some(String::from("password"))
)
.is_ok());
// Check session and scp
assert!(client.session.is_some());
// Search for file (let's search for pop3-*.png); there should be 2
let search_res: Vec<FsFile> = client.find("pop3-*.png").ok().unwrap();
assert_eq!(search_res.len(), 2);
// verify names
assert_eq!(search_res[0].name.as_str(), "pop3-browser.png");
assert_eq!(search_res[1].name.as_str(), "pop3-console-client.png");
// Disconnect
assert!(client.disconnect().is_ok());
// Verify err
assert!(client.find("pippo").is_err());
}
#[test]