flams_system/building/
mod.rs

1use std::{
2    any::Any,
3    num::NonZeroU32,
4    path::{Path, PathBuf},
5};
6
7use either::Either;
8use flams_ontology::uris::{
9    ArchiveId, ArchiveURI, ArchiveURIRef, ArchiveURITrait, DocumentURI, ModuleURI, URIRefTrait,
10};
11use flams_utils::{
12    time::Eta,
13    triomphe::Arc,
14    vecmap::{VecMap, VecSet},
15};
16use parking_lot::RwLock;
17
18use crate::formats::{BuildArtifactTypeId, BuildTargetId};
19
20mod queue;
21pub mod queue_manager;
22pub use queue::QueueName;
23mod queueing;
24
25lazy_static::lazy_static! {
26    pub(crate) static ref BUILD_QUEUE_SPAN:tracing::Span = {
27            //println!("Here!");
28            tracing::info_span!(target:"build queue",parent:None,"Build Queue")
29    };
30}
31
32#[cfg(all(test, feature = "tokio"))]
33mod tests;
34
35pub use queue::Queue;
36
37#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
38pub enum TaskState {
39    Running,
40    Queued,
41    Blocked,
42    Done,
43    Failed,
44    None,
45}
46
47#[derive(Debug, Clone, Hash, PartialEq, Eq)]
48pub struct TaskRef {
49    pub archive: ArchiveId,
50    pub rel_path: std::sync::Arc<str>,
51    pub target: BuildTargetId,
52}
53
54#[derive(Debug, Clone, PartialEq, Eq)]
55pub enum Dependency {
56    Physical {
57        task: TaskRef,
58        strict: bool,
59    },
60    Logical {
61        uri: ModuleURI,
62        strict: bool,
63    },
64    Resolved {
65        task: BuildTask,
66        step: BuildTargetId,
67        strict: bool,
68    },
69}
70
71#[derive(Copy, Clone, Debug, PartialEq, Eq)]
72pub struct BuildTaskId(NonZeroU32);
73impl From<BuildTaskId> for u32 {
74    #[inline]
75    fn from(id: BuildTaskId) -> Self {
76        id.0.get()
77    }
78}
79
80#[derive(Debug, PartialEq, Eq)]
81struct BuildTaskI {
82    id: BuildTaskId,
83    archive: ArchiveURI,
84    steps: Box<[BuildStep]>,
85    source: Either<PathBuf, String>,
86    rel_path: std::sync::Arc<str>,
87}
88
89#[derive(Debug, Clone, PartialEq, Eq)]
90pub struct BuildTask(Arc<BuildTaskI>);
91impl BuildTask {
92    #[must_use]
93    #[inline]
94    pub fn document_uri(&self) -> eyre::Result<DocumentURI> {
95        DocumentURI::from_archive_relpath(self.archive().owned(), self.rel_path())
96    }
97    #[must_use]
98    pub fn get_task_ref(&self, target: BuildTargetId) -> TaskRef {
99        TaskRef {
100            archive: self.0.archive.archive_id().clone(),
101            rel_path: self.0.rel_path.clone(),
102            target,
103        }
104    }
105
106    #[inline]
107    #[must_use]
108    pub fn source(&self) -> Either<&Path, &str> {
109        match &self.0.source {
110            Either::Left(p) => Either::Left(p),
111            Either::Right(s) => Either::Right(s),
112        }
113    }
114
115    #[inline]
116    #[must_use]
117    pub fn archive(&self) -> ArchiveURIRef {
118        self.0.archive.archive_uri()
119    }
120
121    #[inline]
122    #[must_use]
123    pub fn rel_path(&self) -> &str {
124        &self.0.rel_path
125    }
126
127    #[inline]
128    #[must_use]
129    pub fn steps(&self) -> &[BuildStep] {
130        &self.0.steps
131    }
132
133    #[inline]
134    #[must_use]
135    pub fn get_step(&self, target: BuildTargetId) -> Option<&BuildStep> {
136        self.0.steps.iter().find(|s| s.0.target == target)
137    }
138
139    #[must_use]
140    #[allow(clippy::cast_possible_truncation)]
141    pub fn as_message(&self) -> QueueEntry {
142        /*let idx = self.steps().iter().enumerate().find(|s|
143            matches!(&*s.1.0.state.read(),TaskState::Running | TaskState::Queued | TaskState::Blocked | TaskState::Failed)
144        );
145        let idx = if let Some((idx,_)) = idx {(idx - 1) as u8} else {self.steps().len() as u8};
146        */
147        QueueEntry {
148            id: self.0.id,
149            archive: self.0.archive.archive_id().clone(),
150            rel_path: self.0.rel_path.clone(),
151            steps: self
152                .steps()
153                .iter()
154                .map(|s| (s.0.target, *s.0.state.read()))
155                .collect(),
156        }
157    }
158}
159
160#[derive(Debug)]
161struct BuildStepI {
162    //task:std::sync::Weak<BuildTaskI>,
163    target: BuildTargetId,
164    state: RwLock<TaskState>,
165    //yields:RwLock<Vec<ModuleURI>>,
166    requires: RwLock<VecSet<Dependency>>,
167    dependents: RwLock<Vec<(BuildTaskId, BuildTargetId)>>,
168}
169impl PartialEq for BuildStepI {
170    fn eq(&self, other: &Self) -> bool {
171        self.target == other.target
172    }
173}
174impl Eq for BuildStepI {}
175
176#[derive(Debug, Clone, PartialEq, Eq)]
177pub struct BuildStep(Arc<BuildStepI>);
178impl BuildStep {
179    pub fn add_dependency(&self, dep: Dependency) {
180        self.0.requires.write().insert(dep);
181    }
182    /*
183    #[must_use]
184    pub fn get_task(&self) -> BuildTask {
185        BuildTask(self.0.task.upgrade().unwrap_or_else(|| unreachable!()))
186    }
187    */
188}
189
190pub trait BuildArtifact: Any + 'static {
191    fn get_type_id() -> BuildArtifactTypeId
192    where
193        Self: Sized;
194    /// #### Errors
195    fn load(p: &Path) -> Result<Self, std::io::Error>
196    where
197        Self: Sized;
198    fn get_type(&self) -> BuildArtifactTypeId;
199    /// ### Errors
200    fn write(&self, path: &Path) -> Result<(), std::io::Error>;
201    fn as_any(&self) -> &dyn Any;
202}
203
204pub enum BuildResultArtifact {
205    File(BuildArtifactTypeId, PathBuf),
206    Data(Box<dyn BuildArtifact>),
207    None,
208}
209
210pub struct BuildResult {
211    pub log: Either<String, PathBuf>,
212    pub result: Result<BuildResultArtifact, Vec<Dependency>>,
213}
214impl BuildResult {
215    #[must_use]
216    #[inline]
217    pub const fn empty() -> Self {
218        Self {
219            log: Either::Left(String::new()),
220            result: Ok(BuildResultArtifact::None),
221        }
222    }
223    #[must_use]
224    #[inline]
225    pub const fn err() -> Self {
226        Self {
227            log: Either::Left(String::new()),
228            result: Err(Vec::new()),
229        }
230    }
231
232    #[inline]
233    pub fn with_err(s: String) -> Self {
234        Self {
235            log: Either::Left(s),
236            result: Err(Vec::new()),
237        }
238    }
239}
240
241#[derive(Debug, Clone)]
242pub struct QueueEntry {
243    pub id: BuildTaskId,
244    pub archive: ArchiveId,
245    pub rel_path: std::sync::Arc<str>,
246    pub steps: VecMap<BuildTargetId, TaskState>,
247}
248
249#[derive(Debug, Clone)]
250pub enum QueueMessage {
251    Idle(Vec<QueueEntry>),
252    Started {
253        running: Vec<QueueEntry>,
254        queue: Vec<QueueEntry>,
255        blocked: Vec<QueueEntry>,
256        failed: Vec<QueueEntry>,
257        done: Vec<QueueEntry>,
258    },
259    Finished {
260        failed: Vec<QueueEntry>,
261        done: Vec<QueueEntry>,
262    },
263    TaskStarted {
264        id: BuildTaskId,
265        target: BuildTargetId,
266    },
267    TaskSuccess {
268        id: BuildTaskId,
269        target: BuildTargetId,
270        eta: Eta,
271    },
272    TaskFailed {
273        id: BuildTaskId,
274        target: BuildTargetId,
275        eta: Eta,
276    },
277}