oranda/data/artifacts/
inference.rs1use camino::Utf8PathBuf;
2
3use super::*;
4
5use axoproject::platforms::{KNOWN_LINUX_TARGETS, KNOWN_MAC_TARGETS, KNOWN_WINDOWS_TARGETS};
17
18const EXTS_FOR_TAR_BZIP2: &[&str] = &[".tar.bz2", ".tb2", ".tbz", ".tbz2", ".tz2"];
20const EXTS_FOR_TAR_GZIP: &[&str] = &[".tar.gz", ".taz", ".tgz"];
21const EXTS_FOR_TAR_LZIP: &[&str] = &[".tar.lz"];
22const EXTS_FOR_TAR_LZMA: &[&str] = &[".tar.lzma", ".tlz"];
23const EXTS_FOR_TAR_XZ: &[&str] = &[".tar.xz", ".txz"];
24const EXTS_FOR_TAR_COMPRESS: &[&str] = &[".tar.Z", ".tZ", ".taZ"];
25const EXTS_FOR_TAR_ZSTD: &[&str] = &[".tar.zst", ".tzst"];
26const EXTS_FOR_TAR_BROTLI: &[&str] = &[".tar.br"];
27const EXTS_FOR_ZIP: &[&str] = &[".zip"];
28const EXTS_FOR_RAR: &[&str] = &[".rar"];
29const EXTS_FOR_7ZIP: &[&str] = &[".7z"];
30
31const KNOWN_ARCHIVE_EXTS: &[&[&str]] = &[
32 EXTS_FOR_TAR_BZIP2,
33 EXTS_FOR_TAR_GZIP,
34 EXTS_FOR_TAR_LZIP,
35 EXTS_FOR_TAR_LZMA,
36 EXTS_FOR_TAR_XZ,
37 EXTS_FOR_TAR_COMPRESS,
38 EXTS_FOR_TAR_ZSTD,
39 EXTS_FOR_TAR_BROTLI,
40 EXTS_FOR_ZIP,
41 EXTS_FOR_RAR,
42 EXTS_FOR_7ZIP,
43];
44
45const EXT_BUNDLE_MSI: &str = ".msi";
47const EXT_BUNDLE_APP: &str = ".app";
48const EXT_BUNDLE_DMG: &str = ".dmg";
49const EXT_BUNDLE_DEB: &str = ".deb";
50const EXT_BUNDLE_RPM: &str = ".rpm";
51const EXT_BUNDLE_PACMAN: &str = ".pkg.tar.";
54const EXT_BUNDLE_FLATPAK: &str = ".flatpak";
55const EXT_BUNDLE_SNAP: &str = ".snap";
56
57const KNOWN_WINDOWS_BUNDLE_EXTS: &[&str] = &[EXT_BUNDLE_MSI];
58const KNOWN_MAC_BUNDLE_EXTS: &[&str] = &[EXT_BUNDLE_APP, EXT_BUNDLE_DMG];
59const KNOWN_LINUX_BUNDLE_EXTS: &[&str] = &[
60 EXT_BUNDLE_DMG,
61 EXT_BUNDLE_DEB,
62 EXT_BUNDLE_RPM,
63 EXT_BUNDLE_PACMAN,
64 EXT_BUNDLE_FLATPAK,
65 EXT_BUNDLE_SNAP,
66];
67const KNOWN_BUNDLE_EXTS: &[&str] = &[
68 EXT_BUNDLE_MSI,
69 EXT_BUNDLE_APP,
70 EXT_BUNDLE_DMG,
71 EXT_BUNDLE_DEB,
72 EXT_BUNDLE_RPM,
73 EXT_BUNDLE_FLATPAK,
74 EXT_BUNDLE_SNAP,
75 EXT_BUNDLE_PACMAN,
76];
77
78const EXT_SCRIPT_SHELL: &str = ".sh";
80const EXT_SCRIPT_POWERSHELL: &str = ".ps1";
81const KNOWN_WINDOWS_SCRIPT_EXTS: &[&str] = &[EXT_SCRIPT_POWERSHELL];
84const KNOWN_UNIX_SCRIPT_EXTS: &[&str] = &[EXT_SCRIPT_SHELL];
85pub(crate) const KNOWN_SCRIPT_EXTS: &[&str] = &[EXT_SCRIPT_SHELL, EXT_SCRIPT_POWERSHELL];
86
87impl ReleaseArtifacts {
88 pub fn add_inference(&mut self) {
90 let app_name = self.app_name.clone();
92 for file_idx in self.file_indices() {
93 let file = self.file_mut(file_idx);
94 if !file.infer {
96 continue;
97 }
98 if let Some(app_name) = &app_name {
99 if !file.name.contains(app_name) {
102 continue;
103 }
104 }
105
106 let mut targets = vec![];
108 for target in KNOWN_TARGET_TRIPLES.iter().copied().flatten().copied() {
109 if file.name.contains(target) {
110 targets.push(target.to_owned());
111 }
112 }
113
114 let label;
115 let description = String::new();
116 let method;
117 let preference;
118
119 if file.name.contains("install")
121 && KNOWN_SCRIPT_EXTS.iter().any(|ext| file.name.ends_with(ext))
122 {
123 if targets.is_empty() {
127 targets = infer_targets_for_script(file);
128 }
129 let run_hint = infer_run_hint_for_script(file);
130 label = infer_label_for_script(file);
131 preference = InstallerPreference::Script;
132 method = InstallMethod::Run {
133 file: Some(file_idx),
134 run_hint,
135 };
136 } else if KNOWN_BUNDLE_EXTS.iter().any(|ext| file.name.ends_with(ext)) {
137 if targets.is_empty() {
144 targets = infer_targets_for_bundle(file);
145 }
146 label = infer_label_for_bundle(file);
147 preference = InstallerPreference::Native;
148 method = InstallMethod::Download { file: file_idx };
149 } else if KNOWN_ARCHIVE_EXTS
150 .iter()
151 .copied()
152 .flatten()
153 .any(|ext| file.name.ends_with(ext))
154 {
155 if targets.is_empty() {
159 continue;
160 }
161 label = infer_label_for_archive(file);
162 preference = InstallerPreference::Archive;
163 method = InstallMethod::Download { file: file_idx };
164 } else {
165 continue;
167 }
168
169 let targets = preference_to_targets(targets, preference);
170 let installer = Installer {
171 label,
172 description,
173 app_name: self.app_name.clone(),
174 targets,
175 method,
176 display: DisplayPreference::Preferred,
177 };
178 self.add_installer(installer);
179 }
180 }
181}
182
183fn infer_targets_for_bundle(file: &File) -> Vec<TargetTriple> {
186 let mut targets = vec![];
187 if KNOWN_WINDOWS_BUNDLE_EXTS
188 .iter()
189 .any(|ext| file.name.contains(ext))
190 {
191 targets.extend(KNOWN_WINDOWS_TARGETS.iter().copied().map(|t| t.to_owned()));
192 }
193 if KNOWN_MAC_BUNDLE_EXTS
194 .iter()
195 .any(|ext| file.name.contains(ext))
196 {
197 targets.extend(KNOWN_MAC_TARGETS.iter().copied().map(|t| t.to_owned()));
198 }
199 if KNOWN_LINUX_BUNDLE_EXTS
200 .iter()
201 .any(|ext| file.name.contains(ext))
202 {
203 targets.extend(
204 KNOWN_LINUX_TARGETS
205 .iter()
206 .copied()
207 .flatten()
208 .copied()
209 .map(|t| t.to_owned()),
210 );
211 }
212 targets
213}
214
215fn infer_targets_for_script(file: &File) -> Vec<TargetTriple> {
217 let mut targets = vec![];
218 if KNOWN_WINDOWS_SCRIPT_EXTS
219 .iter()
220 .any(|ext| file.name.contains(ext))
221 {
222 targets.extend(KNOWN_WINDOWS_TARGETS.iter().copied().map(|t| t.to_owned()));
223 }
224 if KNOWN_UNIX_SCRIPT_EXTS
225 .iter()
226 .any(|ext| file.name.contains(ext))
227 {
228 targets.extend(
229 KNOWN_LINUX_TARGETS
230 .iter()
231 .copied()
232 .flatten()
233 .copied()
234 .map(|t| t.to_owned()),
235 );
236 targets.extend(KNOWN_MAC_TARGETS.iter().copied().map(|t| t.to_owned()));
237 }
238 targets
239}
240
241fn infer_run_hint_for_script(file: &File) -> String {
243 if file.name.ends_with(EXT_SCRIPT_SHELL) {
244 format!(
245 "curl --proto '=https' --tlsv1.2 -LsSf {} | sh",
246 file.download_url
247 )
248 } else if file.name.ends_with(EXT_SCRIPT_POWERSHELL) {
249 format!(r#"powershell -c "irm {} | iex""#, file.download_url)
250 } else {
251 unimplemented!(
252 "Looks like someone added a new kind of script but didn't add a run hint for it?"
253 );
254 }
255}
256
257fn infer_label_for_bundle(file: &File) -> String {
259 Utf8PathBuf::from(&file.name)
261 .extension()
262 .expect("we determined a file was a bundle based on its extension, but it had none?")
263 .to_owned()
264}
265
266fn infer_label_for_archive(file: &File) -> String {
268 if EXTS_FOR_RAR.iter().any(|ext| file.name.ends_with(ext)) {
270 "rar".to_owned()
271 } else if EXTS_FOR_7ZIP.iter().any(|ext| file.name.ends_with(ext)) {
272 "7zip".to_owned()
273 } else if EXTS_FOR_ZIP.iter().any(|ext| file.name.ends_with(ext)) {
274 "zip".to_owned()
275 } else {
276 "tarball".to_owned()
277 }
278}
279
280fn infer_label_for_script(file: &File) -> String {
282 if file.name.ends_with(EXT_SCRIPT_POWERSHELL) {
283 "powershell".to_owned()
284 } else if file.name.ends_with(EXT_SCRIPT_SHELL) {
285 "shell".to_owned()
286 } else {
287 Utf8PathBuf::from(&file.name)
288 .extension()
289 .expect("we determined a file was a script based on its extension, but it had none?")
290 .to_owned()
291 }
292}