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.

274 lines
7.1 KiB

7 years ago
8 years ago
8 years ago
8 years ago
5 years ago
5 years ago
8 years ago
5 years ago
8 years ago
5 years ago
8 years ago
8 years ago
5 years ago
8 years ago
7 years ago
5 years ago
8 years ago
7 years ago
5 years ago
7 years ago
8 years ago
7 years ago
5 years ago
8 years ago
8 years ago
5 years ago
8 years ago
8 years ago
7 years ago
5 years ago
7 years ago
8 years ago
7 years ago
5 years ago
7 years ago
7 years ago
8 years ago
7 years ago
5 years ago
7 years ago
5 years ago
5 years ago
8 years ago
8 years ago
5 years ago
8 years ago
8 years ago
8 years ago
8 years ago
5 years ago
5 years ago
8 years ago
5 years ago
8 years ago
5 years ago
8 years ago
8 years ago
8 years ago
5 years ago
8 years ago
8 years ago
8 years ago
8 years ago
5 years ago
5 years ago
8 years ago
  1. use crate::loggers::Logger;
  2. use crate::symbols::Symbol;
  3. use std::cell::RefCell;
  4. use std::error::Error;
  5. use std::fmt;
  6. use std::fmt::Debug;
  7. pub trait SymbolRunner {
  8. fn run_symbol<S: Symbol + Debug>(&self, symbol: &S, force: bool) -> Result<bool, Box<dyn Error>>;
  9. }
  10. impl<R: SymbolRunner + ?Sized> SymbolRunner for Box<R> {
  11. fn run_symbol<S: Symbol + Debug>(&self, symbol: &S, force: bool) -> Result<bool, Box<dyn Error>> {
  12. (**self).run_symbol(symbol, force)
  13. }
  14. }
  15. #[derive(Debug)]
  16. pub enum SymbolRunError {
  17. Symbol(Box<dyn Error>),
  18. ExecuteDidNotReach(()),
  19. }
  20. impl Error for SymbolRunError {
  21. fn cause(&self) -> Option<&dyn Error> {
  22. match self {
  23. Self::Symbol(ref e) => Some(&**e),
  24. Self::ExecuteDidNotReach(_) => None,
  25. }
  26. }
  27. }
  28. impl fmt::Display for SymbolRunError {
  29. fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
  30. match self {
  31. Self::Symbol(ref e) => write!(f, "{}", e),
  32. Self::ExecuteDidNotReach(_) => write!(f, "Target not reached after executing symbol"),
  33. }
  34. }
  35. }
  36. pub struct InitializingSymbolRunner<L: Logger> {
  37. logger: RefCell<L>,
  38. }
  39. impl<L: Logger> InitializingSymbolRunner<L> {
  40. pub fn new(logger: L) -> Self {
  41. Self {
  42. logger: RefCell::new(logger),
  43. }
  44. }
  45. fn exec_symbol<S: Symbol + Debug>(&self, symbol: &S) -> Result<(), Box<dyn Error>> {
  46. let mut logger = self.logger.borrow_mut();
  47. logger.write(format!("Executing {:?}", symbol).as_str());
  48. symbol.execute()?;
  49. let target_reached = symbol.target_reached()?;
  50. logger.debug(
  51. format!(
  52. "Symbol reports target_reached: {:?} (should be true)",
  53. target_reached
  54. )
  55. .as_str(),
  56. );
  57. if target_reached {
  58. Ok(())
  59. } else {
  60. Err(Box::new(SymbolRunError::ExecuteDidNotReach(())))
  61. }
  62. }
  63. }
  64. impl<L: Logger> SymbolRunner for InitializingSymbolRunner<L> {
  65. fn run_symbol<S: Symbol + Debug>(&self, symbol: &S, force: bool) -> Result<bool, Box<dyn Error>> {
  66. let mut logger = self.logger.borrow_mut();
  67. let executed = if force {
  68. logger.debug("Forcing symbol execution");
  69. drop(logger);
  70. self.exec_symbol(symbol)?;
  71. true
  72. } else {
  73. let target_reached = symbol.target_reached()?;
  74. if target_reached {
  75. logger.write(format!("{:?} already reached", symbol).as_str());
  76. } else {
  77. logger.debug(format!("Symbol reports target_reached: {:?}", target_reached).as_str());
  78. drop(logger);
  79. self.exec_symbol(symbol)?;
  80. }
  81. !target_reached
  82. };
  83. Ok(executed)
  84. }
  85. }
  86. pub struct DrySymbolRunner<L: Logger> {
  87. logger: RefCell<L>,
  88. }
  89. impl<L: Logger> DrySymbolRunner<L> {
  90. pub fn new(logger: L) -> Self {
  91. Self {
  92. logger: RefCell::new(logger),
  93. }
  94. }
  95. }
  96. impl<L: Logger> SymbolRunner for DrySymbolRunner<L> {
  97. fn run_symbol<S: Symbol + Debug>(&self, symbol: &S, force: bool) -> Result<bool, Box<dyn Error>> {
  98. let mut logger = self.logger.borrow_mut();
  99. let would_execute = if force {
  100. logger.write(format!("Would force-execute {:?}", symbol).as_str());
  101. true
  102. } else {
  103. let target_reached = symbol.target_reached()?;
  104. logger.debug(format!("Symbol reports target_reached: {:?}", target_reached).as_str());
  105. if !target_reached {
  106. logger.write(format!("Would execute {:?}", symbol).as_str());
  107. }
  108. !target_reached
  109. };
  110. Ok(would_execute)
  111. }
  112. }
  113. pub struct ReportingSymbolRunner<'a, R, L>(&'a R, RefCell<L>);
  114. impl<'a, R, L> ReportingSymbolRunner<'a, R, L> {
  115. pub fn new(symbol_runner: &'a R, logger: L) -> Self {
  116. ReportingSymbolRunner(symbol_runner, RefCell::new(logger))
  117. }
  118. }
  119. impl<'a, R, L> SymbolRunner for ReportingSymbolRunner<'a, R, L>
  120. where
  121. R: SymbolRunner,
  122. L: Logger,
  123. {
  124. fn run_symbol<S: Symbol + Debug>(&self, symbol: &S, force: bool) -> Result<bool, Box<dyn Error>> {
  125. let mut logger = self.1.borrow_mut();
  126. logger.debug(format!("Running symbol {:?}", symbol).as_str());
  127. let res = self.0.run_symbol(symbol, force);
  128. if let Err(ref e) = res {
  129. logger.write(format!("Failed on {:?} with {}, aborting.", symbol, e).as_str())
  130. } else {
  131. logger.debug(format!("Successfully finished {:?}", symbol).as_str())
  132. }
  133. res
  134. }
  135. }
  136. #[cfg(test)]
  137. mod test {
  138. use std::cell::RefCell;
  139. use std::error::Error;
  140. use std::fmt;
  141. use crate::loggers::Logger;
  142. use crate::schema::InitializingSymbolRunner;
  143. use crate::schema::SymbolRunner;
  144. use crate::symbols::Symbol;
  145. #[derive(Debug, PartialEq, Clone)]
  146. enum DummySymbolError {
  147. Error(()),
  148. }
  149. impl Error for DummySymbolError {}
  150. impl fmt::Display for DummySymbolError {
  151. fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
  152. write!(f, "Dummy symbol error")
  153. }
  154. }
  155. #[derive(Debug)]
  156. struct DummySymbol<T, E> {
  157. _target_reached: RefCell<T>,
  158. _execute: RefCell<E>,
  159. }
  160. impl<
  161. E: Iterator<Item = Result<(), Box<dyn Error>>>,
  162. T: Iterator<Item = Result<bool, Box<dyn Error>>>,
  163. > Symbol for DummySymbol<T, E>
  164. {
  165. fn target_reached(&self) -> Result<bool, Box<dyn Error>> {
  166. self._target_reached.borrow_mut().next().unwrap()
  167. }
  168. fn execute(&self) -> Result<(), Box<dyn Error>> {
  169. self._execute.borrow_mut().next().unwrap()
  170. }
  171. }
  172. impl<
  173. E: Iterator<Item = Result<(), Box<dyn Error>>>,
  174. T: Iterator<Item = Result<bool, Box<dyn Error>>>,
  175. > DummySymbol<T, E>
  176. {
  177. fn new<
  178. IE: IntoIterator<IntoIter = E, Item = Result<(), Box<dyn Error>>>,
  179. IT: IntoIterator<IntoIter = T, Item = Result<bool, Box<dyn Error>>>,
  180. >(
  181. target_reached: IT,
  182. execute: IE,
  183. ) -> Self {
  184. Self {
  185. _target_reached: RefCell::new(target_reached.into_iter()),
  186. _execute: RefCell::new(execute.into_iter()),
  187. }
  188. }
  189. }
  190. struct DummyLogger {
  191. log: Vec<String>,
  192. }
  193. impl DummyLogger {
  194. fn new() -> DummyLogger {
  195. DummyLogger { log: Vec::new() }
  196. }
  197. }
  198. impl Logger for DummyLogger {
  199. fn write(&mut self, line: &str) {
  200. self.log.push(line.into());
  201. }
  202. fn debug(&mut self, line: &str) {
  203. self.log.push(line.into());
  204. }
  205. }
  206. #[test]
  207. fn nothing_needed_to_be_done() {
  208. let result = InitializingSymbolRunner::new(DummyLogger::new())
  209. .run_symbol(&DummySymbol::new(vec![Ok(true)], vec![Ok(())]), false);
  210. assert!(result.is_ok());
  211. }
  212. #[test]
  213. fn everything_is_ok() {
  214. let result = InitializingSymbolRunner::new(DummyLogger::new()).run_symbol(
  215. &DummySymbol::new(vec![Ok(true), Ok(false)], vec![Ok(())]),
  216. false,
  217. );
  218. assert!(result.is_ok());
  219. }
  220. #[test]
  221. fn executing_did_not_change_state() {
  222. let result = InitializingSymbolRunner::new(DummyLogger::new()).run_symbol(
  223. &DummySymbol::new(vec![Ok(false), Ok(false)], vec![Ok(())]),
  224. false,
  225. );
  226. assert_eq!(
  227. result.unwrap_err().to_string(),
  228. "Target not reached after executing symbol"
  229. );
  230. }
  231. #[test]
  232. fn executing_did_not_work() {
  233. let err = InitializingSymbolRunner::new(DummyLogger::new())
  234. .run_symbol(
  235. &DummySymbol::new(
  236. vec![Ok(false)],
  237. vec![Err(Box::new(DummySymbolError::Error(())) as Box<dyn Error>)],
  238. ),
  239. false,
  240. )
  241. .unwrap_err();
  242. assert_eq!(err.to_string(), "Dummy symbol error");
  243. }
  244. }