From 570633de10cdb421a4d2492fe0cd2f180b9bc40a Mon Sep 17 00:00:00 2001 From: Brian Picciano Date: Thu, 6 Jul 2023 19:19:51 +0200 Subject: [PATCH] Implement origin::Store::get_file, to deprecate read_file_into --- src/origin.rs | 24 +++++++++++++++++++++--- src/origin/git.rs | 46 ++++++++++++++++++++++++++++++++++++++++++++++ src/origin/mux.rs | 12 ++++++++++++ 3 files changed, 79 insertions(+), 3 deletions(-) diff --git a/src/origin.rs b/src/origin.rs index 3522371..078f22e 100644 --- a/src/origin.rs +++ b/src/origin.rs @@ -1,5 +1,6 @@ use crate::error::unexpected; -use std::sync; +use futures::stream; +use std::{io, sync}; pub mod git; pub mod mux; @@ -29,7 +30,7 @@ pub enum AllDescrsError { } #[derive(thiserror::Error, Debug)] -pub enum ReadFileIntoError { +pub enum GetFileError { #[error("descr not synced")] DescrNotSynced, @@ -40,6 +41,8 @@ pub enum ReadFileIntoError { Unexpected(#[from] unexpected::Error), } +pub type ReadFileIntoError = GetFileError; + #[mockall::automock] /// Describes a storage mechanism for Origins. Each Origin is uniquely identified by its Descr. pub trait Store { @@ -47,6 +50,8 @@ pub trait Store { /// the origin into the storage. fn sync(&self, descr: &Descr) -> Result<(), SyncError>; + fn all_descrs(&self) -> Result, AllDescrsError>; + fn read_file_into( &self, descr: &Descr, @@ -54,7 +59,11 @@ pub trait Store { into: &mut dyn std::io::Write, ) -> Result<(), ReadFileIntoError>; - fn all_descrs(&self) -> Result, AllDescrsError>; + fn get_file( + &self, + descr: &Descr, + path: &str, + ) -> Result>>, GetFileError>; } pub fn new_mock() -> sync::Arc> { @@ -70,6 +79,7 @@ impl Store for sync::Arc> { self.lock().unwrap().all_descrs() } + /// Deprecated, use get_file fn read_file_into( &self, descr: &Descr, @@ -78,4 +88,12 @@ impl Store for sync::Arc> { ) -> Result<(), ReadFileIntoError> { self.lock().unwrap().read_file_into(descr, path, into) } + + fn get_file<'store>( + &'store self, + descr: &Descr, + path: &str, + ) -> Result>>, GetFileError> { + self.lock().unwrap().get_file(descr, path) + } } diff --git a/src/origin/git.rs b/src/origin/git.rs index b1369a1..55ff404 100644 --- a/src/origin/git.rs +++ b/src/origin/git.rs @@ -4,6 +4,8 @@ use crate::origin; use std::path::{Path, PathBuf}; use std::{collections, fs, io, sync}; +use futures::stream; + #[derive(Clone)] struct RepoSnapshot { repo: sync::Arc, @@ -331,6 +333,50 @@ impl super::Store for FSStore { Ok(()) } + + // TODO test this + fn get_file<'store>( + &'store self, + descr: &origin::Descr, + path: &str, + ) -> Result>>, origin::GetFileError> { + let repo_snapshot = match self.get_repo_snapshot(descr) { + Ok(Some(repo_snapshot)) => repo_snapshot, + Ok(None) => return Err(origin::GetFileError::DescrNotSynced), + Err(e) => return Err(e.into()), + }; + + let mut clean_path = Path::new(path); + clean_path = clean_path.strip_prefix("/").unwrap_or(clean_path); + + let repo = repo_snapshot.repo.to_thread_local(); + + let file_object = repo + .find_object(repo_snapshot.tree_object_id) + .map_unexpected_while(|| { + format!("finding tree object {}", repo_snapshot.tree_object_id) + })? + .peel_to_tree() + .map_unexpected_while(|| { + format!("peeling tree object {}", repo_snapshot.tree_object_id) + })? + .lookup_entry_by_path(clean_path) + .map_unexpected_while(|| { + format!( + "looking up {} in tree object {}", + clean_path.display(), + repo_snapshot.tree_object_id + ) + })? + .ok_or(origin::GetFileError::FileNotFound)? + .object() + .or_unexpected()?; + + // TODO this is very not ideal, the whole file is first read totally into memory, and then + // that is cloned. + let data = file_object.data.clone(); + Ok(Box::pin(stream::once(async move { Ok(data) }))) + } } #[cfg(test)] diff --git a/src/origin/mux.rs b/src/origin/mux.rs index f7f1066..fbf1288 100644 --- a/src/origin/mux.rs +++ b/src/origin/mux.rs @@ -1,5 +1,7 @@ use crate::error::unexpected::Mappable; use crate::origin; +use futures::stream; +use std::io; pub struct Store where @@ -51,6 +53,16 @@ where .or_unexpected_while(format!("mapping {:?} to store", &descr))? .read_file_into(descr, path, into) } + + fn get_file<'store>( + &'store self, + descr: &origin::Descr, + path: &str, + ) -> Result>>, origin::GetFileError> { + (self.mapping_fn)(descr) + .or_unexpected_while(format!("mapping {:?} to store", &descr))? + .get_file(descr, path) + } } #[cfg(test)]