1use core::convert::TryFrom;
8
9use crate::catalog::package::{CatalogInstaller, CatalogPackage};
10use crate::catalog::raw::{RawCatalogInstaller, RawCatalogPackage};
11use crate::package::Package;
12use crate::package::PackageId;
13use crate::shared::ModelError;
14
15impl From<&Package> for CatalogPackage {
16 fn from(package: &Package) -> Self {
17 let package_id = PackageId::parse(package.id.as_ref()).expect("package id should parse");
18
19 Self {
20 id: package.id.clone().into(),
21 name: package.name.clone(),
22 version: package.version.clone(),
23 source: package_id.source(),
24 namespace: package_id.namespace().map(str::to_string),
25 source_id: package_id.source_id().to_string(),
26 created_at: None,
27 updated_at: None,
28 description: package.description.clone(),
29 homepage: package.homepage.clone(),
30 license: package.license.clone(),
31 publisher: package.publisher.clone(),
32 locale: None,
33 moniker: None,
34 platform: None,
35 commands: None,
36 protocols: None,
37 file_extensions: None,
38 capabilities: None,
39 tags: None,
40 bin: None,
41 env_add_path: None,
42 }
43 }
44}
45
46impl TryFrom<RawCatalogPackage> for CatalogPackage {
47 type Error = ModelError;
48
49 fn try_from(raw: RawCatalogPackage) -> Result<Self, Self::Error> {
50 let source = raw.source.parse()?;
51
52 let package = Self {
53 id: raw.id.into(),
54 name: raw.name,
55 version: raw.version.parse()?,
56 source,
57 namespace: raw.namespace,
58 source_id: raw.source_id,
59 created_at: None,
60 updated_at: None,
61 description: raw.description,
62 homepage: raw.homepage,
63 license: raw.license,
64 publisher: raw.publisher,
65 locale: raw.locale,
66 moniker: raw.moniker,
67 platform: raw.platform,
68 commands: raw.commands,
69 protocols: raw.protocols,
70 file_extensions: raw.file_extensions,
71 capabilities: raw.capabilities,
72 tags: raw.tags,
73 bin: raw.bin,
74 env_add_path: raw.env_add_path,
75 };
76
77 package.validate()?;
78 Ok(package)
79 }
80}
81
82impl TryFrom<RawCatalogInstaller> for CatalogInstaller {
83 type Error = ModelError;
84
85 fn try_from(raw: RawCatalogInstaller) -> Result<Self, Self::Error> {
86 let installer = Self {
87 package_id: raw.package_id.into(),
88 url: raw.url,
89 hash: raw.hash,
90 hash_algorithm: raw.hash_algorithm,
91 installer_type: raw.installer_type,
92 installer_switches: raw.installer_switches,
93 platform: raw.platform,
94 commands: raw.commands,
95 protocols: raw.protocols,
96 file_extensions: raw.file_extensions,
97 capabilities: raw.capabilities,
98 arch: raw.arch.parse()?,
99 kind: raw.kind.parse()?,
100 nested_kind: raw.nested_kind.map(|kind| kind.parse()).transpose()?,
101 scope: raw.scope,
102 };
103
104 installer.validate()?;
105 Ok(installer)
106 }
107}
108
109#[cfg(test)]
110mod tests {
111 use super::{CatalogInstaller, CatalogPackage};
112 use crate::catalog::installer_type::CatalogInstallerType;
113 use crate::catalog::raw::{RawCatalogInstaller, RawCatalogPackage};
114 use crate::install::{Architecture, InstallerType};
115 use crate::package::PackageSource;
116
117 #[test]
118 fn raw_catalog_package_converts_and_derives_source() {
119 let package = RawCatalogPackage {
120 id: "winget/Contoso.App".to_string(),
121 name: "Contoso App".to_string(),
122 version: "1.2.3".to_string(),
123 source: "winget".to_string(),
124 namespace: None,
125 source_id: "Contoso.App".to_string(),
126 description: Some("Example package".to_string()),
127 homepage: None,
128 license: None,
129 publisher: Some("Contoso Ltd.".to_string()),
130 locale: Some("en-US".to_string()),
131 moniker: Some("contoso".to_string()),
132 platform: Some("[\"Windows.Desktop\"]".to_string()),
133 commands: Some("[\"contoso\"]".to_string()),
134 protocols: Some("[\"contoso-protocol\"]".to_string()),
135 file_extensions: Some("[\".app\"]".to_string()),
136 capabilities: Some("[\"internetClient\"]".to_string()),
137 tags: Some("[\"utility\"]".to_string()),
138 bin: Some("[\"tool.exe\"]".to_string()),
139 env_add_path: Some("[\"bin\"]".to_string()),
140 };
141
142 let converted = CatalogPackage::try_from(package).expect("raw package should convert");
143
144 assert_eq!(converted.source, PackageSource::Winget);
145 assert_eq!(converted.namespace, None);
146 assert_eq!(converted.source_id, "Contoso.App");
147 assert_eq!(converted.version.to_string(), "1.2.3");
148 assert_eq!(converted.locale.as_deref(), Some("en-US"));
149 assert_eq!(converted.moniker.as_deref(), Some("contoso"));
150 assert_eq!(converted.platform.as_deref(), Some("[\"Windows.Desktop\"]"));
151 assert_eq!(converted.commands.as_deref(), Some("[\"contoso\"]"));
152 assert_eq!(
153 converted.protocols.as_deref(),
154 Some("[\"contoso-protocol\"]")
155 );
156 assert_eq!(converted.file_extensions.as_deref(), Some("[\".app\"]"));
157 assert_eq!(
158 converted.capabilities.as_deref(),
159 Some("[\"internetClient\"]")
160 );
161 assert_eq!(converted.tags.as_deref(), Some("[\"utility\"]"));
162 assert_eq!(converted.bin.as_deref(), Some("[\"tool.exe\"]"));
163 assert_eq!(converted.env_add_path.as_deref(), Some("[\"bin\"]"));
164 }
165
166 #[test]
167 fn raw_catalog_installer_converts() {
168 let installer = RawCatalogInstaller {
169 package_id: "winget/Contoso.App".to_string(),
170 url: "https://example.test/app.exe".to_string(),
171 hash: String::default(),
172 hash_algorithm: crate::shared::HashAlgorithm::Sha256,
173 installer_type: CatalogInstallerType::Zip,
174 installer_switches: Some("/S".to_string()),
175 platform: Some("[\"Windows.Desktop\"]".to_string()),
176 commands: Some("[\"contoso\"]".to_string()),
177 protocols: Some("[\"contoso-protocol\"]".to_string()),
178 file_extensions: Some("[\".exe\"]".to_string()),
179 capabilities: Some("[\"internetClient\"]".to_string()),
180 arch: String::default(),
181 kind: "portable".to_string(),
182 nested_kind: Some("msi".to_string()),
183 scope: Some("machine".to_string()),
184 };
185
186 let converted =
187 CatalogInstaller::try_from(installer).expect("raw installer should convert");
188
189 assert_eq!(converted.arch, Architecture::Any);
190 assert_eq!(converted.kind, InstallerType::Portable);
191 assert_eq!(converted.nested_kind, Some(InstallerType::Msi));
192 assert_eq!(converted.scope.as_deref(), Some("machine"));
193 assert_eq!(converted.platform.as_deref(), Some("[\"Windows.Desktop\"]"));
194 assert_eq!(converted.commands.as_deref(), Some("[\"contoso\"]"));
195 assert_eq!(
196 converted.protocols.as_deref(),
197 Some("[\"contoso-protocol\"]")
198 );
199 assert_eq!(converted.file_extensions.as_deref(), Some("[\".exe\"]"));
200 assert_eq!(
201 converted.capabilities.as_deref(),
202 Some("[\"internetClient\"]")
203 );
204 assert_eq!(
205 converted.hash_algorithm,
206 crate::shared::HashAlgorithm::Sha256
207 );
208 assert_eq!(converted.installer_type, CatalogInstallerType::Zip);
209 assert_eq!(converted.installer_switches.as_deref(), Some("/S"));
210 }
211}