assemble_core/dependencies/
dependency_container.rs

1use crate::dependencies::configurations::Configuration;
2use crate::dependencies::RegistryContainer;
3use crate::identifier::ProjectId;
4
5use std::collections::HashMap;
6use std::sync::{Arc, Mutex};
7
8#[derive(Debug)]
9pub struct ConfigurationHandler {
10    owner: ProjectId,
11    registries: Arc<Mutex<RegistryContainer>>,
12    configurations: HashMap<String, Configuration>,
13}
14
15unsafe impl Send for ConfigurationHandler {}
16unsafe impl Sync for ConfigurationHandler {}
17
18impl ConfigurationHandler {
19    pub(crate) fn new(owner: ProjectId, registries: &Arc<Mutex<RegistryContainer>>) -> Self {
20        Self {
21            owner,
22            registries: registries.clone(),
23            configurations: Default::default(),
24        }
25    }
26
27    /// Create a [`Configuration`](Configuration) with a given `name`.
28    ///
29    /// Returns `None` if configuration already exists.
30    pub fn create<S: AsRef<str>>(&mut self, name: S) -> &mut Configuration {
31        let name = name.as_ref();
32        if self.configurations.contains_key(name) {
33            panic!("configuration with name {:?} already exists", name);
34        }
35
36        self.configurations
37            .insert(name.to_string(), Configuration::new(name, &self.registries));
38        self.get_mut(name).unwrap()
39    }
40
41    /// Create a [`Configuration`](Configuration) with a given `name`.
42    ///
43    /// Returns `None` if configuration already exists.
44    pub fn create_with<S, F>(&mut self, name: S, configure: F) -> &mut Configuration
45    where
46        S: AsRef<str>,
47        F: FnOnce(&mut Configuration),
48    {
49        self.create(name.as_ref());
50        let mutable = self.get_mut(name.as_ref()).unwrap();
51        (configure)(mutable);
52        self.get_mut(name.as_ref()).unwrap()
53    }
54
55    /// Get a reference configuration if it exists
56    pub fn get<S: AsRef<str>>(&self, name: S) -> Option<&Configuration> {
57        self.configurations.get(name.as_ref())
58    }
59
60    /// Get a mutable reference to a configuration if it exists
61    pub fn get_mut<S: AsRef<str>>(&mut self, name: S) -> Option<&mut Configuration> {
62        self.configurations.get_mut(name.as_ref())
63    }
64
65    /// Get the owner of this handler
66    pub fn owner(&self) -> &ProjectId {
67        &self.owner
68    }
69}
70
71#[cfg(test)]
72mod tests {
73    use super::*;
74
75    use crate::dependencies::RegistryContainer;
76    use crate::file_collection::FileCollection;
77    use crate::flow::output::SinglePathOutputTask;
78
79    use crate::project::buildable::Buildable;
80
81    use crate::task::create_task::CreateTask;
82
83    use crate::task::initialize_task::InitializeTask;
84    use crate::task::task_io::TaskIO;
85    use crate::task::up_to_date::UpToDate;
86
87    use crate::{BuildResult, Executable, Project, Task};
88    use std::collections::HashSet;
89    use std::fmt::Debug;
90    use std::path::PathBuf;
91    use tempfile::TempDir;
92
93    #[test]
94    fn file_only_configuration() {
95        let registries = Arc::new(Mutex::new(RegistryContainer::new()));
96
97        let mut dependency_container = ConfigurationHandler::new(ProjectId::default(), &registries);
98
99        let temp_dir = TempDir::new().unwrap();
100
101        let file1 = temp_dir.path().join("file1.txt");
102        let file2 = temp_dir.path().join("file2.txt");
103
104        let deps = dependency_container.create_with("libs", |config| {
105            config.add_dependency(file1.clone());
106            config.add_dependency(file2.clone());
107        });
108
109        let resolved = deps.resolved().expect("couldn't resolve configuration");
110
111        println!("resolved = {:#}", resolved);
112
113        assert_eq!(resolved.files(), HashSet::from_iter([file1, file2]));
114    }
115
116    #[test]
117    fn add_artifact_task() {
118        #[derive(Debug, Default)]
119        struct TestArtifactTask;
120
121        impl UpToDate for TestArtifactTask {}
122        impl InitializeTask for TestArtifactTask {}
123        impl TaskIO for TestArtifactTask {}
124
125        impl Task for TestArtifactTask {
126            fn task_action(_task: &mut Executable<Self>, _project: &Project) -> BuildResult {
127                todo!()
128            }
129        }
130
131        impl SinglePathOutputTask for TestArtifactTask {
132            fn get_path(_task: &Executable<Self>) -> PathBuf {
133                PathBuf::from("test.txt")
134            }
135        }
136
137        let registries = Arc::new(Mutex::new(RegistryContainer::new()));
138
139        let mut dependency_container = ConfigurationHandler::new(ProjectId::default(), &registries);
140
141        let project = Project::temp("temp");
142        let task = project
143            .register_task::<TestArtifactTask>("artifactExample")
144            .unwrap();
145
146        let deps = dependency_container.create_with("libs", |config| {
147            config.add_dependency(task.clone());
148        });
149
150        let built_by = project.with(|p| deps.get_dependencies(p)).unwrap();
151        assert_eq!(
152            deps.resolved().unwrap().files(),
153            HashSet::from_iter([PathBuf::from("test.txt")])
154        );
155        assert_eq!(built_by, HashSet::from_iter([task.id().clone()]))
156    }
157}