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