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(fmt::layer().with_writer(bufcl).with_ansi(false));
38 let ret = tracing::subscriber::with_default(sub, f);
39 let s = buffer
40 .0
41 .lock()
42 .map(|mut l| String::from_utf8_lossy(&std::mem::take(&mut *l)).into_owned())
43 .unwrap_or_default();
44 (s, ret)
45}
46
47#[cfg(feature = "zip")]
48pub mod zip;
49
50use building::queue_manager::QueueManager;
51use flams_math_archives::{
52 artifacts::Artifact, backend::AnyBackend, utils::AsyncEngine, LocalArchive,
53};
54use ftml_uris::{DocumentUri, UriPath};
55use settings::SettingsSpec;
56
57pub use inventory::submit as register_exension;
58
59pub struct FlamsExtension {
60 pub name: &'static str,
61 pub on_start: fn(),
62 pub on_build_result: fn(&AnyBackend, &DocumentUri, &UriPath, &dyn Artifact),
63}
64
65#[cfg(feature = "tokio")]
66pub struct TokioEngine;
67#[cfg(feature = "tokio")]
68impl AsyncEngine for TokioEngine {
69 fn background(f: impl FnOnce() + Send + 'static) {
70 let span = tracing::Span::current();
71 tokio::task::spawn_blocking(move || span.in_scope(f));
72 }
73 async fn block_on<R: Send + Sync + 'static>(
74 f: impl FnOnce() -> R + Send + Sync + 'static,
75 ) -> R {
76 tokio::task::spawn_blocking(f).await.expect("this is a bug")
77 }
78 fn exec_after(delay: std::time::Duration, f: impl FnOnce() + Send + 'static) {
79 tokio::task::spawn(async move {
80 tokio::time::sleep(delay).await;
81 f();
82 });
83 }
84}
85
86inventory::collect!(FlamsExtension);
87
88pub fn initialize<A: AsyncEngine>(settings: SettingsSpec) {
90 settings::Settings::initialize(settings);
91 let settings = settings::Settings::get();
92 #[cfg(feature = "rocksdb")]
93 if let Some(p) = &settings.rdf_database {
94 flams_math_archives::backend::set_global(p);
95 }
96 if settings.lsp {
97 use tracing::Level;
98 use tracing_subscriber::layer::SubscriberExt;
99 use tracing_subscriber::Layer;
100 #[cfg(feature = "tokio")]
101 let logger = logging::LogStore::new();
102 let debug = settings.debug;
103 let level = if debug { Level::TRACE } else { Level::INFO };
104
105 let l = tracing_subscriber::fmt::layer()
106 .with_ansi(false)
108 .with_target(true)
109 .with_writer(std::io::stderr)
110 .with_filter(tracing::level_filters::LevelFilter::from(Level::INFO)); #[cfg(feature = "tokio")]
112 let sub = tracing_subscriber::registry()
113 .with(logger.with_filter(tracing::level_filters::LevelFilter::from(level)))
114 .with(l);
115 #[cfg(not(feature = "tokio"))]
116 let sub = tracing_subscriber::registry().with(l);
117 tracing::subscriber::set_global_default(sub)
118 .expect("Failed to set global default logging subscriber");
119 } else {
120 #[cfg(feature = "tokio")]
121 logging::LogStore::initialize();
122 }
123 tracing::info_span!(target:"initializing",parent:None,"initializing").in_scope(move || {
124 #[cfg(feature = "gitlab")]
125 {
126 if let Some(url) = &settings.gitlab_url {
127 let cfg = flams_git::gl::GitlabConfig::new(
128 url.clone(),
129 settings.gitlab_token.as_ref().map(ToString::to_string),
130 settings.gitlab_app_id.as_ref().map(ToString::to_string),
131 settings.gitlab_app_secret.as_ref().map(ToString::to_string),
132 );
133 flams_git::gl::GLInstance::global().clone().load(cfg);
134 }
135 }
136 backend::initialize::<A>();
137 QueueManager::initialize(settings.num_threads);
138 for e in inventory::iter::<FlamsExtension>() {
139 A::background(|| {
140 tracing::info_span!("Initializing", extension = e.name).in_scope(|| (e.on_start)());
141 });
142 }
143 });
144}
145
146#[cfg(feature = "gitlab")]
147pub trait LocalArchiveExt {
148 fn is_managed(&self) -> Option<&flams_git::GitUrl>;
149}
150
151#[cfg(feature = "gitlab")]
152impl LocalArchiveExt for LocalArchive {
153 fn is_managed(&self) -> Option<&flams_git::GitUrl> {
154 let gl = crate::settings::Settings::get().gitlab_url.as_ref()?;
155 self.git_url(gl)
156 }
157}