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.

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