1use {
8 crate::{
9 binary_package_control::BinaryPackageControlFile,
10 dependency::{
11 BinaryDependency, DependencyVersionConstraint, PackageDependencyFields,
12 SingleDependency,
13 },
14 error::Result,
15 package_version::PackageVersion,
16 },
17 std::collections::{HashMap, HashSet, VecDeque},
18};
19
20#[derive(Clone, Debug)]
22pub struct BinaryPackageSingleDependencyResolution<'file, 'data: 'file> {
23 pub expression: SingleDependency,
24 pub candidates: Vec<&'file BinaryPackageControlFile<'data>>,
25}
26
27impl<'file, 'data: 'file> BinaryPackageSingleDependencyResolution<'file, 'data> {
28 pub fn is_empty(&self) -> bool {
30 self.candidates.is_empty()
31 }
32
33 pub fn packages(&self) -> impl Iterator<Item = &'file BinaryPackageControlFile<'data>> + '_ {
35 self.candidates.iter().copied()
36 }
37
38 pub fn packages_with_expression(
40 &self,
41 ) -> impl Iterator<Item = (&'_ SingleDependency, &'file BinaryPackageControlFile<'data>)> + '_
42 {
43 self.candidates.iter().map(|p| (&self.expression, *p))
44 }
45
46 pub fn group_by_package_name(
48 &self,
49 ) -> HashMap<&'file str, Vec<&'file BinaryPackageControlFile<'data>>> {
50 let mut h: HashMap<&str, Vec<&BinaryPackageControlFile>> = HashMap::new();
51
52 for cf in self.candidates.iter() {
53 let entry = h
54 .entry(cf.package().expect(
55 "Package field should have been validated during dependency resolution",
56 ))
57 .or_default();
58
59 entry.push(cf);
60 }
61
62 h
63 }
64}
65
66#[derive(Clone, Debug, Default)]
68pub struct BinaryPackageAlternativesResolution<'file, 'data: 'file> {
69 pub alternatives: Vec<BinaryPackageSingleDependencyResolution<'file, 'data>>,
70}
71
72impl<'file, 'data: 'file> BinaryPackageAlternativesResolution<'file, 'data> {
73 pub fn is_empty(&self) -> bool {
78 self.alternatives.is_empty() || self.alternatives.iter().any(|x| x.is_empty())
79 }
80
81 pub fn alternative_constraints(&self) -> impl Iterator<Item = &'_ SingleDependency> {
83 self.alternatives.iter().map(|alt| &alt.expression)
84 }
85
86 pub fn packages(&self) -> impl Iterator<Item = &'file BinaryPackageControlFile<'data>> + '_ {
90 self.alternatives.iter().flat_map(|alt| alt.packages())
91 }
92
93 pub fn packages_with_expression(
95 &self,
96 ) -> impl Iterator<Item = (&'_ SingleDependency, &'file BinaryPackageControlFile<'data>)> + '_
97 {
98 self.alternatives
99 .iter()
100 .flat_map(|alt| alt.packages_with_expression())
101 }
102
103 pub fn prune_empty(&mut self) {
107 self.alternatives = self
108 .alternatives
109 .drain(..)
110 .filter(|alt| !alt.is_empty())
111 .collect::<Vec<_>>();
112 }
113}
114
115#[derive(Clone, Debug, Default)]
117pub struct BinaryPackageDependenciesResolution<'file, 'data: 'file> {
118 pub parts: Vec<BinaryPackageAlternativesResolution<'file, 'data>>,
119}
120
121impl<'file, 'data: 'file> BinaryPackageDependenciesResolution<'file, 'data> {
122 pub fn packages(&self) -> impl Iterator<Item = &'file BinaryPackageControlFile<'data>> + '_ {
128 self.parts.iter().flat_map(|req| req.packages())
129 }
130
131 pub fn packages_with_expression(
133 &self,
134 ) -> impl Iterator<Item = (&'_ SingleDependency, &'file BinaryPackageControlFile<'data>)> + '_
135 {
136 self.parts
137 .iter()
138 .flat_map(|req| req.packages_with_expression())
139 }
140
141 pub fn empty_requirements(
143 &self,
144 ) -> impl Iterator<Item = &'_ BinaryPackageAlternativesResolution<'file, 'data>> {
145 self.parts.iter().filter(|alts| alts.is_empty())
146 }
147
148 pub fn has_unsatisfied(&self) -> bool {
152 self.empty_requirements().next().is_none()
153 }
154}
155
156#[derive(Clone, Debug)]
158pub struct BinaryPackageDependencySource<'file, 'data> {
159 pub package: &'file BinaryPackageControlFile<'data>,
161 pub field: BinaryDependency,
163 pub constraint: SingleDependency,
165}
166
167#[derive(Clone, Debug, Default)]
168pub struct BinaryPackageTransitiveDependenciesResolution<'file, 'data: 'file> {
169 evaluation_order: Vec<&'file BinaryPackageControlFile<'data>>,
170 reverse_dependencies: HashMap<
171 &'file BinaryPackageControlFile<'data>,
172 Vec<BinaryPackageDependencySource<'file, 'data>>,
173 >,
174}
175
176impl<'file, 'data: 'file> BinaryPackageTransitiveDependenciesResolution<'file, 'data> {
177 pub fn packages(&self) -> impl Iterator<Item = &'file BinaryPackageControlFile<'data>> + '_ {
183 self.evaluation_order.iter().rev().copied()
184 }
185
186 pub fn packages_with_sources(
191 &self,
192 ) -> impl Iterator<
193 Item = (
194 &'file BinaryPackageControlFile<'data>,
195 &'_ Vec<BinaryPackageDependencySource<'file, 'data>>,
196 ),
197 > + '_ {
198 self.evaluation_order.iter().rev().map(|key| {
199 (
200 *key,
201 self.reverse_dependencies
202 .get(key)
203 .expect("reverse dependencies should have key for all packages"),
204 )
205 })
206 }
207}
208
209#[derive(Clone, Debug)]
210struct BinaryPackageEntry<'file, 'data: 'file> {
211 file: &'file BinaryPackageControlFile<'data>,
212 name: String,
213 version: PackageVersion,
214 arch: String,
215 deps: PackageDependencyFields,
216}
217
218#[derive(Clone, Debug)]
219struct VirtualBinaryPackageEntry<'file, 'data: 'file> {
220 file: &'file BinaryPackageControlFile<'data>,
221
222 provided_version: Option<DependencyVersionConstraint>,
224
225 #[allow(unused)]
227 name: String,
228
229 #[allow(unused)]
231 version: PackageVersion,
232}
233
234#[derive(Clone, Debug, Default)]
236pub struct DependencyResolver<'file, 'data: 'file> {
237 binary_packages: HashMap<String, Vec<BinaryPackageEntry<'file, 'data>>>,
239
240 virtual_binary_packages: HashMap<String, Vec<VirtualBinaryPackageEntry<'file, 'data>>>,
242}
243
244impl<'file, 'data: 'file> DependencyResolver<'file, 'data> {
245 pub fn load_binary_packages(
250 &mut self,
251 files: impl Iterator<Item = &'file BinaryPackageControlFile<'data>>,
252 ) -> Result<()> {
253 for cf in files {
254 let package = cf.package()?;
255
256 let entry = BinaryPackageEntry {
257 file: cf,
258 name: package.to_string(),
259 version: cf.version()?,
260 arch: cf.architecture()?.to_string(),
261 deps: cf.package_dependency_fields()?,
262 };
263
264 if let Some(provides) = &entry.deps.provides {
265 for variants in provides.requirements() {
266 for dep in variants.iter() {
267 let virtual_entry = VirtualBinaryPackageEntry {
268 file: cf,
269 provided_version: dep.version_constraint.clone(),
270 name: entry.name.clone(),
271 version: entry.version.clone(),
272 };
273
274 self.virtual_binary_packages
275 .entry(dep.package.clone())
276 .or_default()
277 .push(virtual_entry);
278 }
279 }
280 }
281
282 self.binary_packages
283 .entry(package.to_string())
284 .or_default()
285 .push(entry);
286 }
287
288 Ok(())
289 }
290
291 pub fn find_direct_binary_package_dependencies(
296 &self,
297 cf: &BinaryPackageControlFile,
298 dep: BinaryDependency,
299 ) -> Result<BinaryPackageDependenciesResolution<'file, 'data>> {
300 let fields = cf.package_dependency_fields()?;
301
302 let mut res = BinaryPackageDependenciesResolution::default();
303
304 if let Some(deps) = fields.binary_dependency(dep) {
305 for req in deps.requirements() {
306 let mut variants_res = BinaryPackageAlternativesResolution::default();
307
308 for alt in req.iter() {
309 let mut deps_res = BinaryPackageSingleDependencyResolution {
310 expression: alt.clone(),
311 candidates: vec![],
312 };
313
314 if let Some(entries) = self.binary_packages.get(&alt.package) {
316 for entry in entries {
317 if alt.package_satisfies(&entry.name, &entry.version, &entry.arch) {
318 deps_res.candidates.push(entry.file);
319 }
320 }
321 }
322
323 if let Some(entries) = self.virtual_binary_packages.get(&alt.package) {
325 for entry in entries {
326 if alt.package_satisfies_virtual(
327 &alt.package,
328 entry.provided_version.as_ref(),
329 ) {
330 deps_res.candidates.push(entry.file);
331 }
332 }
333 }
334
335 variants_res.alternatives.push(deps_res);
336 }
337
338 res.parts.push(variants_res);
339 }
340 }
341
342 Ok(res)
343 }
344
345 pub fn find_transitive_binary_package_dependencies(
361 &self,
362 cf: &'file BinaryPackageControlFile<'data>,
363 fields: impl Iterator<Item = BinaryDependency>,
364 ) -> Result<BinaryPackageTransitiveDependenciesResolution<'file, 'data>> {
365 let fields = fields.collect::<Vec<_>>();
366
367 let mut remaining = VecDeque::new();
369 remaining.push_back(cf);
370
371 let mut evaluation_order = vec![];
374
375 let mut seen = HashSet::new();
376
377 let mut reverse_dependencies: HashMap<_, Vec<_>> = HashMap::new();
378 reverse_dependencies.insert(cf, vec![]);
379
380 while let Some(cf) = remaining.pop_front() {
382 if seen.contains(cf) {
384 continue;
385 }
386
387 for field in &fields {
388 let deps = self.find_direct_binary_package_dependencies(cf, *field)?;
389
390 for (expression, package) in deps.packages_with_expression() {
395 reverse_dependencies.entry(package).or_default().push(
396 BinaryPackageDependencySource {
397 package: cf,
398 field: *field,
399 constraint: expression.clone(),
400 },
401 );
402 }
403
404 remaining.extend(deps.packages());
405 }
406
407 evaluation_order.push(cf);
408 seen.insert(cf);
409 }
410
411 Ok(BinaryPackageTransitiveDependenciesResolution {
412 evaluation_order,
413 reverse_dependencies,
414 })
415 }
416}