Skip to main content

flams_system/
lib.rs

1#![cfg_attr(docsrs, feature(doc_cfg))]
2//#![feature(file_buffered)]
3//#![feature(lazy_type_alias)]
4
5pub mod backend;
6//pub mod formats;
7pub 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
96/// #### Panics
97pub 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_max_level(Level::INFO)//(if debug {Level::TRACE} else {Level::INFO})
115            .with_ansi(false)
116            .with_target(true)
117            .with_writer(std::io::stderr)
118            .with_filter(tracing::level_filters::LevelFilter::from(Level::INFO)); //.init();
119        #[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}