From 599ad7f4dcf7a5610dedab7d304a414b73da5061 Mon Sep 17 00:00:00 2001 From: Brian Picciano Date: Sat, 6 May 2023 15:38:43 +0200 Subject: [PATCH] Implement all_descrs on the store --- Cargo.lock | 20 ++++++++- Cargo.toml | 2 + src/origin/descr.rs | 16 ++++--- src/origin/store.rs | 106 +++++++++++++++++++++++++++++++++++--------- 4 files changed, 114 insertions(+), 30 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d07a5a5..24c4783 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -404,6 +404,8 @@ version = "0.1.0" dependencies = [ "gix", "hex", + "serde", + "serde_json", "sha2", "tempdir", ] @@ -1819,9 +1821,23 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.160" +version = "1.0.162" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb2f3770c8bce3bcda7e149193a069a0f4365bda1fa5cd88e03bca26afc1216c" +checksum = "71b2f6e1ab5c2b98c05f0f35b236b22e8df7ead6ffbf51d7808da7f8817e7ab6" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.162" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2a0814352fd64b58489904a44ea8d90cb1a91dcb6b4f5ebabc32c8318e93cb6" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.15", +] [[package]] name = "serde_json" diff --git a/Cargo.toml b/Cargo.toml index 8445623..93e18af 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,3 +13,5 @@ gix = { version = "0.44.1", features = [ "blocking-http-transport-reqwest-rust-tls", ]} tempdir = "0.3.7" +serde = { version = "1.0.162", features = [ "derive" ]} +serde_json = "1.0.96" diff --git a/src/origin/descr.rs b/src/origin/descr.rs index 4e4b9e5..27a6272 100644 --- a/src/origin/descr.rs +++ b/src/origin/descr.rs @@ -1,16 +1,17 @@ use sha2::{Sha256, Digest}; use hex::ToHex; +use serde::{Serialize, Deserialize}; -#[derive(Clone,Copy)] +#[derive(Clone,Debug,PartialEq,Serialize,Deserialize)] /// A unique description of an origin, from where a domain might be served. -pub enum Descr<'a> { - Git{url: &'a str, branch_name: &'a str}, +pub enum Descr { + Git{url: String, branch_name: String}, } -impl<'a> Descr<'a> { +impl Descr { /// Returns a globally unique string for the Descr. - pub fn id(&'a self) -> String { + pub fn id(&self) -> String { let mut h = Sha256::new(); @@ -38,7 +39,10 @@ mod descr_tests { fn id() { assert_eq!( - super::Descr::Git{url:"foo", branch_name:"bar"}.id(), + super::Descr::Git{ + url: String::from("foo"), + branch_name: String::from("bar"), + }.id(), "424130b9e6c1675c983b4b97579877e16d8a6377e4fe10970e6d210811c3b7ac", ) } diff --git a/src/origin/store.rs b/src/origin/store.rs index 4afcfb4..488217d 100644 --- a/src/origin/store.rs +++ b/src/origin/store.rs @@ -1,10 +1,17 @@ use std::error::Error; +use serde_json; + use super::Descr; #[derive(Clone,Copy)] pub struct Limits {} +#[derive(Debug)] +pub enum AllDescrsError { + Unexpected(Box), +} + #[derive(Debug)] pub enum SyncError { InvalidURL, @@ -22,18 +29,24 @@ pub trait Store { fn write_file( &self, - descr: Descr, + descr: &Descr, path: &str, into: &mut W, ) -> Result<(), WriteFileError> where W: std::io::Write + ?Sized; - fn sync(&self, descr: Descr, limits: Limits) -> Result<(), SyncError>; + fn sync(&self, descr: &Descr, limits: Limits) -> Result<(), SyncError>; + + fn all_descrs(&self) -> Result< + Box> + '_>, + AllDescrsError, + >; } pub mod git { use std::path::{Path, PathBuf}; + use std::{fs,io}; use super::*; use gix::clone::Error as gixCloneErr; @@ -60,14 +73,18 @@ pub mod git { impl<'a> Store<'a> { - pub fn new(dir_path: &Path) -> std::io::Result { - std::fs::create_dir_all(dir_path)?; + pub fn new(dir_path: &Path) -> io::Result { + fs::create_dir_all(dir_path)?; Ok(Store{dir_path}) } - fn repo_path(&self, descr: Descr) -> PathBuf { + fn repo_path(&self, descr: &Descr) -> PathBuf { self.dir_path.clone().join(descr.id()) } + + fn descr_file_path(&self, descr_id: &str) -> PathBuf { + self.dir_path.clone().join(descr_id).join("descr.json") + } fn branch_ref(branch_name: &str) -> String { format!("origin/{branch_name}") @@ -76,29 +93,39 @@ pub mod git { impl<'a> super::Store for Store<'a> { - fn sync(&self, descr: Descr, _limits: Limits) -> Result<(), SyncError> { + fn sync(&self, descr: &Descr, _limits: Limits) -> Result<(), SyncError> { let should_interrupt = &core::sync::atomic::AtomicBool::new(false); - let repo_path = &self.repo_path(descr); + let repo_path = &self.repo_path(&descr); // if the path doesn't exist then use the gix clone feature to clone it into the // directory. - if std::fs::read_dir(repo_path).is_err() { + if fs::read_dir(repo_path).is_err() { - std::fs::create_dir_all(repo_path) + fs::create_dir_all(repo_path) .map_err(|e| SyncError::Unexpected(Box::from(e)))?; let Descr::Git{url, branch_name} = descr; - let (repo, _) = gix::prepare_clone_bare(url, repo_path)? + let (repo, _) = gix::prepare_clone_bare(url.clone(), repo_path)? .fetch_only(Discard, should_interrupt) .map_err(|_| SyncError::InvalidURL)?; - repo.try_find_reference(&Self::branch_ref(branch_name)) + // Check to make sure the branch name exists + // TODO if this fails we should delete the whole repo + repo.try_find_reference(&Self::branch_ref(&branch_name)) .map_err(|e| SyncError::Unexpected(Box::from(e)))? .ok_or(SyncError::InvalidBranchName)?; + // Add the descr to the repo directory, so we can know the actual descr later + // TODO if this fails we should delete the whole repo + let descr_file = fs::File::create(self.descr_file_path(descr.id().as_ref())) + .map_err(|e| SyncError::Unexpected(Box::from(e)))?; + + serde_json::to_writer(descr_file, &descr) + .map_err(|e| SyncError::Unexpected(Box::from(e)))?; + return Ok(()); } @@ -125,15 +152,15 @@ pub mod git { fn write_file( &self, - descr: Descr, + descr: &Descr, path: &str, into: &mut W, ) -> Result<(), WriteFileError> - where W: std::io::Write + ?Sized { + where W: io::Write + ?Sized { let Descr::Git{branch_name, ..} = descr; - let repo_path = &self.repo_path(descr); - let branch_ref = &Self::branch_ref(branch_name); + let repo_path = &self.repo_path(&descr); + let branch_ref = &Self::branch_ref(&branch_name); let mut clean_path = Path::new(path); clean_path = clean_path.strip_prefix("/").unwrap_or(clean_path); @@ -168,11 +195,39 @@ pub mod git { Ok(()) } + + fn all_descrs(&self) -> Result< + Box> + '_>, + AllDescrsError, + > { + let inner_iter = fs::read_dir(self.dir_path) + .map_err(|e| AllDescrsError::Unexpected(Box::from(e)))? + .map(|dir_entry_res: io::Result| -> Result { + + let descr_id: String = dir_entry_res + .map_err(|e| AllDescrsError::Unexpected(Box::from(e)))? + .file_name() + .to_str() + .ok_or_else(|| AllDescrsError::Unexpected(Box::from("couldn't convert os string to &str")))? + .into(); + + let descr_file_path = self.descr_file_path(descr_id.as_ref()); + + let descr_file = fs::File::open(descr_file_path) + .map_err(|e| AllDescrsError::Unexpected(Box::from(e)))?; + + let descr = serde_json::from_reader(descr_file) + .map_err(|e| AllDescrsError::Unexpected(Box::from(e)))?; + + Ok(descr) + }); + + Ok(Box::from(inner_iter)) + } } #[cfg(test)] mod tests { - use super::Descr; use super::super::Store; @@ -186,20 +241,20 @@ pub mod git { let curr_dir = format!("file://{}", std::env::current_dir().unwrap().display()); let descr = Descr::Git{ - url: curr_dir.as_ref(), - branch_name: "master", + url: curr_dir, + branch_name: String::from("master"), }; let limits = super::Limits{}; let store = super::Store::new(tmp_dir.path()).expect("store created"); - store.sync(descr, limits).expect("sync should succeed"); - store.sync(descr, limits).expect("second sync should succeed"); + store.sync(&descr, limits).expect("sync should succeed"); + store.sync(&descr, limits).expect("second sync should succeed"); let assert_write = |path: &str| { let mut into: Vec = vec![]; - store.write_file(descr, path, &mut into).expect("write should succeed"); + store.write_file(&descr, path, &mut into).expect("write should succeed"); assert!(into.len() > 0); }; @@ -209,10 +264,17 @@ pub mod git { // File doesn't exist let mut into: Vec = vec![]; assert!(matches!( - store.write_file(descr, "DNE", &mut into), + store.write_file(&descr, "DNE", &mut into), Err::<(), super::WriteFileError>(super::WriteFileError::FileNotFound), )); assert_eq!(into.len(), 0); + + let descrs = store.all_descrs() + .expect("all_descrs callsed") + .collect::>>(); + + assert_eq!(1, descrs.len()); + assert_eq!(&descr, descrs[0].as_ref().unwrap()); } } }