use crate::configuration::Configuration; use std::io::{Error, Result}; use std::process::{Command, Stdio}; const COMMAND: &str = "rsync"; pub struct Publish; impl Publish { pub fn new() -> Self { Publish } } impl super::Command for Publish { fn before_dependencies(&self) -> Vec> { vec![] } fn execute( &self, input: Option<&String>, configuration: &Configuration, _: &str, ) -> Result<()> { let input = input.ok_or_else(|| Error::other("You must provide a location to publish the blog"))?; Command::new(COMMAND) .arg("--version") .stdout(Stdio::null()) .stderr(Stdio::null()) .status() .map_err(|_| Error::other("Publishing requires rsync"))?; let status = Command::new(COMMAND) .arg("-r") .arg(format!( "{}/", &configuration.blog_output_directory.display() )) .arg(input.as_str()) .stdout(Stdio::null()) .stderr(Stdio::null()) .status() .map_err(|_| Error::other("Rsync failed to publish."))?; if !status.success() { return Err(Error::other("Rsync failed to publish.")); } Ok(()) } fn after_dependencies(&self) -> Vec> { vec![] } fn command(&self) -> &'static str { "publish" } fn help(&self) -> &'static str { "\t\tPublishes the blog to a remote host" } } #[cfg(test)] mod tests { use std::fs::create_dir_all; use super::*; use crate::command::Command; use crate::configuration::Configuration; use test_utilities::*; #[test] fn test_publish_command() { let publish = Publish::new(); let test_dir = setup_test_dir(); let local_dir = test_dir.join("publishlocal"); let remote_dir = test_dir.join("publishremote"); create_dir_all(&local_dir).expect("Could not create local test directory"); create_dir_all(&remote_dir).expect("Could not create remote test directory"); let remote_dir_as_string = remote_dir.display().to_string(); let mut configuration = Configuration::new().unwrap(); configuration.blog_output_directory = local_dir.clone(); create_test_file( &local_dir.join("very_local_file.txt"), "I like my cornershop.", ); assert!(!&remote_dir.join("very_local.txt").exists()); assert!(!&remote_dir.join("second_file.txt").exists()); publish .execute(Some(&remote_dir_as_string), &configuration, "publish") .expect("Could not publish"); assert_file_contents( &local_dir.join("very_local_file.txt"), "I like my cornershop.", ); assert!(!&remote_dir.join("second_file.txt").exists()); create_test_file( &local_dir.join("second_file.txt"), "Me, I don't care at all.", ); publish .execute(Some(&remote_dir_as_string), &configuration, "publish") .expect("Could not publish second file."); assert_file_contents( &local_dir.join("very_local_file.txt"), "I like my cornershop.", ); assert_file_contents( &local_dir.join("second_file.txt"), "Me, I don't care at all.", ); cleanup_test_dir(&test_dir); } #[test] fn test_publish_command_should_fail_if_it_has_invalid_string() { let publish = Publish::new(); let test_dir = setup_test_dir(); let local_dir = test_dir.join("publishlocal"); create_dir_all(&local_dir).expect("Could not create local test directory"); let remote_dir_as_string = "/zzzzz/\0".to_string(); let mut configuration = Configuration::new().unwrap(); configuration.blog_output_directory = local_dir.clone(); create_test_file( &local_dir.join("very_local_file.txt"), "I like my cornershop.", ); let result = publish.execute(Some(&remote_dir_as_string), &configuration, "publish"); assert!(result.is_err()); cleanup_test_dir(&test_dir); } #[test] fn test_publish_command_should_fail_if_cannot_reach_destination() { let publish = Publish::new(); let test_dir = setup_test_dir(); let local_dir = test_dir.join("publishlocal"); create_dir_all(&local_dir).expect("Could not create local test directory"); let remote_dir_as_string = "/zzzzz/ifthissucceeds/honestly/noidea/whattomakeofyour/directorystructure/but/welldone".to_string(); let mut configuration = Configuration::new().unwrap(); configuration.blog_output_directory = local_dir.clone(); create_test_file( &local_dir.join("very_local_file.txt"), "I like my cornershop.", ); let result = publish.execute(Some(&remote_dir_as_string), &configuration, "publish"); assert!(result.is_err()); cleanup_test_dir(&test_dir); } #[test] fn test_publish_command_should_fail_if_cannot_reach_source() { let publish = Publish::new(); let test_dir = setup_test_dir(); let local_dir = test_dir.join("absolutelynot_we_cannot"); let remote_dir = test_dir.join("publishremote"); create_dir_all(&remote_dir).expect("Could not create remote test directory"); let remote_dir_as_string = remote_dir.display().to_string(); let mut configuration = Configuration::new().unwrap(); configuration.blog_output_directory = local_dir.clone(); let result = publish.execute(Some(&remote_dir_as_string), &configuration, "publish"); assert!(result.is_err()); cleanup_test_dir(&test_dir); } #[test] fn publish_before_dependencies() { let publish = Publish::new(); let dependencies = publish.before_dependencies(); assert_eq!(dependencies.len(), 0); } #[test] fn publish_after_dependencies() { let publish = Publish::new(); let dependencies = publish.after_dependencies(); assert_eq!(dependencies.len(), 0); } // These two tests feel pointless but I'm doing it for the coverage :p #[test] fn publish_command_output() { let publish = Publish::new(); publish.command(); } #[test] fn publish_help_output() { let publish = Publish::new(); publish.help(); } }