|
|
|
@ -7,54 +7,42 @@ pub struct Limits { |
|
|
|
|
// TODO storage limits
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
#[derive(Debug)] |
|
|
|
|
#[derive(thiserror::Error, Debug)] |
|
|
|
|
pub enum ReadFileIntoError { |
|
|
|
|
#[error("file not found")] |
|
|
|
|
FileNotFound, |
|
|
|
|
Unexpected(Box<dyn Error>), |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
impl<E: Error + 'static> From<E> for ReadFileIntoError { |
|
|
|
|
fn from(e: E) -> ReadFileIntoError { |
|
|
|
|
ReadFileIntoError::Unexpected(Box::from(e)) |
|
|
|
|
} |
|
|
|
|
#[error(transparent)] |
|
|
|
|
Unexpected(Box<dyn Error>), |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
#[derive(Debug)] |
|
|
|
|
#[derive(thiserror::Error, Debug)] |
|
|
|
|
pub enum SyncError { |
|
|
|
|
#[error("invalid url")] |
|
|
|
|
InvalidURL, |
|
|
|
|
|
|
|
|
|
#[error("invalid branch name")] |
|
|
|
|
InvalidBranchName, |
|
|
|
|
Unexpected(Box<dyn Error>), |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
impl<E: Error + 'static> From<E> for SyncError { |
|
|
|
|
fn from(e: E) -> SyncError { |
|
|
|
|
SyncError::Unexpected(Box::from(e)) |
|
|
|
|
} |
|
|
|
|
#[error(transparent)] |
|
|
|
|
Unexpected(Box<dyn Error>), |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
#[derive(Debug)] |
|
|
|
|
#[derive(thiserror::Error, Debug)] |
|
|
|
|
pub enum GetError { |
|
|
|
|
#[error("not found")] |
|
|
|
|
NotFound, |
|
|
|
|
Unexpected(Box<dyn Error>), |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
impl<E: Error + 'static> From<E> for GetError { |
|
|
|
|
fn from(e: E) -> GetError { |
|
|
|
|
GetError::Unexpected(Box::from(e)) |
|
|
|
|
} |
|
|
|
|
#[error(transparent)] |
|
|
|
|
Unexpected(Box<dyn Error>), |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
#[derive(Debug)] |
|
|
|
|
#[derive(thiserror::Error, Debug)] |
|
|
|
|
pub enum AllDescrsError { |
|
|
|
|
#[error(transparent)] |
|
|
|
|
Unexpected(Box<dyn Error>), |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
impl<E: Error + 'static> From<E> for AllDescrsError { |
|
|
|
|
fn from(e: E) -> AllDescrsError { |
|
|
|
|
AllDescrsError::Unexpected(Box::from(e)) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
#[automock] |
|
|
|
|
pub trait Origin { |
|
|
|
|
fn descr(&self) -> &Descr; |
|
|
|
@ -80,15 +68,37 @@ pub trait Store<'a> { |
|
|
|
|
fn all_descrs(&'a self) -> AllDescrsResult<Self::AllDescrsIter>; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
//mockall::mock! {
|
|
|
|
|
// pub MyStore {}
|
|
|
|
|
// impl<'a> Store<'a> for MyStore {
|
|
|
|
|
// type AllDescrsIter = Vec<AllDescrsResult<Descr>>;
|
|
|
|
|
// fn sync(&'a self, descr: &Descr, limits: Limits) -> Result<(), SyncError>;
|
|
|
|
|
// fn get(&'a self, descr: Descr) -> Result<Box<dyn Origin>, GetError>;
|
|
|
|
|
// fn all_descrs(&'a self) -> AllDescrsResult<<self::MockMyStore as self::Store<'a>>::AllDescrsIter>;
|
|
|
|
|
// }
|
|
|
|
|
//}
|
|
|
|
|
pub struct MockStore<SyncFn, GetFn, AllDescrsFn> |
|
|
|
|
where |
|
|
|
|
SyncFn: Fn(&Descr, Limits) -> Result<(), SyncError>, |
|
|
|
|
GetFn: Fn(Descr) -> Result<Box<dyn Origin>, GetError>, |
|
|
|
|
AllDescrsFn: Fn() -> AllDescrsResult<Vec<AllDescrsResult<Descr>>>, |
|
|
|
|
{ |
|
|
|
|
pub sync_fn: SyncFn, |
|
|
|
|
pub get_fn: GetFn, |
|
|
|
|
pub all_descrs_fn: AllDescrsFn, |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
impl<'a, SyncFn, GetFn, AllDescrsFn> Store<'a> for MockStore<SyncFn, GetFn, AllDescrsFn> |
|
|
|
|
where |
|
|
|
|
SyncFn: Fn(&Descr, Limits) -> Result<(), SyncError>, |
|
|
|
|
GetFn: Fn(Descr) -> Result<Box<dyn Origin>, GetError>, |
|
|
|
|
AllDescrsFn: Fn() -> AllDescrsResult<Vec<AllDescrsResult<Descr>>>, |
|
|
|
|
{ |
|
|
|
|
type AllDescrsIter = Vec<AllDescrsResult<Descr>>; |
|
|
|
|
|
|
|
|
|
fn sync(&'a self, descr: &Descr, limits: Limits) -> Result<(), SyncError> { |
|
|
|
|
(self.sync_fn)(descr, limits) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
fn get(&'a self, descr: Descr) -> Result<Box<dyn Origin>, GetError> { |
|
|
|
|
(self.get_fn)(descr) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
fn all_descrs(&'a self) -> AllDescrsResult<Self::AllDescrsIter> { |
|
|
|
|
(self.all_descrs_fn)() |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
pub mod git { |
|
|
|
|
|
|
|
|
@ -117,13 +127,18 @@ pub mod git { |
|
|
|
|
|
|
|
|
|
let file_object = self |
|
|
|
|
.repo |
|
|
|
|
.find_object(self.tree_object_id)? |
|
|
|
|
.peel_to_tree()? |
|
|
|
|
.lookup_entry_by_path(clean_path)? |
|
|
|
|
.find_object(self.tree_object_id) |
|
|
|
|
.map_err(|e| ReadFileIntoError::Unexpected(Box::from(e)))? |
|
|
|
|
.peel_to_tree() |
|
|
|
|
.map_err(|e| ReadFileIntoError::Unexpected(Box::from(e)))? |
|
|
|
|
.lookup_entry_by_path(clean_path) |
|
|
|
|
.map_err(|e| ReadFileIntoError::Unexpected(Box::from(e)))? |
|
|
|
|
.ok_or(ReadFileIntoError::FileNotFound)? |
|
|
|
|
.object()?; |
|
|
|
|
.object() |
|
|
|
|
.map_err(|e| ReadFileIntoError::Unexpected(Box::from(e)))?; |
|
|
|
|
|
|
|
|
|
into.write_all(file_object.data.as_ref())?; |
|
|
|
|
into.write_all(file_object.data.as_ref()) |
|
|
|
|
.map_err(|e| ReadFileIntoError::Unexpected(Box::from(e)))?; |
|
|
|
|
|
|
|
|
|
Ok(()) |
|
|
|
|
} |
|
|
|
@ -167,7 +182,7 @@ pub mod git { |
|
|
|
|
// if the path doesn't exist then use the gix clone feature to clone it into the
|
|
|
|
|
// directory.
|
|
|
|
|
if fs::read_dir(repo_path).is_err() { |
|
|
|
|
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; |
|
|
|
|
|
|
|
|
@ -186,30 +201,37 @@ pub mod git { |
|
|
|
|
|
|
|
|
|
// Check to make sure the branch name exists
|
|
|
|
|
// TODO if this fails we should delete repo_path
|
|
|
|
|
repo.try_find_reference(&self.branch_ref(branch_name))? |
|
|
|
|
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 repo_path
|
|
|
|
|
let descr_file = fs::File::create(self.descr_file_path(descr.id().as_ref()))?; |
|
|
|
|
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)?; |
|
|
|
|
serde_json::to_writer(descr_file, &descr) |
|
|
|
|
.map_err(|e| SyncError::Unexpected(Box::from(e)))?; |
|
|
|
|
|
|
|
|
|
return Ok(()); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
let direction = gix::remote::Direction::Fetch; |
|
|
|
|
|
|
|
|
|
let repo = gix::open(repo_path)?; |
|
|
|
|
let repo = gix::open(repo_path).map_err(|e| SyncError::Unexpected(Box::from(e)))?; |
|
|
|
|
|
|
|
|
|
let remote = repo |
|
|
|
|
.find_default_remote(direction) |
|
|
|
|
.ok_or_else(|| SyncError::Unexpected(Box::from("no default configured")))??; |
|
|
|
|
.ok_or_else(|| SyncError::Unexpected(Box::from("no default configured")))? |
|
|
|
|
.map_err(|e| SyncError::Unexpected(Box::from(e)))?; |
|
|
|
|
|
|
|
|
|
remote |
|
|
|
|
.connect(direction)? |
|
|
|
|
.prepare_fetch(Discard, Default::default())? |
|
|
|
|
.receive(Discard, should_interrupt)?; |
|
|
|
|
.connect(direction) |
|
|
|
|
.map_err(|e| SyncError::Unexpected(Box::from(e)))? |
|
|
|
|
.prepare_fetch(Discard, Default::default()) |
|
|
|
|
.map_err(|e| SyncError::Unexpected(Box::from(e)))? |
|
|
|
|
.receive(Discard, should_interrupt) |
|
|
|
|
.map_err(|e| SyncError::Unexpected(Box::from(e)))?; |
|
|
|
|
|
|
|
|
|
Ok(()) |
|
|
|
|
} |
|
|
|
@ -222,19 +244,23 @@ pub mod git { |
|
|
|
|
|
|
|
|
|
fs::read_dir(&repo_path).map_err(|e| match e.kind() { |
|
|
|
|
io::ErrorKind::NotFound => GetError::NotFound, |
|
|
|
|
_ => e.into(), |
|
|
|
|
_ => GetError::Unexpected(Box::from(e)), |
|
|
|
|
})?; |
|
|
|
|
|
|
|
|
|
let repo = gix::open(&repo_path)?; |
|
|
|
|
let repo = gix::open(&repo_path).map_err(|e| GetError::Unexpected(Box::from(e)))?; |
|
|
|
|
|
|
|
|
|
let commit_object_id = repo |
|
|
|
|
.find_reference(&self.branch_ref(branch_name))? |
|
|
|
|
.peel_to_id_in_place()? |
|
|
|
|
.find_reference(&self.branch_ref(branch_name)) |
|
|
|
|
.map_err(|e| GetError::Unexpected(Box::from(e)))? |
|
|
|
|
.peel_to_id_in_place() |
|
|
|
|
.map_err(|e| GetError::Unexpected(Box::from(e)))? |
|
|
|
|
.detach(); |
|
|
|
|
|
|
|
|
|
let tree_object_id = repo |
|
|
|
|
.find_object(commit_object_id)? |
|
|
|
|
.try_to_commit_ref()? |
|
|
|
|
.find_object(commit_object_id) |
|
|
|
|
.map_err(|e| GetError::Unexpected(Box::from(e)))? |
|
|
|
|
.try_to_commit_ref() |
|
|
|
|
.map_err(|e| GetError::Unexpected(Box::from(e)))? |
|
|
|
|
.tree(); |
|
|
|
|
|
|
|
|
|
return Ok(Box::from(Origin { |
|
|
|
@ -245,27 +271,34 @@ pub mod git { |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
fn all_descrs(&'a self) -> AllDescrsResult<Self::AllDescrsIter> { |
|
|
|
|
Ok(Box::from(fs::read_dir(&self.dir_path)?.map( |
|
|
|
|
|dir_entry_res: io::Result<fs::DirEntry>| -> AllDescrsResult<Descr> { |
|
|
|
|
let descr_id: String = dir_entry_res? |
|
|
|
|
.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)?; |
|
|
|
|
|
|
|
|
|
let descr = serde_json::from_reader(descr_file)?; |
|
|
|
|
|
|
|
|
|
Ok(descr) |
|
|
|
|
}, |
|
|
|
|
))) |
|
|
|
|
Ok(Box::from( |
|
|
|
|
fs::read_dir(&self.dir_path) |
|
|
|
|
.map_err(|e| AllDescrsError::Unexpected(Box::from(e)))? |
|
|
|
|
.map( |
|
|
|
|
|dir_entry_res: io::Result<fs::DirEntry>| -> AllDescrsResult<Descr> { |
|
|
|
|
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) |
|
|
|
|
}, |
|
|
|
|
), |
|
|
|
|
)) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|