oi_pkg_checker_core/
problems.rs

1use std::path::PathBuf;
2
3use fmri::{FMRI, Publisher};
4use log::{error, info, warn};
5use serde::{Deserialize, Serialize};
6
7use crate::{
8    packages::{depend_types::DependTypes, dependency_type::DependencyTypes},
9    problems::Problem::{
10        MissingComponentForPackage, NonExistingPackageInPkg5, NonExistingRequired,
11        NonExistingRequiredByRenamed, ObsoletedPackageInComponent, ObsoletedRequired,
12        ObsoletedRequiredByRenamed, PackageInMultipleComponents, PartlyObsoletedRequired,
13        PartlyObsoletedRequiredByRenamed, RenamedNeedsRenamed, RenamedPackageInComponent,
14        UnRunnableMakeCommand, UselessComponent,
15    },
16};
17use crate::problems::Problem::SamePackageHasTwoPublishers;
18
19#[derive(Serialize, Deserialize, Clone, PartialEq, Debug)]
20pub enum Problem {
21    MissingComponentForPackage(FMRI),
22    RenamedNeedsRenamed(FMRI, FMRI),
23    RenamedPackageInComponent(FMRI, String),
24    ObsoletedPackageInComponent(FMRI, String),
25    UnRunnableMakeCommand(String, PathBuf),
26    NonExistingRequired(DependTypes, DependencyTypes, FMRI, String),
27    NonExistingRequiredByRenamed(DependTypes, DependencyTypes, FMRI),
28    ObsoletedRequired(DependTypes, DependencyTypes, FMRI, String),
29    ObsoletedRequiredByRenamed(DependTypes, DependencyTypes, FMRI),
30    PartlyObsoletedRequired(DependTypes, DependencyTypes, FMRI, String),
31    PartlyObsoletedRequiredByRenamed(DependTypes, DependencyTypes, FMRI),
32    UselessComponent(String),
33    PackageInMultipleComponents(FMRI, Vec<String>),
34    NonExistingPackageInPkg5(FMRI, String),
35    SamePackageHasTwoPublishers(FMRI, Publisher, Publisher, Option<Publisher>),
36}
37
38#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
39pub struct Problems(Vec<Problem>);
40
41impl Problems {
42    pub fn new() -> Self {
43        Self(vec![])
44    }
45
46    pub fn get_ref(&self) -> &Vec<Problem> {
47        &self.0
48    }
49
50    pub fn add_problem(&mut self, mut problem: Problem) {
51        match &mut problem {
52            MissingComponentForPackage(f)
53            | NonExistingRequired(_, _, f, _)
54            | NonExistingRequiredByRenamed(_, _, f)
55            | ObsoletedRequired(_, _, f, _)
56            | ObsoletedRequiredByRenamed(_, _, f)
57            | PartlyObsoletedRequired(_, _, f, _)
58            | PartlyObsoletedRequiredByRenamed(_, _, f)
59            | RenamedPackageInComponent(f, _)
60            | ObsoletedPackageInComponent(f, _)
61            | PackageInMultipleComponents(f, _)
62            | NonExistingPackageInPkg5(f, _)
63            | SamePackageHasTwoPublishers(f, _, _, _) => {
64                f.remove_version();
65                f.remove_publisher();
66            }
67            RenamedNeedsRenamed(fmri_a, fmri_b) => {
68                fmri_a.remove_version();
69                fmri_b.remove_version();
70                fmri_a.remove_publisher();
71                fmri_b.remove_publisher();
72            }
73            UnRunnableMakeCommand(_, _) => {}
74            UselessComponent(_) => {}
75        }
76
77        if !self.contains(&problem) {
78            self.0.push(problem)
79        }
80    }
81
82    fn contains(&self, problem: &Problem) -> bool {
83        let contains_component = |depend_type: &DependTypes,
84                                  dependency_type: &DependencyTypes,
85                                  component_name: &String|
86         -> bool {
87            if dependency_type != &DependencyTypes::Runtime {
88                return self.0.iter().any(|p| {
89                    if let NonExistingRequired(a, b, _, c) = p {
90                        if a == depend_type && b == dependency_type && c == component_name {
91                            return true;
92                        }
93                    }
94
95                    if let ObsoletedRequired(a, b, _, c) = p {
96                        if a == depend_type && b == dependency_type && c == component_name {
97                            return true;
98                        }
99                    }
100
101                    if let PartlyObsoletedRequired(a, b, _, c) = p {
102                        if a == depend_type && b == dependency_type && c == component_name {
103                            return true;
104                        }
105                    }
106
107                    false
108                });
109            }
110
111            false
112        };
113
114        match problem {
115            NonExistingRequired(depend_type, dependency_type, _, component_name) => {
116                if contains_component(depend_type, dependency_type, component_name) {
117                    return true;
118                }
119            }
120            ObsoletedRequired(depend_type, dependency_type, _, component_name) => {
121                if contains_component(depend_type, dependency_type, component_name) {
122                    return true;
123                }
124            }
125            PartlyObsoletedRequired(depend_type, dependency_type, _, component_name) => {
126                if contains_component(depend_type, dependency_type, component_name) {
127                    return true;
128                }
129            }
130            _ => {}
131        };
132
133        self.0.contains(problem)
134    }
135
136    pub fn sort(&mut self) {
137        let priority = |item: &Problem| -> usize {
138            match item {
139                UselessComponent(_) => 0,
140                PartlyObsoletedRequired(_, _, _, _) => 1,
141                PartlyObsoletedRequiredByRenamed(_, _, _) => 2,
142                MissingComponentForPackage(_) => 3,
143                NonExistingRequired(_, _, _, _) => 4,
144                NonExistingRequiredByRenamed(_, _, _) => 5,
145                RenamedNeedsRenamed(_, _) => 6,
146                RenamedPackageInComponent(_, _) => 7,
147                ObsoletedPackageInComponent(_, _) => 8,
148                ObsoletedRequired(_, _, _, _) => 9,
149                ObsoletedRequiredByRenamed(_, _, _) => 10,
150                UnRunnableMakeCommand(_, _) => 11,
151                PackageInMultipleComponents(_, _) => 12,
152                NonExistingPackageInPkg5(_, _) => 13,
153                SamePackageHasTwoPublishers(_, _, _, _) => 14,
154            }
155        };
156
157        self.0.sort_by_key(priority)
158    }
159
160    fn count(&self) {
161        let mut counter: [i16; 15] = [0; 15];
162        for problem in self.get_ref() {
163            match problem {
164                UselessComponent(_) => counter[0] += 1,
165                PartlyObsoletedRequired(_, _, _, _) => counter[1] += 1,
166                PartlyObsoletedRequiredByRenamed(_, _, _) => counter[2] += 1,
167                MissingComponentForPackage(_) => counter[3] += 1,
168                NonExistingRequired(_, _, _, _) => counter[4] += 1,
169                NonExistingRequiredByRenamed(_, _, _) => counter[5] += 1,
170                RenamedNeedsRenamed(_, _) => counter[6] += 1,
171                RenamedPackageInComponent(_, _) => counter[7] += 1,
172                ObsoletedPackageInComponent(_, _) => counter[8] += 1,
173                ObsoletedRequired(_, _, _, _) => counter[9] += 1,
174                ObsoletedRequiredByRenamed(_, _, _) => counter[10] += 1,
175                UnRunnableMakeCommand(_, _) => counter[11] += 1,
176                PackageInMultipleComponents(_, _) => counter[12] += 1,
177                NonExistingPackageInPkg5(_, _) => counter[13] += 1,
178                SamePackageHasTwoPublishers(_, _, _, _) => counter[14] += 1,
179            }
180        }
181
182        for (problem_type, count) in counter.iter().enumerate() {
183            match problem_type {
184                0 => info!("Number of components that are not needed by any package: {}", count),
185                1 => warn!("Number of obsoleted packages with older normal version which are needed as dependency: {}", count),
186                2 => warn!("Number of obsoleted packages with older normal version which are needed as dependency in renamed package: {}", count),
187                3 => warn!("Number of packages that do not belong to a component: {}", count),
188                4 => warn!("Number of non existing packages which are needed as dependency: {}", count),
189                5 => warn!("Number of non existing packages which are needed as dependency in renamed package: {}", count),
190                6 => error!("Number of renamed packages that need renamed packages: {}", count),
191                7 => error!("Number of renamed packages which are in component: {}", count),
192                8 => error!("Number of obsoleted packages which are in component: {}", count),
193                9 => error!("Number of obsoleted packages which are needed as dependency: {}", count),
194                10 => error!("Number of obsoleted packages which are needed as dependency in renamed package: {}", count),
195                11 => error!("Number of un-runnable make commands: {}", count),
196                12 => error!("Number of packages that are in multiple components: {}", count),
197                13 => error!("Number of packages that are in pkg5 file but do not exist: {}", count),
198                14 => error!("Number of problems with packages that have same publisher: {}", count),
199                _ => panic!("invalid problem type"),
200            }
201        }
202    }
203
204    pub fn get_problems_related_to_fmri(&self, fmri: &FMRI) -> Vec<Problem> {
205        let mut problems: Vec<Problem> = Vec::new();
206        for problem in self.get_ref() {
207            match problem {
208                UselessComponent(_) => {}
209                UnRunnableMakeCommand(_, _) => {}
210                NonExistingPackageInPkg5(f, _)
211                | SamePackageHasTwoPublishers(f, _, _, _)
212                | PackageInMultipleComponents(f, _)
213                | MissingComponentForPackage(f)
214                | RenamedPackageInComponent(f, _)
215                | ObsoletedPackageInComponent(f, _) => {
216                    if f.package_name_eq(fmri) {
217                        problems.push(problem.clone());
218                    }
219                }
220                RenamedNeedsRenamed(f_a, f_b) => {
221                    if f_a.package_name_eq(fmri) || f_b.package_name_eq(fmri) {
222                        problems.push(problem.clone());
223                    }
224                }
225                NonExistingRequired(depend_type, _, f, _)
226                | NonExistingRequiredByRenamed(depend_type, _, f)
227                | ObsoletedRequired(depend_type, _, f, _)
228                | ObsoletedRequiredByRenamed(depend_type, _, f)
229                | PartlyObsoletedRequired(depend_type, _, f, _)
230                | PartlyObsoletedRequiredByRenamed(depend_type, _, f) => {
231                    if f.package_name_eq(fmri) {
232                        problems.push(problem.clone());
233                        continue;
234                    }
235
236                    match depend_type {
237                        DependTypes::Require(f)
238                        | DependTypes::Optional(f)
239                        | DependTypes::Exclude(f)
240                        | DependTypes::Incorporate(f)
241                        | DependTypes::Origin(f)
242                        | DependTypes::Group(f)
243                        | DependTypes::Parent(f) => {
244                            if f.package_name_eq(fmri) {
245                                problems.push(problem.clone());
246                            }
247                        }
248                        DependTypes::RequireAny(f_list) => {
249                            if f_list.contains(fmri) {
250                                problems.push(problem.clone());
251                            }
252                        }
253                        DependTypes::GroupAny(f_list) => {
254                            if f_list.contains(fmri) {
255                                problems.push(problem.clone());
256                            }
257                        }
258                        DependTypes::Conditional(f, predicate) => {
259                            if f.package_name_eq(fmri) || predicate.package_name_eq(fmri) {
260                                problems.push(problem.clone());
261                            }
262                        }
263                    }
264                }
265            }
266        }
267        problems
268    }
269}
270
271impl Default for Problems {
272    fn default() -> Self {
273        Self::new()
274    }
275}
276
277pub fn report(problems: &Problems) {
278    for problem in problems.get_ref() {
279        report_problem(problem);
280    }
281    problems.count();
282}
283
284pub fn report_problem(problem: &Problem) {
285    match problem {
286        SamePackageHasTwoPublishers(fmri, publisher_a, publisher_b, p) => {
287            if let Some(p) = p {
288                error!(
289                    "package {} has two publishers ({} and {}), but the latest version with publisher {} is not obsoleted",
290                    fmri, publisher_a, publisher_b, p
291                )
292            } else {
293                error!(
294                    "package {} has two publishers ({} and {}), but wrong package is obsoleted",
295                    fmri, publisher_a, publisher_b
296                )
297            }
298        }
299        NonExistingPackageInPkg5(fmri, component_name) => {
300            error!(
301                "package {} does not exist but it is in the pkg5, component: {}",
302                fmri, component_name
303            )
304        }
305        PackageInMultipleComponents(fmri, components) => {
306            error!(
307                "package {} is in multiple components: {}",
308                fmri,
309                components.join(",")
310            )
311        }
312        UselessComponent(name) => info!("component {} is not needed by any package", name),
313        MissingComponentForPackage(fmri) => warn!("missing component for {}", fmri),
314        RenamedNeedsRenamed(fmri_a, fmri_b) => error!(
315            "renamed package {} needs renamed package {}",
316            fmri_a.get_package_name_as_ref_string(),
317            fmri_b.get_package_name_as_ref_string()
318        ),
319        RenamedPackageInComponent(package, component) => error!(
320            "package {} is renamed and is in component {}",
321            package.get_package_name_as_ref_string(),
322            component
323        ),
324        ObsoletedPackageInComponent(package, component) => error!(
325            "package {} is obsolete and is in component {}",
326            package.get_package_name_as_ref_string(),
327            component
328        ),
329        UnRunnableMakeCommand(command, path) => error!("can't run {} in {:?}", command, path),
330
331        NonExistingRequired(depend_type, dependency_type, required_by, component_name) => {
332            let (name, fmri) = depend_type.clone().get_name_and_content_as_string();
333
334            let package_or_component_name = if dependency_type == &DependencyTypes::Runtime {
335                required_by.get_package_name_as_ref_string().clone()
336            } else {
337                format!("component {}", component_name)
338            };
339
340            warn!(
341                "package {} doesn't exist, but is required by {}",
342                fmri,
343                match dependency_type {
344                    DependencyTypes::Runtime => {
345                        format!("package {} (runtime, {})", package_or_component_name, name)
346                    }
347                    DependencyTypes::Build => {
348                        format!("{} (build, component)", package_or_component_name)
349                    }
350                    DependencyTypes::Test => {
351                        format!("{} (test, component)", package_or_component_name)
352                    }
353                    DependencyTypes::SystemBuild => {
354                        format!("{} (build, system)", package_or_component_name)
355                    }
356                    DependencyTypes::SystemTest => {
357                        format!("{} (test, system)", package_or_component_name)
358                    }
359                }
360            )
361        }
362        NonExistingRequiredByRenamed(depend_type, dependency_type, required_by) => {
363            let (name, fmri) = depend_type.clone().get_name_and_content_as_string();
364
365            let package_name = required_by.get_package_name_as_ref_string();
366
367            warn!(
368                "package {} doesn't exist, but is required by renamed package {}",
369                fmri,
370                match dependency_type {
371                    DependencyTypes::Runtime => {
372                        format!("{} (runtime, {})", package_name, name)
373                    }
374                    DependencyTypes::Build => {
375                        format!("{} (build, {})", package_name, name)
376                    }
377                    DependencyTypes::Test => {
378                        format!("{} (test, {})", package_name, name)
379                    }
380                    DependencyTypes::SystemBuild => {
381                        format!("{} (system-build)", package_name)
382                    }
383                    DependencyTypes::SystemTest => {
384                        format!("{} (system-test)", package_name)
385                    }
386                }
387            )
388        }
389
390        ObsoletedRequired(depend_type, dependency_type, required_by, component_name) => {
391            let (name, fmri) = depend_type.clone().get_name_and_content_as_string();
392
393            let package_or_component_name = if dependency_type == &DependencyTypes::Runtime {
394                required_by.get_package_name_as_ref_string().clone()
395            } else {
396                format!("component {}", component_name)
397            };
398
399            error!(
400                "obsoleted package {} is required by {}",
401                fmri,
402                match dependency_type {
403                    DependencyTypes::Runtime => {
404                        format!("package {} (runtime, {})", package_or_component_name, name)
405                    }
406                    DependencyTypes::Build => {
407                        format!("{} (build, component)", package_or_component_name)
408                    }
409                    DependencyTypes::Test => {
410                        format!("{} (test, component)", package_or_component_name)
411                    }
412                    DependencyTypes::SystemBuild => {
413                        format!("{} (build, system)", package_or_component_name)
414                    }
415                    DependencyTypes::SystemTest => {
416                        format!("{} (test, system)", package_or_component_name)
417                    }
418                }
419            );
420        }
421
422        ObsoletedRequiredByRenamed(depend_type, dependency_type, required_by) => {
423            let (name, fmri) = depend_type.clone().get_name_and_content_as_string();
424
425            let package_name = required_by.get_package_name_as_ref_string();
426
427            error!(
428                "obsoleted package {} is required by renamed package {}",
429                fmri,
430                match dependency_type {
431                    DependencyTypes::Runtime => {
432                        format!("{} (runtime, {})", package_name, name)
433                    }
434                    DependencyTypes::Build => {
435                        format!("{} (build, component)", package_name)
436                    }
437                    DependencyTypes::Test => {
438                        format!("{} (test, component)", package_name)
439                    }
440                    DependencyTypes::SystemBuild => {
441                        format!("{} (system-build, system)", package_name)
442                    }
443                    DependencyTypes::SystemTest => {
444                        format!("{} (system-test, system)", package_name)
445                    }
446                }
447            );
448        }
449
450        PartlyObsoletedRequired(depend_type, dependency_type, required_by, component_name) => {
451            let (name, fmri) = depend_type.clone().get_name_and_content_as_string();
452
453            let package_or_component_name = if dependency_type == &DependencyTypes::Runtime {
454                required_by.get_package_name_as_ref_string().clone()
455            } else {
456                format!("component {}", component_name)
457            };
458
459            warn!(
460                "obsoleted package {} is required by {}",
461                fmri,
462                match dependency_type {
463                    DependencyTypes::Runtime => {
464                        format!("package {} (runtime, {})", package_or_component_name, name)
465                    }
466                    DependencyTypes::Build => {
467                        format!("{} (build, component)", package_or_component_name)
468                    }
469                    DependencyTypes::Test => {
470                        format!("{} (test, component)", package_or_component_name)
471                    }
472                    DependencyTypes::SystemBuild => {
473                        format!("{} (build, system)", package_or_component_name)
474                    }
475                    DependencyTypes::SystemTest => {
476                        format!("{} (test, system)", package_or_component_name)
477                    }
478                }
479            );
480        }
481        PartlyObsoletedRequiredByRenamed(depend_type, dependency_type, required_by) => {
482            let (name, fmri) = depend_type.clone().get_name_and_content_as_string();
483
484            let package_name = required_by.get_package_name_as_ref_string();
485
486            warn!(
487                "obsoleted package {} is required by renamed package {}",
488                fmri,
489                match dependency_type {
490                    DependencyTypes::Runtime => {
491                        format!("{} (runtime, {})", package_name, name)
492                    }
493                    DependencyTypes::Build => {
494                        format!("{} (build, component)", package_name)
495                    }
496                    DependencyTypes::Test => {
497                        format!("{} (test, component)", package_name)
498                    }
499                    DependencyTypes::SystemBuild => {
500                        format!("{} (system-build, system)", package_name)
501                    }
502                    DependencyTypes::SystemTest => {
503                        format!("{} (system-test, system)", package_name)
504                    }
505                }
506            );
507        }
508    }
509}