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