mod git; use std::fs::{create_dir_all, remove_file, write, File}; use std::io::{Error, ErrorKind::Other, Read, Result}; use std::path::Path; use git::Git; pub trait Remote { fn can_handle(&self, remote: &str) -> bool; fn sync_up(&self, remote: &str, directory: &Path) -> Result<()>; fn sync_down(&self, remote: &str, directory: &Path) -> Result<()>; } pub fn add(config_directory: &Path, remote_config: &Path, remote: &str) -> Result<()> { create_dir_all(config_directory)?; write(remote_config, remote)?; Ok(()) } pub fn remove(remote_config: &Path) -> Result<()> { if remote_config.exists() { remove_file(remote_config)?; } Ok(()) } pub fn sync_up(data_directory: &Path, remote_config: &Path) -> Result<()> { let remote_address = read_remote(remote_config).ok_or_else(|| Error::new(Other, "No remote is configured"))?; create_dir_all(data_directory)?; let remotes = available_remotes(); for remote in remotes { if remote.can_handle(&remote_address) { return remote.sync_up(&remote_address, data_directory); } } Err(Error::new( Other, "No valid strategies found for your configured remote.", )) } pub fn sync_down(data_directory: &Path, remote_config: &Path) -> Result<()> { let remote_address = read_remote(remote_config).ok_or_else(|| Error::new(Other, "No remote is configured"))?; create_dir_all(data_directory)?; let remotes = available_remotes(); for remote in remotes { if remote.can_handle(&remote_address) { return remote.sync_down(&remote_address, data_directory); } } Err(Error::new( Other, "No valid strategies found for your configured remote.", )) } fn available_remotes() -> Vec> { vec![Box::new(Git::new())] } fn read_remote(file_path: &Path) -> Option { let mut file = File::open(file_path).ok()?; let mut contents = String::new(); file.read_to_string(&mut contents).ok()?; Some(contents) } #[cfg(test)] mod tests { use super::*; use test_utilities::*; #[test] fn test_adds_a_remote() { let test_dir = setup_test_dir(); let config_dir = test_dir.join("config"); let remote_config = config_dir.join("remoteconfig"); assert!(!&config_dir.exists()); add(&config_dir, &remote_config, "whaaat").expect("Could not add a remote"); assert!(&config_dir.exists()); assert_file_contents(&remote_config, "whaaat"); cleanup_test_dir(&test_dir); } #[test] fn test_removes_a_remote() { let test_dir = setup_test_dir(); let remote_config = test_dir.join("remoteconfig"); create_test_file(&remote_config, "remote control"); assert_file_contents(&remote_config, "remote control"); remove(&remote_config).expect("Could not remove a remote"); assert!(!&remote_config.exists()); cleanup_test_dir(&test_dir); } }