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