1#![cfg_attr(docsrs, feature(doc_cfg))]
2pub mod backend;
6pub mod building;
8#[cfg(feature = "tokio")]
9pub mod logging;
10pub mod settings;
11
12pub fn span_capture<R>(f: impl FnOnce() -> R) -> (String, R) {
13 use tracing_subscriber::{fmt, layer::SubscriberExt};
14 #[derive(Clone)]
15 struct Buffer(std::sync::Arc<std::sync::Mutex<Vec<u8>>>);
16 impl std::io::Write for &Buffer {
17 fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
18 if let Ok(mut l) = self.0.lock() {
19 l.extend_from_slice(buf);
20 }
21 Ok(buf.len())
22 }
23 #[inline]
24 fn flush(&mut self) -> std::io::Result<()> {
25 Ok(())
26 }
27 }
28 impl<'a> fmt::MakeWriter<'a> for Buffer {
29 type Writer = &'a Self;
30 #[inline]
31 fn make_writer(&'a self) -> Self::Writer {
32 self
33 }
34 }
35 let buffer = Buffer(std::sync::Arc::new(std::sync::Mutex::new(Vec::<u8>::new())));
36 let bufcl = buffer.clone();
37 let sub = tracing_subscriber::registry().with(
38 fmt::layer()
39 .with_writer(bufcl)
40 .with_ansi(false)
41 .with_filter(tracing_subscriber::filter::LevelFilter::INFO),
42 );
43 let ret = tracing::subscriber::with_default(sub, f);
44 let s = buffer
45 .0
46 .lock()
47 .map(|mut l| String::from_utf8_lossy(&std::mem::take(&mut *l)).into_owned())
48 .unwrap_or_default();
49 (s, ret)
50}
51
52#[cfg(feature = "zip")]
53pub mod zip;
54
55use building::queue_manager::QueueManager;
56use flams_math_archives::{
57 artifacts::Artifact, backend::AnyBackend, utils::AsyncEngine, LocalArchive,
58};
59use ftml_uris::{DocumentUri, UriPath};
60use settings::SettingsSpec;
61
62pub use inventory::iter;
63pub use inventory::submit as register_exension;
64use tracing_subscriber::Layer;
65
66pub struct FlamsExtension {
67 pub name: &'static str,
68 pub on_start: fn(),
69 pub on_build_result: fn(&AnyBackend, &DocumentUri, &UriPath, &dyn Artifact),
70 pub on_reload: fn(),
71}
72
73#[cfg(feature = "tokio")]
74pub struct TokioEngine;
75#[cfg(feature = "tokio")]
76impl AsyncEngine for TokioEngine {
77 fn background(f: impl FnOnce() + Send + 'static) {
78 let span = tracing::Span::current();
79 tokio::task::spawn_blocking(move || span.in_scope(f));
80 }
81 async fn block_on<R: Send + Sync + 'static>(
82 f: impl FnOnce() -> R + Send + Sync + 'static,
83 ) -> R {
84 tokio::task::spawn_blocking(f).await.expect("this is a bug")
85 }
86 fn exec_after(delay: std::time::Duration, f: impl FnOnce() + Send + 'static) {
87 tokio::task::spawn(async move {
88 tokio::time::sleep(delay).await;
89 f();
90 });
91 }
92}
93
94inventory::collect!(FlamsExtension);
95
96pub fn initialize<A: AsyncEngine>(settings: SettingsSpec) {
98 settings::Settings::initialize(settings);
99 let settings = settings::Settings::get();
100 #[cfg(feature = "rocksdb")]
101 if let Some(p) = &settings.rdf_database {
102 flams_math_archives::backend::set_global(p);
103 }
104 if settings.lsp {
105 use tracing::Level;
106 use tracing_subscriber::layer::SubscriberExt;
107 use tracing_subscriber::Layer;
108 #[cfg(feature = "tokio")]
109 let logger = logging::LogStore::new();
110 let debug = settings.debug;
111 let level = if debug { Level::TRACE } else { Level::INFO };
112
113 let l = tracing_subscriber::fmt::layer()
114 .with_ansi(false)
116 .with_target(true)
117 .with_writer(std::io::stderr)
118 .with_filter(tracing::level_filters::LevelFilter::from(Level::INFO)); #[cfg(feature = "tokio")]
120 let sub = tracing_subscriber::registry()
121 .with(logger.with_filter(tracing::level_filters::LevelFilter::from(level)))
122 .with(l);
123 #[cfg(not(feature = "tokio"))]
124 let sub = tracing_subscriber::registry().with(l);
125 tracing::subscriber::set_global_default(sub)
126 .expect("Failed to set global default logging subscriber");
127 } else {
128 #[cfg(feature = "tokio")]
129 logging::LogStore::initialize();
130 }
131 tracing::info_span!(target:"initializing",parent:None,"initializing").in_scope(move || {
132 #[cfg(feature = "gitlab")]
133 {
134 if let Some(url) = &settings.gitlab_url {
135 let cfg = flams_git::gl::GitlabConfig::new(
136 url.clone(),
137 settings.gitlab_token.as_ref().map(ToString::to_string),
138 settings.gitlab_app_id.as_ref().map(ToString::to_string),
139 settings.gitlab_app_secret.as_ref().map(ToString::to_string),
140 );
141 flams_git::gl::GLInstance::global().clone().load(cfg);
142 }
143 }
144 backend::initialize::<A>();
145 QueueManager::initialize(settings.num_threads);
146 for e in inventory::iter::<FlamsExtension>() {
147 A::background(|| {
148 tracing::info_span!("Initializing", extension = e.name).in_scope(|| (e.on_start)());
149 });
150 }
151 });
152}
153
154#[cfg(feature = "gitlab")]
155pub trait LocalArchiveExt {
156 fn is_managed(&self) -> Option<&flams_git::GitUrl>;
157}
158
159#[cfg(feature = "gitlab")]
160impl LocalArchiveExt for LocalArchive {
161 fn is_managed(&self) -> Option<&flams_git::GitUrl> {
162 let gl = crate::settings::Settings::get().gitlab_url.as_ref()?;
163 self.git_url(gl)
164 }
165}