implement git store sync (maybe)
This commit is contained in:
parent
72df0f0b21
commit
2663838af0
1
.gitignore
vendored
1
.gitignore
vendored
@ -1 +1,2 @@
|
||||
/target
|
||||
.cargo
|
||||
|
2432
Cargo.lock
generated
2432
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
@ -8,3 +8,8 @@ edition = "2021"
|
||||
[dependencies]
|
||||
sha2 = "0.10.6"
|
||||
hex = "0.4.3"
|
||||
gix = { version = "0.44.1", features = [
|
||||
"blocking-network-client",
|
||||
"blocking-http-transport-reqwest-rust-tls",
|
||||
]}
|
||||
tempdir = "0.3.7"
|
||||
|
@ -35,16 +35,16 @@
|
||||
},
|
||||
"nixpkgs_2": {
|
||||
"locked": {
|
||||
"lastModified": 1683020768,
|
||||
"narHash": "sha256-ZyZl6k9NWS5QPwD3NoAVz/eSgodQDvl+y+fu8MVbrHc=",
|
||||
"lastModified": 1683103914,
|
||||
"narHash": "sha256-Mbrst3sLaiL55eOlZOEL8kB+XTWffaQVfcI03YWiryg=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "44f30edf5661d86fb3a95841c35127f3d0ea8b0f",
|
||||
"rev": "54495a4eafe99c537695a87fe04cb50bf17e651d",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "NixOS",
|
||||
"ref": "nixpkgs-unstable",
|
||||
"ref": "nixos-22.11",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
{
|
||||
inputs = {
|
||||
naersk.url = "github:nix-community/naersk/master";
|
||||
nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable";
|
||||
nixpkgs.url = "github:NixOS/nixpkgs/nixos-22.11";
|
||||
utils.url = "github:numtide/flake-utils";
|
||||
};
|
||||
|
||||
@ -16,6 +16,9 @@
|
||||
devShell = with pkgs; mkShell {
|
||||
buildInputs = [ cargo rustc rustfmt pre-commit rustPackages.clippy ];
|
||||
RUST_SRC_PATH = rustPlatform.rustLibSrc;
|
||||
shellHook = ''
|
||||
export CARGO_HOME=$(pwd)/.cargo
|
||||
'';
|
||||
};
|
||||
});
|
||||
}
|
||||
|
1
src/lib.rs
Normal file
1
src/lib.rs
Normal file
@ -0,0 +1 @@
|
||||
pub mod origin;
|
13
src/main.rs
13
src/main.rs
@ -1,13 +0,0 @@
|
||||
mod origin;
|
||||
|
||||
use crate::origin::Descr;
|
||||
|
||||
fn main() {
|
||||
|
||||
let d = Descr::Git{
|
||||
url: "foo",
|
||||
branch: "bar",
|
||||
};
|
||||
|
||||
println!("{}", d.id());
|
||||
}
|
@ -1,44 +1,10 @@
|
||||
use sha2::{Sha256, Digest};
|
||||
use hex::ToHex;
|
||||
mod descr;
|
||||
pub use self::descr::Descr;
|
||||
|
||||
/// A unique description of an origin, from where a domain might be served.
|
||||
pub enum Descr<'a> {
|
||||
Git{url: &'a str, branch: &'a str},
|
||||
pub mod store;
|
||||
|
||||
/// A View of an origin is used to read the files of that origin at a particular point in time. A
|
||||
/// single instance of a View should remain consistent across its lifetime.
|
||||
pub trait View {
|
||||
fn open(&self, path: &str) -> &dyn std::io::Read;
|
||||
}
|
||||
|
||||
impl<'a> Descr<'a> {
|
||||
|
||||
/// Returns a globally unique string for the Descr.
|
||||
pub fn id(&'a self) -> String {
|
||||
|
||||
let mut h = Sha256::new();
|
||||
|
||||
let mut h_update = |b: &str| {
|
||||
h.update(b);
|
||||
h.update("\n");
|
||||
};
|
||||
|
||||
match self {
|
||||
Descr::Git{url, branch} => {
|
||||
h_update("git");
|
||||
h_update(url);
|
||||
h_update(branch);
|
||||
}
|
||||
}
|
||||
|
||||
h.finalize().encode_hex::<String>()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod descr_tests {
|
||||
|
||||
#[test]
|
||||
fn id() {
|
||||
|
||||
assert_eq!(
|
||||
super::Descr::Git{url:"foo", branch:"bar"}.id(),
|
||||
"424130b9e6c1675c983b4b97579877e16d8a6377e4fe10970e6d210811c3b7ac",
|
||||
)
|
||||
}
|
||||
//}
|
||||
|
@ -1,9 +1,10 @@
|
||||
use sha2::{Sha256, Digest};
|
||||
use hex::ToHex;
|
||||
|
||||
#[derive(Clone,Copy)]
|
||||
/// A unique description of an origin, from where a domain might be served.
|
||||
pub enum Descr<'a> {
|
||||
Git{url: &'a str, branch: &'a str},
|
||||
Git{url: &'a str, branch_name: &'a str},
|
||||
}
|
||||
|
||||
impl<'a> Descr<'a> {
|
||||
@ -19,10 +20,10 @@ impl<'a> Descr<'a> {
|
||||
};
|
||||
|
||||
match self {
|
||||
Descr::Git{url, branch} => {
|
||||
Descr::Git{url, branch_name} => {
|
||||
h_update("git");
|
||||
h_update(url);
|
||||
h_update(branch);
|
||||
h_update(branch_name);
|
||||
}
|
||||
}
|
||||
|
||||
@ -37,7 +38,7 @@ mod descr_tests {
|
||||
fn id() {
|
||||
|
||||
assert_eq!(
|
||||
super::Descr::Git{url:"foo", branch:"bar"}.id(),
|
||||
super::Descr::Git{url:"foo", branch_name:"bar"}.id(),
|
||||
"424130b9e6c1675c983b4b97579877e16d8a6377e4fe10970e6d210811c3b7ac",
|
||||
)
|
||||
}
|
||||
|
138
src/origin/store.rs
Normal file
138
src/origin/store.rs
Normal file
@ -0,0 +1,138 @@
|
||||
use std::error::Error;
|
||||
|
||||
use super::Descr;
|
||||
use super::View;
|
||||
|
||||
#[derive(Clone,Copy)]
|
||||
pub struct Limits {}
|
||||
|
||||
pub enum GetViewError {
|
||||
TODO,
|
||||
Unexpected(Box<dyn Error>),
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum SyncError {
|
||||
InvalidURL,
|
||||
InvalidBranchName,
|
||||
Unexpected(Box<dyn Error>),
|
||||
}
|
||||
|
||||
pub trait Store {
|
||||
fn get_view(&self, descr: Descr) -> Result<&dyn View, GetViewError>;
|
||||
fn sync(&self, descr: Descr, limits: Limits) -> Result<(), SyncError>;
|
||||
}
|
||||
|
||||
pub mod git {
|
||||
|
||||
use std::path::Path;
|
||||
use super::{Store as originStore, *};
|
||||
|
||||
use gix::clone::Error as gixCloneErr;
|
||||
use gix::progress::Discard;
|
||||
|
||||
// Catching error from gix::prepare_clone_bare
|
||||
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)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Store<'a> {
|
||||
dir_path: &'a Path,
|
||||
}
|
||||
|
||||
impl<'a> Store<'a> {
|
||||
|
||||
pub fn new(dir_path: &Path) -> std::io::Result<Store> {
|
||||
std::fs::create_dir_all(dir_path)?;
|
||||
println!("{}", &dir_path.display());
|
||||
Ok(Store{dir_path})
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> originStore for Store<'a> {
|
||||
|
||||
fn sync(&self, descr: Descr, _limits: Limits) -> Result<(), SyncError> {
|
||||
|
||||
let should_interrupt = &core::sync::atomic::AtomicBool::new(false);
|
||||
|
||||
let Descr::Git{url, ..} = descr;
|
||||
|
||||
let path = &self.dir_path.clone().join(descr.id());
|
||||
|
||||
// if the path doesn't exist then use the gix clone feature to clone it into the
|
||||
// directory.
|
||||
if std::fs::read_dir(path).is_err() {
|
||||
|
||||
std::fs::create_dir_all(path)
|
||||
.map_err(|e| SyncError::Unexpected(Box::from(e)))?;
|
||||
|
||||
gix::prepare_clone_bare(url, path)?
|
||||
.fetch_only(Discard, should_interrupt)
|
||||
.map_err(|_| SyncError::InvalidURL)?;
|
||||
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let direction = gix::remote::Direction::Fetch;
|
||||
|
||||
let repo = gix::open(path)
|
||||
.map_err(|e| SyncError::Unexpected(Box::from(e)))?;
|
||||
|
||||
let remote = repo.find_default_remote(direction)
|
||||
.ok_or(SyncError::Unexpected(Box::from("no default configured")))?
|
||||
.map_err(|e| SyncError::Unexpected(Box::from(e)))?;
|
||||
|
||||
remote
|
||||
.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(())
|
||||
}
|
||||
|
||||
fn get_view(&self, _descr: Descr) -> Result<&dyn View, GetViewError> {
|
||||
Err(GetViewError::TODO)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
||||
use super::Descr;
|
||||
use super::super::Store;
|
||||
|
||||
use tempdir::TempDir;
|
||||
|
||||
#[test]
|
||||
fn sync() {
|
||||
|
||||
let tmp_dir = TempDir::new("origin_store_git").unwrap();
|
||||
|
||||
let descr = Descr::Git{
|
||||
url: "https://github.com/mediocregopher/priority-finder.git",
|
||||
branch_name: "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");
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user