mirror of
https://github.com/veeso/termscp.git
synced 2025-12-07 01:26:04 -08:00
find method for FileTransfer trait
This commit is contained in:
7
Cargo.lock
generated
7
Cargo.lock
generated
@@ -1409,6 +1409,7 @@ dependencies = [
|
|||||||
"ureq",
|
"ureq",
|
||||||
"users",
|
"users",
|
||||||
"whoami",
|
"whoami",
|
||||||
|
"wildmatch",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -1703,6 +1704,12 @@ dependencies = [
|
|||||||
"web-sys",
|
"web-sys",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wildmatch"
|
||||||
|
version = "1.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7f44b95f62d34113cf558c93511ac93027e03e9c29a60dd0fd70e6e025c7270a"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "winapi"
|
name = "winapi"
|
||||||
version = "0.3.9"
|
version = "0.3.9"
|
||||||
|
|||||||
@@ -39,6 +39,7 @@ toml = "0.5.8"
|
|||||||
tui = { version = "0.14.0", features = ["crossterm"], default-features = false }
|
tui = { version = "0.14.0", features = ["crossterm"], default-features = false }
|
||||||
ureq = { version = "2.0.2", features = ["json"] }
|
ureq = { version = "2.0.2", features = ["json"] }
|
||||||
whoami = "1.1.0"
|
whoami = "1.1.0"
|
||||||
|
wildmatch = "1.0.13"
|
||||||
|
|
||||||
[target.'cfg(any(target_os = "unix", target_os = "macos", target_os = "linux"))'.dependencies]
|
[target.'cfg(any(target_os = "unix", target_os = "macos", target_os = "linux"))'.dependencies]
|
||||||
users = "0.11.0"
|
users = "0.11.0"
|
||||||
|
|||||||
@@ -976,7 +976,7 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_filetransfer_sftp_copy() {
|
fn test_filetransfer_ftp_copy() {
|
||||||
let mut ftp: FtpFileTransfer = FtpFileTransfer::new(false);
|
let mut ftp: FtpFileTransfer = FtpFileTransfer::new(false);
|
||||||
// Connect
|
// Connect
|
||||||
assert!(ftp
|
assert!(ftp
|
||||||
@@ -1090,6 +1090,32 @@ mod tests {
|
|||||||
assert!(ftp.disconnect().is_ok());
|
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]
|
#[test]
|
||||||
fn test_filetransfer_ftp_uninitialized() {
|
fn test_filetransfer_ftp_uninitialized() {
|
||||||
let file: FsFile = FsFile {
|
let file: FsFile = FsFile {
|
||||||
|
|||||||
@@ -23,12 +23,15 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
// dependencies
|
||||||
|
extern crate wildmatch;
|
||||||
|
// locals
|
||||||
|
use crate::fs::{FsEntry, FsFile};
|
||||||
|
// ext
|
||||||
use std::io::{Read, Write};
|
use std::io::{Read, Write};
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
|
use wildmatch::WildMatch;
|
||||||
use crate::fs::{FsEntry, FsFile};
|
// exports
|
||||||
|
|
||||||
// Transfers
|
|
||||||
pub mod ftp_transfer;
|
pub mod ftp_transfer;
|
||||||
pub mod scp_transfer;
|
pub mod scp_transfer;
|
||||||
pub mod sftp_transfer;
|
pub mod sftp_transfer;
|
||||||
@@ -229,6 +232,66 @@ pub trait FileTransfer {
|
|||||||
/// This mighe be necessary for some protocols.
|
/// This mighe be necessary for some protocols.
|
||||||
/// You must call this method each time you want to finalize the read of the remote file.
|
/// 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>;
|
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
|
// Traits
|
||||||
|
|||||||
@@ -1056,6 +1056,31 @@ mod tests {
|
|||||||
assert!(client.disconnect().is_ok());
|
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]
|
#[test]
|
||||||
fn test_filetransfer_scp_recv() {
|
fn test_filetransfer_scp_recv() {
|
||||||
let mut client: ScpFileTransfer = ScpFileTransfer::new(SshKeyStorage::empty());
|
let mut client: ScpFileTransfer = ScpFileTransfer::new(SshKeyStorage::empty());
|
||||||
|
|||||||
@@ -603,15 +603,13 @@ impl FileTransfer for SftpFileTransfer {
|
|||||||
/// Execute a command on remote host
|
/// Execute a command on remote host
|
||||||
fn exec(&mut self, cmd: &str) -> Result<String, FileTransferError> {
|
fn exec(&mut self, cmd: &str) -> Result<String, FileTransferError> {
|
||||||
match self.is_connected() {
|
match self.is_connected() {
|
||||||
true => {
|
true => match self.perform_shell_cmd_with_path(cmd) {
|
||||||
match self.perform_shell_cmd_with_path(cmd) {
|
Ok(output) => Ok(output),
|
||||||
Ok(output) => Ok(output),
|
Err(err) => Err(FileTransferError::new_ex(
|
||||||
Err(err) => Err(FileTransferError::new_ex(
|
FileTransferErrorType::ProtocolError,
|
||||||
FileTransferErrorType::ProtocolError,
|
format!("{}", err),
|
||||||
format!("{}", err),
|
)),
|
||||||
)),
|
},
|
||||||
}
|
|
||||||
}
|
|
||||||
false => Err(FileTransferError::new(
|
false => Err(FileTransferError::new(
|
||||||
FileTransferErrorType::UninitializedSession,
|
FileTransferErrorType::UninitializedSession,
|
||||||
)),
|
)),
|
||||||
@@ -876,6 +874,9 @@ mod tests {
|
|||||||
.is_err());
|
.is_err());
|
||||||
// Disconnect
|
// Disconnect
|
||||||
assert!(client.disconnect().is_ok());
|
assert!(client.disconnect().is_ok());
|
||||||
|
assert!(client
|
||||||
|
.change_dir(PathBuf::from("gomar/pett").as_path())
|
||||||
|
.is_err());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -899,6 +900,8 @@ mod tests {
|
|||||||
assert_eq!(files.len(), 3); // There are 3 files
|
assert_eq!(files.len(), 3); // There are 3 files
|
||||||
// Disconnect
|
// Disconnect
|
||||||
assert!(client.disconnect().is_ok());
|
assert!(client.disconnect().is_ok());
|
||||||
|
// Verify err
|
||||||
|
assert!(client.list_dir(pwd.as_path()).is_err());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -944,6 +947,33 @@ mod tests {
|
|||||||
assert_eq!(client.exec("echo 5").ok().unwrap().as_str(), "5\n");
|
assert_eq!(client.exec("echo 5").ok().unwrap().as_str(), "5\n");
|
||||||
// Disconnect
|
// Disconnect
|
||||||
assert!(client.disconnect().is_ok());
|
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]
|
#[test]
|
||||||
|
|||||||
Reference in New Issue
Block a user