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.

201 lines
5.5 KiB

8 years ago
7 years ago
8 years ago
7 years ago
8 years ago
7 years ago
8 years ago
  1. use std::error::Error;
  2. use std::fmt;
  3. use loggers::Logger;
  4. use symbols::Symbol;
  5. #[derive(Debug,PartialEq)]
  6. pub enum SymbolRunError<E: Error> {
  7. Symbol(E),
  8. ExecuteDidNotReach(())
  9. }
  10. impl<E: Error> Error for SymbolRunError<E> {
  11. fn description(&self) -> &str {
  12. match self {
  13. &SymbolRunError::Symbol(_) => "Symbol execution error",
  14. &SymbolRunError::ExecuteDidNotReach(_) => "Target not reached after executing symbol"
  15. }
  16. }
  17. fn cause(&self) -> Option<&Error> {
  18. match self {
  19. &SymbolRunError::Symbol(ref e) => Some(e),
  20. &SymbolRunError::ExecuteDidNotReach(_) => None
  21. }
  22. }
  23. }
  24. impl<E: Error> fmt::Display for SymbolRunError<E> {
  25. fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
  26. match self {
  27. &SymbolRunError::Symbol(ref e) => write!(f, "{}", e),
  28. &SymbolRunError::ExecuteDidNotReach(_) => write!(f, "{}", self.description())
  29. }
  30. }
  31. }
  32. impl<E: Error> From<E> for SymbolRunError<E> {
  33. fn from(err: E) -> SymbolRunError<E> {
  34. SymbolRunError::Symbol(err)
  35. }
  36. }
  37. pub trait SymbolRunner {
  38. fn run_symbol<S: ?Sized + Symbol + fmt::Display>(&self, logger: &mut Logger, symbol: &S) -> Result<(), SymbolRunError<S::Error>>
  39. where S::Error: Error;
  40. }
  41. pub struct InitializingSymbolRunner;
  42. impl SymbolRunner for InitializingSymbolRunner {
  43. fn run_symbol<S: ?Sized + Symbol + fmt::Display>(&self, logger: &mut Logger, symbol: &S) -> Result<(), SymbolRunError<S::Error>>
  44. where S::Error: Error
  45. {
  46. let target_reached = try!(symbol.target_reached());
  47. if target_reached {
  48. logger.write(format!("{} already reached", symbol).as_str());
  49. } else {
  50. logger.debug(format!("Symbol reports target_reached: {:?}", target_reached).as_str());
  51. logger.write(format!("Executing {}", symbol).as_str());
  52. try!(symbol.execute());
  53. let target_reached = try!(symbol.target_reached());
  54. logger.debug(format!("Symbol reports target_reached: {:?} (should be true)", target_reached).as_str());
  55. if !target_reached {
  56. return Err(SymbolRunError::ExecuteDidNotReach(()));
  57. }
  58. }
  59. Ok(())
  60. }
  61. }
  62. pub struct DrySymbolRunner;
  63. impl SymbolRunner for DrySymbolRunner {
  64. fn run_symbol<S: ?Sized + Symbol + fmt::Display>(&self, logger: &mut Logger, symbol: &S) -> Result<(), SymbolRunError<S::Error>>
  65. where S::Error: Error
  66. {
  67. let target_reached = try!(symbol.target_reached());
  68. logger.debug(format!("Symbol reports target_reached: {:?}", target_reached).as_str());
  69. if !target_reached {
  70. logger.write(format!("Would execute {}", symbol).as_str());
  71. }
  72. Ok(())
  73. }
  74. }
  75. // FIXME: Add ExpectingSymbolRunner
  76. #[cfg(test)]
  77. mod test {
  78. use std::cell::RefCell;
  79. use std::error::Error;
  80. use std::fmt;
  81. use loggers::Logger;
  82. use symbols::Symbol;
  83. use schema::SymbolRunner;
  84. use schema::InitializingSymbolRunner;
  85. use schema::SymbolRunError;
  86. #[derive(Debug, PartialEq, Clone)]
  87. enum DummySymbolError {
  88. Error(())
  89. }
  90. impl Error for DummySymbolError {
  91. fn description(&self) -> &str {
  92. return "Description";
  93. }
  94. }
  95. impl fmt::Display for DummySymbolError {
  96. fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
  97. write!(f, "Dummy symbol error")
  98. }
  99. }
  100. #[derive(Debug)]
  101. struct DummySymbol {
  102. _target_reacheds: Vec<Result<bool, DummySymbolError>>,
  103. _cur_target_reached: RefCell<usize>,
  104. _execute: Result<(), DummySymbolError>,
  105. }
  106. impl Symbol for DummySymbol {
  107. type Error = DummySymbolError;
  108. fn target_reached(&self) -> Result<bool, Self::Error> {
  109. let mut cur = self._cur_target_reached.borrow_mut();
  110. let ret = self._target_reacheds[*cur].clone();
  111. *cur = *cur + 1;
  112. ret
  113. }
  114. fn execute(&self) -> Result<(), Self::Error> { self._execute.clone() }
  115. }
  116. impl fmt::Display for DummySymbol {
  117. fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
  118. write!(f, "Dummy symbol")
  119. }
  120. }
  121. impl DummySymbol {
  122. fn new(target_reached: Vec<Result<bool, DummySymbolError>>,
  123. execute: Result<(), DummySymbolError>) -> DummySymbol {
  124. DummySymbol { _target_reacheds: target_reached, _cur_target_reached: RefCell::new(0), _execute: execute }
  125. }
  126. }
  127. struct DummyLogger {
  128. log: Vec<String>
  129. }
  130. impl DummyLogger {
  131. fn new() -> DummyLogger {
  132. DummyLogger { log: Vec::new() }
  133. }
  134. }
  135. impl Logger for DummyLogger {
  136. fn write(&mut self, line: &str) {
  137. self.log.push(From::from(line));
  138. }
  139. fn debug(&mut self, line: &str) {
  140. self.log.push(From::from(line));
  141. }
  142. }
  143. #[test]
  144. fn nothing_needed_to_be_done() {
  145. let result: Result<(), SymbolRunError<DummySymbolError>> = InitializingSymbolRunner.run_symbol( &mut DummyLogger::new(), &DummySymbol::new(vec![Ok(true)], Ok(())) );
  146. assert_eq!(
  147. result,
  148. Ok(())
  149. );
  150. }
  151. #[test]
  152. fn everything_is_ok() {
  153. let result: Result<(), SymbolRunError<DummySymbolError>> = InitializingSymbolRunner.run_symbol( &mut DummyLogger::new(), &DummySymbol::new(vec![Ok(false), Ok(true)], Ok(())) );
  154. assert_eq!(
  155. result,
  156. Ok(())
  157. );
  158. }
  159. #[test]
  160. fn executing_did_not_change_state() {
  161. let result: Result<(), SymbolRunError<DummySymbolError>> = InitializingSymbolRunner.run_symbol( &mut DummyLogger::new(), &DummySymbol::new(vec![Ok(false), Ok(false)], Ok(())));
  162. assert_eq!(
  163. result,
  164. Err(SymbolRunError::ExecuteDidNotReach(()))
  165. );
  166. }
  167. #[test]
  168. fn executing_did_not_work() {
  169. assert_eq!(
  170. InitializingSymbolRunner.run_symbol( &mut DummyLogger::new(), &DummySymbol::new(vec![Ok(false)], Err(DummySymbolError::Error(()))) ),
  171. Err(SymbolRunError::Symbol(DummySymbolError::Error(())))
  172. );
  173. }
  174. }