From 416061a632ce08d1bcd25e145be626d2aa62ecea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Val=C3=A9rio?= Date: Sun, 6 Dec 2020 17:52:03 +0000 Subject: [PATCH] step fifty nine: download missing objects pointed by remote refs --- src/base.rs | 49 ++++++++++++++++++++++++++++++++++++++++++++++++- src/data.rs | 20 ++++++++++++++++++++ src/remote.rs | 8 +++++++- 3 files changed, 75 insertions(+), 2 deletions(-) diff --git a/src/base.rs b/src/base.rs index 68cb406..de6c59e 100644 --- a/src/base.rs +++ b/src/base.rs @@ -159,6 +159,53 @@ pub fn iter_commits_and_parents(mut oids: VecDeque) -> Vec { 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 = HashSet::new(); + let mut commits = oids + .into_iter() + .map(|oid| oid.clone()) + .rev() + .collect::>(); + + 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, 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; } diff --git a/src/data.rs b/src/data.rs index dd28775..57b92c8 100644 --- a/src/data.rs +++ b/src/data.rs @@ -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(); +} diff --git a/src/remote.rs b/src/remote.rs index 0ace815..2724c3a 100644 --- a/src/remote.rs +++ b/src/remote.rs @@ -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() {