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.

145 lines
4.4 KiB

7 years ago
7 years ago
7 years ago
7 years ago
6 years ago
7 years ago
5 years ago
7 years ago
7 years ago
7 years ago
7 years ago
5 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
  1. use std::error::Error;
  2. use std::fmt;
  3. use resources::Resource;
  4. use symbols::{Action, OwnedSymbolAction, Symbol, SymbolAction, SymbolRunner};
  5. pub struct Hook<A, B> where A: Symbol, B: Symbol {
  6. a: A,
  7. b: B
  8. }
  9. // A and B are executed if either A or B are not reached
  10. impl<A, B> Hook<A, B> where A: Symbol, B: Symbol {
  11. pub fn new(a: A, b: B) -> Self {
  12. Hook { a, b }
  13. }
  14. }
  15. impl<A, B> Symbol for Hook<A, B> where A: Symbol, B: Symbol {
  16. fn target_reached(&self) -> Result<bool, Box<Error>> {
  17. self.a.target_reached().and_then(|reached| if reached { self.b.target_reached() } else { Ok(reached) })
  18. }
  19. fn execute(&self) -> Result<(), Box<Error>> {
  20. try!(self.a.execute());
  21. self.b.execute()
  22. }
  23. fn get_prerequisites(&self) -> Vec<Resource> {
  24. let mut r = vec![];
  25. r.extend(self.a.get_prerequisites().into_iter());
  26. r.extend(self.b.get_prerequisites().into_iter());
  27. r
  28. }
  29. fn provides(&self) -> Option<Vec<Resource>> {
  30. let mut r = vec![];
  31. if let Some(provides) = self.a.provides() {
  32. r.extend(provides.into_iter());
  33. }
  34. if let Some(provides) = self.b.provides() {
  35. r.extend(provides.into_iter());
  36. }
  37. if r.is_empty() { None } else { Some(r) }
  38. }
  39. fn as_action<'a>(&'a self, runner: &'a SymbolRunner) -> Box<Action + 'a> {
  40. Box::new(SymbolAction::new(runner, self))
  41. }
  42. fn into_action<'a>(self: Box<Self>, runner: &'a SymbolRunner) -> Box<Action + 'a> where Self: 'a {
  43. Box::new(OwnedSymbolAction::new(runner, *self))
  44. }
  45. }
  46. impl<A, B> fmt::Display for Hook<A, B> where A: Symbol, B: Symbol {
  47. fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error>{
  48. write!(f, "Hook {} and then {}", self.a, self.b)
  49. }
  50. }
  51. #[cfg(test)]
  52. mod test {
  53. use std::error::Error;
  54. use std::fmt;
  55. use symbols::{Action, OwnedSymbolAction, Symbol, SymbolAction, SymbolRunner};
  56. use symbols::hook::Hook;
  57. struct ErrSymbol(String);
  58. impl Symbol for ErrSymbol {
  59. fn target_reached(&self) -> Result<bool, Box<Error>> { Err(self.0.clone().into()) }
  60. fn execute(&self) -> Result<(), Box<Error>> { Err(self.0.clone().into()) }
  61. fn as_action<'a>(&'a self, runner: &'a SymbolRunner) -> Box<Action + 'a> {
  62. Box::new(SymbolAction::new(runner, self))
  63. }
  64. fn into_action<'a>(self: Box<Self>, runner: &'a SymbolRunner) -> Box<Action + 'a> where Self: 'a {
  65. Box::new(OwnedSymbolAction::new(runner, *self))
  66. }
  67. }
  68. impl fmt::Display for ErrSymbol { fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error>{ write!(f, "") } }
  69. struct OkSymbol(bool);
  70. impl Symbol for OkSymbol {
  71. fn target_reached(&self) -> Result<bool, Box<Error>> { Ok(self.0) }
  72. fn execute(&self) -> Result<(), Box<Error>> { Ok(()) }
  73. fn as_action<'a>(&'a self, runner: &'a SymbolRunner) -> Box<Action + 'a> {
  74. Box::new(SymbolAction::new(runner, self))
  75. }
  76. fn into_action<'a>(self: Box<Self>, runner: &'a SymbolRunner) -> Box<Action + 'a> where Self: 'a {
  77. Box::new(OwnedSymbolAction::new(runner, *self))
  78. }
  79. }
  80. impl fmt::Display for OkSymbol { fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error>{ write!(f, "") } }
  81. #[test]
  82. fn first_target_reached_fails() {
  83. let res = Hook::new(ErrSymbol("first".into()), ErrSymbol("second".into())).target_reached();
  84. assert_eq!(res.unwrap_err().description(), "first");
  85. }
  86. #[test]
  87. fn first_target_not_reached() {
  88. let res = Hook::new(OkSymbol(false), ErrSymbol("second".into())).target_reached();
  89. assert_eq!(res.unwrap(), false);
  90. }
  91. #[test]
  92. fn second_target_reached_fails() {
  93. let res = Hook::new(OkSymbol(true), ErrSymbol("second".into())).target_reached();
  94. assert_eq!(res.unwrap_err().description(), "second");
  95. }
  96. #[test]
  97. fn second_target_not_reached() {
  98. let res = Hook::new(OkSymbol(true), OkSymbol(false)).target_reached();
  99. assert_eq!(res.unwrap(), false);
  100. }
  101. #[test]
  102. fn everything_reached() {
  103. let res = Hook::new(OkSymbol(true), OkSymbol(true)).target_reached();
  104. assert_eq!(res.unwrap(), true);
  105. }
  106. #[test]
  107. fn first_execute_fails() {
  108. let res = Hook::new(ErrSymbol("first".into()), ErrSymbol("second".into())).execute();
  109. assert_eq!(res.unwrap_err().description(), "first");
  110. }
  111. #[test]
  112. fn second_execute_fails() {
  113. let res = Hook::new(OkSymbol(true), ErrSymbol("second".into())).execute();
  114. assert_eq!(res.unwrap_err().description(), "second");
  115. }
  116. #[test]
  117. fn everything_executes() {
  118. let res = Hook::new(OkSymbol(true), OkSymbol(true)).execute();
  119. assert_eq!(res.unwrap(), ());
  120. }
  121. }