provenant/parsers/debian/
tarball.rs1use std::path::Path;
2
3use crate::models::{DatasourceId, PackageData, PackageType};
4use crate::parsers::utils::truncate_field;
5
6use super::utils::build_debian_purl;
7use super::{PACKAGE_TYPE, default_package_data};
8use crate::parsers::PackageParser;
9
10pub struct DebianOrigTarParser;
12
13impl PackageParser for DebianOrigTarParser {
14 const PACKAGE_TYPE: PackageType = PACKAGE_TYPE;
15
16 fn is_match(path: &Path) -> bool {
17 path.file_name()
18 .and_then(|n| n.to_str())
19 .map(|name| name.contains(".orig.tar."))
20 .unwrap_or(false)
21 }
22
23 fn extract_packages(path: &Path) -> Vec<PackageData> {
24 let filename = match path.file_name().and_then(|n| n.to_str()) {
25 Some(f) => f,
26 None => {
27 return vec![default_package_data(
28 DatasourceId::DebianOriginalSourceTarball,
29 )];
30 }
31 };
32
33 vec![parse_source_tarball_filename(
34 filename,
35 DatasourceId::DebianOriginalSourceTarball,
36 )]
37 }
38}
39
40crate::register_parser!(
41 "Debian original source tarball",
42 &["**/*.orig.tar.*"],
43 "deb",
44 "",
45 Some("https://www.debian.org/doc/debian-policy/ch-source.html"),
46);
47
48pub struct DebianDebianTarParser;
50
51impl PackageParser for DebianDebianTarParser {
52 const PACKAGE_TYPE: PackageType = PACKAGE_TYPE;
53
54 fn is_match(path: &Path) -> bool {
55 path.file_name()
56 .and_then(|n| n.to_str())
57 .map(|name| name.contains(".debian.tar."))
58 .unwrap_or(false)
59 }
60
61 fn extract_packages(path: &Path) -> Vec<PackageData> {
62 let filename = match path.file_name().and_then(|n| n.to_str()) {
63 Some(f) => f,
64 None => {
65 return vec![default_package_data(
66 DatasourceId::DebianSourceMetadataTarball,
67 )];
68 }
69 };
70
71 vec![parse_source_tarball_filename(
72 filename,
73 DatasourceId::DebianSourceMetadataTarball,
74 )]
75 }
76}
77
78crate::register_parser!(
79 "Debian source metadata tarball",
80 &["**/*.debian.tar.*"],
81 "deb",
82 "",
83 Some("https://www.debian.org/doc/debian-policy/ch-source.html"),
84);
85
86fn parse_source_tarball_filename(filename: &str, datasource_id: DatasourceId) -> PackageData {
87 let without_tar_ext = filename
88 .trim_end_matches(".gz")
89 .trim_end_matches(".xz")
90 .trim_end_matches(".bz2")
91 .trim_end_matches(".tar");
92
93 let parts: Vec<&str> = without_tar_ext.splitn(2, '_').collect();
94 if parts.len() < 2 {
95 return default_package_data(datasource_id);
96 }
97
98 let name = truncate_field(parts[0].to_string());
99 let version_with_suffix = parts[1];
100
101 let version = version_with_suffix
102 .trim_end_matches(".orig")
103 .trim_end_matches(".debian")
104 .to_string();
105 let version = truncate_field(version);
106
107 let namespace = Some("debian".to_string());
108
109 PackageData {
110 datasource_id: Some(datasource_id),
111 package_type: Some(PACKAGE_TYPE),
112 namespace: namespace.clone(),
113 name: Some(name.clone()),
114 version: Some(version.clone()),
115 purl: build_debian_purl(&name, Some(&version), namespace.as_deref(), None),
116 ..Default::default()
117 }
118}
119
120#[cfg(test)]
121mod tests {
122 use super::*;
123 use crate::models::DatasourceId;
124 use std::path::PathBuf;
125
126 #[test]
127 fn test_orig_tar_parser_is_match() {
128 assert!(DebianOrigTarParser::is_match(&PathBuf::from(
129 "package_1.0.orig.tar.gz"
130 )));
131 assert!(DebianOrigTarParser::is_match(&PathBuf::from(
132 "abseil_0~20200923.3.orig.tar.xz"
133 )));
134 assert!(!DebianOrigTarParser::is_match(&PathBuf::from(
135 "package.debian.tar.gz"
136 )));
137 assert!(!DebianOrigTarParser::is_match(&PathBuf::from("control")));
138 }
139
140 #[test]
141 fn test_debian_tar_parser_is_match() {
142 assert!(DebianDebianTarParser::is_match(&PathBuf::from(
143 "package_1.0-1.debian.tar.xz"
144 )));
145 assert!(DebianDebianTarParser::is_match(&PathBuf::from(
146 "abseil_20220623.1-1.debian.tar.gz"
147 )));
148 assert!(!DebianDebianTarParser::is_match(&PathBuf::from(
149 "package.orig.tar.gz"
150 )));
151 assert!(!DebianDebianTarParser::is_match(&PathBuf::from("control")));
152 }
153
154 #[test]
155 fn test_parse_orig_tar_filename() {
156 let pkg = parse_source_tarball_filename(
157 "abseil_0~20200923.3.orig.tar.gz",
158 DatasourceId::DebianOriginalSourceTarball,
159 );
160 assert_eq!(pkg.name, Some("abseil".to_string()));
161 assert_eq!(pkg.version, Some("0~20200923.3".to_string()));
162 assert_eq!(pkg.namespace, Some("debian".to_string()));
163 assert_eq!(
164 pkg.purl,
165 Some("pkg:deb/debian/abseil@0~20200923.3".to_string())
166 );
167 assert_eq!(
168 pkg.datasource_id,
169 Some(DatasourceId::DebianOriginalSourceTarball)
170 );
171 }
172
173 #[test]
174 fn test_parse_debian_tar_filename() {
175 let pkg = parse_source_tarball_filename(
176 "abseil_20220623.1-1.debian.tar.xz",
177 DatasourceId::DebianSourceMetadataTarball,
178 );
179 assert_eq!(pkg.name, Some("abseil".to_string()));
180 assert_eq!(pkg.version, Some("20220623.1-1".to_string()));
181 assert_eq!(pkg.namespace, Some("debian".to_string()));
182 assert_eq!(
183 pkg.purl,
184 Some("pkg:deb/debian/abseil@20220623.1-1".to_string())
185 );
186 }
187
188 #[test]
189 fn test_parse_source_tarball_various_compressions() {
190 let pkg_gz = parse_source_tarball_filename(
191 "test_1.0.orig.tar.gz",
192 DatasourceId::DebianOriginalSourceTarball,
193 );
194 let pkg_xz = parse_source_tarball_filename(
195 "test_1.0.orig.tar.xz",
196 DatasourceId::DebianOriginalSourceTarball,
197 );
198 let pkg_bz2 = parse_source_tarball_filename(
199 "test_1.0.orig.tar.bz2",
200 DatasourceId::DebianOriginalSourceTarball,
201 );
202
203 assert_eq!(pkg_gz.version, Some("1.0".to_string()));
204 assert_eq!(pkg_xz.version, Some("1.0".to_string()));
205 assert_eq!(pkg_bz2.version, Some("1.0".to_string()));
206 }
207
208 #[test]
209 fn test_parse_source_tarball_invalid_format() {
210 let pkg = parse_source_tarball_filename(
211 "invalid-no-underscore.tar.gz",
212 DatasourceId::DebianOriginalSourceTarball,
213 );
214 assert!(pkg.name.is_none());
215 assert!(pkg.version.is_none());
216 }
217}