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.

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