1use std::{
2 cmp::Ordering,
3 collections::{HashMap, HashSet},
4 fmt::Debug,
5};
6
7use fmri::{FMRIList, FMRI};
8
9use crate::problems::Problem::SamePackageHasTwoPublishers;
10use crate::{
11 clone, downgrade, get, get_mut, new,
12 packages::{
13 dependency_type::{
14 DependencyTypes,
15 DependencyTypes::{Build, Runtime, SystemBuild, SystemTest, Test},
16 },
17 package::Package,
18 rev_depend_type::{RevDependType, RevDependType::*},
19 },
20 problems::{
21 Problem,
22 Problem::{
23 MissingComponentForPackage, NonExistingPackageInPkg5, NonExistingRequired,
24 NonExistingRequiredByRenamed, ObsoletedPackageInComponent, ObsoletedRequired,
25 ObsoletedRequiredByRenamed, PartlyObsoletedRequired, PartlyObsoletedRequiredByRenamed,
26 RenamedNeedsRenamed, RenamedPackageInComponent, UselessComponent,
27 },
28 },
29 shared_type, weak_type, DependTypes, Problems,
30};
31
32#[derive(Default, Clone, Debug)]
33pub struct Components {
34 pub(crate) components: Vec<shared_type!(Component)>,
36 pub(crate) hash_components: HashMap<String, shared_type!(Component)>,
37 pub(crate) packages: Vec<shared_type!(Package)>,
39 pub(crate) hash_packages: HashMap<String, shared_type!(Package)>,
40 pub problems: Problems,
41}
42
43impl Components {
44 pub fn add_package(&mut self, mut package: Package) {
45 let package_name = package.fmri.clone().get_package_name_as_string();
46
47 let mut existing_package = get_mut!(match self.get_package_by_fmri(&package.fmri) {
48 Ok(e) => e,
49 Err(_) => {
50 let rc_package = new!(package);
51 self.packages.push(clone!(&rc_package));
52 self.hash_packages.insert(package_name, rc_package);
53 return;
54 }
55 });
56
57 let mut existing_package_versions = existing_package.get_versions().clone();
58 existing_package_versions.sort_by(|a, b| a.version.cmp(&b.version));
59 package.versions.sort_by(|a, b| a.version.cmp(&b.version));
60
61 let o = existing_package_versions.first().unwrap();
62 let n = package.versions.first().unwrap();
63
64 match (o.is_obsolete(), n.is_obsolete()) {
65 (true, false) => {
66 match o.version.cmp(&n.version) {
67 Ordering::Equal | Ordering::Less => {
68 *existing_package = package;
71 }
72 Ordering::Greater => {
73 let p_a = existing_package.fmri.clone().get_publisher().unwrap();
76 let p_b = package.fmri.clone().get_publisher().unwrap();
77
78 drop(existing_package);
79
80 self.problems.add_problem(SamePackageHasTwoPublishers(
81 package.fmri.clone(),
82 p_a.clone(),
83 p_b.clone(),
84 None,
85 ));
86 }
87 }
88 }
89 (false, true) => {
90 match o.version.cmp(&n.version) {
91 Ordering::Equal | Ordering::Less => {
92 let p_a = existing_package.fmri.clone().get_publisher().unwrap();
95 let p_b = package.fmri.clone().get_publisher().unwrap();
96
97 drop(existing_package);
98
99 self.problems.add_problem(SamePackageHasTwoPublishers(
100 package.fmri.clone(),
101 p_a.clone(),
102 p_b.clone(),
103 None,
104 ));
105 }
106 Ordering::Greater => {
107 }
109 }
110 }
111 (false, false) => {
112 let p_a = existing_package.fmri.clone().get_publisher().unwrap();
115 let p_b = package.fmri.clone().get_publisher().unwrap();
116
117 drop(existing_package);
118
119 self.problems.add_problem(SamePackageHasTwoPublishers(
120 package.fmri.clone(),
121 p_a.clone(),
122 p_b.clone(),
123 Some(match o.version.cmp(&n.version) {
124 Ordering::Equal => p_a,
125 Ordering::Greater | Ordering::Less => p_b,
126 }),
127 ));
128 }
129 (true, true) => {
130 }
132 }
133 }
134
135 pub fn new_component(
136 &mut self,
137 component_name: String,
138 packages: Vec<FMRI>,
139 ) -> Result<(), String> {
140 let rc_component = new!(Component::new(component_name.clone()));
141
142 for fmri in packages {
143 let res = match self.get_package_by_fmri(&fmri) {
144 Ok(rc_package) => {
145 get_mut!(rc_component).add_package(downgrade!(rc_package));
146 get_mut!(rc_package).set_component(clone!(&rc_component))
147 }
148 Err(_) => Some(Box::new(NonExistingPackageInPkg5(
149 fmri,
150 component_name.clone(),
151 ))),
152 };
153
154 if let Some(p) = res {
155 self.problems.add_problem(*p);
156 }
157 }
158
159 self.components.push(clone!(&rc_component));
160 self.hash_components.insert(component_name, rc_component);
161
162 Ok(())
163 }
164
165 pub fn get_component_by_name(&self, name: &String) -> Result<&shared_type!(Component), String> {
166 return match self.hash_components.get(name) {
167 None => Err(format!("component {} does not exist", name)),
168 Some(component) => Ok(component),
169 };
170 }
171
172 pub fn get_package_by_fmri(&self, fmri: &FMRI) -> Result<&shared_type!(Package), String> {
173 return match self
174 .hash_packages
175 .get(fmri.get_package_name_as_ref_string())
176 {
177 None => Err(format!("package {} does not exist", fmri)),
178 Some(package) => Ok(package),
179 };
180 }
181
182 pub fn get_components(&self) -> &Vec<shared_type!(Component)> {
183 &self.components
184 }
185
186 pub fn get_packages(&self) -> &Vec<shared_type!(Package)> {
187 &self.packages
188 }
189
190 pub fn add_repo_dependencies(
192 &mut self,
193 component_name: &String,
194 dependencies: Vec<FMRI>,
195 dependency_type: &DependencyTypes,
196 ) -> Result<(), String> {
197 for fmri in dependencies {
198 let rc_package = if let Ok(p) = self.get_package_by_fmri(&fmri) {
199 p
200 } else {
201 self.problems.add_problem(NonExistingRequired(
202 DependTypes::Require(fmri),
203 dependency_type.clone(),
204 FMRI::parse_raw("none").unwrap(),
205 component_name.clone(),
206 ));
207
208 continue;
209 };
210
211 let component = self
212 .get_component_by_name(component_name)
213 .map_err(|e| format!("failed to get component: {}", e))?;
214
215 let mut component_mut = get_mut!(component);
216
217 match dependency_type {
218 Build => component_mut.build.push(downgrade!(rc_package)),
219 Test => component_mut.test.push(downgrade!(rc_package)),
220 SystemBuild => component_mut.sys_build.push(downgrade!(rc_package)),
221 SystemTest => component_mut.sys_test.push(downgrade!(rc_package)),
222 Runtime => {
223 return Err("can not insert runtime dependencies into component".to_owned())
224 }
225 }
226
227 get_mut!(rc_package)
228 .add_dependent(clone!(component), dependency_type)
229 .map_err(|e| format!("failed to add dependent: {}", e))?;
230 }
231
232 Ok(())
233 }
234
235 pub fn set_package_obsolete(&mut self, fmri: FMRI) -> Result<(), String> {
236 let mut fmri_clone = fmri.clone();
237 let rc_package = self
238 .get_package_by_fmri(fmri_clone.remove_version())
239 .map_err(|e| format!("failed to get package: {}", e))?;
240
241 match fmri.get_version() {
242 None => get_mut!(rc_package).set_obsolete(true),
243 Some(fmri_version) => {
244 for version in get_mut!(rc_package).get_versions_mut() {
245 if version.version == fmri_version {
246 version.set_obsolete(true);
247 }
248 }
249 }
250 }
251
252 Ok(())
253 }
254
255 pub fn set_package_renamed(&mut self, fmri: FMRI) -> Result<(), String> {
256 let mut fmri_clone = fmri.clone();
257 let rc_package = self
258 .get_package_by_fmri(fmri_clone.remove_version())
259 .map_err(|e| format!("failed to get package: {}", e))?;
260
261 match fmri.get_version() {
262 None => get_mut!(rc_package).set_renamed(true),
263 Some(fmri_version) => {
264 for version in get_mut!(rc_package).get_versions_mut() {
265 if version.version == fmri_version {
266 version.set_renamed(true);
267 }
268 }
269 }
270 }
271
272 Ok(())
273 }
274
275 pub fn distribute_reverse_runtime_dependencies(&mut self) {
277 let mut rev_run_deps: HashMap<FMRI, HashSet<RevDependType>> = HashMap::new();
278
279 let mut add = |fmri: FMRI, rev_depend_type: RevDependType| {
280 rev_run_deps
281 .entry(fmri)
282 .or_default()
283 .insert(rev_depend_type);
284 };
285
286 for p in &*self.packages {
287 let package = get!(p);
288 for version in &package.versions {
289 for d in &version.runtime {
290 match d.clone() {
291 DependTypes::Require(f) => add(f, Require(package.fmri.clone())),
292 DependTypes::Optional(f) => add(f, Optional(package.fmri.clone())),
293 DependTypes::Incorporate(f) => add(f, Incorporate(package.fmri.clone())),
294 DependTypes::RequireAny(l) => {
295 for f in l.get() {
296 add(f, Require(package.fmri.clone()))
297 }
298 }
299 DependTypes::Conditional(f, p) => {
300 add(f, ConditionalFmri(package.fmri.clone()));
301 add(p, ConditionalPredicate(package.fmri.clone()));
302 }
303 DependTypes::Group(f) => add(f, Group(package.fmri.clone())),
304 _ => unimplemented!(),
305 };
306 }
307 }
308 }
309
310 for (fmri, hash_rev_deps) in rev_run_deps {
311 let mut rev_deps = hash_rev_deps
312 .iter()
313 .cloned()
314 .collect::<Vec<RevDependType>>();
315
316 match self.get_package_by_fmri(&fmri) {
317 Ok(package) => get_mut!(package).runtime_dependents.append(&mut rev_deps),
318 Err(_) => {
319 for rev_dep in rev_deps {
320 let (f, d_type) = match rev_dep {
321 Require(f) => (f, DependTypes::Require(fmri.clone())),
322 Optional(f) => (f, DependTypes::Optional(fmri.clone())),
323 Incorporate(f) => (f, DependTypes::Incorporate(fmri.clone())),
324 RequireAny(f) => (
325 f,
326 DependTypes::RequireAny(FMRIList::from(vec![fmri.clone()])),
327 ),
328 ConditionalFmri(f) => (
329 f,
330 DependTypes::Conditional(
331 fmri.clone(),
332 FMRI::parse_raw("none").unwrap(),
333 ),
334 ),
335 ConditionalPredicate(f) => (
336 f,
337 DependTypes::Conditional(
338 FMRI::parse_raw("none").unwrap(),
339 fmri.clone(),
340 ),
341 ),
342 Group(f) => (f, DependTypes::Group(fmri.clone())),
343 };
344
345 self.problems
346 .add_problem(match self.get_package_by_fmri(&f) {
347 Ok(p) => match get!(p).is_renamed() {
348 true => NonExistingRequiredByRenamed(d_type, Runtime, f),
349 false => NonExistingRequired(d_type, Runtime, f, "".to_owned()),
350 },
351 Err(_) => {
352 panic!("non existing as required by non existing?")
353 }
354 });
355 }
356 }
357 }
358 }
359 }
360
361 pub fn remove_old_versions(&mut self) {
362 for p in &mut self.packages {
363 let mut package = get_mut!(p);
364
365 package.versions.sort_by(|a, b| b.version.cmp(&a.version));
366
367 let mut new_ver = package.versions.first().unwrap().clone();
368
369 for ver in &package.versions {
370 if !ver.is_obsolete() && !ver.is_renamed() {
371 new_ver = ver.clone();
372 break;
373 }
374 }
375
376 package.change_versions(vec![new_ver]);
377 }
378 }
379
380 pub fn check_problems(&mut self) -> Result<(), String> {
381 for c in &*self.components {
383 let component = get!(c);
384 for p in &component.packages {
385 let t = p.upgrade().unwrap();
386 let package = get!(t);
387 if package.is_obsolete() {
388 self.problems.add_problem(ObsoletedPackageInComponent(
389 package.fmri.clone(),
390 component.name.clone(),
391 ));
392 } else if package.is_renamed() {
393 self.problems.add_problem(RenamedPackageInComponent(
394 package.fmri.clone(),
395 component.name.clone(),
396 ));
397 }
398 }
399 }
400
401 for p in &*self.packages {
403 let package = get!(p);
404
405 if package.is_in_component().is_none()
406 && !package.is_renamed()
407 && !package.is_obsolete()
408 {
409 self.problems
410 .add_problem(MissingComponentForPackage(package.fmri.clone()));
411 }
412 }
413
414 'main: for c in &*self.components {
416 let component = get!(c);
417 if component.packages.iter().all(|p| {
418 let tmp = p.upgrade().unwrap();
419 let package = get!(tmp);
420
421 if package.is_obsolete() || package.is_renamed() {
422 return false;
423 }
424
425 for dep in &package.runtime_dependents {
426 if let Incorporate(_) = dep {
427 } else {
428 return false;
429 }
430 }
431
432 if package.build_dependents.is_empty()
433 && package.test_dependents.is_empty()
434 && package.sys_build_dependents.is_empty()
435 && package.sys_build_dependents.is_empty()
436 {
437 return true;
438 }
439
440 false
441 }) {
442 self.problems
443 .add_problem(UselessComponent(component.get_name().clone()));
444 } else {
445 let name = component.name.clone();
446 let packages_fmris = component
447 .packages
448 .iter()
449 .map(|p| get!(p.upgrade().unwrap()).fmri.clone())
450 .collect::<Vec<FMRI>>();
451
452 let packages = component.packages.clone();
453
454 drop(component);
455
456 for p in packages.iter().map(|a| a.upgrade().unwrap()) {
457 let package = get!(p);
458
459 for a in &package.runtime_dependents {
460 match a {
461 Require(f)
462 | Optional(f)
463 | RequireAny(f)
464 | ConditionalFmri(f)
465 | ConditionalPredicate(f)
466 | Group(f) => {
467 if !packages_fmris.contains(f) {
468 continue 'main;
469 }
470 }
471 Incorporate(_) => {}
472 }
473 }
474
475 let check = |deps: &Vec<shared_type!(Component)>| -> bool {
476 !deps.iter().all(|c| name == get!(c).name)
477 };
478
479 if check(&package.build_dependents)
480 || check(&package.sys_build_dependents)
481 || check(&package.test_dependents)
482 || check(&package.sys_test_dependents)
483 {
484 continue 'main;
485 }
486 }
487
488 self.problems.add_problem(UselessComponent(name));
489 }
490 }
491
492 for p in &*self.packages {
494 let package = get!(p);
495
496 if !package.is_renamed() {
497 continue;
498 }
499
500 for rev_dep in &package.runtime_dependents {
501 match rev_dep {
502 Require(fmri)
503 | Optional(fmri)
504 | Incorporate(fmri)
505 | RequireAny(fmri)
506 | ConditionalFmri(fmri)
507 | ConditionalPredicate(fmri)
508 | Group(fmri) => {
509 let package_b = self
510 .get_package_by_fmri(fmri)
511 .map_err(|e| format!("failed to get package: {}", e))?;
512 if !get!(package_b).is_renamed() {
513 continue;
514 }
515 let fmri_b = get!(package_b).fmri.clone();
516 self.problems
517 .add_problem(RenamedNeedsRenamed(fmri_b, package.fmri.clone()));
518 }
519 }
520 }
521
522 match &package.component {
523 None => {}
524 Some(c) => {
525 let component = get!(c);
526
527 let mut check_dependencies = |dependencies: &Vec<weak_type!(Package)>| {
528 for dep in dependencies {
529 let p = dep.upgrade().unwrap();
530 let package_b = get!(p);
531 if package_b.is_renamed() {
532 self.problems.add_problem(RenamedNeedsRenamed(
533 package.fmri.clone(),
534 package_b.fmri.clone(),
535 ));
536 }
537 }
538 };
539
540 check_dependencies(&component.build);
541 check_dependencies(&component.test);
542 check_dependencies(&component.sys_build);
543 check_dependencies(&component.sys_test);
544 }
545 }
546 }
547
548 for p in &self.packages.clone() {
550 let package = get!(p);
551
552 if !package.is_obsolete() {
553 continue;
554 }
555
556 if package.versions.first().unwrap().is_obsolete() {
557 check_obsoleted_required_packages(
558 self,
559 &package,
560 ObsoletedRequired,
561 ObsoletedRequiredByRenamed,
562 );
563 } else {
564 check_obsoleted_required_packages(
565 self,
566 &package,
567 PartlyObsoletedRequired,
568 PartlyObsoletedRequiredByRenamed,
569 );
570 }
571 }
572
573 Ok(())
574 }
575}
576
577fn check_obsoleted_required_packages(
578 components: &mut Components,
579 package: &Package,
580 problem_type: fn(DependTypes, DependencyTypes, FMRI, String) -> Problem,
581 problem_type_renamed: fn(DependTypes, DependencyTypes, FMRI) -> Problem,
582) {
583 let mut check = |deps: &Vec<shared_type!(Component)>, dt: DependencyTypes| {
584 for c in deps {
585 components.problems.add_problem(problem_type(
586 DependTypes::Require(package.fmri.clone()),
587 dt.clone(),
588 FMRI::parse_raw("none").unwrap(),
589 get!(c).name.clone(),
590 ));
591 }
592 };
593
594 check(&package.build_dependents, Build);
595 check(&package.sys_build_dependents, SystemBuild);
596 check(&package.test_dependents, Test);
597 check(&package.sys_test_dependents, SystemTest);
598
599 for d in &package.runtime_dependents {
600 let required_by_fmri = match d {
601 Require(fmri)
602 | Optional(fmri)
603 | RequireAny(fmri)
604 | ConditionalFmri(fmri)
605 | ConditionalPredicate(fmri)
606 | Group(fmri) => fmri.clone(),
607 Incorporate(_) => continue,
608 };
609
610 let p = get!(components.get_package_by_fmri(&required_by_fmri).unwrap());
611 let o = p.is_obsolete();
612 let r = p.is_renamed();
613 drop(p);
614
615 if o {
616 continue;
617 } else if r {
618 components.problems.add_problem(problem_type_renamed(
619 DependTypes::Require(package.fmri.clone()),
620 Runtime,
621 required_by_fmri,
622 ));
623 } else {
624 components.problems.add_problem(problem_type(
625 DependTypes::Require(package.fmri.clone()),
626 Runtime,
627 required_by_fmri,
628 "".to_owned(),
629 ));
630 }
631 }
632}
633
634#[derive(Clone, Debug)]
636pub struct Component {
637 pub(crate) name: String,
638 pub(crate) packages: Vec<weak_type!(Package)>,
640 pub(crate) build: Vec<weak_type!(Package)>,
642 pub(crate) test: Vec<weak_type!(Package)>,
643 pub(crate) sys_build: Vec<weak_type!(Package)>,
644 pub(crate) sys_test: Vec<weak_type!(Package)>,
645}
646
647impl Component {
648 pub fn new(component_name: String) -> Self {
649 Self {
650 name: component_name,
651 packages: Vec::new(),
652 build: Vec::new(),
653 test: Vec::new(),
654 sys_build: Vec::new(),
655 sys_test: Vec::new(),
656 }
657 }
658
659 fn add_package(&mut self, package: weak_type!(Package)) {
660 self.packages.push(package)
661 }
662
663 pub fn get_name(&self) -> &String {
664 &self.name
665 }
666
667 pub fn get_build_dependencies(&self) -> &Vec<weak_type!(Package)> {
668 &self.build
669 }
670
671 pub fn get_sys_build_dependencies(&self) -> &Vec<weak_type!(Package)> {
672 &self.sys_build
673 }
674
675 pub fn get_test_dependencies(&self) -> &Vec<weak_type!(Package)> {
676 &self.test
677 }
678
679 pub fn get_sys_test_dependencies(&self) -> &Vec<weak_type!(Package)> {
680 &self.sys_test
681 }
682}