use console::Emoji;
use anyhow::{Result};
use yaml_rust::{Yaml};
use std::collections::HashMap;
use std::{fmt};
pub static ROOT: &str = "call";
pub static CONFIG: &str = "config";
pub static EXCLUDE: &str = "exclude";
pub static MAPPING: &str = "mapping";
pub static SERVER: &str = "server";
pub static ACTIVE: &str = "active";
pub static RUNNER: &str = "runner";
pub static MODE: &str = "mode";
pub static USERNAME: &str = "username";
pub static HOST: &str = "host";
pub static PORT: &str = "port";
pub static OPENSSH: &str = "openssh";
pub static PASSWORD: &str = "password";
pub static KEYPAIR: &str = "keypair";
pub static AUTHENTICATION_TYPE: &str = "authentication_type";
pub static PRIVATE_KEY_FILE: &str = "private_key_file";
pub static PASS_PHRASE: &str = "pass_phrase";
pub static SRC: &str = "src";
pub static DEST: &str = "dest";
pub static LOOKING_GLASS: Emoji<'_, '_> = Emoji("🔍 ", "");
pub static TRUCK: Emoji<'_, '_> = Emoji("🚚 ", "");
pub static CLIP: Emoji<'_, '_> = Emoji("🔗 ", "");
pub static PAPER: Emoji<'_, '_> = Emoji("📃 ", "");
pub static SPARKLE: Emoji<'_, '_> = Emoji("✨ ", ":-)");
pub static INIT_CONFIG: &str = r#"
call:
config:
active:
openssh:
- dev
password:
- stage
keypair:
- prod
runner: make
mapping:
src: .
dest: ~/workspace/call
exclude:
- ./target
- README.md
server:
openssh:
dev:
host:
- 127.0.0.1
port: 22
authentication_type: openssh
username: rust
password:
stage:
host:
- 127.0.0.1
port: 22
authentication_type: password
username: rust
password: "123456"
keypair:
prod:
host:
- 127.0.0.1
port: 22
authentication_type: keypair
username: rust
private_key_file: rust
pass_phrase: rust
"#;
#[derive(Clone)]
pub struct Openssh {
pub host: Vec<String>,
pub port: i64,
pub authentication_type: String,
pub username: String,
}
#[derive(Clone)]
pub struct Password {
pub host: Vec<String>,
pub port: i64,
pub authentication_type: String,
pub username: String,
pub password: String,
}
#[derive(Clone)]
pub struct Keypair {
pub host: Vec<String>,
pub port: i64,
pub authentication_type: String,
pub username: String,
pub private_key_file: String,
pub pass_phrase: String,
}
#[derive(Clone, Debug)]
pub enum ServerValue {
Openssh { host: Vec<String>, port: i64, authentication_type: String, username: String },
Password { host: Vec<String>, port: i64, authentication_type: String, username: String, password: String },
Keypair { host: Vec<String>, port: i64, authentication_type: String, username: String, private_key_file: String, pass_phrase: String },
}
#[derive(PartialEq, Eq, Hash, Clone, Debug)]
pub enum ServerKey {
Openssh,
Password,
Keypair,
}
impl fmt::Display for ServerKey {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
let res = match self {
ServerKey::Openssh => "openssh",
ServerKey::Password => "password",
ServerKey::Keypair => "keypair",
};
write!(fmt, "{}", res)
}
}
impl ServerKey {
fn as_str(&self) -> &'static str {
match *self { ServerKey::Openssh => "openssh",
ServerKey::Password => "password",
ServerKey::Keypair => "keypair",
}
}
}
#[derive(Clone, Debug)]
pub struct Mapping {
pub src: String,
pub dest: String,
pub exclude: Vec<String>,
}
#[derive(Clone, Debug)]
pub struct CallConfig {
pub active: HashMap<ServerKey, Vec<ServerValue>>,
pub runner: String,
pub mapping: Mapping,
}
impl CallConfig {
pub fn build(yaml_config: Yaml) -> Result<CallConfig> {
let mut active_server = HashMap::new();
let server_yaml = &yaml_config[ROOT][SERVER];
let mapping_yaml = &yaml_config[ROOT][MAPPING];
let config_yaml = &yaml_config[ROOT][CONFIG];
for server_list in config_yaml[ACTIVE][OPENSSH].as_vec() {
let mut openssh_server_list = Vec::new();
for server in server_list {
let server_name = server.as_str().unwrap_or_default();
if !server_yaml[OPENSSH][server_name].is_badvalue() {
let openssh_server = ServerValue::Openssh {
host: call_vec!(server_yaml[OPENSSH][server_name][HOST]),
port: call_i64!(server_yaml[OPENSSH][server_name][PORT]),
authentication_type: call_string!(server_yaml[OPENSSH][server_name][AUTHENTICATION_TYPE]),
username: call_string!(server_yaml[OPENSSH][server_name][USERNAME]),
};
openssh_server_list.push(openssh_server);
}
}
active_server.insert(ServerKey::Openssh, openssh_server_list);
}
for server_list in config_yaml[ACTIVE][PASSWORD].as_vec() {
let mut password_server_list = Vec::new();
for server in server_list {
let server_name = server.as_str().unwrap_or_default();
if !server_yaml[PASSWORD][server_name].is_badvalue() {
let password_server = ServerValue::Password {
host: call_vec!(server_yaml[PASSWORD][server_name][HOST]),
port: call_i64!(server_yaml[PASSWORD][server_name][PORT]),
authentication_type: call_string!(server_yaml[PASSWORD][server_name][AUTHENTICATION_TYPE]),
username: call_string!(server_yaml[PASSWORD][server_name][USERNAME]),
password: call_string!(server_yaml[PASSWORD][server_name][PASSWORD]),
};
password_server_list.push(password_server);
}
}
active_server.insert(ServerKey::Password, password_server_list);
}
for server_list in config_yaml[ACTIVE][KEYPAIR].as_vec() {
let mut keypair_server_list = Vec::new();
for server in server_list {
let server_name = server.as_str().unwrap_or_default();
if !server_yaml[KEYPAIR][server_name].is_badvalue() {
let password_server = ServerValue::Keypair {
host: call_vec!(server_yaml[KEYPAIR][server_name][HOST]),
port: call_i64!(server_yaml[KEYPAIR][server_name][PORT]),
authentication_type: call_string!(server_yaml[KEYPAIR][server_name][AUTHENTICATION_TYPE]),
username: call_string!(server_yaml[KEYPAIR][server_name][USERNAME]),
private_key_file: call_string!(server_yaml[KEYPAIR][server_name][PRIVATE_KEY_FILE]),
pass_phrase: call_string!(server_yaml[KEYPAIR][server_name][PASS_PHRASE]),
};
keypair_server_list.push(password_server);
}
}
active_server.insert(ServerKey::Keypair, keypair_server_list);
}
Ok(CallConfig {
active: active_server,
runner: call_string!(config_yaml[RUNNER]),
mapping: Mapping {
src: call_string!(mapping_yaml[SRC]),
dest: call_string!(mapping_yaml[DEST]),
exclude: call_vec!(mapping_yaml[EXCLUDE]),
},
})
}
}