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.

191 lines
5.8 KiB

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