use checks::Dependencies;
use error::SyncError;
use logic::{ip, Synchronizer};
use std::{
env::{home_dir, temp_dir},
fs::{read_to_string, write},
path::Path,
process::Command,
};
mod checks;
mod error;
mod logic;
fn main() -> Result<(), SyncError> {
if let Ok(dep) = checks::Dependencies::new().installed() {
if dep {
println!("Dependencies met, let's go!")
}
}
if let Ok(container) = Dependencies::new().container() {
if container {
println!("This is running in a container");
}
}
let mut tgt_comparison = vec![];
let path = Path::new(&home_dir().unwrap()).join(".synchronizer.yml");
if !path.exists() {
let contents = serde_yaml::to_string(&Synchronizer::new()).unwrap();
write(path, contents).map_err(|_| SyncError::DirectoryDoesntExist)?;
} else {
let decoded: Synchronizer = serde_yaml::from_str(&*read_to_string(path).unwrap()).unwrap();
let addr = match ip(&*decoded.hosts[0].1) {
Ok(it) => it,
Err(err) => return Err(err),
};
println!("Making backup and for diffing on the main host");
let default_file = Path::new(&home_dir().unwrap())
.join("docker-compose.yml")
.to_str()
.unwrap()
.to_owned();
let cfg_file = decoded.file.clone().unwrap_or(default_file);
Command::new("ssh")
.args([
&*format!("{}@{}", decoded.hosts[0].0, addr),
"cp",
&cfg_file,
Path::new(&temp_dir()).join("orig.yml").to_str().unwrap(),
])
.status()
.map_err(|_| SyncError::NoHostsConfigured)?;
println!("Copying the original file to the other hosts");
for host in 1..decoded.hosts.len() {
let addr_str = &decoded.hosts[host].1;
Command::new("scp")
.args([
format!("{}@{}:{}", decoded.hosts[0].0, decoded.hosts[0].1, cfg_file),
format!("{}@{}:{}", decoded.hosts[host].0, addr_str, cfg_file),
])
.status()
.map_err(|_| SyncError::NoHostsConfigured)?;
}
for host in &decoded.hosts {
tgt_comparison.push(
Command::new("ssh")
.args([&*format!("{}@{}", host.0, host.1), "cat", &cfg_file])
.output()
.map_err(|_| SyncError::NoHostsConfigured)?
.status
.to_string(),
);
}
loop {
let orig = Command::new("ssh")
.args([
&*format!("{}@{}", decoded.hosts[0].0, ip(&decoded.hosts[0].1)?),
"cat",
&cfg_file,
])
.output()
.map_err(|_| SyncError::NoHostsConfigured)?
.status
.to_string();
for cfgs in &tgt_comparison {
if *cfgs != orig {
println!("Propagating changes");
for host in 1..decoded.hosts.len() { match decoded.backend {
logic::Backend::Podman => {
Command::new("ssh")
.arg(format!("{}@{}", decoded.hosts[host].0, decoded.hosts[host].1))
.args(["podman", "compose","-f", &cfg_file, "up", "-d"])
.status()
.map_err(|_| SyncError::NoHostsConfigured)?;
}
logic::Backend::Docker => {
Command::new("ssh")
.arg(format!("{}@{}", decoded.hosts[host].0, decoded.hosts[host].1))
.args(["docker", "compose","-f", &cfg_file, "up", "-d"])
.status()
.map_err(|_| SyncError::NoHostsConfigured)?;
}
}
}
} else {
continue;
}
}
}
}
Ok(())
}