use crate::configuration::Configuration; use std::io::{Error, Result}; use std::process::{Command, Stdio}; const COMMAND: &str = "rsync"; pub struct PublishArchive; impl PublishArchive { pub fn new() -> Self { PublishArchive } } impl super::Command for PublishArchive { 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 archive"))?; 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.archive_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-archive" } fn help(&self) -> &'static str { "\tPublishes the archive 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_archive_command() { let publish_archive = PublishArchive::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.archive_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_archive .execute( Some(&remote_dir_as_string), &configuration, "publish_archive", ) .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_archive .execute( Some(&remote_dir_as_string), &configuration, "publish_archive", ) .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_archive_command_should_fail_if_it_has_invalid_string() { let publish_archive = PublishArchive::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.archive_output_directory = local_dir.clone(); create_test_file( &local_dir.join("very_local_file.txt"), "I like my cornershop.", ); let result = publish_archive.execute( Some(&remote_dir_as_string), &configuration, "publish_archive", ); assert!(result.is_err()); cleanup_test_dir(&test_dir); } #[test] fn test_publish_archive_command_should_fail_if_cannot_reach_destination() { let publish_archive = PublishArchive::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.archive_output_directory = local_dir.clone(); create_test_file( &local_dir.join("very_local_file.txt"), "I like my cornershop.", ); let result = publish_archive.execute( Some(&remote_dir_as_string), &configuration, "publish_archive", ); assert!(result.is_err()); cleanup_test_dir(&test_dir); } #[test] fn test_publish_archive_command_should_fail_if_cannot_reach_source() { let publish_archive = PublishArchive::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.archive_output_directory = local_dir.clone(); let result = publish_archive.execute( Some(&remote_dir_as_string), &configuration, "publish_archive", ); assert!(result.is_err()); cleanup_test_dir(&test_dir); } #[test] fn publish_archive_before_dependencies() { let publish_archive = PublishArchive::new(); let dependencies = publish_archive.before_dependencies(); assert_eq!(dependencies.len(), 0); } #[test] fn publish_archive_after_dependencies() { let publish_archive = PublishArchive::new(); let dependencies = publish_archive.after_dependencies(); assert_eq!(dependencies.len(), 0); } // These two tests feel pointless but I'm doing it for the coverage :p #[test] fn publish_archive_command_output() { let publish_archive = PublishArchive::new(); publish_archive.command(); } #[test] fn publish_archive_help_output() { let publish_archive = PublishArchive::new(); publish_archive.help(); } }