assemble_core/dependencies/
configurations.rs1use crate::__export::TaskId;
4use crate::dependencies::{
5 AcquisitionError, Dependency, IntoDependency, RegistryContainer, ResolvedDependency,
6};
7use crate::file_collection::{FileCollection, FileSet};
8use crate::flow::shared::{Artifact, ImmutableArtifact};
9
10use crate::lazy_evaluation::Provider;
11use crate::prelude::ProjectResult;
12use crate::project::buildable::{Buildable, BuildableObject, BuiltByContainer, GetBuildable};
13
14use crate::Project;
15use once_cell::sync::OnceCell;
16use std::collections::HashSet;
17use std::fmt::{Debug, Display, Formatter};
18use std::path::PathBuf;
19use std::sync::{Arc, Mutex};
20use crate::error::PayloadError;
21
22#[derive(Debug, Clone)]
23pub struct Configuration {
24 inner: Arc<Mutex<ConfigurationInner>>,
25}
26
27impl Configuration {
28 pub(crate) fn new(name: &str, registry_container: &Arc<Mutex<RegistryContainer>>) -> Self {
30 Self {
31 inner: Arc::new(Mutex::new(ConfigurationInner {
32 name: name.to_string(),
33 parents: vec![],
34 dependencies: vec![],
35 resolved: OnceCell::new(),
36 built_by: OnceCell::new(),
37 registry_container: registry_container.clone(),
38 })),
39 }
40 }
41
42 fn inner<R, F: FnOnce(&mut ConfigurationInner) -> R>(&self, func: F) -> R {
43 let mut inner = self.inner.lock().unwrap();
44 (func)(&mut inner)
45 }
46
47 fn inner_mut<R, F: FnOnce(&mut ConfigurationInner) -> R>(&mut self, func: F) -> R {
48 let mut inner = self.inner.lock().unwrap();
49 if inner.resolved.get().is_some() {
50 panic!("{} already resolved", inner);
51 }
52 (func)(&mut inner)
53 }
54
55 pub fn resolved(&self) -> Result<ResolvedConfiguration, AcquisitionError> {
59 self.inner(ConfigurationInner::resolve)
60 }
61
62 pub fn add_dependency<D: IntoDependency>(&mut self, dependency: D)
64 where
65 D::IntoDep: 'static + Send + Sync,
66 {
67 let dependency = dependency.into_dependency();
68 self.inner_mut(move |config| config.dependencies.push(Box::new(dependency)))
69 }
70
71 pub fn extends_from(&mut self, other: &Configuration) {
73 self.inner_mut(|inner| {
74 inner.parents.push(other.clone());
75 })
76 }
77}
78
79impl Display for Configuration {
80 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
81 write!(f, "Configuration {:?}", self.inner.lock().unwrap().name)
82 }
83}
84
85impl Provider<FileSet> for Configuration {
86 fn try_get(&self) -> Option<FileSet> {
87 self.inner
88 .lock()
89 .unwrap()
90 .resolved
91 .get()
92 .map(|resolved| FileSet::from_iter(resolved.files()))
93 }
94}
95
96impl Buildable for Configuration {
97 fn get_dependencies(&self, project: &Project) -> ProjectResult<HashSet<TaskId>> {
98 self.inner.lock().map_err(PayloadError::new)?.get_dependencies(project)
99 }
100}
101
102struct ConfigurationInner {
103 name: String,
104 parents: Vec<Configuration>,
105 dependencies: Vec<Box<dyn Dependency + Send + Sync>>,
106 resolved: OnceCell<ResolvedConfiguration>,
107 built_by: OnceCell<BuildableObject>,
108
109 registry_container: Arc<Mutex<RegistryContainer>>,
110}
111
112impl ConfigurationInner {
113 fn resolve(&mut self) -> Result<ResolvedConfiguration, AcquisitionError> {
114 self.resolved
115 .get_or_try_init(|| {
116 let mut resolved = vec![];
117 let dependencies = self.dependencies.drain(..).collect::<Vec<_>>();
118
119 let mut built_by = BuiltByContainer::new();
120
121 'outer: for dependency in dependencies {
122 debug!("attempting to resolve {}", dependency);
123
124 built_by.add(dependency.as_buildable());
125
126 let registry_c = self.registry_container.lock().unwrap();
127 let mut errors = vec![];
128 let mut found = false;
129 for registry in registry_c.supported_registries(&dependency.dep_type()) {
130 match dependency.try_resolve(registry, registry_c.cache_location()) {
131 Ok(resolved_dep) => {
132 resolved.push(resolved_dep);
133
134 found = true;
135 continue 'outer;
136 }
137 Err(e) => {
138 errors.push(e);
139 }
140 }
141 }
142
143 if !found {
144 return Err(AcquisitionError::from_iter(errors));
145 }
146 }
147
148 self.built_by
149 .set(BuildableObject::from(built_by))
150 .expect("Shouldn't be set");
151
152 Ok(ResolvedConfiguration {
153 dependencies: resolved,
154 })
155 })
156 .map(|res| res.clone())
157 }
158}
159
160impl Buildable for ConfigurationInner {
161 fn get_dependencies(&self, project: &Project) -> ProjectResult<HashSet<TaskId>> {
163 self.built_by
164 .get()
165 .map(|b| b.get_dependencies(project))
166 .unwrap_or_else(|| {
167 let mut output = HashSet::new();
168 for dep in &self.dependencies {
169 trace!("Getting dependencies for dependency: {:#?}", dep);
170 let buildable = dep.as_buildable();
171 output.extend(buildable.get_dependencies(project)?);
172 }
173 Ok(output)
174 })
175 }
176}
177
178impl Debug for ConfigurationInner {
179 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
180 f.debug_struct(&format!("{}", self))
181 .field("parents", &self.parents)
182 .field("dependencies", &self.dependencies.len())
183 .field("is resolved", &self.resolved.get().is_some())
184 .finish()
185 }
186}
187
188impl Display for ConfigurationInner {
189 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
190 write!(f, "Configuration {:?}", self.name)
191 }
192}
193
194#[derive(Debug, Clone)]
196pub struct ResolvedConfiguration {
197 dependencies: Vec<ResolvedDependency>,
198}
199
200impl Display for ResolvedConfiguration {
201 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
202 let mut list = f.debug_list();
203 for dep in &self.dependencies {
204 let artifacts = dep
205 .artifacts()
206 .into_iter()
207 .map(|s| ImmutableArtifact::new(s).file())
208 .collect::<Vec<_>>();
209 list.entries(artifacts);
210 }
211 list.finish()
212 }
213}
214
215impl FileCollection for ResolvedConfiguration {
216 fn files(&self) -> HashSet<PathBuf> {
217 self.dependencies
218 .iter()
219 .flat_map(|dep| {
220 let artifact_files = dep.artifact_files();
221 artifact_files.files()
222 })
223 .collect()
224 }
225}