use crate::models::common::enums::Filetype;
use crate::utils::platform_info::{CpuArch, OSKind};
const ARCHIVE_EXTENSIONS: &[&str] = &[
".zip", ".tar", ".tar.gz", ".tgz", ".tar.bz2", ".tbz2", ".tbz", ".tar.xz", ".txz", ".7z",
".rar", ".tar.zst", ".tzst",
];
const COMPRESSION_EXTENSIONS: &[&str] = &[".gz", ".br", ".bz2", ".zst"];
const CHECKSUM_EXTENSIONS: &[&str] = &[
".sha256", ".sha512", ".sha1", ".md5", ".sig", ".asc", ".minisig", ".sum",
];
pub fn parse_os(filename: &str) -> Option<OSKind> {
let name = filename.to_lowercase();
if contains_marker(
&name,
&[
".exe", ".msi", ".dll", "windows", "win64", "win32", "win", "msvc",
],
) {
return Some(OSKind::Windows);
}
if contains_marker(&name, &["ios", "iphone", "ipad"]) {
return Some(OSKind::Ios);
}
if contains_marker(&name, &["macos", "darwin", "osx", "mac", ".dmg", ".app"]) {
return Some(OSKind::MacOS);
}
if contains_marker(&name, &["android", ".apk", ".aab"]) {
return Some(OSKind::Android);
}
if contains_marker(&name, &["linux", "gnu", ".appimage", "musl"]) {
return Some(OSKind::Linux);
}
if contains_marker(&name, &["freebsd", "fbsd"]) {
return Some(OSKind::FreeBSD);
}
if contains_marker(&name, &["openbsd", "obsd"]) {
return Some(OSKind::OpenBSD);
}
if contains_marker(&name, &["netbsd", "nbsd"]) {
return Some(OSKind::NetBSD);
}
None
}
pub fn parse_arch(filename: &str) -> Option<CpuArch> {
let name = filename.to_lowercase();
if contains_marker(&name, &["aarch64", "arm64", "armv8"]) {
return Some(CpuArch::Aarch64);
}
if contains_marker(&name, &["armv7", "armv7l", "armv6", "arm"]) {
return Some(CpuArch::Arm);
}
if contains_marker(&name, &["x86_64", "x86-64", "amd64", "x64", "win64"]) {
return Some(CpuArch::X86_64);
}
if contains_marker(&name, &["x86_32", "x86-32", "win32"]) {
return Some(CpuArch::X86);
}
if contains_marker(&name, &["x86"]) {
if name.contains("32") {
return Some(CpuArch::X86);
}
return Some(CpuArch::X86_64);
}
None
}
pub fn parse_filetype(filename: &str) -> Filetype {
let filename = filename.to_lowercase();
if filename.ends_with(".appimage") {
return Filetype::AppImage;
}
if filename.ends_with(".exe") {
return Filetype::WinExe;
}
if ARCHIVE_EXTENSIONS.iter().any(|ext| filename.ends_with(ext)) {
return Filetype::Archive;
}
if COMPRESSION_EXTENSIONS
.iter()
.any(|ext| filename.ends_with(ext))
{
return Filetype::Compressed;
}
if CHECKSUM_EXTENSIONS
.iter()
.any(|ext| filename.ends_with(ext))
{
return Filetype::Checksum;
}
Filetype::Binary
}
fn contains_marker(filename: &str, markers: &[&str]) -> bool {
for marker in markers {
if marker.starts_with('.') {
if filename.ends_with(marker) {
return true;
}
continue;
}
if let Some(mut index) = filename.find(marker) {
loop {
let valid_start =
index == 0 || !filename.chars().nth(index - 1).unwrap().is_alphanumeric();
let valid_end = index + marker.len() >= filename.len()
|| !filename
.chars()
.nth(index + marker.len())
.unwrap()
.is_alphanumeric();
if valid_start && valid_end {
return true;
}
match filename[index + 1..].find(marker) {
Some(offset) => index = index + 1 + offset,
None => break,
}
}
}
}
false
}
#[cfg(test)]
#[path = "../../tests/utils/filename_parser.rs"]
mod tests;