1use serde::{Deserialize, Serialize};
2use std::collections::HashMap;
3
4use super::license_detection::OutputLicenseDetection;
5use super::party::OutputParty;
6use super::serde_helpers::serialize_optional_map_as_object;
7
8#[derive(Serialize, Deserialize, Debug, Clone)]
9pub struct OutputPackage {
10 #[serde(rename = "type")]
11 pub package_type: Option<crate::models::PackageType>,
12 pub namespace: Option<String>,
13 pub name: Option<String>,
14 pub version: Option<String>,
15 #[serde(default, serialize_with = "serialize_optional_map_as_object")]
16 pub qualifiers: Option<HashMap<String, String>>,
17 pub subpath: Option<String>,
18 pub primary_language: Option<String>,
19 pub description: Option<String>,
20 pub release_date: Option<String>,
21 #[serde(default)]
22 pub parties: Vec<OutputParty>,
23 #[serde(default)]
24 pub keywords: Vec<String>,
25 pub homepage_url: Option<String>,
26 pub download_url: Option<String>,
27 pub size: Option<u64>,
28 #[serde(skip_serializing_if = "Option::is_none")]
29 pub sha1: Option<String>,
30 #[serde(skip_serializing_if = "Option::is_none")]
31 pub md5: Option<String>,
32 #[serde(skip_serializing_if = "Option::is_none")]
33 pub sha256: Option<String>,
34 #[serde(skip_serializing_if = "Option::is_none")]
35 pub sha512: Option<String>,
36 pub bug_tracking_url: Option<String>,
37 pub code_view_url: Option<String>,
38 pub vcs_url: Option<String>,
39 pub copyright: Option<String>,
40 pub holder: Option<String>,
41 pub declared_license_expression: Option<String>,
42 pub declared_license_expression_spdx: Option<String>,
43 #[serde(default)]
44 pub license_detections: Vec<OutputLicenseDetection>,
45 pub other_license_expression: Option<String>,
46 pub other_license_expression_spdx: Option<String>,
47 #[serde(default)]
48 pub other_license_detections: Vec<OutputLicenseDetection>,
49 pub extracted_license_statement: Option<String>,
50 pub notice_text: Option<String>,
51 #[serde(default)]
52 pub source_packages: Vec<String>,
53 #[serde(default)]
54 pub is_private: bool,
55 #[serde(default)]
56 pub is_virtual: bool,
57 #[serde(default, serialize_with = "serialize_optional_map_as_object")]
58 pub extra_data: Option<HashMap<String, serde_json::Value>>,
59 pub repository_homepage_url: Option<String>,
60 pub repository_download_url: Option<String>,
61 pub api_data_url: Option<String>,
62 pub purl: Option<String>,
63 pub package_uid: String,
64 pub datafile_paths: Vec<String>,
65 pub datasource_ids: Vec<crate::models::DatasourceId>,
66}
67
68impl From<&crate::models::Package> for OutputPackage {
69 fn from(value: &crate::models::Package) -> Self {
70 Self {
71 package_type: value.package_type,
72 namespace: value.namespace.clone(),
73 name: value.name.clone(),
74 version: value.version.clone(),
75 qualifiers: value.qualifiers.clone(),
76 subpath: value.subpath.clone(),
77 primary_language: value.primary_language.clone(),
78 description: value.description.clone(),
79 release_date: value.release_date.clone(),
80 parties: value.parties.iter().map(OutputParty::from).collect(),
81 keywords: value.keywords.clone(),
82 homepage_url: value.homepage_url.clone(),
83 download_url: value.download_url.clone(),
84 size: value.size,
85 sha1: value.sha1.as_ref().map(|d| d.as_hex()),
86 md5: value.md5.as_ref().map(|d| d.as_hex()),
87 sha256: value.sha256.as_ref().map(|d| d.as_hex()),
88 sha512: value.sha512.as_ref().map(|d| d.as_hex()),
89 bug_tracking_url: value.bug_tracking_url.clone(),
90 code_view_url: value.code_view_url.clone(),
91 vcs_url: value.vcs_url.clone(),
92 copyright: value.copyright.clone(),
93 holder: value.holder.clone(),
94 declared_license_expression: value.declared_license_expression.clone(),
95 declared_license_expression_spdx: value.declared_license_expression_spdx.clone(),
96 license_detections: value
97 .license_detections
98 .iter()
99 .map(OutputLicenseDetection::from)
100 .collect(),
101 other_license_expression: value.other_license_expression.clone(),
102 other_license_expression_spdx: value.other_license_expression_spdx.clone(),
103 other_license_detections: value
104 .other_license_detections
105 .iter()
106 .map(OutputLicenseDetection::from)
107 .collect(),
108 extracted_license_statement: value.extracted_license_statement.clone(),
109 notice_text: value.notice_text.clone(),
110 source_packages: value.source_packages.clone(),
111 is_private: value.is_private,
112 is_virtual: value.is_virtual,
113 extra_data: value.extra_data.clone(),
114 repository_homepage_url: value.repository_homepage_url.clone(),
115 repository_download_url: value.repository_download_url.clone(),
116 api_data_url: value.api_data_url.clone(),
117 purl: value.purl.clone(),
118 package_uid: value.package_uid.to_string(),
119 datafile_paths: value.datafile_paths.clone(),
120 datasource_ids: value.datasource_ids.clone(),
121 }
122 }
123}
124
125impl TryFrom<&OutputPackage> for crate::models::Package {
126 type Error = String;
127 fn try_from(value: &OutputPackage) -> Result<Self, Self::Error> {
128 let mut parties = Vec::with_capacity(value.parties.len());
129 for p in &value.parties {
130 parties.push(crate::models::Party::try_from(p)?);
131 }
132 let mut license_detections = Vec::with_capacity(value.license_detections.len());
133 for d in &value.license_detections {
134 license_detections.push(crate::models::LicenseDetection::try_from(d)?);
135 }
136 let mut other_license_detections = Vec::with_capacity(value.other_license_detections.len());
137 for d in &value.other_license_detections {
138 other_license_detections.push(crate::models::LicenseDetection::try_from(d)?);
139 }
140 Ok(Self {
141 package_type: value.package_type,
142 namespace: value.namespace.clone(),
143 name: value.name.clone(),
144 version: value.version.clone(),
145 qualifiers: value.qualifiers.clone(),
146 subpath: value.subpath.clone(),
147 primary_language: value.primary_language.clone(),
148 description: value.description.clone(),
149 release_date: value.release_date.clone(),
150 parties,
151 keywords: value.keywords.clone(),
152 homepage_url: value.homepage_url.clone(),
153 download_url: value.download_url.clone(),
154 size: value.size,
155 sha1: value
156 .sha1
157 .as_ref()
158 .map(|s| crate::models::Sha1Digest::from_hex(s))
159 .transpose()
160 .map_err(|e| format!("invalid sha1: {}", e))?,
161 md5: value
162 .md5
163 .as_ref()
164 .map(|s| crate::models::Md5Digest::from_hex(s))
165 .transpose()
166 .map_err(|e| format!("invalid md5: {}", e))?,
167 sha256: value
168 .sha256
169 .as_ref()
170 .map(|s| crate::models::Sha256Digest::from_hex(s))
171 .transpose()
172 .map_err(|e| format!("invalid sha256: {}", e))?,
173 sha512: value
174 .sha512
175 .as_ref()
176 .map(|s| crate::models::Sha512Digest::from_hex(s))
177 .transpose()
178 .map_err(|e| format!("invalid sha512: {}", e))?,
179 bug_tracking_url: value.bug_tracking_url.clone(),
180 code_view_url: value.code_view_url.clone(),
181 vcs_url: value.vcs_url.clone(),
182 copyright: value.copyright.clone(),
183 holder: value.holder.clone(),
184 declared_license_expression: value.declared_license_expression.clone(),
185 declared_license_expression_spdx: value.declared_license_expression_spdx.clone(),
186 license_detections,
187 other_license_expression: value.other_license_expression.clone(),
188 other_license_expression_spdx: value.other_license_expression_spdx.clone(),
189 other_license_detections,
190 extracted_license_statement: value.extracted_license_statement.clone(),
191 notice_text: value.notice_text.clone(),
192 source_packages: value.source_packages.clone(),
193 is_private: value.is_private,
194 is_virtual: value.is_virtual,
195 extra_data: value.extra_data.clone(),
196 repository_homepage_url: value.repository_homepage_url.clone(),
197 repository_download_url: value.repository_download_url.clone(),
198 api_data_url: value.api_data_url.clone(),
199 purl: value.purl.clone(),
200 package_uid: crate::models::PackageUid::from_raw(value.package_uid.clone()),
201 datafile_paths: value.datafile_paths.clone(),
202 datasource_ids: value.datasource_ids.clone(),
203 })
204 }
205}