feat(sftp): introduce helper functions for directory listing and stat commands
- Added `list_dir_command` and `stat_command` functions to streamline the creation of shell commands for listing directories and retrieving file statistics with numeric owner and group information. - Updated `stat_remote_properties` and `list_dir` methods to utilize the new command functions, improving code readability and maintainability. - Enhanced unit tests to validate the new command functions and ensure correct parsing of directory entries.
This commit is contained in:
1 parent
8605ae7b25
commit
f0267a6538
1 file changed
+65
-12
@@ -323,6 +323,14 @@ fn split_ls_fields(line: &str) -> Option<(Vec<&str>, &str)> {
|
||||
(cursor < bytes.len()).then(|| (fields, &line[cursor..]))
|
||||
}
|
||||
|
||||
fn list_dir_command(path: &str) -> String {
|
||||
format!("LC_ALL=C ls -la -n -- {}", sh_quote(path))
|
||||
}
|
||||
|
||||
fn stat_command(path: &str) -> String {
|
||||
format!("LC_ALL=C ls -lad -n -- {}", sh_quote(path))
|
||||
}
|
||||
|
||||
fn parse_ls_line(line: &str) -> Option<FileEntry> {
|
||||
let line = line.trim_start();
|
||||
if line.trim_end().is_empty() || line.starts_with("total ") {
|
||||
@@ -442,11 +450,7 @@ async fn stat_remote_properties(
|
||||
ssh_handle: &Arc<SshConnectionHandles>,
|
||||
path: &str,
|
||||
) -> AppResult<FileProperties> {
|
||||
let result = exec_command(
|
||||
ssh_handle,
|
||||
&format!("LC_ALL=C ls -lad -- {}", sh_quote(path)),
|
||||
)
|
||||
.await?;
|
||||
let result = exec_command(ssh_handle, &stat_command(path)).await?;
|
||||
if result.exit_code != Some(0) {
|
||||
let stderr_text = String::from_utf8_lossy(&result.stderr);
|
||||
return Err(AppError::Channel(format!(
|
||||
@@ -888,9 +892,7 @@ impl RemoteFs for ScpNormalBackend {
|
||||
|
||||
async fn list_dir(&self, path: &str) -> AppResult<Vec<FileEntry>> {
|
||||
let listing_path = remote_dir_listing_path(path);
|
||||
let output = self
|
||||
.exec_ok(&format!("LC_ALL=C ls -la -- {}", sh_quote(&listing_path)))
|
||||
.await?;
|
||||
let output = self.exec_ok(&list_dir_command(&listing_path)).await?;
|
||||
let mut entries = Vec::new();
|
||||
for line in output.lines() {
|
||||
if let Some(mut entry) = parse_ls_line(line) {
|
||||
@@ -908,9 +910,7 @@ impl RemoteFs for ScpNormalBackend {
|
||||
}
|
||||
|
||||
async fn stat(&self, path: &str) -> AppResult<FileProperties> {
|
||||
let output = self
|
||||
.exec_ok(&format!("LC_ALL=C ls -lad -- {}", sh_quote(path)))
|
||||
.await?;
|
||||
let output = self.exec_ok(&stat_command(path)).await?;
|
||||
let line = output
|
||||
.lines()
|
||||
.find(|l| !l.trim().is_empty() && !l.starts_with("total "))
|
||||
@@ -1558,7 +1558,60 @@ impl RemoteFs for ScpNormalBackend {
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::parse_ls_line_to_properties;
|
||||
use super::{list_dir_command, parse_ls_line, parse_ls_line_to_properties, stat_command};
|
||||
|
||||
#[test]
|
||||
fn ls_parser_handles_numeric_owner_and_group() {
|
||||
let entry = parse_ls_line("-rw-r--r-- 1 1000 100513 203 Aug 3 16:37 .zshrc").unwrap();
|
||||
assert_eq!(entry.name, ".zshrc");
|
||||
assert_eq!(entry.owner, "1000");
|
||||
assert_eq!(entry.group, "100513");
|
||||
assert_eq!(entry.size, 203);
|
||||
assert!(!entry.is_dir);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn ls_parser_keeps_hidden_directory_name() {
|
||||
let entry = parse_ls_line("drwx------ 4 1000 100513 4096 Sep 1 09:31 .copilot").unwrap();
|
||||
assert_eq!(entry.name, ".copilot");
|
||||
assert!(entry.is_dir);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn ls_parser_keeps_spaces_in_file_name() {
|
||||
let entry =
|
||||
parse_ls_line("-rw-r--r-- 1 1000 100513 123 Sep 1 09:31 hello world.txt").unwrap();
|
||||
assert_eq!(entry.name, "hello world.txt");
|
||||
assert!(!entry.is_dir);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn ls_parser_keeps_spaces_in_directory_name() {
|
||||
let entry = parse_ls_line("drwxr-xr-x 2 1000 100513 4096 Sep 1 09:31 My Folder").unwrap();
|
||||
assert_eq!(entry.name, "My Folder");
|
||||
assert!(entry.is_dir);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn ls_parser_strips_symlink_target_from_name() {
|
||||
let entry =
|
||||
parse_ls_line("lrwxrwxrwx 1 1000 100513 11 Aug 29 12:00 current -> releases/v2")
|
||||
.unwrap();
|
||||
assert_eq!(entry.name, "current");
|
||||
assert!(entry.is_symlink);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn ls_commands_request_numeric_owner_and_group() {
|
||||
assert_eq!(
|
||||
list_dir_command("/home/user/My Folder"),
|
||||
"LC_ALL=C ls -la -n -- '/home/user/My Folder'"
|
||||
);
|
||||
assert_eq!(
|
||||
stat_command("/home/user/My Folder"),
|
||||
"LC_ALL=C ls -lad -n -- '/home/user/My Folder'"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn ls_properties_parser_keeps_relative_symlink_target() {
|
||||
|
||||
Reference in new issue
Block a user