From faf4e47cac1a1c93bc15429c6890ec930b23f126 Mon Sep 17 00:00:00 2001 From: Steppy Date: Mon, 3 Feb 2025 17:55:34 +0100 Subject: [PATCH] Don't use shell command on local machine --- src/file.rs | 4 ++- src/main.rs | 99 +++++++++++++++++++++++++++++++++-------------------- 2 files changed, 65 insertions(+), 38 deletions(-) diff --git a/src/file.rs b/src/file.rs index 986a110..2e9d9db 100644 --- a/src/file.rs +++ b/src/file.rs @@ -2,6 +2,7 @@ use std::error::Error; use std::fmt::{Display, Formatter}; use std::path::PathBuf; +//TODO this whole structure should probably use OsString instead of String #[derive(Debug, Clone, Eq, PartialEq, Hash)] pub struct FileNameInfo { pub name: String, @@ -82,6 +83,7 @@ impl Display for FileInfoError { impl Error for FileInfoError {} +//TODO this structure should probably work with OsString instead of String #[derive(Debug, Clone)] pub struct FileMatcher { name: String, @@ -108,7 +110,7 @@ impl FileMatcher { ..self } } - + pub fn matches(&self, file_name: &str) -> bool { file_name.starts_with(&self.name) && self diff --git a/src/main.rs b/src/main.rs index 0e3150c..ff06a4a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -15,7 +15,7 @@ use clap::{Parser, Subcommand, ValueEnum}; use lazy_regex::{lazy_regex, Lazy, Regex}; use server::{Server, ServerReference}; use std::cell::LazyCell; -use std::ffi::OsStr; +use std::ffi::{OsStr, OsString}; use std::hash::Hash; use std::io::Write; use std::iter::once; @@ -292,23 +292,35 @@ fn main() -> Result<(), String> { Ok(ServerActions { server, actions: { - let mut ls_command = match &server.address { - ServerAddress::Ssh { ssh_address } => { - let mut cmd = ShellCmd::new("ssh"); - cmd.arg(ssh_address).arg(osf!("ls ") + &working_directory); - cmd - } - ServerAddress::Localhost => { - //TODO don't use shell command on localhost, this will fail on windows - let mut cmd = ShellCmd::new("ls"); - cmd.arg(&working_directory); - cmd - } + let present_file_names: Vec = match &server.address { + ServerAddress::Ssh { ssh_address } => ShellCmd::new("ls") + .arg(ssh_address) + .arg(osf!("ls ") + &working_directory) + .collect_output() + .map_err(|e| { + format!( + "Failed to query present files on server {}: {e}", + server.get_name() + ) + })? + .stdout + .split(|&b| b == b'\n') + .map(|bytes| OsStr::from_bytes(bytes).to_os_string()) + .collect(), + ServerAddress::Localhost => fs::read_dir(&working_directory) + .map_err(|e| format!("Failed to get files in working directory: {e}"))? + .map(|entry| entry.map_err(|e| format!("Failed to access directory entry: {e}"))) + .collect::, _>>()? + .into_iter() + .filter_map(|entry| { + if entry.path().is_file() { + Some(entry.file_name()) + } else { + None + } + }) + .collect(), }; - let ls_output = ls_command - .collect_output() - .map_err(|e| format!("failed to query files: {e}"))?; - let ls_output = String::from_utf8_lossy(&ls_output.stdout); file_details .iter() @@ -319,43 +331,56 @@ fn main() -> Result<(), String> { file_matcher = file_matcher.and_extension(extension); } - let file_name = file_name_info.to_full_file_name(); + let file_name = OsString::from(file_name_info.to_full_file_name()); let add_action = FileAction::new(file, Action::Add).expect("path points to file"); - let mut ls_lines = ls_output.lines(); - - if pure && ls_lines.clone().any(|file| file == file_name) { - log!(logger, debug, "file is already present on {}: {}", server.get_name(), file_name); + if pure && present_file_names.iter().any(|file| *file == file_name) { + log!( + logger, + debug, + "file is already present on {}: {}", + server.get_name(), + file_name.to_string_lossy() + ); return vec![]; //ignore that file, since it is already present } match old_version_policy { OldVersionPolicy::Ignore => { - if !ls_lines.any(|file| file == file_name) { + if !present_file_names.iter().any(|file| *file == file_name) { vec![add_action] //file doesn't exist yet } else { vec![FileAction::new(&file_name, Action::Replace) .expect("path points to file")] } } - OldVersionPolicy::Archive => ls_lines - .filter(|file| file_matcher.matches(file)) - .map(|file| { - FileAction::new( - file, - Action::rename(format!("{file}{}", file.chars().last().unwrap_or('1'))), - ) - .expect("path points to file") - }) - .chain(once(add_action)) - .collect(), + OldVersionPolicy::Archive => { + //TODO avoid lossy match + present_file_names + .iter() + .filter(|file| file_matcher.matches(&file.to_string_lossy())) + .map(|file| { + FileAction::new( + file, + Action::rename(format!( + "{}{}", + file.to_string_lossy(), + file.to_string_lossy().chars().last().unwrap_or('1') + )), + ) + .expect("path points to file") + }) + .chain(once(add_action)) + .collect() + }, OldVersionPolicy::Delete => { - let mut actions = ls_lines - .filter(|file| file_matcher.matches(file)) + //TODO avoid lossy match + let mut actions = present_file_names.iter() + .filter(|file| file_matcher.matches(&file.to_string_lossy())) .map(|file| { //special case -> file has the same name as current file, then we just need to replace it - if file == file_name { + if *file == file_name { FileAction::new(file, Action::Replace).expect("path points to file") } else { FileAction::new(file, Action::Delete).expect("path points to file")