step fifty nine: download missing objects pointed by remote refs

This commit is contained in:
Gonçalo Valério 2020-12-06 17:52:03 +00:00
parent 70a660e2f5
commit 416061a632
3 changed files with 75 additions and 2 deletions

View File

@ -159,6 +159,53 @@ pub fn iter_commits_and_parents(mut oids: VecDeque<String>) -> Vec<String> {
return oid_sequence;
}
pub fn copy_objects_in_commits_and_parents(mut oids: Vec<&String>, remote_path: String) {
// This one is a little be different than the functions in the tutorial
// But the end result is the same, copy all missing objects from the remote
// repository
let mut visited: HashSet<String> = HashSet::new();
let mut commits = oids
.into_iter()
.map(|oid| oid.clone())
.rev()
.collect::<VecDeque<String>>();
while !commits.is_empty() {
let oid = commits.pop_front().unwrap();
if oid == "" || visited.contains(&oid) {
continue;
}
data::fetch_object_if_missing(oid.clone(), remote_path.clone());
visited.insert(oid.clone());
let commit = get_commit(oid.clone());
copy_tree_objects(commit.tree, &mut visited, remote_path.clone());
let parent1 = commit.parents[0].clone();
// Deal with parent next
commits.push_front(parent1);
// Deal with other parents later
if commit.parents.len() > 1 {
let parent2 = commit.parents[1].clone();
commits.push_back(parent2);
}
}
}
fn copy_tree_objects(oid: String, visited: &mut HashSet<String>, remote_path: String) {
// get_tree already walks recursively the provided tree. Lets use that instead.
visited.insert(oid.clone());
data::fetch_object_if_missing(oid.clone(), remote_path.clone());
for (path, object_id) in get_tree(oid, "./".to_owned()).iter() {
if visited.contains(object_id) {
continue;
}
data::fetch_object_if_missing(object_id.clone(), remote_path.clone());
}
}
pub fn checkout(name: String) {
let oid = get_oid(name.clone());
let commit = get_commit(oid.clone());
@ -206,7 +253,7 @@ pub fn get_oid(mut name: String) -> String {
for reference in refs_to_try.iter() {
let found = data::get_ref(reference.clone(), false);
if found.value != "" {
return found.value;
return data::get_ref(reference.clone(), true).value;
} else {
continue;
}

View File

@ -159,3 +159,23 @@ pub fn get_ref_internal(reference: String, deref: bool) -> (String, RefValue) {
return (reference, RefValue { value, symbolic });
}
pub fn fetch_object_if_missing(oid: String, remote_git_dir: String) {
if object_exists(oid.clone()) {
return;
}
let dir = RGIT_DIR.lock().unwrap().to_owned();
let rgit_remote = remote_git_dir + "/.rgit";
fs::copy(
format!("{}/objects/{}", rgit_remote, oid.clone()),
format!("{}/objects/{}", dir, oid),
)
.expect(format!("Failed to fetch {}", oid).as_str());
}
fn object_exists(oid: String) -> bool {
let dir = RGIT_DIR.lock().unwrap().to_owned();
let path = format!("{}/objects/{}", dir.clone(), oid.clone());
return Path::new(path.as_str()).exists();
}

View File

@ -3,12 +3,18 @@ use std::collections::HashMap;
#[path = "data.rs"]
mod data;
#[path = "base.rs"]
mod base;
static REMOTE_REFS_BASE: &'static str = "refs/heads/";
static LOCAL_REFS_BASE: &'static str = "refs/remote/";
pub fn fetch(path: String) {
// Get refs from server
let refs = get_remote_refs(path, REMOTE_REFS_BASE);
let refs = get_remote_refs(path.clone(), REMOTE_REFS_BASE);
let commit_oids: Vec<&String> = refs.values().collect();
base::copy_objects_in_commits_and_parents(commit_oids, path.clone());
// Update local refs to match server
for (remote_name, value) in refs.iter() {