From 8144a96321fc2c566d1227424aab8b7d9891273d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Val=C3=A9rio?= Date: Sun, 6 Dec 2020 18:25:41 +0000 Subject: [PATCH] step sixty: push, naive implementation --- src/base.rs | 27 +++++++++++++++++++-------- src/data.rs | 10 ++++++++++ src/main.rs | 15 +++++++++++++++ src/remote.rs | 21 ++++++++++++++++++++- 4 files changed, 64 insertions(+), 9 deletions(-) diff --git a/src/base.rs b/src/base.rs index de6c59e..68438c1 100644 --- a/src/base.rs +++ b/src/base.rs @@ -159,10 +159,14 @@ 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) { +pub fn copy_objects_in_commits_and_parents( + mut oids: Vec<&String>, + remote_path: String, + push: bool, +) { // 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 + // But the end result is the same, copy all missing objects from one repo + // to another let mut visited: HashSet = HashSet::new(); let mut commits = oids .into_iter() @@ -175,12 +179,15 @@ pub fn copy_objects_in_commits_and_parents(mut oids: Vec<&String>, remote_path: if oid == "" || visited.contains(&oid) { continue; } - - data::fetch_object_if_missing(oid.clone(), remote_path.clone()); + if push { + data::push_object(oid.clone(), remote_path.clone()); + } else { + 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()); + copy_tree_objects(commit.tree, &mut visited, remote_path.clone(), push); let parent1 = commit.parents[0].clone(); // Deal with parent next @@ -193,7 +200,7 @@ pub fn copy_objects_in_commits_and_parents(mut oids: Vec<&String>, remote_path: } } -fn copy_tree_objects(oid: String, visited: &mut HashSet, remote_path: String) { +fn copy_tree_objects(oid: String, visited: &mut HashSet, remote_path: String, push: bool) { // 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()); @@ -202,7 +209,11 @@ fn copy_tree_objects(oid: String, visited: &mut HashSet, remote_path: St if visited.contains(object_id) { continue; } - data::fetch_object_if_missing(object_id.clone(), remote_path.clone()); + if push { + data::push_object(object_id.clone(), remote_path.clone()); + } else { + data::fetch_object_if_missing(object_id.clone(), remote_path.clone()); + } } } diff --git a/src/data.rs b/src/data.rs index 57b92c8..7c9a7ca 100644 --- a/src/data.rs +++ b/src/data.rs @@ -174,6 +174,16 @@ pub fn fetch_object_if_missing(oid: String, remote_git_dir: String) { .expect(format!("Failed to fetch {}", oid).as_str()); } +pub fn push_object(oid: String, remote_git_dir: String) { + let rgit_remote = remote_git_dir + "/.rgit"; + let dir = RGIT_DIR.lock().unwrap().to_owned(); + fs::copy( + format!("{}/objects/{}", dir, oid), + format!("{}/objects/{}", rgit_remote, oid.clone()), + ) + .expect(format!("Failed to push {}", 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()); diff --git a/src/main.rs b/src/main.rs index d5f89e3..34c4c10 100644 --- a/src/main.rs +++ b/src/main.rs @@ -98,6 +98,12 @@ fn main() { .about("Fetch refs and objects from another repository") .arg(Arg::with_name("remote").index(1).required(true)), ) + .subcommand( + SubCommand::with_name("push") + .about("Push refs and objects to another repository") + .arg(Arg::with_name("remote").index(1).required(true)) + .arg(Arg::with_name("branch").index(2).required(true)), + ) .get_matches(); data::set_rgit_dir("."); @@ -120,6 +126,7 @@ fn main() { Some("merge") => merge(matches), Some("merge-base") => merge_base(matches), Some("fetch") => fetch(matches), + Some("push") => push(matches), _ => println!("unknown sub command"), } data::reset_rgit_dir(); @@ -357,6 +364,14 @@ fn fetch(matches: ArgMatches) { } } +fn push(matches: ArgMatches) { + if let Some(cmd_matches) = matches.subcommand_matches("push") { + let remote_path = cmd_matches.value_of("remote").unwrap().to_owned(); + let branch_name = cmd_matches.value_of("branch").unwrap().to_owned(); + remote::push(remote_path, format!("refs/heads/{}", branch_name)); + } +} + fn print_commit(oid: String, commit: &base::Commit, mut refs: HashMap>) { let ref_str = if refs.contains_key(&oid) { refs.get_mut(&oid).unwrap().join(", ") diff --git a/src/remote.rs b/src/remote.rs index 2724c3a..0ba41c4 100644 --- a/src/remote.rs +++ b/src/remote.rs @@ -14,7 +14,7 @@ pub fn fetch(path: String) { 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()); + base::copy_objects_in_commits_and_parents(commit_oids, path.clone(), false); // Update local refs to match server for (remote_name, value) in refs.iter() { @@ -30,6 +30,25 @@ pub fn fetch(path: String) { } } +pub fn push(remote_path: String, reference: String) { + let local_ref = data::get_ref(reference.clone(), true).value; + assert!(local_ref != "".to_string()); + + let commit_oids = vec![&local_ref]; + base::copy_objects_in_commits_and_parents(commit_oids, remote_path.clone(), true); + + data::set_rgit_dir(remote_path.as_str()); + data::update_ref( + reference, + data::RefValue { + symbolic: false, + value: local_ref, + }, + true, + ); + data::reset_rgit_dir(); +} + fn get_remote_refs(path: String, prefix: &str) -> HashMap { let mut refs = HashMap::new(); data::set_rgit_dir(path.as_str());