/*! A Ship is a star ship, or an installation ISO */ use tokio::process::Command; use std::process::{ExitStatus, Output}; use std::os::unix::process::ExitStatusExt; use std::str::FromStr; use crate::{errors::Error, star::Star}; use serde::{Serialize, Deserialize}; /// Describes a hash of a file #[derive(Serialize, Deserialize)] pub struct Sha256(pub String); impl FromStr for Sha256 { type Err = Error; fn from_str(s: &str) -> Result { let sum = s.clone(); Ok(Sha256(sum.to_string())) } } impl ToString for Sha256 { fn to_string(&self) -> String { self.0.clone() } } /// Describes a starship, or a way to install a distribution #[derive(Serialize, Deserialize)] pub struct Ship { /// The common name of the distribution (e.g "Arch Linux") pub name: String, /// The SHA-256 hash of the downloaded file pub shasum: Sha256, /// Where the ISO can be downloaded from pub download_url: String, /// The commonly accepted version (e.g "rolling", "21.11", "unstable") pub version: String, } impl Ship { pub fn new(name: String, shasum: String, download_url: String, version: String ) -> Self { Self { name, shasum: Sha256(shasum), download_url, version } } pub async fn download(&self, target: Star) -> Result<(), Error> { let mut output: Output; if target.remote { output = Command::new("ssh") .args([ "-oStrictHostKeyChecking=accept-new", &target.address.clone(), "wget", "-O", &format!("/var/lib/libvirt/images/{}", self.make_pretty_name().clone()), &self.download_url.clone(), ]) .output() .await?; } else { output = Command::new("wget") .args([ "-O", &format!("/var/lib/libvirt/images/{}", self.make_pretty_name().clone()), &self.download_url.clone(), ]) .output() .await?; } if output.status != ExitStatus::from_raw(0) { Err(Error::RemoteCommand(String::from_utf8(output.stdout).unwrap())) } else { Ok(()) } } pub fn make_pretty_name(&self) -> String { let safe_name = self.name.clone().to_lowercase().replace(" ", "-"); let file_name = format!("{}-{}-{}.van", safe_name, self.version.clone(), self.shasum.0.clone()); file_name } }