Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make sure all cache access is encapsulated in the ProtofetchGitCache #113

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/api/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use std::{env, error::Error, path::PathBuf};

use home::home_dir;

use crate::{cache::ProtofetchGitCache, Protofetch};
use crate::{git::cache::ProtofetchGitCache, Protofetch};

#[derive(Default)]
pub struct ProtofetchBuilder {
Expand Down
7 changes: 4 additions & 3 deletions src/api/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ use std::{
};

use crate::{
cache::ProtofetchGitCache,
cli::command_handlers::{do_clean, do_clear_cache, do_fetch, do_init, do_lock, do_migrate},
cli::command_handlers::{do_clean, do_fetch, do_init, do_lock, do_migrate},
git::cache::ProtofetchGitCache,
};

mod builder;
Expand Down Expand Up @@ -89,6 +89,7 @@ impl Protofetch {
}

pub fn clear_cache(&self) -> Result<(), Box<dyn Error>> {
do_clear_cache(&self.cache)
self.cache.clear()?;
Ok(())
}
}
33 changes: 33 additions & 0 deletions src/cache/git.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
use std::path::PathBuf;

use crate::{
git::cache::ProtofetchGitCache,
model::protofetch::{Coordinate, DependencyName, RevisionSpecification},
};

use super::RepositoryCache;

impl RepositoryCache for ProtofetchGitCache {
fn fetch(
&self,
coordinate: &Coordinate,
specification: &RevisionSpecification,
_commit_hash: &str,
) -> anyhow::Result<()> {
self.clone_or_update(coordinate)?
.resolve_commit_hash(specification)?;
Ok(())
}

fn create_worktree(
&self,
coordinate: &Coordinate,
commit_hash: &str,
name: &DependencyName,
) -> anyhow::Result<PathBuf> {
let path = self
.clone_or_update(coordinate)?
.create_worktree(name, commit_hash)?;
Ok(path)
}
}
21 changes: 21 additions & 0 deletions src/cache/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
mod git;

use std::path::PathBuf;

use crate::model::protofetch::{Coordinate, DependencyName, RevisionSpecification};

pub trait RepositoryCache {
fn fetch(
&self,
coordinate: &Coordinate,
specification: &RevisionSpecification,
commit_hash: &str,
) -> anyhow::Result<()>;

fn create_worktree(
&self,
coordinate: &Coordinate,
commit_hash: &str,
name: &DependencyName,
) -> anyhow::Result<PathBuf>;
}
25 changes: 3 additions & 22 deletions src/cli/command_handlers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ use log::{debug, info};

