use crate::sshcfg;
use colored::Colorize;
use std::path::Path;
#[derive(clap::Args)]
pub struct Args {
#[arg(required = true, num_args = 2..)]
pub paths: Vec<String>,
}
pub fn run(args: Args) {
let (dst, srcs) = args.paths.split_last().unwrap();
let known: Vec<String> = sshcfg::list_hosts().into_iter().map(|h| h.alias).collect();
for token in &args.paths {
if let Some(alias) = remote_alias(token)
&& !known.contains(&alias)
{
eprintln!(
"{}",
format!("essh: '{alias}' isn't in your ~/.ssh/config - passing it to scp as-is.").yellow()
);
}
}
let recursive = srcs.iter().any(|s| remote_alias(s).is_none() && Path::new(s).is_dir());
let mut cmd = std::process::Command::new("scp");
if recursive {
cmd.arg("-r");
}
cmd.args(srcs).arg(dst);
match cmd.status() {
Ok(status) if status.success() => {}
Ok(status) => std::process::exit(status.code().unwrap_or(1)),
Err(e) => {
eprintln!("{}", format!("essh: could not run scp: {e}").red());
std::process::exit(127);
}
}
}
fn remote_alias(token: &str) -> Option<String> {
let (head, _tail) = token.split_once(':')?;
if head.is_empty() || head.contains('/') || head.contains('\\') || head.len() == 1 {
return None; }
Some(head.to_string())
}