|
6 | 6 | // option. This file may not be copied, modified, or distributed
|
7 | 7 | // except according to those terms.
|
8 | 8 |
|
9 |
| -// #![deny(warnings)] |
| 9 | +#![deny(warnings)] |
10 | 10 | extern crate rustc_serialize;
|
11 | 11 | extern crate router;
|
12 | 12 | extern crate iron;
|
@@ -391,57 +391,120 @@ fn main() {
|
391 | 391 | }
|
392 | 392 |
|
393 | 393 |
|
394 |
| -pub fn credentials(_url: &str, |
395 |
| - user_from_url: Option<&str>, |
396 |
| - _cred: git2::CredentialType) |
397 |
| - -> Result<git2::Cred, git2::Error> { |
398 |
| - // TODO: allow more options |
399 |
| - if let Some(user) = user_from_url { |
400 |
| - let r = Cred::ssh_key_from_agent(user); |
401 |
| - return r; |
| 394 | +fn credentials(url: &str, |
| 395 | + user_from_url: Option<&str>, |
| 396 | + cred: git2::CredentialType, |
| 397 | + origin_config: &OriginConfig) |
| 398 | + -> Result<git2::Cred, git2::Error> { |
| 399 | + let mut error = git2::Error::from_str(&format!("Failed to find credentials for {}", url)); |
| 400 | + debug!("credentials"); |
| 401 | + if cred.contains(CredentialType::from(git2::USER_PASS_PLAINTEXT)) { |
| 402 | + match (&origin_config.username, &origin_config.password) { |
| 403 | + (&Some(ref u), &Some(ref p)) => { |
| 404 | + debug!("from username/password"); |
| 405 | + match Cred::userpass_plaintext(&u, &p) { |
| 406 | + Err(e) => { |
| 407 | + debug!("Error: {:?}", e); |
| 408 | + error = e; |
| 409 | + } |
| 410 | + Ok(c) => { |
| 411 | + debug!("Ok!"); |
| 412 | + return Ok(c); |
| 413 | + } |
| 414 | + } |
| 415 | + } |
| 416 | + _ => {} |
| 417 | + } |
| 418 | + } |
| 419 | + if cred.contains(CredentialType::from(git2::DEFAULT)) { |
| 420 | + let config = try!(git2::Config::open_default()); |
| 421 | + match Cred::credential_helper(&config, url, user_from_url) { |
| 422 | + Err(e) => { |
| 423 | + debug!("Error: {:?}", e); |
| 424 | + error = e; |
| 425 | + } |
| 426 | + Ok(c) => { |
| 427 | + debug!("Ok!"); |
| 428 | + return Ok(c); |
| 429 | + } |
| 430 | + } |
402 | 431 | }
|
403 |
| - Err(git2::Error::from_str("no authentication set")) |
| 432 | + if cred.contains(CredentialType::from(git2::SSH_KEY)) { |
| 433 | + if let Some(user) = user_from_url { |
| 434 | + debug!("from ssh agent"); |
| 435 | + match Cred::ssh_key_from_agent(user) { |
| 436 | + Err(e) => { |
| 437 | + debug!("Error: {:?}", e); |
| 438 | + error = e; |
| 439 | + } |
| 440 | + Ok(c) => { |
| 441 | + debug!("Ok"); |
| 442 | + return Ok(c); |
| 443 | + } |
| 444 | + } |
| 445 | + } |
| 446 | + } |
| 447 | + return Err(error); |
404 | 448 | }
|
405 | 449 |
|
406 | 450 | fn poll_index(repo: Repository, config: Config) {
|
407 | 451 |
|
408 | 452 | let mut origin = repo.find_remote("origin").unwrap();
|
409 | 453 | loop {
|
410 | 454 | ::std::thread::sleep(Duration::from_secs(config.poll_intervall.unwrap_or(60) as u64));
|
411 |
| - origin.fetch(&["master"], None, None).unwrap(); |
412 |
| - let head = repo.head().unwrap(); |
413 |
| - |
414 |
| - let parent = repo.find_commit(head.target().unwrap()).unwrap(); |
415 |
| - let remote = repo.find_reference("refs/remotes/origin/master").unwrap(); |
416 |
| - let c = repo.reference_to_annotated_commit(&remote).unwrap(); |
417 |
| - let mut checkout = ::git2::build::CheckoutBuilder::new(); |
418 |
| - let mut merge_option = ::git2::MergeOptions::new(); |
419 |
| - let mut index = repo.index().unwrap(); |
420 |
| - let old_tree = repo.find_tree(index.write_tree().unwrap()).unwrap(); |
421 |
| - repo.merge(&[&c], |
422 |
| - Some(merge_option.file_favor(::git2::FileFavor::Theirs)), |
423 |
| - Some(checkout.force())) |
424 |
| - .unwrap(); |
425 |
| - index.write().unwrap(); |
426 |
| - let tree_id = index.write_tree().unwrap(); |
427 |
| - let tree = repo.find_tree(tree_id).unwrap(); |
428 |
| - let diff = repo.diff_tree_to_tree(Some(&old_tree), Some(&tree), None).unwrap(); |
429 |
| - if diff.stats().unwrap().files_changed() > 0 { |
430 |
| - |
431 |
| - let sig = repo.signature().unwrap(); |
432 |
| - repo.commit(Some("HEAD"), &sig, &sig, "Merge", &tree, &[&parent]) |
433 |
| - .unwrap(); |
434 |
| - |
435 |
| - if let Some(_) = config.registry_config.origin_url.clone() { |
436 |
| - let mut callbacks = git2::RemoteCallbacks::new(); |
437 |
| - callbacks.credentials(credentials); |
438 |
| - let mut remote = repo.find_remote("local").unwrap(); |
439 |
| - let mut opts = git2::PushOptions::new(); |
440 |
| - opts.remote_callbacks(callbacks); |
441 |
| - remote.push(&["refs/heads/master"], Some(&mut opts)).unwrap(); |
| 455 | + 'retry: for i in 0..20 { |
| 456 | + match try_merge(&repo, &config, &mut origin) { |
| 457 | + Ok(()) => break 'retry, |
| 458 | + Err(ref e) if i == 19 => { |
| 459 | + panic!("{:?}", e); |
| 460 | + } |
| 461 | + _ => { |
| 462 | + debug!("Retry {}", i); |
| 463 | + } |
442 | 464 | }
|
443 |
| - info!("updated index"); |
444 | 465 | }
|
445 | 466 | }
|
446 | 467 |
|
447 | 468 | }
|
| 469 | + |
| 470 | +fn try_merge(repo: &Repository, |
| 471 | + config: &Config, |
| 472 | + origin: &mut git2::Remote) |
| 473 | + -> Result<(), git2::Error> { |
| 474 | + try!(origin.fetch(&["master"], None, None)); |
| 475 | + let head = try!(repo.head()); |
| 476 | + |
| 477 | + let parent = try!(repo.find_commit(head.target().unwrap())); |
| 478 | + let remote = try!(repo.find_reference("refs/remotes/origin/master")); |
| 479 | + let c = try!(repo.reference_to_annotated_commit(&remote)); |
| 480 | + let mut checkout = ::git2::build::CheckoutBuilder::new(); |
| 481 | + let mut merge_option = ::git2::MergeOptions::new(); |
| 482 | + let mut index = try!(repo.index()); |
| 483 | + let old_tree = try!(repo.find_tree(try!(index.write_tree()))); |
| 484 | + try!(repo.merge(&[&c], |
| 485 | + Some(merge_option.file_favor(::git2::FileFavor::Theirs)), |
| 486 | + Some(checkout.force()))); |
| 487 | + try!(index.write()); |
| 488 | + let tree_id = try!(index.write_tree()); |
| 489 | + let tree = try!(repo.find_tree(tree_id)); |
| 490 | + let diff = try!(repo.diff_tree_to_tree(Some(&old_tree), Some(&tree), None)); |
| 491 | + if try!(diff.stats()).files_changed() > 0 { |
| 492 | + |
| 493 | + let sig = try!(repo.signature()); |
| 494 | + try!(repo.commit(Some("HEAD"), &sig, &sig, "Merge", &tree, &[&parent])); |
| 495 | + |
| 496 | + if let Some(_) = config.registry_config.origin_url { |
| 497 | + let mut callbacks = git2::RemoteCallbacks::new(); |
| 498 | + callbacks.credentials(credentials); |
| 499 | + let mut remote = try!(repo.find_remote("local")); |
| 500 | + let mut opts = git2::PushOptions::new(); |
| 501 | + opts.remote_callbacks(callbacks); |
| 502 | + try!(remote.push(&["refs/heads/master"], Some(&mut opts))); |
| 503 | + } |
| 504 | + debug!("updated index"); |
| 505 | + } else { |
| 506 | + debug!("Nothing to update"); |
| 507 | + try!(repo.cleanup_state()); |
| 508 | + } |
| 509 | + Ok(()) |
| 510 | +} |
0 commit comments