Implement all_descrs on the store
This commit is contained in:
parent
a4febdc40e
commit
599ad7f4dc
20
Cargo.lock
generated
20
Cargo.lock
generated
@ -404,6 +404,8 @@ version = "0.1.0"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"gix",
|
"gix",
|
||||||
"hex",
|
"hex",
|
||||||
|
"serde",
|
||||||
|
"serde_json",
|
||||||
"sha2",
|
"sha2",
|
||||||
"tempdir",
|
"tempdir",
|
||||||
]
|
]
|
||||||
@ -1819,9 +1821,23 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde"
|
name = "serde"
|
||||||
version = "1.0.160"
|
version = "1.0.162"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
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]]
|
[[package]]
|
||||||
name = "serde_json"
|
name = "serde_json"
|
||||||
|
@ -13,3 +13,5 @@ gix = { version = "0.44.1", features = [
|
|||||||
"blocking-http-transport-reqwest-rust-tls",
|
"blocking-http-transport-reqwest-rust-tls",
|
||||||
]}
|
]}
|
||||||
tempdir = "0.3.7"
|
tempdir = "0.3.7"
|
||||||
|
serde = { version = "1.0.162", features = [ "derive" ]}
|
||||||
|
serde_json = "1.0.96"
|
||||||
|
@ -1,16 +1,17 @@
|
|||||||
use sha2::{Sha256, Digest};
|
use sha2::{Sha256, Digest};
|
||||||
use hex::ToHex;
|
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.
|
/// A unique description of an origin, from where a domain might be served.
|
||||||
pub enum Descr<'a> {
|
pub enum Descr {
|
||||||
Git{url: &'a str, branch_name: &'a str},
|
Git{url: String, branch_name: String},
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Descr<'a> {
|
impl Descr {
|
||||||
|
|
||||||
/// Returns a globally unique string for the 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();
|
let mut h = Sha256::new();
|
||||||
|
|
||||||
@ -38,7 +39,10 @@ mod descr_tests {
|
|||||||
fn id() {
|
fn id() {
|
||||||
|
|
||||||
assert_eq!(
|
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",
|
"424130b9e6c1675c983b4b97579877e16d8a6377e4fe10970e6d210811c3b7ac",
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -1,10 +1,17 @@
|
|||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
|
|
||||||
|
use serde_json;
|
||||||
|
|
||||||
use super::Descr;
|
use super::Descr;
|
||||||
|
|
||||||
#[derive(Clone,Copy)]
|
#[derive(Clone,Copy)]
|
||||||
pub struct Limits {}
|
pub struct Limits {}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum AllDescrsError {
|
||||||
|
Unexpected(Box<dyn Error>),
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum SyncError {
|
pub enum SyncError {
|
||||||
InvalidURL,
|
InvalidURL,
|
||||||
@ -22,18 +29,24 @@ pub trait Store {
|
|||||||
|
|
||||||
fn write_file<W>(
|
fn write_file<W>(
|
||||||
&self,
|
&self,
|
||||||
descr: Descr,
|
descr: &Descr,
|
||||||
path: &str,
|
path: &str,
|
||||||
into: &mut W,
|
into: &mut W,
|
||||||
) -> Result<(), WriteFileError>
|
) -> Result<(), WriteFileError>
|
||||||
where W: std::io::Write + ?Sized;
|
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<dyn Iterator<Item = Result<Descr, AllDescrsError>> + '_>,
|
||||||
|
AllDescrsError,
|
||||||
|
>;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub mod git {
|
pub mod git {
|
||||||
|
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
|
use std::{fs,io};
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
use gix::clone::Error as gixCloneErr;
|
use gix::clone::Error as gixCloneErr;
|
||||||
@ -60,15 +73,19 @@ pub mod git {
|
|||||||
|
|
||||||
impl<'a> Store<'a> {
|
impl<'a> Store<'a> {
|
||||||
|
|
||||||
pub fn new(dir_path: &Path) -> std::io::Result<Store> {
|
pub fn new(dir_path: &Path) -> io::Result<Store> {
|
||||||
std::fs::create_dir_all(dir_path)?;
|
fs::create_dir_all(dir_path)?;
|
||||||
Ok(Store{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())
|
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 {
|
fn branch_ref(branch_name: &str) -> String {
|
||||||
format!("origin/{branch_name}")
|
format!("origin/{branch_name}")
|
||||||
}
|
}
|
||||||
@ -76,29 +93,39 @@ pub mod git {
|
|||||||
|
|
||||||
impl<'a> super::Store for Store<'a> {
|
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 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
|
// if the path doesn't exist then use the gix clone feature to clone it into the
|
||||||
// directory.
|
// 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)))?;
|
.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, repo_path)?
|
let (repo, _) = gix::prepare_clone_bare(url.clone(), repo_path)?
|
||||||
.fetch_only(Discard, should_interrupt)
|
.fetch_only(Discard, should_interrupt)
|
||||||
.map_err(|_| SyncError::InvalidURL)?;
|
.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)))?
|
.map_err(|e| SyncError::Unexpected(Box::from(e)))?
|
||||||
.ok_or(SyncError::InvalidBranchName)?;
|
.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(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -125,15 +152,15 @@ pub mod git {
|
|||||||
|
|
||||||
fn write_file<W>(
|
fn write_file<W>(
|
||||||
&self,
|
&self,
|
||||||
descr: Descr,
|
descr: &Descr,
|
||||||
path: &str,
|
path: &str,
|
||||||
into: &mut W,
|
into: &mut W,
|
||||||
) -> Result<(), WriteFileError>
|
) -> Result<(), WriteFileError>
|
||||||
where W: std::io::Write + ?Sized {
|
where W: io::Write + ?Sized {
|
||||||
|
|
||||||
let Descr::Git{branch_name, ..} = descr;
|
let Descr::Git{branch_name, ..} = descr;
|
||||||
let repo_path = &self.repo_path(descr);
|
let repo_path = &self.repo_path(&descr);
|
||||||
let branch_ref = &Self::branch_ref(branch_name);
|
let branch_ref = &Self::branch_ref(&branch_name);
|
||||||
|
|
||||||
let mut clean_path = Path::new(path);
|
let mut clean_path = Path::new(path);
|
||||||
clean_path = clean_path.strip_prefix("/").unwrap_or(clean_path);
|
clean_path = clean_path.strip_prefix("/").unwrap_or(clean_path);
|
||||||
@ -168,11 +195,39 @@ pub mod git {
|
|||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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> {
|
||||||
|
|
||||||
|
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)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
|
||||||
use super::Descr;
|
use super::Descr;
|
||||||
use super::super::Store;
|
use super::super::Store;
|
||||||
|
|
||||||
@ -186,20 +241,20 @@ pub mod git {
|
|||||||
let curr_dir = format!("file://{}", std::env::current_dir().unwrap().display());
|
let curr_dir = format!("file://{}", std::env::current_dir().unwrap().display());
|
||||||
|
|
||||||
let descr = Descr::Git{
|
let descr = Descr::Git{
|
||||||
url: curr_dir.as_ref(),
|
url: curr_dir,
|
||||||
branch_name: "master",
|
branch_name: String::from("master"),
|
||||||
};
|
};
|
||||||
|
|
||||||
let limits = super::Limits{};
|
let limits = super::Limits{};
|
||||||
|
|
||||||
let store = super::Store::new(tmp_dir.path()).expect("store created");
|
let store = super::Store::new(tmp_dir.path()).expect("store created");
|
||||||
|
|
||||||
store.sync(descr, limits).expect("sync should succeed");
|
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 assert_write = |path: &str| {
|
||||||
let mut into: Vec<u8> = vec![];
|
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);
|
assert!(into.len() > 0);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -209,10 +264,17 @@ pub mod git {
|
|||||||
// File doesn't exist
|
// File doesn't exist
|
||||||
let mut into: Vec<u8> = vec![];
|
let mut into: Vec<u8> = vec![];
|
||||||
assert!(matches!(
|
assert!(matches!(
|
||||||
store.write_file(descr, "DNE", &mut into),
|
store.write_file(&descr, "DNE", &mut into),
|
||||||
Err::<(), super::WriteFileError>(super::WriteFileError::FileNotFound),
|
Err::<(), super::WriteFileError>(super::WriteFileError::FileNotFound),
|
||||||
));
|
));
|
||||||
assert_eq!(into.len(), 0);
|
assert_eq!(into.len(), 0);
|
||||||
|
|
||||||
|
let descrs = store.all_descrs()
|
||||||
|
.expect("all_descrs callsed")
|
||||||
|
.collect::<Vec<Result<Descr, super::AllDescrsError>>>();
|
||||||
|
|
||||||
|
assert_eq!(1, descrs.len());
|
||||||
|
assert_eq!(&descr, descrs[0].as_ref().unwrap());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user