Add file-server parameter to upload command

This commit is contained in:
Leonard Steppy 2025-02-02 14:16:16 +01:00
parent aa1f53d225
commit 4b4c7b9416
2 changed files with 84 additions and 10 deletions

View File

@ -19,10 +19,6 @@ impl TryFrom<PathBuf> for FileNameInfo {
type Error = FileInfoError; type Error = FileInfoError;
fn try_from(file: PathBuf) -> Result<Self, Self::Error> { fn try_from(file: PathBuf) -> Result<Self, Self::Error> {
if !file.is_file() {
return Err(FileInfoError::NotAFile);
}
let file_name = file.file_name().ok_or(FileInfoError::NotAFile)?; let file_name = file.file_name().ok_or(FileInfoError::NotAFile)?;
let file_name = file_name let file_name = file_name
.to_str() .to_str()

View File

@ -6,7 +6,7 @@ mod os_string_builder;
mod server; mod server;
use crate::action::{Action, FileAction, ServerActions}; use crate::action::{Action, FileAction, ServerActions};
use crate::command::LogRunnable; use crate::command::{ExecutionError, LogRunnable};
use crate::file::{FileMatcher, FileNameInfo}; use crate::file::{FileMatcher, FileNameInfo};
use crate::logger::{LogLevel, Logger}; use crate::logger::{LogLevel, Logger};
use crate::os_string_builder::ReplaceWithOsStr; use crate::os_string_builder::ReplaceWithOsStr;
@ -18,7 +18,7 @@ use std::cell::LazyCell;
use std::hash::Hash; use std::hash::Hash;
use std::io::Write; use std::io::Write;
use std::iter::once; use std::iter::once;
use std::path::PathBuf; use std::path::{Path, PathBuf};
use std::str::FromStr; use std::str::FromStr;
use std::{env, fs, io}; use std::{env, fs, io};
@ -63,6 +63,12 @@ enum Command {
Upload { Upload {
/// The file to upload /// The file to upload
file: PathBuf, 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<ServerReference>,
/// How to handle older versions of the file /// How to handle older versions of the file
#[arg(short = 'a', long, default_value = "delete", default_missing_value = "archive", num_args = 0..=1)] #[arg(short = 'a', long, default_value = "delete", default_missing_value = "archive", num_args = 0..=1)]
old_version_policy: OldVersionPolicy, old_version_policy: OldVersionPolicy,
@ -157,14 +163,14 @@ fn main() -> Result<(), String> {
.servers .servers
.iter() .iter()
.map(|server_reference| { .map(|server_reference| {
let server_name = server_reference.get_identifier(); let server_identifier = server_reference.get_identifier();
server_reference server_reference
.clone() .clone()
.try_resolve_lazy(&mut configured_servers) .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| { .and_then(|opt_server| {
opt_server.ok_or(format!( 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 { match args.command {
Command::Upload { Command::Upload {
file, file,
file_server,
old_version_policy, old_version_policy,
upload_directory, upload_directory,
no_confirm, no_confirm,
@ -181,6 +188,55 @@ fn main() -> Result<(), String> {
require_non_empty_servers(&servers)?; require_non_empty_servers(&servers)?;
start_ssh_agent(&logger)?; 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 = let file_name_info =
FileNameInfo::try_from(file.clone()).map_err(|e| format!("bad file: {e}"))?; 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 { for file_action in server_actions.actions {
match file_action.kind { match file_action.kind {
Action::Add | Action::Replace => { 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 { let scp_target = osf!(match &server.address {
ServerAddress::Ssh { ssh_address } => format!("{ssh_address}:"), ServerAddress::Ssh { ssh_address } => format!("{ssh_address}:"),
ServerAddress::Localhost => "".to_string(), ServerAddress::Localhost => "".to_string(),
}) + &server_actions.working_directory; }) + &server_actions.working_directory;
ShellCmd::new("scp") ShellCmd::new("scp")
.arg(file.clone()) .arg(scp_source)
.arg(scp_target) .arg(scp_target)
.run(&logger) .run(&logger)
.map_err(|e| format!("upload failure: {e}"))?; .map_err(|e| format!("upload failure: {e}"))?;
@ -470,6 +533,21 @@ fn main() -> Result<(), String> {
Ok(()) Ok(())
} }
fn check_local_file_exists<P>(path: P) -> Result<(), String>
where
P: AsRef<Path>,
{
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<PathBuf, String> { fn get_home_directory() -> Result<PathBuf, String> {
homedir::my_home() homedir::my_home()
.map_err(|e| format!("Failed to determine home directory: {e}")) .map_err(|e| format!("Failed to determine home directory: {e}"))