diff --git a/src/file.rs b/src/file.rs index 161631b..986a110 100644 --- a/src/file.rs +++ b/src/file.rs @@ -19,10 +19,6 @@ impl TryFrom for FileNameInfo { type Error = FileInfoError; fn try_from(file: PathBuf) -> Result { - if !file.is_file() { - return Err(FileInfoError::NotAFile); - } - let file_name = file.file_name().ok_or(FileInfoError::NotAFile)?; let file_name = file_name .to_str() diff --git a/src/main.rs b/src/main.rs index c595e9e..794450f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -6,7 +6,7 @@ mod os_string_builder; mod server; use crate::action::{Action, FileAction, ServerActions}; -use crate::command::LogRunnable; +use crate::command::{ExecutionError, LogRunnable}; use crate::file::{FileMatcher, FileNameInfo}; use crate::logger::{LogLevel, Logger}; use crate::os_string_builder::ReplaceWithOsStr; @@ -18,7 +18,7 @@ use std::cell::LazyCell; use std::hash::Hash; use std::io::Write; use std::iter::once; -use std::path::PathBuf; +use std::path::{Path, PathBuf}; use std::str::FromStr; use std::{env, fs, io}; @@ -63,6 +63,12 @@ enum Command { Upload { /// The file to upload file: PathBuf, + /// The ssh server to get the file from. + /// + /// When this option is set, the file path must be absolute, or relative to the server directory. + /// The upload-directory has no influence on where the file will be taken from. + #[arg(short = 'S', long)] + file_server: Option, /// How to handle older versions of the file #[arg(short = 'a', long, default_value = "delete", default_missing_value = "archive", num_args = 0..=1)] old_version_policy: OldVersionPolicy, @@ -157,14 +163,14 @@ fn main() -> Result<(), String> { .servers .iter() .map(|server_reference| { - let server_name = server_reference.get_identifier(); + let server_identifier = server_reference.get_identifier(); server_reference .clone() .try_resolve_lazy(&mut configured_servers) - .map_err(|msg| format!("Can't resolve server directory for '{server_name}': {msg}")) + .map_err(|msg| format!("Can't resolve server directory for '{server_identifier}': {msg}")) .and_then(|opt_server| { opt_server.ok_or(format!( - "no server directory has been configured for server '{server_name}'" + "no server directory has been configured for server '{server_identifier}'" )) }) }) @@ -173,6 +179,7 @@ fn main() -> Result<(), String> { match args.command { Command::Upload { file, + file_server, old_version_policy, upload_directory, no_confirm, @@ -181,6 +188,55 @@ fn main() -> Result<(), String> { require_non_empty_servers(&servers)?; start_ssh_agent(&logger)?; + //resolve file server + let file_server = match file_server { + Some(server_reference) => { + let file_server_identifier = server_reference.get_identifier().to_string(); + let server = server_reference.try_resolve_lazy(&mut configured_servers) + .map_err(|e| format!("Can't resolve server directory for file-server '{file_server_identifier}': {e}"))? + .ok_or_else(|| format!("no server directory has been configured for file-server '{file_server_identifier}'"))?; + Some(server) + } + None => None, + }; + + //make sure file exists and is a file + match &file_server { + Some(file_server) => { + match &file_server.address { + ServerAddress::Ssh { ssh_address } => { + match ShellCmd::new("ssh") + .arg(ssh_address) + .arg(osf!("test -f ") + file_server.server_directory_path.join(&file)) + .collect_output() + { + Ok(_) => {} //file exists on file server + Err(e) => { + match &e.error { + ExecutionError::StartError(_) => { + //error occurred + Err(format!( + "Failed to check whether file exists on file-server: {e}" + ))?; + } + ExecutionError::BadExitStatus(_) => { + //file does not exist on file server + Err("File doesn't exist on file server")?; + } + } + } + }; + } + ServerAddress::Localhost => { + check_local_file_exists(file_server.server_directory_path.join(&file))?; + } + } + } + None => { + check_local_file_exists(&file)?; + } + } + let file_name_info = FileNameInfo::try_from(file.clone()).map_err(|e| format!("bad file: {e}"))?; @@ -294,12 +350,19 @@ fn main() -> Result<(), String> { for file_action in server_actions.actions { match file_action.kind { Action::Add | Action::Replace => { + let scp_source = match &file_server { + Some(file_server) => osf!(match &file_server.address { + ServerAddress::Ssh{ ssh_address } => format!("{ssh_address}:"), + ServerAddress::Localhost => "".to_string(), + }) + file_server.server_directory_path.join(&file), + None => osf!(&file), + }; let scp_target = osf!(match &server.address { ServerAddress::Ssh { ssh_address } => format!("{ssh_address}:"), ServerAddress::Localhost => "".to_string(), }) + &server_actions.working_directory; ShellCmd::new("scp") - .arg(file.clone()) + .arg(scp_source) .arg(scp_target) .run(&logger) .map_err(|e| format!("upload failure: {e}"))?; @@ -470,6 +533,21 @@ fn main() -> Result<(), String> { Ok(()) } +fn check_local_file_exists

(path: P) -> Result<(), String> +where + P: AsRef, +{ + let path = path.as_ref(); + if !path.is_file() { + return Err(format!( + "{} does not point to a file", + path.to_string_lossy() + )); + } + + Ok(()) +} + fn get_home_directory() -> Result { homedir::my_home() .map_err(|e| format!("Failed to determine home directory: {e}"))