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.

199 lines
6.0 KiB

  1. use super::runnable::Runnable;
  2. use super::setup::Setup;
  3. use super::util::{AddableResource, InternalAddResult};
  4. use super::SymbolRunner;
  5. use crate::async_utils::try_join;
  6. use crate::loggers::{Logger, StoringLogger};
  7. use crate::resources::{FromArtifact, FromResource};
  8. use crate::symbols::Symbol;
  9. use crate::to_artifact::ToArtifact;
  10. use crate::{ImplementationBuilder, ResourceLocator};
  11. use async_trait::async_trait;
  12. use std::error::Error;
  13. use std::fmt::Debug;
  14. use std::hash::Hash;
  15. use std::marker::PhantomData;
  16. #[async_trait(?Send)]
  17. pub trait AddGeneric<X: ToArtifact> {
  18. async fn add_generic(&self, x: X) -> InternalAddResult<X>;
  19. }
  20. macro_rules! add_generic {
  21. ( $($name:ident)* ) => (
  22. #[async_trait(?Send)]
  23. #[allow(non_snake_case)]
  24. impl<SR: 'static, _L: 'static, _B: 'static, Rs: 'static + Hash + Eq, As: 'static + Clone, $($name: AddableResource,)*>
  25. AddGeneric<($($name,)*)> for Setup<SR, _L, _B, Rs, As>
  26. where
  27. $(
  28. RegularSetupCore<SR, _L, _B>: SetupCore<$name, Self>,
  29. As: FromArtifact<$name>,
  30. Rs: FromResource<$name>,
  31. $name::Artifact: Clone
  32. ),*
  33. {
  34. #[allow(unused)]
  35. async fn add_generic(&self, ($($name,)*): ($($name,)*)) -> Result<(StoringLogger, ($($name::Artifact,)*), bool), (StoringLogger, Box<dyn Error>)>
  36. {
  37. let x: Result<_, _> = try_join!($(self.add($name, false),)*);
  38. let ($($name,)*) = x?;
  39. let logger = StoringLogger::default();
  40. $(logger.put($name.0.release());)*
  41. Ok((logger, ($($name.1,)*), false $(|| $name.2)*))
  42. }
  43. }
  44. );
  45. }
  46. for_each_tuple!(add_generic);
  47. // This is for self-referential T
  48. // FIXME: Wait for specialization
  49. #[async_trait(?Send)]
  50. impl<
  51. SR: 'static + SymbolRunner,
  52. T: AddableResource,
  53. Rs: 'static + Hash + Eq + FromResource<T>,
  54. As: 'static + FromArtifact<T> + Clone,
  55. L: 'static + ResourceLocator<T, Prerequisites = Option<T>>,
  56. B: 'static + ImplementationBuilder<T>,
  57. > AddGeneric<Option<T>> for Setup<SR, L, B, Rs, As>
  58. where
  59. <B as ImplementationBuilder<T>>::Implementation: Runnable + Debug,
  60. Self: AddGeneric<B::Prerequisites>,
  61. T::Artifact: Clone,
  62. {
  63. async fn add_generic(&self, r: Option<T>) -> InternalAddResult<Option<T>> {
  64. Ok(match r {
  65. Some(r) => {
  66. let (logger, result, did_run) = self.add(r, false).await?;
  67. (logger, Some(result), did_run)
  68. }
  69. None => (StoringLogger::default(), None, false),
  70. })
  71. }
  72. }
  73. #[async_trait(?Send)]
  74. impl<
  75. T: AddableResource,
  76. Rs: 'static + Hash + Eq + FromResource<T>,
  77. As: 'static + FromArtifact<T> + Clone,
  78. SR: 'static,
  79. L: 'static,
  80. B: 'static,
  81. > AddGeneric<T> for Setup<SR, L, B, Rs, As>
  82. where
  83. T::Artifact: Clone,
  84. RegularSetupCore<SR, L, B>: 'static + SetupCore<T, Self>,
  85. {
  86. async fn add_generic(&self, r: T) -> InternalAddResult<T> {
  87. self.add(r, false).await
  88. }
  89. }
  90. #[async_trait(?Send)]
  91. pub trait SetupCore<R: AddableResource, S> {
  92. async fn add<RR: AsRef<R>>(
  93. &self,
  94. setup: &S,
  95. resource: RR,
  96. force_run: bool,
  97. ) -> InternalAddResult<R>;
  98. }
  99. #[derive(Debug)]
  100. pub struct RegularSetupCore<SR, L, B> {
  101. symbol_runner: SR,
  102. phantom: PhantomData<(L, B)>,
  103. }
  104. impl<SR, L, B> RegularSetupCore<SR, L, B> {
  105. pub fn new(symbol_runner: SR) -> Self {
  106. Self {
  107. symbol_runner,
  108. phantom: PhantomData::default(),
  109. }
  110. }
  111. }
  112. #[async_trait(?Send)]
  113. impl<SR: SymbolRunner, L, B, R: AddableResource, S> SetupCore<R, S> for RegularSetupCore<SR, L, B>
  114. where
  115. B: ImplementationBuilder<R>,
  116. <B as ImplementationBuilder<R>>::Implementation: Runnable + Debug,
  117. L: ResourceLocator<R>,
  118. S: AddGeneric<B::Prerequisites> + AddGeneric<<L as ResourceLocator<R>>::Prerequisites>,
  119. {
  120. async fn add<RR: AsRef<R>>(
  121. &self,
  122. setup: &S,
  123. resource: RR,
  124. force_run: bool,
  125. ) -> InternalAddResult<R> {
  126. let resource = resource.as_ref();
  127. let logger = StoringLogger::new();
  128. logger.write(4, format!("Adding {:?} ... ", resource));
  129. logger.write(4, format!("(force_run is {})", force_run));
  130. let (location, location_prereqs) = L::locate(resource);
  131. logger.trace(format!("Adding location prereqs for {:?}", resource));
  132. let result = setup.add_generic(location_prereqs).await;
  133. if let Err((log, e)) = result {
  134. logger.put(log.release());
  135. return Err((logger, e));
  136. }
  137. let (location_prereq_logger, _, location_prereqs_did_run) = result.unwrap();
  138. logger.put(location_prereq_logger.release());
  139. logger.trace(format!(
  140. "Location prereqs for {:?} did_run: {}",
  141. resource, location_prereqs_did_run
  142. ));
  143. logger.trace(format!("Adding implementation prereqs for {:?}", resource));
  144. let result = setup.add_generic(B::prerequisites(resource)).await;
  145. if let Err((log, e)) = result {
  146. logger.put(log.release());
  147. return Err((logger, e));
  148. }
  149. let (impl_prereq_logger, prereqs, prereqs_did_run) = result.unwrap();
  150. logger.put(impl_prereq_logger.release());
  151. logger.trace(format!(
  152. "Implementation prereqs for {:?} did_run: {}",
  153. resource, prereqs_did_run
  154. ));
  155. logger.trace(format!("Running implementation for {:?}", resource));
  156. let implementation = B::create(resource, &location, prereqs);
  157. let did_run_result = implementation
  158. .run(
  159. &self.symbol_runner,
  160. &logger,
  161. force_run || location_prereqs_did_run || prereqs_did_run,
  162. )
  163. .await;
  164. match did_run_result {
  165. Ok(did_run) => {
  166. logger.write(4, "done.");
  167. Ok((logger, location, did_run))
  168. }
  169. Err(e) => Err((logger, e)),
  170. }
  171. }
  172. }
  173. #[async_trait(?Send)]
  174. impl<SR: SymbolRunner, L, B> SymbolRunner for RegularSetupCore<SR, L, B> {
  175. async fn run_symbol<S: Symbol + Debug, LOG: Logger>(
  176. &self,
  177. symbol: &S,
  178. parent_logger: &LOG,
  179. force: bool,
  180. ) -> Result<bool, Box<dyn Error>> {
  181. let logger = StoringLogger::new();
  182. logger.write(4, format!("Directly running {:?} ...", symbol));
  183. let result = self.symbol_runner.run_symbol(symbol, &logger, force).await;
  184. logger.write(4, "done.");
  185. let max_level = if result.is_err() { 5 } else { 3 };
  186. parent_logger.put(logger.release().into_iter().filter(|e| e.0 <= max_level));
  187. result
  188. }
  189. }