A library for writing host-specific, single-binary configuration management and deployment tools
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

88 lines
2.8 KiB

8 years ago
7 years ago
8 years ago
7 years ago
7 years ago
8 years ago
6 years ago
8 years ago
8 years ago
6 years ago
8 years ago
6 years ago
8 years ago
6 years ago
8 years ago
6 years ago
7 years ago
6 years ago
8 years ago
7 years ago
8 years ago
6 years ago
6 years ago
8 years ago
8 years ago
6 years ago
8 years ago
6 years ago
8 years ago
7 years ago
6 years ago
7 years ago
6 years ago
7 years ago
7 years ago
8 years ago
  1. use std::error::Error;
  2. use std::fmt;
  3. use std::io;
  4. use std::path::Path;
  5. use command_runner::CommandRunner;
  6. use resources::Resource;
  7. use symbols::{Action, OwnedSymbolAction, Symbol, SymbolAction, SymbolRunner};
  8. pub struct GitCheckout<'a, C: 'a + CommandRunner, T: AsRef<str>> {
  9. target: T,
  10. source: &'a str,
  11. branch: &'a str,
  12. command_runner: &'a C
  13. }
  14. impl<'a, C: CommandRunner, T: AsRef<str>> GitCheckout<'a, C, T> {
  15. pub fn new(target: T, source: &'a str, branch: &'a str, command_runner: &'a C) -> Self {
  16. GitCheckout {
  17. target: target,
  18. source: source,
  19. branch: branch,
  20. command_runner: command_runner
  21. }
  22. }
  23. }
  24. impl<'a, C: CommandRunner, T: AsRef<str>> fmt::Display for GitCheckout<'a, C, T> {
  25. fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
  26. write!(f, "Checkout {} (branch {}) into {}", self.source, self.branch, self.target.as_ref())
  27. }
  28. }
  29. use std::fs::metadata;
  30. impl<'a, C: CommandRunner, T: AsRef<str>> GitCheckout<'a, C, T> {
  31. fn _run_in_target_repo(&self, args: &[&str]) -> Result<Vec<u8>, Box<Error>> {
  32. let mut new_args = vec!["-C", self.target.as_ref()];
  33. new_args.extend_from_slice(args);
  34. self.command_runner.get_output("git", &new_args)
  35. }
  36. }
  37. impl<'a, C: CommandRunner, T: AsRef<str>> Symbol for GitCheckout<'a, C, T> {
  38. fn target_reached(&self) -> Result<bool, Box<Error>> {
  39. if let Err(e) = metadata(self.target.as_ref()) {
  40. return if e.kind() == io::ErrorKind::NotFound {
  41. Ok(false)
  42. } else {
  43. Err(Box::new(e))
  44. };
  45. }
  46. try!(self._run_in_target_repo(&["fetch", self.source, self.branch]));
  47. // git rev-list resolves tag objects
  48. let fetch_head = try!(self._run_in_target_repo(&["rev-list", "-1", "FETCH_HEAD"]));
  49. let head = try!(self._run_in_target_repo(&["rev-list", "-1", "HEAD"]));
  50. Ok(fetch_head == head)
  51. }
  52. fn execute(&self) -> Result<(), Box<Error>> {
  53. if !Path::new(self.target.as_ref()).exists() {
  54. return self.command_runner.run_successfully("git", &["clone", "--depth", "1", "-b", self.branch, self.source, self.target.as_ref()]);
  55. }
  56. try!(self._run_in_target_repo(&["fetch", self.source, self.branch]));
  57. try!(self._run_in_target_repo(&["merge", "FETCH_HEAD"]));
  58. Ok(())
  59. }
  60. fn get_prerequisites(&self) -> Vec<Resource> {
  61. vec![ Resource::new("dir", Path::new(self.target.as_ref()).parent().unwrap().to_string_lossy()) ]
  62. }
  63. fn provides(&self) -> Option<Vec<Resource>> {
  64. Some(vec![ Resource::new("dir", self.target.as_ref().to_string()) ])
  65. }
  66. fn as_action<'b>(&'b self, runner: &'b SymbolRunner) -> Box<Action + 'b> {
  67. Box::new(SymbolAction::new(runner, self))
  68. }
  69. fn into_action<'b>(self: Box<Self>, runner: &'b SymbolRunner) -> Box<Action + 'b> where Self: 'b {
  70. Box::new(OwnedSymbolAction::new(runner, *self))
  71. }
  72. }
  73. #[cfg(test)]
  74. mod test {
  75. }