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.

342 lines
8.5 KiB

7 years ago
8 years ago
7 years ago
8 years ago
5 years ago
5 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
5 years ago
8 years ago
8 years ago
5 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
7 years ago
5 years ago
8 years ago
5 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
5 years ago
7 years ago
5 years ago
8 years ago
7 years ago
5 years ago
7 years ago
5 years ago
7 years ago
7 years ago
5 years ago
5 years ago
5 years ago
7 years ago
5 years ago
5 years ago
7 years ago
5 years ago
5 years ago
7 years ago
5 years ago
7 years ago
6 years ago
7 years ago
7 years ago
7 years ago
5 years ago
7 years ago
5 years ago
5 years ago
7 years ago
8 years ago
5 years ago
8 years ago
5 years ago
8 years ago
5 years ago
5 years ago
8 years ago
5 years ago
5 years ago
8 years ago
5 years ago
5 years ago
8 years ago
8 years ago
5 years ago
8 years ago
5 years ago
8 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
  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<dyn 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<&dyn 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 {
  40. logger: RefCell::new(logger),
  41. }
  42. }
  43. }
  44. impl<L: Logger> SymbolRunner for InitializingSymbolRunner<L> {
  45. fn run_symbol(&self, symbol: &dyn Symbol) -> Result<(), Box<dyn Error>> {
  46. let mut logger = self.logger.borrow_mut();
  47. let target_reached = symbol.target_reached()?;
  48. if target_reached {
  49. logger.write(format!("{} already reached", symbol).as_str());
  50. } else {
  51. logger.debug(format!("Symbol reports target_reached: {:?}", target_reached).as_str());
  52. logger.write(format!("Executing {}", symbol).as_str());
  53. symbol.execute()?;
  54. let target_reached = symbol.target_reached()?;
  55. logger.debug(
  56. format!(
  57. "Symbol reports target_reached: {:?} (should be true)",
  58. target_reached
  59. )
  60. .as_str(),
  61. );
  62. if !target_reached {
  63. return Err(Box::new(SymbolRunError::ExecuteDidNotReach(())));
  64. }
  65. }
  66. Ok(())
  67. }
  68. }
  69. pub struct DrySymbolRunner<L: Logger> {
  70. logger: RefCell<L>,
  71. }
  72. impl<L: Logger> DrySymbolRunner<L> {
  73. pub fn new(logger: L) -> Self {
  74. Self {
  75. logger: RefCell::new(logger),
  76. }
  77. }
  78. }
  79. impl<L: Logger> SymbolRunner for DrySymbolRunner<L> {
  80. fn run_symbol(&self, symbol: &dyn Symbol) -> Result<(), Box<dyn Error>> {
  81. let mut logger = self.logger.borrow_mut();
  82. let target_reached = symbol.target_reached()?;
  83. logger.debug(format!("Symbol reports target_reached: {:?}", target_reached).as_str());
  84. if !target_reached {
  85. logger.write(format!("Would execute {}", symbol).as_str());
  86. }
  87. Ok(())
  88. }
  89. }
  90. pub struct ReportingSymbolRunner<'a, R: 'a + SymbolRunner, L: Logger>(&'a R, RefCell<L>);
  91. impl<'a, R, L> ReportingSymbolRunner<'a, R, L>
  92. where
  93. R: SymbolRunner,
  94. L: Logger,
  95. {
  96. pub fn new(symbol_runner: &'a R, logger: L) -> Self {
  97. ReportingSymbolRunner(symbol_runner, RefCell::new(logger))
  98. }
  99. }
  100. impl<'a, R, L> SymbolRunner for ReportingSymbolRunner<'a, R, L>
  101. where
  102. R: SymbolRunner,
  103. L: Logger,
  104. {
  105. fn run_symbol(&self, symbol: &dyn Symbol) -> Result<(), Box<dyn Error>> {
  106. let mut logger = self.1.borrow_mut();
  107. logger.debug(format!("Running symbol {}", symbol).as_str());
  108. let res = self.0.run_symbol(symbol);
  109. match res {
  110. Err(ref e) => {
  111. logger.write(format!("Failed on {} with {}, aborting.", symbol, e).as_str());
  112. }
  113. Ok(_) => {
  114. logger.debug(format!("Successfully finished {}", symbol).as_str());
  115. }
  116. }
  117. res
  118. }
  119. }
  120. use resources::Resource;
  121. use std::collections::HashSet;
  122. pub struct NonRepeatingSymbolRunner<R: SymbolRunner> {
  123. upstream: R,
  124. done: RefCell<HashSet<Resource>>,
  125. }
  126. impl<R> NonRepeatingSymbolRunner<R>
  127. where
  128. R: SymbolRunner,
  129. {
  130. pub fn new(symbol_runner: R) -> Self {
  131. NonRepeatingSymbolRunner {
  132. upstream: symbol_runner,
  133. done: RefCell::new(HashSet::new()),
  134. }
  135. }
  136. }
  137. impl<R: SymbolRunner> SymbolRunner for NonRepeatingSymbolRunner<R> {
  138. fn run_symbol(&self, symbol: &dyn Symbol) -> Result<(), Box<dyn Error>> {
  139. if let Some(resources) = symbol.provides() {
  140. let mut done = self.done.borrow_mut();
  141. let mut has_to_run = false;
  142. for resource in resources {
  143. if !done.contains(&resource) {
  144. has_to_run = true;
  145. assert!(done.insert(resource.clone()));
  146. }
  147. }
  148. if !has_to_run {
  149. return Ok(());
  150. }
  151. }
  152. self.upstream.run_symbol(&*symbol)
  153. }
  154. }
  155. use std::marker::PhantomData;
  156. pub struct RequirementsResolvingSymbolRunner<
  157. 'a,
  158. 's,
  159. R: 'a + SymbolRunner,
  160. G: 'a + SymbolRepository<'s>,
  161. >(R, &'a G, PhantomData<Box<dyn Symbol + 's>>);
  162. impl<'s, 'a: 's, R, G> RequirementsResolvingSymbolRunner<'a, 's, R, G>
  163. where
  164. R: SymbolRunner,
  165. G: SymbolRepository<'s>,
  166. {
  167. pub fn new(symbol_runner: R, symbol_repo: &'a G) -> Self {
  168. RequirementsResolvingSymbolRunner(symbol_runner, symbol_repo, PhantomData)
  169. }
  170. }
  171. impl<'s, 'a: 's, R, G> SymbolRunner for RequirementsResolvingSymbolRunner<'a, 's, R, G>
  172. where
  173. R: SymbolRunner,
  174. G: SymbolRepository<'s>,
  175. {
  176. fn run_symbol(&self, symbol: &dyn Symbol) -> Result<(), Box<dyn Error>> {
  177. for resource in symbol.get_prerequisites() {
  178. if let Some(dep) = self.1.get_symbol(&resource) {
  179. dep.as_action(self).run()?;
  180. }
  181. }
  182. self.0.run_symbol(&*symbol)
  183. }
  184. }
  185. // FIXME: Add ExpectingSymbolRunner
  186. #[cfg(test)]
  187. mod test {
  188. use std::cell::RefCell;
  189. use std::error::Error;
  190. use std::fmt;
  191. use loggers::Logger;
  192. use schema::InitializingSymbolRunner;
  193. use schema::SymbolRunner;
  194. use symbols::{Action, OwnedSymbolAction, Symbol, SymbolAction};
  195. #[derive(Debug, PartialEq, Clone)]
  196. enum DummySymbolError {
  197. Error(()),
  198. }
  199. impl Error for DummySymbolError {
  200. fn description(&self) -> &str {
  201. return "Description";
  202. }
  203. }
  204. impl fmt::Display for DummySymbolError {
  205. fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
  206. write!(f, "Dummy symbol error")
  207. }
  208. }
  209. struct DummySymbol<'a> {
  210. _execute: &'a dyn Fn() -> Result<(), Box<dyn Error>>,
  211. _target_reached: &'a dyn Fn() -> Result<bool, Box<dyn Error>>,
  212. }
  213. impl<'b> Symbol for DummySymbol<'b> {
  214. fn target_reached(&self) -> Result<bool, Box<dyn Error>> {
  215. (self._target_reached)()
  216. }
  217. fn execute(&self) -> Result<(), Box<dyn Error>> {
  218. (self._execute)()
  219. }
  220. fn as_action<'a>(&'a self, runner: &'a dyn SymbolRunner) -> Box<dyn Action + 'a> {
  221. Box::new(SymbolAction::new(runner, self))
  222. }
  223. fn into_action<'a>(self: Box<Self>, runner: &'a dyn SymbolRunner) -> Box<dyn Action + 'a>
  224. where
  225. Self: 'a,
  226. {
  227. Box::new(OwnedSymbolAction::new(runner, *self))
  228. }
  229. }
  230. impl<'a> fmt::Display for DummySymbol<'a> {
  231. fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
  232. write!(f, "Dummy symbol")
  233. }
  234. }
  235. impl<'a> DummySymbol<'a> {
  236. fn new(
  237. target_reached: &'a dyn Fn() -> Result<bool, Box<dyn Error>>,
  238. execute: &'a dyn Fn() -> Result<(), Box<dyn Error>>,
  239. ) -> DummySymbol<'a> {
  240. DummySymbol {
  241. _target_reached: target_reached,
  242. _execute: execute,
  243. }
  244. }
  245. }
  246. struct DummyLogger {
  247. log: Vec<String>,
  248. }
  249. impl DummyLogger {
  250. fn new() -> DummyLogger {
  251. DummyLogger { log: Vec::new() }
  252. }
  253. }
  254. impl Logger for DummyLogger {
  255. fn write(&mut self, line: &str) {
  256. self.log.push(From::from(line));
  257. }
  258. fn debug(&mut self, line: &str) {
  259. self.log.push(From::from(line));
  260. }
  261. }
  262. #[test]
  263. fn nothing_needed_to_be_done() {
  264. let result = InitializingSymbolRunner::new(DummyLogger::new())
  265. .run_symbol(&DummySymbol::new(&|| Ok(true), &|| Ok(())));
  266. assert!(result.is_ok());
  267. }
  268. #[test]
  269. fn everything_is_ok() {
  270. let first = RefCell::new(true);
  271. let result = InitializingSymbolRunner::new(DummyLogger::new()).run_symbol(&DummySymbol::new(
  272. &|| {
  273. let mut _first = first.borrow_mut();
  274. Ok(if *_first {
  275. *_first = false;
  276. true
  277. } else {
  278. false
  279. })
  280. },
  281. &|| Ok(()),
  282. ));
  283. assert!(result.is_ok());
  284. }
  285. #[test]
  286. fn executing_did_not_change_state() {
  287. let result = InitializingSymbolRunner::new(DummyLogger::new())
  288. .run_symbol(&DummySymbol::new(&|| Ok(false), &|| Ok(())));
  289. assert_eq!(
  290. result.unwrap_err().description(),
  291. "Target not reached after executing symbol"
  292. );
  293. }
  294. #[test]
  295. fn executing_did_not_work() {
  296. let err = InitializingSymbolRunner::new(DummyLogger::new())
  297. .run_symbol(&DummySymbol::new(&|| Ok(false), &|| {
  298. Err(Box::new(DummySymbolError::Error(())))
  299. }))
  300. .unwrap_err();
  301. assert_eq!(err.description(), "Description");
  302. }
  303. }