Skip to content

Commit f13c47f

Browse files
committedAug 29, 2017
Version 0.3, ✨ now mirrors properly✨
1 parent 293a04e commit f13c47f

File tree

3 files changed

+86
-55
lines changed

3 files changed

+86
-55
lines changed
 

‎Cargo.lock

+7-7
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎Cargo.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "grapple"
3-
version = "0.2.0"
3+
version = "0.3.0"
44
authors = ["Aaron Friel <mayreply@aaronfriel.com>"]
55
license = "BSD"
66

‎src/git_repository.rs

+78-47
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,23 @@
11
use errors::*;
22

3-
use git2::{Repository, RepositoryInitOptions, Remote, PushOptions, RemoteCallbacks, Cred};
4-
use std::path::{Path};
53
use std::fs::{self};
4+
use std::path::{Path};
5+
6+
use std::collections::HashMap;
7+
8+
use git2::{Repository, RepositoryInitOptions, Remote, FetchOptions, Direction, FetchPrune, PushOptions, RemoteCallbacks, Cred};
69

710
use config::RepositoryMapping;
811

912
const ATTEMPTS: u8 = 3;
1013

14+
#[derive(Debug)]
15+
enum RefAction {
16+
Update,
17+
Create,
18+
Delete,
19+
}
20+
1121
pub trait GitRepository {
1222
fn repository_name(&self) -> &str;
1323

@@ -49,24 +59,12 @@ fn attempt_open<T: GitRepository>(repo: &T, attempts: u8) -> Result<Repository>
4959
.mkdir(true)
5060
.mkpath(true);
5161

52-
// let repo = init_bare(repo.repository_name())
53-
5462
Ok(Repository::init_opts(repo.repository_name(), &repo_opts)?)
5563
}
5664

5765
const ALL_HEADS: &'static str = "+refs/heads/*:refs/heads/*";
5866
const ALL_TAGS: &'static str = "+refs/tags/*:refs/tags/*";
5967

60-
fn disconnect_head(repo: &Repository) -> Result<()> {
61-
let head = repo.head()?;
62-
63-
let oid = head.target().ok_or(Error::from_kind(ErrorKind::RepositoryOpenError))?;
64-
65-
repo.set_head_detached(oid)?;
66-
67-
Ok(())
68-
}
69-
7068
const REMOTE_FETCH: &'static str = "fetch";
7169

7270
fn open_remote_fetch<'a>(repo: &'a Repository, uri: &str) -> Result<Remote<'a>> {
@@ -82,45 +80,19 @@ fn open_remote_fetch<'a>(repo: &'a Repository, uri: &str) -> Result<Remote<'a>>
8280
}
8381
}
8482

85-
const REMOTE_PUSH: &'static str = "push";
86-
8783
fn open_remote_push<'a>(repo: &'a Repository, uri: &str) -> Result<Remote<'a>> {
88-
if let Ok(remote) = repo.find_remote(REMOTE_PUSH) {
89-
Ok(remote)
90-
} else {
91-
repo.remote(REMOTE_PUSH, uri)?;
92-
93-
// repo.remote_add_push(REMOTE_PUSH, ALL_HEADS)?;
94-
// repo.remote_add_push(REMOTE_PUSH, ALL_TAGS)?;
95-
96-
open_remote_push(repo, uri)
97-
}
98-
}
99-
100-
fn push_glob(repository: &Repository, remote: &mut Remote, glob: &str, push_options: Option<&mut PushOptions>) -> Result<()> {
101-
let mut refs = repository.references_glob(glob)?;
102-
103-
let mut push_refs : Vec<&str> = Vec::new();
104-
105-
for reference in refs.names() {
106-
if let Ok(name) = reference {
107-
push_refs.push(name);
108-
}
109-
}
110-
111-
for name in &push_refs {
112-
println!("{:?}", name);
113-
}
114-
115-
Ok(())
84+
Ok(repo.remote_anonymous(uri)?)
11685
}
11786

11887
pub fn grapple<T: GitRepository>(payload: &T, mapping: &RepositoryMapping) -> Result<()> {
11988
let repo = open(payload)?;
12089

12190
let mut fetch = open_remote_fetch(&repo, payload.clone_uri())?;
12291

123-
fetch.fetch(&[], None, None)?;
92+
let mut fetch_options = FetchOptions::new();
93+
fetch_options.prune(FetchPrune::On);
94+
95+
fetch.fetch(&[], Some(&mut fetch_options), None)?;
12496

12597
let mut push = open_remote_push(&repo, &mapping.push_uri)?;
12698

@@ -135,8 +107,67 @@ pub fn grapple<T: GitRepository>(payload: &T, mapping: &RepositoryMapping) -> Re
135107
let mut push_options = PushOptions::new();
136108
push_options.remote_callbacks(callbacks);
137109

138-
push_glob(&repo, &mut push, "refs/heads/*", Some(&mut push_options))?;
139-
push_glob(&repo, &mut push, "refs/tags/*", Some(&mut push_options))?;
110+
fetch.connect(Direction::Fetch)?;
111+
112+
let fetch_list = fetch.list()?;
113+
114+
let mut ref_map = HashMap::new();
115+
116+
println!("Fetch refs:");
117+
for reference in fetch_list.iter().filter(|r| r.name().starts_with("refs/")) {
118+
ref_map.insert(reference.name(), reference.oid());
119+
}
120+
121+
122+
let mut callbacks = RemoteCallbacks::new();
123+
callbacks.credentials(
124+
|_, username, _| Cred::ssh_key(
125+
username.unwrap_or("grapple"),
126+
Some(Path::new(&mapping.deploy_public_key)),
127+
Path::new(&mapping.deploy_private_key),
128+
None));
129+
130+
push.connect_auth(Direction::Push, Some(callbacks), None)?;
131+
132+
let push_list = push.list()?;
133+
134+
let mut action_list = Vec::new();
135+
136+
println!("Push refs:");
137+
for reference in push_list.iter().filter(|r| r.name().starts_with("refs/")) {
138+
let ref_name = reference.name();
139+
let push_oid = reference.oid();
140+
match ref_map.remove(ref_name) {
141+
Some(fetch_oid) if fetch_oid != push_oid => action_list.push((ref_name, RefAction::Update)),
142+
Some(_) => (),
143+
None => action_list.push((ref_name, RefAction::Delete)),
144+
}
145+
}
146+
147+
for (ref_name, _) in ref_map.iter() {
148+
action_list.push((ref_name, RefAction::Create));
149+
}
150+
151+
152+
let mut fetch = open_remote_fetch(&repo, payload.clone_uri())?;
153+
154+
let mut push = open_remote_push(&repo, &mapping.push_uri)?;
155+
156+
for (ref_name, action) in action_list {
157+
match action {
158+
RefAction::Create | RefAction::Update => {
159+
// TODO: collect errors
160+
let refspec = format!("+{}:{}", ref_name, ref_name);
161+
fetch.fetch(&[&refspec], Some(&mut fetch_options), None)?;
162+
push.push(&[&refspec], Some(&mut push_options))?;
163+
},
164+
RefAction::Delete => {
165+
let refspec = format!(":{}", ref_name);
166+
println!("Delete: {}", ref_name);
167+
push.push(&[&refspec], Some(&mut push_options))?;
168+
},
169+
}
170+
}
140171

141172
Ok(())
142173
}

0 commit comments

Comments
 (0)