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.

338 lines
8.5 KiB

7 years ago
8 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
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
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
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
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
8 years ago
5 years ago
8 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 crate::loggers::Logger;
  5. use crate::repository::SymbolRepository;
  6. use crate::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. Self::Symbol(_) => "Symbol execution error",
  16. Self::ExecuteDidNotReach(_) => "Target not reached after executing symbol",
  17. }
  18. }
  19. fn cause(&self) -> Option<&dyn Error> {
  20. match self {
  21. Self::Symbol(ref e) => Some(&**e),
  22. Self::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. Self::Symbol(ref e) => write!(f, "{}", e),
  30. Self::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: 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. if let Err(ref e) = res {
  110. logger.write(format!("Failed on {} with {}, aborting.", symbol, e).as_str())
  111. } else {
  112. logger.debug(format!("Successfully finished {}", symbol).as_str())
  113. }
  114. res
  115. }
  116. }
  117. use crate::resources::Resource;
  118. use std::collections::HashSet;
  119. pub struct NonRepeatingSymbolRunner<R: SymbolRunner> {
  120. upstream: R,
  121. done: RefCell<HashSet<Resource>>,
  122. }
  123. impl<R> NonRepeatingSymbolRunner<R>
  124. where
  125. R: SymbolRunner,
  126. {
  127. pub fn new(symbol_runner: R) -> Self {
  128. Self {
  129. upstream: symbol_runner,
  130. done: RefCell::new(HashSet::new()),
  131. }
  132. }
  133. }
  134. impl<R: SymbolRunner> SymbolRunner for NonRepeatingSymbolRunner<R> {
  135. fn run_symbol(&self, symbol: &dyn Symbol) -> Result<(), Box<dyn Error>> {
  136. if let Some(resources) = symbol.provides() {
  137. let mut done = self.done.borrow_mut();
  138. let mut has_to_run = false;
  139. for resource in resources {
  140. if !done.contains(&resource) {
  141. has_to_run = true;
  142. assert!(done.insert(resource.clone()));
  143. }
  144. }
  145. if !has_to_run {
  146. return Ok(());
  147. }
  148. }
  149. self.upstream.run_symbol(&*symbol)
  150. }
  151. }
  152. use std::marker::PhantomData;
  153. pub struct RequirementsResolvingSymbolRunner<'a, 's, R: 'a + SymbolRunner, G: SymbolRepository<'s>>(
  154. R,
  155. &'a G,
  156. PhantomData<Box<dyn Symbol + 's>>,
  157. );
  158. impl<'s, 'a: 's, R, G> RequirementsResolvingSymbolRunner<'a, 's, R, G>
  159. where
  160. R: SymbolRunner,
  161. G: SymbolRepository<'s>,
  162. {
  163. pub fn new(symbol_runner: R, symbol_repo: &'a G) -> Self {
  164. RequirementsResolvingSymbolRunner(symbol_runner, symbol_repo, PhantomData)
  165. }
  166. }
  167. impl<'s, 'a: 's, R, G> SymbolRunner for RequirementsResolvingSymbolRunner<'a, 's, R, G>
  168. where
  169. R: SymbolRunner,
  170. G: SymbolRepository<'s>,
  171. {
  172. fn run_symbol(&self, symbol: &dyn Symbol) -> Result<(), Box<dyn Error>> {
  173. for resource in symbol.get_prerequisites() {
  174. if let Some(dep) = self.1.get_symbol(&resource) {
  175. dep.as_action(self).run()?;
  176. }
  177. }
  178. self.0.run_symbol(&*symbol)
  179. }
  180. }
  181. // FIXME: Add ExpectingSymbolRunner
  182. #[cfg(test)]
  183. mod test {
  184. use std::cell::RefCell;
  185. use std::error::Error;
  186. use std::fmt;
  187. use crate::loggers::Logger;
  188. use crate::schema::InitializingSymbolRunner;
  189. use crate::schema::SymbolRunner;
  190. use crate::symbols::{Action, OwnedSymbolAction, Symbol, SymbolAction};
  191. #[derive(Debug, PartialEq, Clone)]
  192. enum DummySymbolError {
  193. Error(()),
  194. }
  195. impl Error for DummySymbolError {
  196. fn description(&self) -> &str {
  197. return "Description";
  198. }
  199. }
  200. impl fmt::Display for DummySymbolError {
  201. fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
  202. write!(f, "Dummy symbol error")
  203. }
  204. }
  205. struct DummySymbol<'a> {
  206. _execute: &'a dyn Fn() -> Result<(), Box<dyn Error>>,
  207. _target_reached: &'a dyn Fn() -> Result<bool, Box<dyn Error>>,
  208. }
  209. impl<'b> Symbol for DummySymbol<'b> {
  210. fn target_reached(&self) -> Result<bool, Box<dyn Error>> {
  211. (self._target_reached)()
  212. }
  213. fn execute(&self) -> Result<(), Box<dyn Error>> {
  214. (self._execute)()
  215. }
  216. fn as_action<'a>(&'a self, runner: &'a dyn SymbolRunner) -> Box<dyn Action + 'a> {
  217. Box::new(SymbolAction::new(runner, self))
  218. }
  219. fn into_action<'a>(self: Box<Self>, runner: &'a dyn SymbolRunner) -> Box<dyn Action + 'a>
  220. where
  221. Self: 'a,
  222. {
  223. Box::new(OwnedSymbolAction::new(runner, *self))
  224. }
  225. }
  226. impl<'a> fmt::Display for DummySymbol<'a> {
  227. fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
  228. write!(f, "Dummy symbol")
  229. }
  230. }
  231. impl<'a> DummySymbol<'a> {
  232. fn new(
  233. target_reached: &'a dyn Fn() -> Result<bool, Box<dyn Error>>,
  234. execute: &'a dyn Fn() -> Result<(), Box<dyn Error>>,
  235. ) -> DummySymbol<'a> {
  236. DummySymbol {
  237. _target_reached: target_reached,
  238. _execute: execute,
  239. }
  240. }
  241. }
  242. struct DummyLogger {
  243. log: Vec<String>,
  244. }
  245. impl DummyLogger {
  246. fn new() -> DummyLogger {
  247. DummyLogger { log: Vec::new() }
  248. }
  249. }
  250. impl Logger for DummyLogger {
  251. fn write(&mut self, line: &str) {
  252. self.log.push(From::from(line));
  253. }
  254. fn debug(&mut self, line: &str) {
  255. self.log.push(From::from(line));
  256. }
  257. }
  258. #[test]
  259. fn nothing_needed_to_be_done() {
  260. let result = InitializingSymbolRunner::new(DummyLogger::new())
  261. .run_symbol(&DummySymbol::new(&|| Ok(true), &|| Ok(())));
  262. assert!(result.is_ok());
  263. }
  264. #[test]
  265. fn everything_is_ok() {
  266. let first = RefCell::new(true);
  267. let result = InitializingSymbolRunner::new(DummyLogger::new()).run_symbol(&DummySymbol::new(
  268. &|| {
  269. let mut _first = first.borrow_mut();
  270. Ok(if *_first {
  271. *_first = false;
  272. true
  273. } else {
  274. false
  275. })
  276. },
  277. &|| Ok(()),
  278. ));
  279. assert!(result.is_ok());
  280. }
  281. #[test]
  282. fn executing_did_not_change_state() {
  283. let result = InitializingSymbolRunner::new(DummyLogger::new())
  284. .run_symbol(&DummySymbol::new(&|| Ok(false), &|| Ok(())));
  285. assert_eq!(
  286. result.unwrap_err().description(),
  287. "Target not reached after executing symbol"
  288. );
  289. }
  290. #[test]
  291. fn executing_did_not_work() {
  292. let err = InitializingSymbolRunner::new(DummyLogger::new())
  293. .run_symbol(&DummySymbol::new(&|| Ok(false), &|| {
  294. Err(Box::new(DummySymbolError::Error(())))
  295. }))
  296. .unwrap_err();
  297. assert_eq!(err.description(), "Description");
  298. }
  299. }