This commit is contained in:
Brian Picciano 2023-05-07 13:03:59 +02:00
parent 599ad7f4dc
commit c921e8a479
2 changed files with 78 additions and 81 deletions

View File

@ -1,18 +1,16 @@
use sha2::{Sha256, Digest};
use hex::ToHex;
use serde::{Serialize, Deserialize};
use serde::{Deserialize, Serialize};
use sha2::{Digest, Sha256};
#[derive(Clone,Debug,PartialEq,Serialize,Deserialize)]
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
/// A unique description of an origin, from where a domain might be served.
pub enum Descr {
Git{url: String, branch_name: String},
Git { url: String, branch_name: String },
}
impl Descr {
/// Returns a globally unique string for the Descr.
pub fn id(&self) -> String {
let mut h = Sha256::new();
let mut h_update = |b: &str| {
@ -21,7 +19,7 @@ impl Descr {
};
match self {
Descr::Git{url, branch_name} => {
Descr::Git { url, branch_name } => {
h_update("git");
h_update(url);
h_update(branch_name);
@ -37,14 +35,13 @@ mod descr_tests {
#[test]
fn id() {
assert_eq!(
super::Descr::Git{
super::Descr::Git {
url: String::from("foo"),
branch_name: String::from("bar"),
}.id(),
}
.id(),
"424130b9e6c1675c983b4b97579877e16d8a6377e4fe10970e6d210811c3b7ac",
)
}
}

View File

@ -4,7 +4,7 @@ use serde_json;
use super::Descr;
#[derive(Clone,Copy)]
#[derive(Clone, Copy)]
pub struct Limits {}
#[derive(Debug)]
@ -26,28 +26,22 @@ pub enum WriteFileError {
}
pub trait Store {
fn write_file<W>(
&self,
descr: &Descr,
path: &str,
into: &mut W,
) -> Result<(), WriteFileError>
where W: std::io::Write + ?Sized;
fn write_file<W>(&self, 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 all_descrs(&self) -> Result<
Box<dyn Iterator<Item = Result<Descr, AllDescrsError>> + '_>,
AllDescrsError,
>;
fn all_descrs(
&self,
) -> Result<Box<dyn Iterator<Item = Result<Descr, AllDescrsError>> + '_>, AllDescrsError>;
}
pub mod git {
use std::path::{Path, PathBuf};
use std::{fs,io};
use super::*;
use std::path::{Path, PathBuf};
use std::{fs, io};
use gix::clone::Error as gixCloneErr;
use gix::progress::Discard;
@ -56,13 +50,13 @@ pub mod git {
impl From<gixCloneErr> for SyncError {
fn from(e: gixCloneErr) -> SyncError {
match e {
gixCloneErr::Init(gix::init::Error::InvalidBranchName{..}) =>
SyncError::InvalidBranchName,
gixCloneErr::UrlParse(_) |
gixCloneErr::CanonicalizeUrl{..} =>
SyncError::InvalidURL,
_ =>
SyncError::Unexpected(Box::from(e)),
gixCloneErr::Init(gix::init::Error::InvalidBranchName { .. }) => {
SyncError::InvalidBranchName
}
gixCloneErr::UrlParse(_) | gixCloneErr::CanonicalizeUrl { .. } => {
SyncError::InvalidURL
}
_ => SyncError::Unexpected(Box::from(e)),
}
}
}
@ -72,16 +66,15 @@ pub mod git {
}
impl<'a> Store<'a> {
pub fn new(dir_path: &Path) -> io::Result<Store> {
fs::create_dir_all(dir_path)?;
Ok(Store{dir_path})
Ok(Store { dir_path })
}
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")
}
@ -92,9 +85,7 @@ pub mod git {
}
impl<'a> super::Store for Store<'a> {
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);
@ -102,11 +93,9 @@ 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).map_err(|e| SyncError::Unexpected(Box::from(e)))?;
fs::create_dir_all(repo_path)
.map_err(|e| SyncError::Unexpected(Box::from(e)))?;
let Descr::Git{url, branch_name} = descr;
let Descr::Git { url, branch_name } = descr;
let (repo, _) = gix::prepare_clone_bare(url.clone(), repo_path)?
.fetch_only(Discard, should_interrupt)
@ -131,10 +120,10 @@ pub mod git {
let direction = gix::remote::Direction::Fetch;
let repo = gix::open(repo_path)
.map_err(|e| SyncError::Unexpected(Box::from(e)))?;
let repo = gix::open(repo_path).map_err(|e| SyncError::Unexpected(Box::from(e)))?;
let remote = repo.find_default_remote(direction)
let remote = repo
.find_default_remote(direction)
.ok_or(SyncError::Unexpected(Box::from("no default configured")))?
.map_err(|e| SyncError::Unexpected(Box::from(e)))?;
@ -149,24 +138,24 @@ pub mod git {
Ok(())
}
fn write_file<W>(
&self,
descr: &Descr,
path: &str,
into: &mut W,
) -> Result<(), WriteFileError>
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);
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 mut clean_path = Path::new(path);
clean_path = clean_path.strip_prefix("/").unwrap_or(clean_path);
let repo = gix::open(repo_path)
.map_err(|e| WriteFileError::Unexpected(Box::from(e)))?;
let repo =
gix::open(repo_path).map_err(|e| WriteFileError::Unexpected(Box::from(e)))?;
let commit_object_id = repo
.find_reference(branch_ref)
@ -174,13 +163,15 @@ pub mod git {
.peel_to_id_in_place()
.map_err(|e| WriteFileError::Unexpected(Box::from(e)))?;
let tree_object_id = repo.find_object(commit_object_id)
let tree_object_id = repo
.find_object(commit_object_id)
.map_err(|e| WriteFileError::Unexpected(Box::from(e)))?
.try_to_commit_ref()
.map_err(|e| WriteFileError::Unexpected(Box::from(e)))?
.tree();
let file_object = repo.find_object(tree_object_id)
let file_object = repo
.find_object(tree_object_id)
.map_err(|e| WriteFileError::Unexpected(Box::from(e)))?
.peel_to_tree()
.map_err(|e| WriteFileError::Unexpected(Box::from(e)))?
@ -196,31 +187,36 @@ pub mod git {
Ok(())
}
fn all_descrs(&self) -> Result<
Box<dyn Iterator<Item = Result<Descr, AllDescrsError>> + '_>,
AllDescrsError,
> {
fn all_descrs(
&self,
) -> Result<Box<dyn Iterator<Item = Result<Descr, AllDescrsError>> + '_>, AllDescrsError>
{
let inner_iter = fs::read_dir(self.dir_path)
.map_err(|e| AllDescrsError::Unexpected(Box::from(e)))?
.map(|dir_entry_res: io::Result<fs::DirEntry>| -> Result<Descr, AllDescrsError> {
.map(
|dir_entry_res: io::Result<fs::DirEntry>| -> Result<Descr, AllDescrsError> {
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_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_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_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)))?;
let descr = serde_json::from_reader(descr_file)
.map_err(|e| AllDescrsError::Unexpected(Box::from(e)))?;
Ok(descr)
});
Ok(descr)
},
);
Ok(Box::from(inner_iter))
}
@ -228,33 +224,36 @@ pub mod git {
#[cfg(test)]
mod tests {
use super::Descr;
use super::super::Store;
use super::Descr;
use tempdir::TempDir;
#[test]
fn basic() {
let tmp_dir = TempDir::new("origin_store_git").unwrap();
let curr_dir = format!("file://{}", std::env::current_dir().unwrap().display());
let descr = Descr::Git{
let descr = Descr::Git {
url: curr_dir,
branch_name: String::from("master"),
};
let limits = super::Limits{};
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("second sync should succeed");
let assert_write = |path: &str| {
let mut into: Vec<u8> = 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);
};
@ -269,7 +268,8 @@ pub mod git {
));
assert_eq!(into.len(), 0);
let descrs = store.all_descrs()
let descrs = store
.all_descrs()
.expect("all_descrs callsed")
.collect::<Vec<Result<Descr, super::AllDescrsError>>>();