Don't use shell command on local machine

This commit is contained in:
Leonard Steppy 2025-02-03 17:55:34 +01:00
parent 0109bf6c6f
commit faf4e47cac
2 changed files with 65 additions and 38 deletions

View File

@ -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

View File

@ -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<OsString> = 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::<Result<Vec<_>, _>>()?
.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")