refactor Reader implementation to use enum instead of trait and remove unnecessary public functions

This commit is contained in:
Nikita Galaiko 2023-12-20 16:29:20 +01:00 committed by GitButler
parent 4e52086aa1
commit b72c6317ef
15 changed files with 163 additions and 173 deletions

View File

@ -2,17 +2,25 @@ use std::{collections::HashMap, path};
use anyhow::Result;
use crate::reader;
use crate::{reader, sessions};
use super::Delta;
pub struct DeltasReader<'reader> {
reader: &'reader dyn reader::Reader,
reader: &'reader reader::Reader<'reader>,
}
impl<'reader> From<&'reader reader::Reader<'reader>> for DeltasReader<'reader> {
fn from(reader: &'reader reader::Reader<'reader>) -> Self {
DeltasReader { reader }
}
}
impl<'reader> DeltasReader<'reader> {
pub fn new(reader: &'reader dyn reader::Reader) -> Self {
DeltasReader { reader }
pub fn new(reader: &'reader sessions::Reader<'reader>) -> Self {
DeltasReader {
reader: reader.reader(),
}
}
pub fn read_file<P: AsRef<std::path::Path>>(&self, path: P) -> Result<Option<Vec<Delta>>> {

View File

@ -20,8 +20,7 @@ use crate::{
paths::DataDir,
project_repository,
projects::{self, ProjectId},
reader::{self, Reader},
sessions,
reader, sessions,
sessions::SessionId,
users,
virtual_branches::{self, target},
@ -381,8 +380,8 @@ impl Repository {
pub fn get_or_create_current_session(&self) -> Result<sessions::Session> {
let _lock = self.lock();
let reader = reader::DirReader::open(self.root());
match sessions::Session::try_from(reader) {
let reader = reader::Reader::open(&self.root());
match sessions::Session::try_from(&reader) {
Result::Ok(session) => Ok(session),
Err(sessions::SessionError::NoSession) => {
let project_repository = project_repository::Repository::open(&self.project)
@ -484,8 +483,8 @@ impl Repository {
pub fn get_current_session(&self) -> Result<Option<sessions::Session>> {
let _lock = self.lock();
let reader = reader::DirReader::open(self.root());
match sessions::Session::try_from(reader) {
let reader = reader::Reader::open(&self.root());
match sessions::Session::try_from(&reader) {
Ok(session) => Ok(Some(session)),
Err(sessions::SessionError::NoSession) => Ok(None),
Err(sessions::SessionError::Other(err)) => Err(err),
@ -588,8 +587,8 @@ fn build_wd_tree_from_reference(
})?;
}
let session_reader = reader::DirReader::open(gb_repository.root());
let deltas = deltas::Reader::new(&session_reader)
let session_reader = reader::Reader::open(&gb_repository.root());
let deltas = deltas::Reader::from(&session_reader)
.read(None)
.context("failed to read deltas")?;
let wd_files = session_reader.list_files(path::Path::new("session/wd"))?;

View File

@ -93,8 +93,8 @@ impl Repository {
Ok(ignored)
}
pub fn get_wd_reader(&self) -> reader::DirReader {
reader::DirReader::open(self.root().to_path_buf())
pub fn get_wd_reader(&self) -> reader::Reader {
reader::Reader::open(self.root())
}
pub fn root(&self) -> &std::path::Path {

View File

@ -15,10 +15,59 @@ pub enum Error {
From(#[from] FromError),
}
pub trait Reader {
fn read(&self, file_path: &path::Path) -> Result<Content, Error>;
fn list_files(&self, dir_path: &path::Path) -> Result<Vec<path::PathBuf>>;
fn exists(&self, file_path: &path::Path) -> bool;
pub enum Reader<'reader> {
Dir(DirReader),
Commit(CommitReader<'reader>),
Sub(SubReader<'reader>),
}
impl<'reader> Reader<'reader> {
pub fn open(root: &path::Path) -> Self {
Reader::Dir(DirReader::open(root.to_path_buf()))
}
pub fn sub<P: AsRef<path::Path>>(&'reader self, prefix: P) -> Self {
Reader::Sub(SubReader::new(self, prefix))
}
pub fn commit_id(&self) -> Option<git::Oid> {
match self {
Reader::Dir(_) => None,
Reader::Commit(reader) => Some(reader.get_commit_oid()),
Reader::Sub(reader) => reader.reader.commit_id(),
}
}
pub fn from_commit(
repository: &'reader git::Repository,
commit: &git::Commit<'reader>,
) -> Result<Self> {
Ok(Reader::Commit(CommitReader::new(repository, commit)?))
}
pub fn exists(&self, file_path: &path::Path) -> bool {
match self {
Reader::Dir(reader) => reader.exists(file_path),
Reader::Commit(reader) => reader.exists(file_path),
Reader::Sub(reader) => reader.exists(file_path),
}
}
pub fn read(&self, path: &path::Path) -> Result<Content, Error> {
match self {
Reader::Dir(reader) => reader.read(path),
Reader::Commit(reader) => reader.read(path),
Reader::Sub(reader) => reader.read(path),
}
}
pub fn list_files(&self, dir_path: &path::Path) -> Result<Vec<path::PathBuf>> {
match self {
Reader::Dir(reader) => reader.list_files(dir_path),
Reader::Commit(reader) => reader.list_files(dir_path),
Reader::Sub(reader) => reader.list_files(dir_path),
}
}
}
pub struct DirReader {
@ -26,12 +75,10 @@ pub struct DirReader {
}
impl DirReader {
pub fn open(root: std::path::PathBuf) -> Self {
fn open(root: std::path::PathBuf) -> Self {
Self { root }
}
}
impl Reader for DirReader {
fn exists(&self, file_path: &path::Path) -> bool {
let path = self.root.join(file_path);
path.exists()
@ -61,7 +108,7 @@ pub struct CommitReader<'reader> {
}
impl<'reader> CommitReader<'reader> {
pub fn from_commit(
fn new(
repository: &'reader git::Repository,
commit: &git::Commit<'reader>,
) -> Result<CommitReader<'reader>> {
@ -78,9 +125,7 @@ impl<'reader> CommitReader<'reader> {
pub fn get_commit_oid(&self) -> git::Oid {
self.commit_oid
}
}
impl Reader for CommitReader<'_> {
fn read(&self, path: &path::Path) -> Result<Content, Error> {
let entry = match self
.tree
@ -129,21 +174,19 @@ impl Reader for CommitReader<'_> {
}
}
pub struct SubReader<'r, R: Reader> {
reader: &'r R,
pub struct SubReader<'r> {
reader: &'r Reader<'r>,
prefix: path::PathBuf,
}
impl<'r, R: Reader> SubReader<'r, R> {
pub fn new<P: AsRef<path::Path>>(reader: &'r R, prefix: P) -> Self {
impl<'r> SubReader<'r> {
fn new<P: AsRef<path::Path>>(reader: &'r Reader, prefix: P) -> Self {
SubReader {
reader,
prefix: prefix.as_ref().to_path_buf(),
}
}
}
impl<R: Reader> Reader for SubReader<'_, R> {
fn read(&self, path: &path::Path) -> Result<Content, Error> {
self.reader.read(&self.prefix.join(path))
}
@ -335,7 +378,7 @@ mod tests {
std::fs::write(repository.path().parent().unwrap().join(file_path), "test2")?;
let reader = CommitReader::from_commit(&repository, &repository.find_commit(oid)?)?;
let reader = CommitReader::new(&repository, &repository.find_commit(oid)?)?;
assert_eq!(reader.read(file_path)?, Content::UTF8("test".to_string()));
Ok(())
@ -397,7 +440,7 @@ mod tests {
std::fs::remove_dir_all(repository.path().parent().unwrap().join("dir"))?;
let reader = CommitReader::from_commit(&repository, &repository.find_commit(oid)?)?;
let reader = CommitReader::new(&repository, &repository.find_commit(oid)?)?;
let files = reader.list_files(path::Path::new("dir"))?;
assert_eq!(files.len(), 1);
assert!(files.contains(&path::Path::new("test.txt").to_path_buf()));
@ -425,7 +468,7 @@ mod tests {
std::fs::remove_dir_all(repository.path().parent().unwrap().join("dir"))?;
let reader = CommitReader::from_commit(&repository, &repository.find_commit(oid)?)?;
let reader = CommitReader::new(&repository, &repository.find_commit(oid)?)?;
let files = reader.list_files(path::Path::new(""))?;
assert_eq!(files.len(), 2);
assert!(files.contains(&path::Path::new("test.txt").to_path_buf()));
@ -457,7 +500,7 @@ mod tests {
std::fs::remove_file(repository.path().parent().unwrap().join("test.txt"))?;
let reader = CommitReader::from_commit(&repository, &repository.find_commit(oid)?)?;
let reader = CommitReader::new(&repository, &repository.find_commit(oid)?)?;
assert!(reader.exists(path::Path::new("test.txt")));
assert!(!reader.exists(path::Path::new("test2.txt")));

View File

@ -1,6 +1,6 @@
use anyhow::{Context, Result};
use crate::{git, reader::CommitReader};
use crate::{git, reader};
use super::{Session, SessionError};
@ -49,11 +49,12 @@ impl<'iterator> Iterator for SessionsIterator<'iterator> {
return self.next();
}
let commit_reader = match CommitReader::from_commit(self.git_repository, &commit) {
let commit_reader = match reader::Reader::from_commit(self.git_repository, &commit)
{
Result::Ok(commit_reader) => commit_reader,
Err(err) => return Some(Err(err)),
};
let session = match Session::try_from(commit_reader) {
let session = match Session::try_from(&commit_reader) {
Result::Ok(session) => session,
Err(SessionError::NoSession) => return None,
Err(err) => return Some(Err(err.into())),

View File

@ -2,37 +2,24 @@ use std::{collections::HashMap, path};
use anyhow::{anyhow, Context, Result};
use crate::{
gb_repository,
reader::{self, CommitReader, Reader},
};
use crate::{gb_repository, reader};
use super::Session;
pub struct SessionReader<'reader> {
// reader for the current session. commit or wd
reader: Box<dyn reader::Reader + 'reader>,
reader: reader::Reader<'reader>,
// reader for the previous session's commit
previous_reader: reader::CommitReader<'reader>,
}
impl Reader for SessionReader<'_> {
fn read(&self, file_path: &path::Path) -> Result<reader::Content, reader::Error> {
self.reader.read(file_path)
}
fn list_files(&self, dir_path: &path::Path) -> Result<Vec<path::PathBuf>> {
self.reader.list_files(dir_path)
}
fn exists(&self, file_path: &path::Path) -> bool {
self.reader.exists(file_path)
}
previous_reader: reader::Reader<'reader>,
}
impl<'reader> SessionReader<'reader> {
pub fn reader(&self) -> &reader::Reader<'reader> {
&self.reader
}
pub fn open(repository: &'reader gb_repository::Repository, session: &Session) -> Result<Self> {
let wd_reader = reader::DirReader::open(repository.root());
let wd_reader = reader::Reader::open(&repository.root());
if let Ok(reader::Content::UTF8(current_session_id)) =
wd_reader.read(&repository.session_path().join("meta").join("id"))
@ -40,8 +27,8 @@ impl<'reader> SessionReader<'reader> {
if current_session_id == session.id.to_string() {
let head_commit = repository.git_repository().head()?.peel_to_commit()?;
return Ok(SessionReader {
reader: Box::new(wd_reader),
previous_reader: CommitReader::from_commit(
reader: wd_reader,
previous_reader: reader::Reader::from_commit(
repository.git_repository(),
&head_commit,
)?,
@ -62,12 +49,11 @@ impl<'reader> SessionReader<'reader> {
.git_repository()
.find_commit(*session_hash)
.context("failed to get commit")?;
let commit_reader =
reader::CommitReader::from_commit(repository.git_repository(), &commit)?;
let commit_reader = reader::Reader::from_commit(repository.git_repository(), &commit)?;
Ok(SessionReader {
reader: Box::new(commit_reader),
previous_reader: reader::CommitReader::from_commit(
reader: commit_reader,
previous_reader: reader::Reader::from_commit(
repository.git_repository(),
&commit.parent(0)?,
)?,

View File

@ -38,10 +38,10 @@ pub enum SessionError {
Other(anyhow::Error),
}
impl TryFrom<&dyn reader::Reader> for Session {
impl TryFrom<&reader::Reader<'_>> for Session {
type Error = SessionError;
fn try_from(reader: &dyn reader::Reader) -> Result<Self, Self::Error> {
fn try_from(reader: &reader::Reader) -> Result<Self, Self::Error> {
let id: String = reader
.read(path::Path::new("session/meta/id"))
.map_err(|error| match error {
@ -99,7 +99,7 @@ impl TryFrom<&dyn reader::Reader> for Session {
Ok(Self {
id,
hash: None,
hash: reader.commit_id(),
meta: Meta {
start_timestamp_ms,
last_timestamp_ms,
@ -109,25 +109,3 @@ impl TryFrom<&dyn reader::Reader> for Session {
})
}
}
impl TryFrom<reader::DirReader> for Session {
type Error = SessionError;
fn try_from(reader: reader::DirReader) -> Result<Self, Self::Error> {
let session = Session::try_from(&reader as &dyn reader::Reader)?;
Ok(session)
}
}
impl<'reader> TryFrom<reader::CommitReader<'reader>> for Session {
type Error = SessionError;
fn try_from(reader: reader::CommitReader<'reader>) -> Result<Self, Self::Error> {
let commit_oid = reader.get_commit_oid();
let session = Session::try_from(&reader as &dyn reader::Reader)?;
Ok(Session {
hash: Some(commit_oid),
..session
})
}
}

View File

@ -2,11 +2,7 @@ use std::{path, time};
use anyhow::{anyhow, Context, Result};
use crate::{
gb_repository,
reader::{self, Reader},
writer,
};
use crate::{gb_repository, reader, writer};
use super::Session;
@ -26,7 +22,7 @@ impl<'writer> SessionWriter<'writer> {
return Err(anyhow!("can not open writer for a session with a hash"));
}
let reader = reader::DirReader::open(self.repository.root());
let reader = reader::Reader::open(&self.repository.root());
let current_session_id = if let Ok(reader::Content::UTF8(current_session_id)) =
reader.read(&path::PathBuf::from("session/meta/id"))

View File

@ -67,10 +67,10 @@ pub struct BranchCreateRequest {
pub order: Option<usize>,
}
impl TryFrom<&dyn crate::reader::Reader> for Branch {
impl TryFrom<&crate::reader::Reader<'_>> for Branch {
type Error = crate::reader::Error;
fn try_from(reader: &dyn crate::reader::Reader) -> Result<Self, Self::Error> {
fn try_from(reader: &crate::reader::Reader) -> Result<Self, Self::Error> {
let id: String = reader.read(&path::PathBuf::from("id"))?.try_into()?;
let id: BranchId = id.parse().map_err(|e| {
crate::reader::Error::Io(std::io::Error::new(

View File

@ -1,20 +1,18 @@
use std::path;
use crate::reader::{self, SubReader};
use crate::{reader, sessions};
use super::{Branch, BranchId};
pub struct BranchReader<'r, R: crate::reader::Reader> {
reader: &'r R,
pub struct BranchReader<'r> {
reader: &'r reader::Reader<'r>,
}
impl<'r, R: crate::reader::Reader> BranchReader<'r, R> {
pub fn new(reader: &'r R) -> Self {
Self { reader }
}
pub fn reader(&self) -> &dyn reader::Reader {
self.reader
impl<'r> BranchReader<'r> {
pub fn new(reader: &'r sessions::Reader<'r>) -> Self {
Self {
reader: reader.reader(),
}
}
pub fn read(&self, id: &BranchId) -> Result<Branch, reader::Error> {
@ -25,9 +23,7 @@ impl<'r, R: crate::reader::Reader> BranchReader<'r, R> {
return Err(reader::Error::NotFound);
}
let single_reader: &dyn crate::reader::Reader =
&SubReader::new(self.reader, &format!("branches/{}", id));
Branch::try_from(single_reader)
Branch::try_from(&self.reader.sub(format!("branches/{}", id)))
}
}

View File

@ -2,15 +2,18 @@ use std::{collections::HashSet, path};
use anyhow::Result;
use crate::sessions;
use super::branch::{self, BranchId};
pub struct BranchIterator<'i, R: crate::reader::Reader> {
branch_reader: branch::Reader<'i, R>,
pub struct BranchIterator<'i> {
branch_reader: branch::Reader<'i>,
ids: Vec<BranchId>,
}
impl<'i, R: crate::reader::Reader> BranchIterator<'i, R> {
pub fn new(reader: &'i R) -> Result<Self> {
impl<'i> BranchIterator<'i> {
pub fn new(session_reader: &'i sessions::Reader<'i>) -> Result<Self> {
let reader = session_reader.reader();
let ids_itarator = reader
.list_files(&path::PathBuf::from("branches"))?
.into_iter()
@ -33,13 +36,13 @@ impl<'i, R: crate::reader::Reader> BranchIterator<'i, R> {
.collect();
ids.sort();
Ok(Self {
branch_reader: branch::Reader::new(reader),
branch_reader: branch::Reader::new(session_reader),
ids,
})
}
}
impl<R: crate::reader::Reader> Iterator for BranchIterator<'_, R> {
impl Iterator for BranchIterator<'_> {
type Item = Result<branch::Branch, crate::reader::Error>;
fn next(&mut self) -> Option<Self::Item> {

View File

@ -34,7 +34,7 @@ impl Serialize for Target {
}
// this is a backwards compatibile with the old format
fn read_remote_url<R: crate::reader::Reader>(reader: &R) -> Result<String, crate::reader::Error> {
fn read_remote_url(reader: &crate::reader::Reader) -> Result<String, crate::reader::Error> {
match reader.read(&path::PathBuf::from("remote_url")) {
Ok(url) => Ok(url.try_into()?),
// fallback to the old format
@ -46,8 +46,8 @@ fn read_remote_url<R: crate::reader::Reader>(reader: &R) -> Result<String, crate
}
// returns (remote_name, branch_name)
fn read_remote_name_branch_name<R: crate::reader::Reader>(
reader: &R,
fn read_remote_name_branch_name(
reader: &crate::reader::Reader,
) -> Result<(String, String), crate::reader::Error> {
match reader.read(&path::PathBuf::from("name")) {
Ok(branch) => {
@ -70,7 +70,7 @@ fn read_remote_name_branch_name<R: crate::reader::Reader>(
}
impl Target {
fn try_from<R: crate::reader::Reader>(reader: &R) -> Result<Target, crate::reader::Error> {
fn try_from(reader: &crate::reader::Reader) -> Result<Target, crate::reader::Error> {
let (_, branch_name) = read_remote_name_branch_name(reader).map_err(|e| {
crate::reader::Error::Io(std::io::Error::new(
std::io::ErrorKind::Other,

View File

@ -1,19 +1,18 @@
use std::path;
use crate::{
reader::{self, SubReader},
virtual_branches::BranchId,
};
use crate::{reader, sessions, virtual_branches::BranchId};
use super::Target;
pub struct TargetReader<'r, R: crate::reader::Reader> {
reader: &'r R,
pub struct TargetReader<'r> {
reader: &'r reader::Reader<'r>,
}
impl<'r, R: crate::reader::Reader> TargetReader<'r, R> {
pub fn new(reader: &'r R) -> Self {
Self { reader }
impl<'r> TargetReader<'r> {
pub fn new(reader: &'r sessions::Reader<'r>) -> Self {
Self {
reader: reader.reader(),
}
}
pub fn read_default(&self) -> Result<Target, reader::Error> {
@ -21,7 +20,7 @@ impl<'r, R: crate::reader::Reader> TargetReader<'r, R> {
return Err(reader::Error::NotFound);
}
Target::try_from(&SubReader::new(self.reader, "branches/target"))
Target::try_from(&self.reader.sub("branches/target"))
}
pub fn read(&self, id: &BranchId) -> Result<Target, reader::Error> {
@ -32,10 +31,7 @@ impl<'r, R: crate::reader::Reader> TargetReader<'r, R> {
return self.read_default();
}
Target::try_from(&SubReader::new(
self.reader,
&format!("branches/{}/target", id),
))
Target::try_from(&self.reader.sub(format!("branches/{}/target", id)))
}
}
@ -50,7 +46,6 @@ mod tests {
sessions,
test_utils::{Case, Suite},
virtual_branches::{branch, target::writer::TargetWriter},
writer::Writer,
};
use super::*;

View File

@ -1418,8 +1418,8 @@ pub fn delete_branch(
Ok(())
}
fn set_ownership<R: reader::Reader>(
branch_reader: &R,
fn set_ownership(
session_reader: &sessions::Reader,
branch_writer: &branch::Writer,
target_branch: &mut branch::Branch,
ownership: &branch::Ownership,
@ -1429,7 +1429,7 @@ fn set_ownership<R: reader::Reader>(
return Ok(());
}
let mut virtual_branches = Iterator::new(branch_reader)
let mut virtual_branches = Iterator::new(session_reader)
.context("failed to create branch iterator")?
.collect::<Result<Vec<branch::Branch>, reader::Error>>()
.context("failed to read virtual branches")?

View File

@ -8,8 +8,7 @@ use crate::{
paths::DataDir,
project_repository,
projects::{self, ProjectId},
reader::{self, Reader},
sessions, users,
reader, sessions, users,
};
use super::events;
@ -176,9 +175,7 @@ mod test {
use once_cell::sync::Lazy;
use crate::{
deltas,
reader::Reader,
sessions,
deltas, sessions,
test_utils::{self, Case, Suite},
virtual_branches::{self, branch},
};
@ -940,11 +937,9 @@ mod test {
.git_repository()
.find_commit(flushed_session.hash.unwrap())
.unwrap();
let commit_reader = reader::CommitReader::from_commit(
gb_repository.git_repository(),
&session_commit,
)
.unwrap();
let commit_reader =
reader::Reader::from_commit(gb_repository.git_repository(), &session_commit)
.unwrap();
assert_eq!(
commit_reader.list_files(path::Path::new("wd")).unwrap(),
vec![path::Path::new("test.txt")]
@ -970,11 +965,9 @@ mod test {
.git_repository()
.find_commit(flushed_session.hash.unwrap())
.unwrap();
let commit_reader = reader::CommitReader::from_commit(
gb_repository.git_repository(),
&session_commit,
)
.unwrap();
let commit_reader =
reader::Reader::from_commit(gb_repository.git_repository(), &session_commit)
.unwrap();
assert_eq!(
commit_reader.list_files(path::Path::new("wd")).unwrap(),
vec![
@ -1023,11 +1016,9 @@ mod test {
.git_repository()
.find_commit(flushed_session.hash.unwrap())
.unwrap();
let commit_reader = reader::CommitReader::from_commit(
gb_repository.git_repository(),
&session_commit,
)
.unwrap();
let commit_reader =
reader::Reader::from_commit(gb_repository.git_repository(), &session_commit)
.unwrap();
assert_eq!(
commit_reader.list_files(path::Path::new("wd")).unwrap(),
vec![
@ -1063,11 +1054,9 @@ mod test {
.git_repository()
.find_commit(flushed_session.hash.unwrap())
.unwrap();
let commit_reader = reader::CommitReader::from_commit(
gb_repository.git_repository(),
&session_commit,
)
.unwrap();
let commit_reader =
reader::Reader::from_commit(gb_repository.git_repository(), &session_commit)
.unwrap();
assert!(commit_reader
.list_files(path::Path::new("wd"))
.unwrap()
@ -1103,11 +1092,9 @@ mod test {
.git_repository()
.find_commit(flushed_session.hash.unwrap())
.unwrap();
let commit_reader = reader::CommitReader::from_commit(
gb_repository.git_repository(),
&session_commit,
)
.unwrap();
let commit_reader =
reader::Reader::from_commit(gb_repository.git_repository(), &session_commit)
.unwrap();
assert_eq!(
commit_reader.list_files(path::Path::new("wd")).unwrap(),
vec![
@ -1144,11 +1131,9 @@ mod test {
.git_repository()
.find_commit(flushed_session.hash.unwrap())
.unwrap();
let commit_reader = reader::CommitReader::from_commit(
gb_repository.git_repository(),
&session_commit,
)
.unwrap();
let commit_reader =
reader::Reader::from_commit(gb_repository.git_repository(), &session_commit)
.unwrap();
assert_eq!(
commit_reader.list_files(path::Path::new("wd")).unwrap(),
vec![