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}