1mod about;
2#[cfg(test)]
3mod about_scan_test;
4#[cfg(test)]
5mod about_test;
6mod alpine;
7#[cfg(test)]
8mod alpine_scan_test;
9mod arch;
10#[cfg(test)]
11mod arch_scan_test;
12#[cfg(test)]
13mod arch_test;
14mod autotools;
15#[cfg(test)]
16mod autotools_test;
17mod bazel;
18#[cfg(test)]
19mod bazel_module_test;
20#[cfg(test)]
21mod bazel_test;
22mod bower;
23#[cfg(test)]
24mod bower_scan_test;
25#[cfg(test)]
26mod bower_test;
27mod buck;
28#[cfg(test)]
29mod buck_test;
30mod bun_lock;
31#[cfg(test)]
32mod bun_lock_test;
33mod bun_lockb;
34#[cfg(test)]
35mod bun_lockb_test;
36mod cargo;
37mod cargo_lock;
38#[cfg(test)]
39mod cargo_lock_test;
40#[cfg(test)]
41mod cargo_scan_test;
42#[cfg(test)]
43mod cargo_test;
44mod chef;
45#[cfg(test)]
46mod chef_scan_test;
47#[cfg(test)]
48mod chef_test;
49mod clojure;
50#[cfg(test)]
51mod clojure_test;
52#[cfg(test)]
53mod cocoapods_scan_test;
54mod composer;
55#[cfg(test)]
56mod composer_scan_test;
57#[cfg(test)]
58mod composer_test;
59mod conan;
60mod conan_data;
61#[cfg(test)]
62mod conan_data_test;
63#[cfg(test)]
64mod conan_scan_test;
65#[cfg(test)]
66mod conan_test;
67mod conda;
68mod conda_meta_json;
69#[cfg(test)]
70mod conda_meta_json_test;
71#[cfg(test)]
72mod conda_scan_test;
73#[cfg(test)]
74mod conda_test;
75mod cpan;
76mod cpan_dist_ini;
77#[cfg(test)]
78mod cpan_dist_ini_test;
79mod cpan_makefile_pl;
80#[cfg(test)]
81mod cpan_makefile_pl_test;
82#[cfg(test)]
83mod cpan_scan_test;
84#[cfg(test)]
85mod cpan_test;
86mod cran;
87#[cfg(test)]
88mod cran_scan_test;
89#[cfg(test)]
90mod cran_test;
91mod dart;
92#[cfg(test)]
93mod dart_scan_test;
94#[cfg(test)]
95mod dart_test;
96mod debian;
97#[cfg(test)]
98mod debian_scan_test;
99#[cfg(test)]
100mod debian_test;
101mod deno;
102mod deno_lock;
103#[cfg(test)]
104mod deno_lock_test;
105#[cfg(test)]
106mod deno_scan_test;
107#[cfg(test)]
108mod deno_test;
109mod docker;
110#[cfg(test)]
111mod docker_scan_test;
112#[cfg(test)]
113mod docker_test;
114mod freebsd;
115#[cfg(test)]
116mod freebsd_scan_test;
117#[cfg(test)]
118mod freebsd_test;
119mod gitmodules;
120#[cfg(test)]
121mod gitmodules_scan_test;
122mod go;
123mod go_mod_graph;
124#[cfg(test)]
125mod go_scan_test;
126#[cfg(test)]
127mod go_test;
128#[cfg(test)]
129mod go_work_test;
130#[cfg(all(test, feature = "golden-tests"))]
131pub(crate) mod golden_test_utils;
132mod gradle;
133mod gradle_lock;
134#[cfg(test)]
135mod gradle_lock_test;
136mod gradle_module;
137#[cfg(test)]
138mod gradle_module_scan_test;
139#[cfg(test)]
140mod gradle_module_test;
141#[cfg(test)]
142mod gradle_scan_test;
143mod hackage;
144#[cfg(test)]
145mod hackage_scan_test;
146#[cfg(test)]
147mod hackage_test;
148mod haxe;
149#[cfg(test)]
150mod haxe_scan_test;
151#[cfg(test)]
152mod haxe_test;
153mod helm;
154#[cfg(test)]
155mod helm_scan_test;
156#[cfg(test)]
157mod helm_test;
158mod hex_lock;
159#[cfg(test)]
160mod hex_lock_test;
161mod license_normalization;
162mod maven;
163#[cfg(test)]
164mod maven_scan_test;
165#[cfg(test)]
166mod maven_test;
167mod meson;
168#[cfg(test)]
169mod meson_test;
170pub mod metadata;
171mod microsoft_update_manifest;
172#[cfg(test)]
173mod microsoft_update_manifest_test;
174mod misc;
175#[cfg(test)]
176mod misc_test;
177mod nix;
178#[cfg(test)]
179mod nix_scan_test;
180#[cfg(test)]
181mod nix_test;
182mod npm;
183mod npm_lock;
184#[cfg(test)]
185mod npm_lock_test;
186#[cfg(test)]
187mod npm_scan_test;
188#[cfg(test)]
189mod npm_test;
190mod npm_workspace;
191#[cfg(test)]
192mod npm_workspace_test;
193mod nuget;
194#[cfg(test)]
195mod nuget_scan_test;
196#[cfg(test)]
197mod nuget_test;
198mod opam;
199#[cfg(test)]
200mod opam_scan_test;
201mod os_release;
202#[cfg(test)]
203mod os_release_test;
204#[cfg(test)]
205mod osgi_test;
206mod pep508;
207mod pip_inspect_deplock;
208#[cfg(test)]
209mod pip_inspect_deplock_test;
210mod pipfile_lock;
211#[cfg(test)]
212mod pipfile_lock_test;
213mod pixi;
214#[cfg(test)]
215mod pixi_scan_test;
216#[cfg(test)]
217mod pixi_test;
218mod pnpm_lock;
219#[cfg(test)]
220mod pnpm_lock_test;
221mod podfile;
222mod podfile_lock;
223#[cfg(test)]
224mod podfile_lock_test;
225mod podspec;
226mod podspec_json;
227#[cfg(test)]
228mod podspec_json_test;
229mod poetry_lock;
230#[cfg(test)]
231mod poetry_lock_test;
232mod pylock_toml;
233#[cfg(test)]
234mod pylock_toml_test;
235mod python;
236#[cfg(test)]
237mod python_scan_test;
238#[cfg(test)]
239mod python_test;
240mod readme;
241#[cfg(test)]
242mod readme_test;
243mod requirements_txt;
244#[cfg(test)]
245mod requirements_txt_test;
246pub(crate) mod rfc822;
247mod rpm_db;
248#[cfg(test)]
249mod rpm_db_scan_test;
250mod rpm_license_files;
251#[cfg(test)]
252mod rpm_license_files_test;
253mod rpm_mariner_manifest;
254#[cfg(test)]
255mod rpm_mariner_manifest_test;
256mod rpm_parser;
257#[cfg(test)]
258mod rpm_scan_test;
259mod rpm_specfile;
260#[cfg(test)]
261mod rpm_specfile_test;
262mod rpm_yumdb;
263mod ruby;
264#[cfg(test)]
265mod ruby_scan_test;
266#[cfg(test)]
267mod ruby_test;
268mod sbt;
269#[cfg(test)]
270mod sbt_test;
271#[cfg(test)]
272mod scan_test_utils;
273mod swift_manifest_json;
274#[cfg(test)]
275mod swift_manifest_json_test;
276mod swift_resolved;
277#[cfg(test)]
278mod swift_resolved_test;
279#[cfg(test)]
280mod swift_scan_test;
281mod swift_show_dependencies;
282#[cfg(test)]
283mod swift_show_dependencies_test;
284pub mod utils;
285mod uv_lock;
286#[cfg(test)]
287mod uv_lock_test;
288mod vcpkg;
289#[cfg(test)]
290mod vcpkg_scan_test;
291#[cfg(test)]
292mod vcpkg_test;
293mod yarn_lock;
294#[cfg(test)]
295mod yarn_lock_test;
296
297#[cfg(all(test, feature = "golden-tests"))]
298mod golden_test;
299
300use std::cell::RefCell;
301use std::path::Path;
302
303use crate::models::{PackageData, PackageType};
304use crate::parsers::license_normalization::finalize_package_declared_license_references;
305
306thread_local! {
307 static PARSER_DIAGNOSTIC_STACK: RefCell<Vec<Vec<String>>> = const { RefCell::new(Vec::new()) };
308}
309
310#[derive(Debug, Default)]
311pub struct ParsePackagesResult {
312 pub packages: Vec<PackageData>,
313 pub scan_errors: Vec<String>,
314}
315
316pub(crate) fn capture_parser_diagnostics<F>(extract: F) -> ParsePackagesResult
317where
318 F: FnOnce() -> Vec<PackageData>,
319{
320 PARSER_DIAGNOSTIC_STACK.with(|stack| {
321 stack.borrow_mut().push(Vec::new());
322 });
323
324 let packages = extract()
325 .into_iter()
326 .map(|mut package| {
327 finalize_package_declared_license_references(&mut package);
328 package
329 })
330 .collect();
331 let scan_errors =
332 PARSER_DIAGNOSTIC_STACK.with(|stack| stack.borrow_mut().pop().unwrap_or_default());
333
334 ParsePackagesResult {
335 packages,
336 scan_errors,
337 }
338}
339
340pub(crate) fn record_parser_diagnostic(message: String) -> bool {
341 PARSER_DIAGNOSTIC_STACK.with(|stack| {
342 let mut stack = stack.borrow_mut();
343 let Some(active) = stack.last_mut() else {
344 return false;
345 };
346 active.push(message);
347 true
348 })
349}
350
351#[macro_export]
352macro_rules! parser_warn {
353 ($($arg:tt)*) => {{
354 let message = format!($($arg)*);
355 if !$crate::parsers::record_parser_diagnostic(message.clone()) {
356 log::warn!("{message}");
357 }
358 }};
359}
360
361pub trait PackageParser {
405 const PACKAGE_TYPE: PackageType;
407
408 fn extract_packages(path: &Path) -> Vec<PackageData>;
418
419 fn is_match(path: &Path) -> bool;
424
425 fn extract_first_package(path: &Path) -> PackageData {
428 Self::extract_packages(path)
429 .into_iter()
430 .map(|mut package| {
431 finalize_package_declared_license_references(&mut package);
432 package
433 })
434 .next()
435 .unwrap_or_default()
436 }
437}
438
439pub use self::about::AboutFileParser;
440pub use self::alpine::{AlpineApkParser, AlpineApkbuildParser, AlpineInstalledParser};
441pub use self::arch::{ArchPkginfoParser, ArchSrcinfoParser};
442pub use self::autotools::AutotoolsConfigureParser;
443pub use self::bazel::{BazelBuildParser, BazelModuleParser};
444pub use self::bower::BowerJsonParser;
445pub use self::buck::{BuckBuildParser, BuckMetadataBzlParser};
446pub use self::bun_lock::BunLockParser;
447pub use self::bun_lockb::BunLockbParser;
448pub use self::cargo::CargoParser;
449#[cfg_attr(not(test), allow(unused_imports))]
450pub use self::cargo_lock::CargoLockParser;
451pub use self::chef::{ChefMetadataJsonParser, ChefMetadataRbParser};
452pub use self::clojure::{ClojureDepsEdnParser, ClojureProjectCljParser};
453pub use self::composer::{ComposerJsonParser, ComposerLockParser};
454pub use self::conan::{ConanFilePyParser, ConanLockParser, ConanfileTxtParser};
455pub use self::conan_data::ConanDataParser;
456pub use self::conda::{CondaEnvironmentYmlParser, CondaMetaYamlParser};
457pub use self::conda_meta_json::CondaMetaJsonParser;
458pub use self::cpan::{CpanManifestParser, CpanMetaJsonParser, CpanMetaYmlParser};
459pub use self::cpan_dist_ini::CpanDistIniParser;
460pub use self::cpan_makefile_pl::CpanMakefilePlParser;
461pub use self::cran::CranParser;
462pub use self::dart::{PubspecLockParser, PubspecYamlParser};
463pub use self::debian::{
464 DebianControlInExtractedDebParser, DebianControlParser, DebianCopyrightParser, DebianDebParser,
465 DebianDebianTarParser, DebianDistrolessInstalledParser, DebianDscParser,
466 DebianInstalledListParser, DebianInstalledMd5sumsParser, DebianInstalledParser,
467 DebianMd5sumInPackageParser, DebianOrigTarParser,
468};
469pub use self::deno::DenoParser;
470pub use self::deno_lock::DenoLockParser;
471pub use self::docker::DockerfileParser;
472pub use self::freebsd::FreebsdCompactManifestParser;
473pub use self::gitmodules::GitmodulesParser;
474pub use self::go::{GoModParser, GoSumParser, GoWorkParser, GodepsParser};
475pub use self::go_mod_graph::GoModGraphParser;
476pub use self::gradle::GradleParser;
477pub use self::gradle_lock::GradleLockfileParser;
478pub use self::gradle_module::GradleModuleParser;
479pub use self::hackage::{HackageCabalParser, HackageCabalProjectParser, HackageStackYamlParser};
480pub use self::haxe::HaxeParser;
481pub use self::helm::{HelmChartLockParser, HelmChartYamlParser};
482pub use self::hex_lock::HexLockParser;
483pub use self::maven::MavenParser;
484pub use self::meson::MesonParser;
485pub use self::microsoft_update_manifest::MicrosoftUpdateManifestParser;
486pub use self::misc::{
487 AndroidApkRecognizer, AndroidLibraryRecognizer, AppleDmgRecognizer, Axis2MarRecognizer,
488 Axis2ModuleXmlRecognizer, CabArchiveRecognizer, ChromeCrxRecognizer, InstallShieldRecognizer,
489 IosIpaRecognizer, IsoImageRecognizer, IvyXmlRecognizer, JBossSarRecognizer,
490 JBossServiceXmlRecognizer, JavaEarAppXmlRecognizer, JavaEarRecognizer, JavaJarRecognizer,
491 JavaWarRecognizer, JavaWarWebXmlRecognizer, MeteorPackageRecognizer, MozillaXpiRecognizer,
492 NsisRecognizer, SharArchiveRecognizer, SquashfsRecognizer,
493};
494pub use self::nix::{NixDefaultParser, NixFlakeLockParser, NixFlakeParser};
495pub use self::npm::NpmParser;
496pub use self::npm_lock::NpmLockParser;
497pub use self::npm_workspace::NpmWorkspaceParser;
498pub use self::nuget::{
499 CentralPackageManagementPropsParser, DirectoryBuildPropsParser, DotNetDepsJsonParser,
500 NupkgParser, NuspecParser, PackageReferenceProjectParser, PackagesConfigParser,
501 PackagesLockParser, ProjectJsonParser, ProjectLockJsonParser,
502};
503pub use self::opam::OpamParser;
504pub use self::os_release::OsReleaseParser;
505pub use self::pip_inspect_deplock::PipInspectDeplockParser;
506pub use self::pipfile_lock::PipfileLockParser;
507pub use self::pixi::{PixiLockParser, PixiTomlParser};
508pub use self::pnpm_lock::PnpmLockParser;
509pub use self::podfile::PodfileParser;
510pub use self::podfile_lock::PodfileLockParser;
511pub use self::podspec::PodspecParser;
512pub use self::podspec_json::PodspecJsonParser;
513pub use self::poetry_lock::PoetryLockParser;
514pub use self::pylock_toml::PylockTomlParser;
515pub use self::python::PythonParser;
516pub use self::readme::ReadmeParser;
517pub use self::requirements_txt::RequirementsTxtParser;
518pub use self::rpm_db::{RpmBdbDatabaseParser, RpmNdbDatabaseParser, RpmSqliteDatabaseParser};
519pub use self::rpm_license_files::RpmLicenseFilesParser;
520pub use self::rpm_mariner_manifest::RpmMarinerManifestParser;
521pub use self::rpm_parser::RpmParser;
522pub use self::rpm_specfile::RpmSpecfileParser;
523pub use self::rpm_yumdb::RpmYumdbParser;
524pub use self::ruby::{
525 GemArchiveParser, GemMetadataExtractedParser, GemfileLockParser, GemfileParser, GemspecParser,
526};
527pub use self::sbt::SbtParser;
528pub use self::swift_manifest_json::SwiftManifestJsonParser;
529pub use self::swift_resolved::SwiftPackageResolvedParser;
530pub use self::swift_show_dependencies::SwiftShowDependenciesParser;
531pub use self::uv_lock::UvLockParser;
532pub use self::vcpkg::VcpkgManifestParser;
533pub use self::yarn_lock::YarnLockParser;
534
535macro_rules! register_package_handlers {
541 (
542 parsers: [$($parser:ty),* $(,)?],
543 recognizers: [$($recognizer:ty),* $(,)?] $(,)?
544 ) => {
545 pub fn try_parse_file(path: &Path) -> Option<ParsePackagesResult> {
546 $(
547 if <$parser>::is_match(path) {
548 return Some(capture_parser_diagnostics(|| <$parser>::extract_packages(path)));
549 }
550 )*
551 $(
552 if <$recognizer>::is_match(path) {
553 return Some(capture_parser_diagnostics(|| <$recognizer>::extract_packages(path)));
554 }
555 )*
556 None
557 }
558
559 #[allow(dead_code)]
562 pub fn parse_by_type_name(type_name: &str, path: &Path) -> Option<PackageData> {
563 match type_name {
564 $(
565 stringify!($parser) => Some(<$parser>::extract_first_package(path)),
566 )*
567 $(
568 stringify!($recognizer) => Some(<$recognizer>::extract_first_package(path)),
569 )*
570 _ => None
571 }
572 }
573
574 #[allow(dead_code)]
577 pub fn list_parser_types() -> Vec<&'static str> {
578 vec![
579 $(
580 stringify!($parser),
581 )*
582 $(
583 stringify!($recognizer),
584 )*
585 ]
586 }
587 };
588}
589
590register_package_handlers! {
591 parsers: [
592 AboutFileParser,
593 AlpineApkParser,
594 AlpineApkbuildParser,
595 AlpineInstalledParser,
596 ArchPkginfoParser,
597 ArchSrcinfoParser,
598 AutotoolsConfigureParser,
599 BazelBuildParser,
600 BazelModuleParser,
601 BowerJsonParser,
602 BunLockParser,
603 BunLockbParser,
604 BuckBuildParser,
605 BuckMetadataBzlParser,
606 CargoLockParser,
607 CargoParser,
608 ChefMetadataJsonParser,
609 ChefMetadataRbParser,
610 ClojureDepsEdnParser,
611 ClojureProjectCljParser,
612 ComposerJsonParser,
613 ComposerLockParser,
614 ConanDataParser,
615 ConanFilePyParser,
616 ConanfileTxtParser,
617 ConanLockParser,
618 CondaEnvironmentYmlParser,
619 CondaMetaJsonParser,
620 CondaMetaYamlParser,
621 CpanDistIniParser,
622 CpanMakefilePlParser,
623 CpanManifestParser,
624 CpanMetaJsonParser,
625 CpanMetaYmlParser,
626 CranParser,
627 DebianControlInExtractedDebParser,
628 DebianControlParser,
629 DebianCopyrightParser,
630 DebianDebianTarParser,
631 DebianDebParser,
632 DebianDistrolessInstalledParser,
633 DebianDscParser,
634 DebianInstalledListParser,
635 DebianInstalledMd5sumsParser,
636 DebianInstalledParser,
637 DebianMd5sumInPackageParser,
638 DebianOrigTarParser,
639 DenoParser,
640 DenoLockParser,
641 DockerfileParser,
642 FreebsdCompactManifestParser,
643 GemArchiveParser,
644 GemfileLockParser,
645 GemfileParser,
646 GemMetadataExtractedParser,
647 GemspecParser,
648 GitmodulesParser,
649 GodepsParser,
650 GoModParser,
651 GoModGraphParser,
652 GoSumParser,
653 GoWorkParser,
654 GradleLockfileParser,
655 GradleParser,
656 GradleModuleParser,
657 HackageCabalParser,
658 HackageCabalProjectParser,
659 HackageStackYamlParser,
660 HelmChartYamlParser,
661 HelmChartLockParser,
662 HaxeParser,
663 HexLockParser,
664 MavenParser,
665 MesonParser,
666 MicrosoftUpdateManifestParser,
667 NixDefaultParser,
668 NixFlakeLockParser,
669 NixFlakeParser,
670 NpmLockParser,
671 NpmParser,
672 NpmWorkspaceParser,
673 DotNetDepsJsonParser,
674 CentralPackageManagementPropsParser,
675 DirectoryBuildPropsParser,
676 NupkgParser,
677 NuspecParser,
678 PackageReferenceProjectParser,
679 OpamParser,
680 OsReleaseParser,
681 PackagesConfigParser,
682 PackagesLockParser,
683 ProjectJsonParser,
684 ProjectLockJsonParser,
685 PipfileLockParser,
686 PipInspectDeplockParser,
687 PixiTomlParser,
688 PixiLockParser,
689 PnpmLockParser,
690 PodfileLockParser,
691 PodfileParser,
692 PodspecJsonParser,
693 PodspecParser,
694 PoetryLockParser,
695 PylockTomlParser,
696 PubspecLockParser,
697 PubspecYamlParser,
698 PythonParser,
699 UvLockParser,
700 VcpkgManifestParser,
701 ReadmeParser,
702 RequirementsTxtParser,
703 RpmBdbDatabaseParser,
704 RpmLicenseFilesParser,
705 RpmMarinerManifestParser,
706 RpmNdbDatabaseParser,
707 RpmParser,
708 RpmSpecfileParser,
709 RpmSqliteDatabaseParser,
710 RpmYumdbParser,
711 SbtParser,
712 SwiftManifestJsonParser,
713 SwiftPackageResolvedParser,
714 SwiftShowDependenciesParser,
715 YarnLockParser,
716 ],
717 recognizers: [
718 AndroidApkRecognizer,
719 AndroidLibraryRecognizer,
720 AppleDmgRecognizer,
721 Axis2MarRecognizer,
722 Axis2ModuleXmlRecognizer,
723 CabArchiveRecognizer,
724 ChromeCrxRecognizer,
725 InstallShieldRecognizer,
726 IosIpaRecognizer,
727 IsoImageRecognizer,
728 IvyXmlRecognizer,
729 JavaEarAppXmlRecognizer,
730 JavaEarRecognizer,
731 JavaJarRecognizer,
732 JavaWarRecognizer,
733 JavaWarWebXmlRecognizer,
734 JBossSarRecognizer,
735 JBossServiceXmlRecognizer,
736 MeteorPackageRecognizer,
737 MozillaXpiRecognizer,
738 NsisRecognizer,
739 SharArchiveRecognizer,
740 SquashfsRecognizer,
741 ],
742}