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.

284 lines
7.9 KiB

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