package_parser/pkgs/java/
gradlelock.rs1use packageurl::PackageUrl;
2use crate::types::DependentPackage;
3
4use crate::error::SourcePkgError;
5use crate::pkgs::common::model::{Package, PackageManifest};
6
7use std::fs::File;
8use std::io::{self, BufRead};
9use std::path::Path;
10
11fn read_lines<P>(filename: P) -> io::Result<io::Lines<io::BufReader<File>>>
12where
13 P: AsRef<Path>,
14{
15 let file = File::open(filename)?;
16 Ok(io::BufReader::new(file).lines())
17}
18
19fn is_gradle_lockfile_depline(line: &str) -> bool {
20 let ret = line.starts_with('#') || line.starts_with("empty=");
21 !ret
22}
23
24fn parse_to_gradle_dependency(line: &str) -> Option<DependentPackage> {
25 let parts: Vec<&str> = line.splitn(3, ':').collect();
26 if parts.len() < 3 {
27 return None;
28 }
29
30 let group = parts[0];
31 let artifact = parts[1];
32 let (version, configurations) =
33 if let Some((version, configurations)) = parts[2].split_once('=') {
34 (Some(version), Some(configurations))
35 } else {
36 (None, None)
37 };
38
39 let is_runtime = configurations
40 .map(|c| {
41 c.contains("runtime")
42 || c.contains("Runtime")
43 || c.contains("compile")
44 || c.contains("Compile")
45 })
46 .unwrap_or(false);
47
48 let mut purl = PackageUrl::new("maven", artifact).unwrap();
49 purl.with_namespace(group);
50 if let Some(version) = version {
51 purl.with_version(version);
52 };
53
54 Some(DependentPackage {
55 purl: purl.to_string(),
56 is_resolved: true,
57 requirement: version.unwrap_or_default().to_string(),
58 is_runtime,
59 ..Default::default()
60 })
61}
62
63pub struct GradleLock {}
64
65impl GradleLock {
66 pub fn new() -> Self {
67 Self {}
68 }
69
70 fn parse_gradle_lock(path: impl AsRef<Path>) -> Result<Package, SourcePkgError> {
71 let mut contents = vec![];
72 if let Ok(lines) = read_lines(path) {
73 lines.for_each(|line| {
74 if let Ok(ip) = line {
75 contents.push(ip);
76 }
77 });
78 }
79
80 let mut package = Package {
81 ..Default::default()
82 };
83
84 for line in contents {
85 let line = line.trim();
86 if !is_gradle_lockfile_depline(line) {
87 continue;
88 }
89
90 if let Some(dep) = parse_to_gradle_dependency(line) {
91 package.dependencies.push(dep);
92 };
93 }
94
95 Ok(package)
96 }
97}
98
99#[async_trait::async_trait]
100impl PackageManifest for GradleLock {
101 fn get_name(&self) -> String {
102 "maven".into()
103 }
104
105 async fn recognize(&self, path: &Path) -> Result<Package, SourcePkgError> {
106 Self::parse_gradle_lock(path)
107 }
108
109 fn file_name_patterns(&self) -> &'static [&'static str] {
110 &["gradle.lockfile"]
111 }
112}
113
114#[cfg(test)]
115mod tests {
116 use super::*;
117
118 #[test]
119 fn parse_gradle_dep() {
120 let filepath = Path::new(concat!(
121 env!("CARGO_MANIFEST_DIR"),
122 "/testdata/gradle_lock/5-pkg"
123 ));
124
125 let package = GradleLock::parse_gradle_lock(filepath).unwrap();
126 println!("{:#?}", package);
127 }
128
129 #[test]
130 fn parse_gradle_lockfile() {
131 let filepath = Path::new(concat!(
132 env!("CARGO_MANIFEST_DIR"),
133 "/testdata/gradle_lock/gradle.lockfile"
134 ));
135
136 let package = GradleLock::parse_gradle_lock(filepath).unwrap();
137 println!("{:#?}", package);
138 }
139}