Add ServerReference and parse methods for Server

This commit is contained in:
Leonard Steppy 2024-12-11 16:37:15 +01:00
parent 9e0bf8c8c4
commit 03b7a6f67f

View File

@ -1,7 +1,9 @@
use clap::builder::Str;
use clap::{Parser, Subcommand, ValueEnum};
use std::env;
use std::error::Error;
use std::fmt::{Display, Formatter};
use std::path::PathBuf;
use std::str::FromStr;
const SERVERS_ENV_VAR: &str = "MSSH_SERVERS";
@ -20,8 +22,8 @@ struct Args {
#[command(subcommand)]
command: Command,
/// The ssh names and optionally home directories of the servers to perform the action on
#[arg(num_args = 1..)]
servers: Vec<String>, //TODO directly parse servers and their directories
#[arg(num_args = 1.., value_parser = ServerReference::from_str)]
servers: Vec<ServerReference>,
}
#[derive(Subcommand, Debug)]
@ -54,12 +56,81 @@ enum OldVersionPolicy {
Delete,
}
#[derive(Debug, Clone)]
enum ServerReference {
Resolved(Server),
Name(String),
}
impl ServerReference {
//TODO lazy resolve method which gets a provider for configured servers
pub fn resolve(self, configured_servers: &[Server]) -> Option<Server> {
match self {
ServerReference::Resolved(server) => Some(server),
ServerReference::Name(name) => configured_servers
.iter()
.find(|server| server.ssh_name == name)
.cloned(),
}
}
}
impl FromStr for ServerReference {
type Err = ServerParseError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
Server::from_str(s)
.map(Self::Resolved)
.or_else(|_| Ok(Self::Name(s.to_string())))
}
}
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
struct Server {
pub ssh_name: String,
pub server_directory_path: PathBuf,
}
impl FromStr for Server {
type Err = ServerParseError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
s.split_once(':')
.ok_or(ServerParseError::MissingServerDirectory)
.map(|(name, directory)| Self {
ssh_name: name.to_string(),
server_directory_path: PathBuf::from(directory),
})
}
}
impl Display for Server {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "{}:{:?}", self.ssh_name, self.server_directory_path)
}
}
#[derive(Debug)]
enum ServerParseError {
MissingServerDirectory,
}
impl Display for ServerParseError {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
ServerParseError::MissingServerDirectory => {
write!(
f,
"String is not specifying a server directory. Please use an empty string after a \
double colon to point to the home directory, e.g: 'lobby:'"
)
}
}
}
}
impl Error for ServerParseError {}
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
struct PluginInfo {
pub name: String,
@ -73,19 +144,6 @@ fn main() -> Result<(), String> {
let configured_servers = parse_server_configuration_from_env()?;
dbg!(&configured_servers);
let servers = args
.servers
.iter()
.map(|server_name| {
configured_servers
.iter()
.find(|server| server.ssh_name == *server_name)
.ok_or(format!(
"no server with the name '{server_name}' has been configured"
))
})
.collect::<Result<Vec<_>, _>>()?;
Ok(())
}
@ -96,13 +154,13 @@ fn parse_server_configuration_from_env() -> Result<Vec<Server>, String> {
}
fn parse_server_configuration(config_str: &str) -> Result<Vec<Server>, String> {
config_str.split(',').map(|server_entry| {
let (name, server_directory) = server_entry.split_once(':').ok_or(format!("Server entry doesn't specify a server directory (separate name and directory via double colon) for entry '{}'", server_entry))?;
Ok(Server {
ssh_name: name.to_string(),
server_directory_path: PathBuf::from(server_directory),
config_str
.split(',')
.map(|server_entry| {
Server::from_str(server_entry)
.map_err(|e| format!("Invalid server entry '{server_entry}': {e}"))
})
}).collect()
.collect()
}
#[cfg(test)]