use crate::{
api::LockMode,
cache::ProtofetchGitCache,
fetch,
git::cache::ProtofetchGitCache,
model::{
protodep::ProtodepDescriptor,
protofetch::{lock::LockFile, Descriptor},
Expand All @@ -17,7 +17,6 @@ use std::{
};

const DEFAULT_OUTPUT_DIRECTORY_NAME: &str = "proto_src";
const CACHE_WORKSPACES_DIRECTORY_NAME: &str = "dependencies";

/// Handler to fetch command
pub fn do_fetch(
Expand All @@ -32,18 +31,13 @@ pub fn do_fetch(

let lockfile = do_lock(lock_mode, cache, root, module_file_name, lock_file_name)?;

let cache_dependencies_directory_path = cache.location.join(CACHE_WORKSPACES_DIRECTORY_NAME);
let output_directory_name = output_directory_name
.or_else(|| module_descriptor.proto_out_dir.as_ref().map(Path::new))
.unwrap_or(Path::new(DEFAULT_OUTPUT_DIRECTORY_NAME));
fetch::fetch_sources(cache, &lockfile, &cache_dependencies_directory_path)?;
fetch::fetch_sources(cache, &lockfile)?;

//Copy proto_out files to actual target
proto::copy_proto_files(
&root.join(output_directory_name),
&cache_dependencies_directory_path,
&lockfile,
)?;
proto::copy_proto_files(cache, &lockfile, &root.join(output_directory_name))?;

Ok(())
}
Expand Down Expand Up @@ -177,19 +171,6 @@ pub fn do_clean(
Ok(())
}

pub fn do_clear_cache(cache: &ProtofetchGitCache) -> Result<(), Box<dyn Error>> {
if cache.location.exists() {
info!(
"Clearing protofetch repository cache {}.",
&cache.location.display()
);
std::fs::remove_dir_all(&cache.location)?;
Ok(())
} else {
Ok(())
}
}

fn load_module_descriptor(
root: &Path,
module_file_name: &Path,
Expand Down
61 changes: 11 additions & 50 deletions src/fetch.rs
Original file line number Diff line number Diff line change
@@ -1,35 +1,28 @@
use std::{
collections::BTreeMap,
path::{Path, PathBuf},
str::Utf8Error,
};
use std::{collections::BTreeMap, str::Utf8Error};

use crate::{
cache::{CacheError, RepositoryCache},
cache::RepositoryCache,
model::protofetch::{
lock::{LockFile, LockedDependency},
Dependency, DependencyName, Descriptor,
},
proto_repository::ProtoRepository,
resolver::ModuleResolver,
};
use log::{debug, error, info};
use log::{error, info};
use thiserror::Error;

#[derive(Error, Debug)]
pub enum FetchError {
#[error("Error while fetching repo from cache: {0}")]
Cache(#[from] CacheError),
Cache(anyhow::Error),
#[error("Git error: {0}")]
GitError(#[from] git2::Error),
#[error("Error while decoding utf8 bytes from blob: {0}")]
BlobRead(#[from] Utf8Error),
#[error("Error while parsing descriptor")]
Parsing(#[from] crate::model::ParseError),
#[error("Bad output dir {0}")]
BadOutputDir(String),
#[error("Error while processing protobuf repository: {0}")]
ProtoRepoError(#[from] crate::proto_repository::ProtoRepoError),
ProtoRepoError(#[from] crate::git::repository::ProtoRepoError),
#[error("IO error: {0}")]
IO(#[from] std::io::Error),
#[error(transparent)]
Expand Down Expand Up @@ -114,47 +107,15 @@ pub fn lock(
})
}

pub fn fetch_sources<Cache: RepositoryCache>(
cache: &Cache,
lockfile: &LockFile,
cache_src_dir: &Path,
) -> Result<(), FetchError> {
pub fn fetch_sources(cache: &impl RepositoryCache, lockfile: &LockFile) -> Result<(), FetchError> {
info!("Fetching dependencies source files...");

if !cache_src_dir.exists() {
std::fs::create_dir_all(cache_src_dir)?;
for dep in &lockfile.dependencies {
cache
.fetch(&dep.coordinate, &dep.specification, &dep.commit_hash)
.map_err(FetchError::Cache)?;
}

if cache_src_dir.is_dir() {
for dep in &lockfile.dependencies {
//If the dependency is already in the cache, we don't need to fetch it again
if cache_src_dir
.join(&dep.name.value)
.join(PathBuf::from(&dep.commit_hash))
.exists()
{
debug!("Skipping fetching {:?}. Already in cache", dep.name);
continue;
}
let repo = cache.clone_or_update(&dep.coordinate)?;
let work_tree_res = repo.create_worktrees(
&lockfile.module_name,
&dep.name,
&dep.commit_hash,
cache_src_dir,
);
if let Err(err) = work_tree_res {
error!("Error while trying to create worktrees {err}. \
Most likely the worktree sources have been deleted but the worktree metadata has not. \
Please delete the cache and run protofetch fetch again.")
}
}
Ok(())
} else {
Err(FetchError::BadOutputDir(
cache_src_dir.to_str().unwrap_or("").to_string(),
))
}
Ok(())
}

#[cfg(test)]
Expand Down
67 changes: 36 additions & 31 deletions src/cache.rs → src/git/cache.rs
Original file line number Diff line number Diff line change
@@ -1,22 +1,17 @@
use std::path::{Path, PathBuf};

use git2::Config;
use git2::{build::RepoBuilder, Cred, CredentialType, FetchOptions, RemoteCallbacks, Repository};
use log::trace;
use git2::{
build::RepoBuilder, Config, Cred, CredentialType, FetchOptions, RemoteCallbacks, Repository,
};
use log::{info, trace};
use thiserror::Error;

use crate::{model::protofetch::Coordinate, proto_repository::ProtoGitRepository};
use crate::{git::repository::ProtoGitRepository, model::protofetch::Coordinate};

use crate::proto_repository::ProtoRepository;

pub trait RepositoryCache {
type Repository: ProtoRepository;

fn clone_or_update(&self, entry: &Coordinate) -> Result<Self::Repository, CacheError>;
}
const WORKTREES_DIR: &str = "dependencies";

pub struct ProtofetchGitCache {
pub location: PathBuf,
location: PathBuf,
git_config: Config,
}

Expand All @@ -30,25 +25,6 @@ pub enum CacheError {
IO(#[from] std::io::Error),
}

impl RepositoryCache for ProtofetchGitCache {
type Repository = ProtoGitRepository;

fn clone_or_update(&self, entry: &Coordinate) -> Result<Self::Repository, CacheError> {
let repo = match self.get_entry(entry) {
None => self.clone_repo(entry)?,
Some(path) => {
let mut repo = self.open_entry(&path)?;

self.fetch(&mut repo)?;

repo
}
};

Ok(ProtoGitRepository::new(repo))
}
}

impl ProtofetchGitCache {
pub fn new(location: PathBuf, git_config: Config) -> Result<ProtofetchGitCache, CacheError> {
if location.exists() && location.is_dir() {
Expand All @@ -69,6 +45,35 @@ impl ProtofetchGitCache {
}
}

pub fn clear(&self) -> anyhow::Result<()> {
if self.location.exists() {
info!(
"Clearing protofetch repository cache {}.",
&self.location.display()
);
std::fs::remove_dir_all(&self.location)?;
}
Ok(())
}

pub fn clone_or_update(&self, entry: &Coordinate) -> Result<ProtoGitRepository, CacheError> {
let repo = match self.get_entry(entry) {
None => self.clone_repo(entry)?,
Some(path) => {
let mut repo = self.open_entry(&path)?;

self.fetch(&mut repo)?;

repo
}
};

Ok(ProtoGitRepository::new(
repo,
self.location.join(WORKTREES_DIR),
))
}

fn get_entry(&self, entry: &Coordinate) -> Option<PathBuf> {
let mut full_path = self.location.clone();
full_path.push(entry.as_path());
Expand Down
2 changes: 2 additions & 0 deletions src/git/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
pub mod cache;
pub mod repository;
Loading