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.

183 lines
4.6 KiB

7 years ago
7 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
5 years ago
7 years ago
5 years ago
7 years ago
5 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, Symbol, SymbolRunner};
  5. pub struct List<'a> {
  6. symbols: Vec<Box<Symbol + 'a>>
  7. }
  8. impl<'a> List<'a> {
  9. pub fn new(symbols: Vec<Box<Symbol + 'a>>) -> Self {
  10. List { symbols }
  11. }
  12. }
  13. impl<'a> Symbol for List<'a> {
  14. fn target_reached(&self) -> Result<bool, Box<Error>> {
  15. for symbol in &self.symbols {
  16. if !try!(symbol.target_reached()) {
  17. return Ok(false);
  18. }
  19. }
  20. Ok(true)
  21. }
  22. fn execute(&self) -> Result<(), Box<Error>> {
  23. for symbol in &self.symbols {
  24. try!(symbol.execute());
  25. }
  26. Ok(())
  27. }
  28. fn get_prerequisites(&self) -> Vec<Resource> {
  29. let mut r = vec![];
  30. for symbol in &self.symbols {
  31. for req in symbol.get_prerequisites() {
  32. if self.provides().map_or(true, |p| !p.contains(&req)) { r.push(req) }
  33. }
  34. }
  35. r
  36. }
  37. fn provides(&self) -> Option<Vec<Resource>> {
  38. let mut r = vec![];
  39. for symbol in &self.symbols {
  40. if let Some(provides) = symbol.provides() {
  41. r.extend(provides.into_iter());
  42. }
  43. }
  44. if r.is_empty() { None } else { Some(r) }
  45. }
  46. fn as_action<'b>(&'b self, runner: &'b SymbolRunner) -> Box<Action + 'b> {
  47. Box::new(SymbolListAction::new(runner, &self.symbols))
  48. }
  49. fn into_action<'b>(self: Box<Self>, runner: &'b SymbolRunner) -> Box<Action + 'b> where Self: 'b {
  50. Box::new(ListAction::new(self.symbols.into_iter().map(|s| s.into_action(runner)).collect()))
  51. }
  52. }
  53. struct SymbolListAction<'a> {
  54. runner: &'a SymbolRunner,
  55. symbols: &'a [Box<Symbol + 'a>]
  56. }
  57. impl<'a> SymbolListAction<'a> {
  58. fn new(runner: &'a SymbolRunner, symbols: &'a [Box<Symbol + 'a>]) -> Self {
  59. Self { runner, symbols }
  60. }
  61. }
  62. impl<'a> Action for SymbolListAction<'a> {
  63. fn run(&self) -> Result<(), Box<Error>> {
  64. for symbol in self.symbols {
  65. try!(symbol.as_action(self.runner).run());
  66. }
  67. Ok(())
  68. }
  69. }
  70. pub struct ListAction<'a> {
  71. actions: Vec<Box<Action + 'a>>
  72. }
  73. impl<'a> ListAction<'a> {
  74. pub fn new(actions: Vec<Box<Action + 'a>>) -> Self {
  75. Self { actions }
  76. }
  77. }
  78. impl<'a> Action for ListAction<'a> {
  79. fn run(&self) -> Result<(), Box<Error>> {
  80. for action in &self.actions {
  81. try!(action.run());
  82. }
  83. Ok(())
  84. }
  85. }
  86. impl<'a> fmt::Display for List<'a> {
  87. fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error>{
  88. try!(write!(f, "List [ "));
  89. for symbol in &self.symbols {
  90. try!(write!(f, "{} ", symbol));
  91. }
  92. write!(f, "]")
  93. }
  94. }
  95. /*
  96. #[cfg(test)]
  97. mod test {
  98. use std::error::Error;
  99. use std::fmt;
  100. use symbols::{Action, OwnedSymbolAction, Symbol, SymbolAction, SymbolRunner};
  101. use symbols::hook::List;
  102. struct ErrSymbol(String);
  103. impl Symbol for ErrSymbol {
  104. fn target_reached(&self) -> Result<bool, Box<Error>> { Err(self.0.clone().into()) }
  105. fn execute(&self) -> Result<(), Box<Error>> { Err(self.0.clone().into()) }
  106. }
  107. impl fmt::Display for ErrSymbol { fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error>{ write!(f, "") } }
  108. struct OkSymbol(bool);
  109. impl Symbol for OkSymbol {
  110. fn target_reached(&self) -> Result<bool, Box<Error>> { Ok(self.0) }
  111. fn execute(&self) -> Result<(), Box<Error>> { Ok(()) }
  112. }
  113. impl fmt::Display for OkSymbol { fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error>{ write!(f, "") } }
  114. #[test]
  115. fn first_target_reached_fails() {
  116. let res = List::new(ErrSymbol("first".into()), ErrSymbol("second".into())).target_reached();
  117. assert_eq!(res.unwrap_err().description(), "first");
  118. }
  119. #[test]
  120. fn first_target_not_reached() {
  121. let res = List::new(OkSymbol(false), ErrSymbol("second".into())).target_reached();
  122. assert_eq!(res.unwrap(), false);
  123. }
  124. #[test]
  125. fn second_target_reached_fails() {
  126. let res = List::new(OkSymbol(true), ErrSymbol("second".into())).target_reached();
  127. assert_eq!(res.unwrap_err().description(), "second");
  128. }
  129. #[test]
  130. fn second_target_not_reached() {
  131. let res = List::new(OkSymbol(true), OkSymbol(false)).target_reached();
  132. assert_eq!(res.unwrap(), false);
  133. }
  134. #[test]
  135. fn everything_reached() {
  136. let res = List::new(OkSymbol(true), OkSymbol(true)).target_reached();
  137. assert_eq!(res.unwrap(), true);
  138. }
  139. #[test]
  140. fn first_execute_fails() {
  141. let res = List::new(ErrSymbol("first".into()), ErrSymbol("second".into())).execute();
  142. assert_eq!(res.unwrap_err().description(), "first");
  143. }
  144. #[test]
  145. fn second_execute_fails() {
  146. let res = List::new(OkSymbol(true), ErrSymbol("second".into())).execute();
  147. assert_eq!(res.unwrap_err().description(), "second");
  148. }
  149. #[test]
  150. fn everything_executes() {
  151. let res = List::new(OkSymbol(true), OkSymbol(true)).execute();
  152. assert_eq!(res.unwrap(), ());
  153. }
  154. }
  155. */