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.

113 lines
2.9 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
5 years ago
8 years ago
6 years ago
5 years ago
8 years ago
6 years ago
8 years ago
5 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
5 years ago
6 years ago
5 years ago
8 years ago
5 years ago
6 years ago
5 years ago
8 years ago
5 years ago
8 years ago
7 years ago
5 years ago
7 years ago
5 years ago
7 years ago
7 years ago
5 years ago
7 years ago
5 years ago
7 years ago
8 years ago
5 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,
  18. source,
  19. branch,
  20. 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!(
  27. f,
  28. "Checkout {} (branch {}) into {}",
  29. self.source,
  30. self.branch,
  31. self.target.as_ref()
  32. )
  33. }
  34. }
  35. use std::fs::metadata;
  36. impl<'a, C: CommandRunner, T: AsRef<str>> GitCheckout<'a, C, T> {
  37. fn _run_in_target_repo(&self, args: &[&str]) -> Result<Vec<u8>, Box<dyn Error>> {
  38. let mut new_args = vec!["-C", self.target.as_ref()];
  39. new_args.extend_from_slice(args);
  40. self.command_runner.get_output("git", &new_args)
  41. }
  42. }
  43. impl<'a, C: CommandRunner, T: AsRef<str>> Symbol for GitCheckout<'a, C, T> {
  44. fn target_reached(&self) -> Result<bool, Box<dyn Error>> {
  45. if let Err(e) = metadata(self.target.as_ref()) {
  46. return if e.kind() == io::ErrorKind::NotFound {
  47. Ok(false)
  48. } else {
  49. Err(Box::new(e))
  50. };
  51. }
  52. self._run_in_target_repo(&["fetch", self.source, self.branch])?;
  53. // git rev-list resolves tag objects
  54. let fetch_head = self._run_in_target_repo(&["rev-list", "-1", "FETCH_HEAD"])?;
  55. let head = self._run_in_target_repo(&["rev-list", "-1", "HEAD"])?;
  56. Ok(fetch_head == head)
  57. }
  58. fn execute(&self) -> Result<(), Box<dyn Error>> {
  59. if !Path::new(self.target.as_ref()).exists() {
  60. return self.command_runner.run_successfully(
  61. "git",
  62. &[
  63. "clone",
  64. "--depth",
  65. "1",
  66. "-b",
  67. self.branch,
  68. self.source,
  69. self.target.as_ref(),
  70. ],
  71. );
  72. }
  73. self._run_in_target_repo(&["fetch", self.source, self.branch])?;
  74. self._run_in_target_repo(&["merge", "FETCH_HEAD"])?;
  75. Ok(())
  76. }
  77. fn get_prerequisites(&self) -> Vec<Resource> {
  78. vec![Resource::new(
  79. "dir",
  80. Path::new(self.target.as_ref())
  81. .parent()
  82. .unwrap()
  83. .to_string_lossy(),
  84. )]
  85. }
  86. fn provides(&self) -> Option<Vec<Resource>> {
  87. Some(vec![Resource::new("dir", self.target.as_ref().to_string())])
  88. }
  89. fn as_action<'b>(&'b self, runner: &'b dyn SymbolRunner) -> Box<dyn Action + 'b> {
  90. Box::new(SymbolAction::new(runner, self))
  91. }
  92. fn into_action<'b>(self: Box<Self>, runner: &'b dyn SymbolRunner) -> Box<dyn Action + 'b>
  93. where
  94. Self: 'b,
  95. {
  96. Box::new(OwnedSymbolAction::new(runner, *self))
  97. }
  98. }
  99. #[cfg(test)]
  100. mod test {}