diff --git a/src/bsd/mod.rs b/src/bsd/mod.rs index a0caf56..c9949d8 100644 --- a/src/bsd/mod.rs +++ b/src/bsd/mod.rs @@ -1,8 +1,7 @@ -use crate::store_data::{ArchiveFormat, Config, Disk, Distro, Source, WebSource}; +use crate::store_data::{ArchiveFormat, ChecksumSeparation, Config, Disk, Distro, Source, WebSource}; use crate::utils::capture_page; use quickemu::config::{Arch, GuestOS}; use regex::Regex; -use std::collections::HashMap; use std::sync::Arc; const FREEBSD_X86_64_RELEASES: &str = "https://download.freebsd.org/ftp/releases/amd64/amd64/"; @@ -18,7 +17,6 @@ impl Distro for FreeBSD { const DESCRIPTION: Option<&'static str> = Some("Operating system used to power modern servers, desktops, and embedded platforms."); async fn generate_configs() -> Option> { let freebsd_regex = Arc::new(Regex::new(r#"href="([0-9\.]+)-RELEASE"#).unwrap()); - let checksum_regex = Arc::new(Regex::new(r#"SHA256 \(([^)]+)\) = ([0-9a-f]+)"#).unwrap()); let futures = [ (FREEBSD_X86_64_RELEASES, "amd64", Arch::x86_64), (FREEBSD_AARCH64_RELEASES, "arm64-aarch64", Arch::aarch64), @@ -26,19 +24,8 @@ impl Distro for FreeBSD { ] .iter() .map(|(mirror, denom, arch)| { - let checksum_regex = checksum_regex.clone(); let freebsd_regex = freebsd_regex.clone(); - let build_checksums = |cs_url: String, cs_regex: Arc| async move { - let checksum_page = capture_page(&cs_url).await; - checksum_page.map(|cs| { - cs_regex - .captures_iter(&cs) - .map(|c| (c[1].to_string(), c[2].to_string())) - .collect::>() - }) - }; - async move { if let Some(page) = capture_page(mirror).await { let futures = freebsd_regex @@ -46,8 +33,6 @@ impl Distro for FreeBSD { .flat_map(|c| { let release = c[1].to_string(); let vm_image_release = release.clone(); - let normal_checksum_regex = checksum_regex.clone(); - let vm_checksum_regex = checksum_regex.clone(); let vm_image_mirror = { let arch = if *arch == Arch::x86_64 { "amd64" } else { &arch.to_string() }; @@ -56,7 +41,7 @@ impl Distro for FreeBSD { let normal_editions = tokio::spawn(async move { let checksum_url = format!("{mirror}ISO-IMAGES/{release}/CHECKSUM.SHA256-FreeBSD-{release}-RELEASE-{denom}"); - let mut checksums = build_checksums(checksum_url, normal_checksum_regex).await; + let mut checksums = ChecksumSeparation::Sha256Regex.build(&checksum_url).await; FREEBSD_EDITIONS .iter() .map(|edition| { @@ -78,7 +63,8 @@ impl Distro for FreeBSD { let vm_image = tokio::spawn(async move { let iso = format!("FreeBSD-{vm_image_release}-RELEASE-{denom}.qcow2.xz"); let checksum_url = format!("{vm_image_mirror}CHECKSUM.SHA256"); - let checksum = build_checksums(checksum_url, vm_checksum_regex) + let checksum = ChecksumSeparation::Sha256Regex + .build(&checksum_url) .await .and_then(|mut cs| cs.remove(&iso)); let url = vm_image_mirror + &iso; diff --git a/src/linux/arch.rs b/src/linux/arch.rs index 3a80cc2..13223ef 100644 --- a/src/linux/arch.rs +++ b/src/linux/arch.rs @@ -1,12 +1,12 @@ pub mod manjaro; use crate::{ - store_data::{Config, Distro, Source, WebSource}, + store_data::{ChecksumSeparation, Config, Distro, Source, WebSource}, utils::{capture_page, GatherData, GithubAPI}, }; use regex::Regex; use serde::Deserialize; -use std::{collections::HashMap, sync::Arc}; +use std::sync::Arc; const ARCHCRAFT_MIRROR: &str = "https://sourceforge.net/projects/archcraft/files/"; @@ -117,13 +117,10 @@ impl Distro for ArcoLinux { let release = c[1].to_string(); let mirror = format!("{ARCOLINUX_MIRROR}{release}/"); let iso_regex = iso_regex.clone(); - let checksum_regex = checksum_regex.clone(); + let checksums = ChecksumSeparation::CustomRegex(checksum_regex.clone(), 2, 1); async move { let page = capture_page(&mirror).await?; - let checksums = checksum_regex - .captures_iter(&page) - .map(|c| (c[2].to_string(), c[1].to_string())) - .collect::>(); + let checksums = checksums.build_with_data(&page).await; let futures = iso_regex .captures_iter(&page) @@ -177,11 +174,7 @@ impl Distro for ArtixLinux { let page = capture_page(ARTIX_MIRROR).await?; let iso_regex = Regex::new(r#"href="(artix-(.*?)-([^-]+-[0-9]+)-x86_64.iso)""#).unwrap(); - let checksums = capture_page(&format!("{ARTIX_MIRROR}sha256sums")).await.map(|c| { - c.lines() - .filter_map(|l| l.split_once(" ").map(|(hash, file)| (file.to_string(), hash.to_string()))) - .collect::>() - }); + let checksums = ChecksumSeparation::Whitespace.build(&format!("{ARTIX_MIRROR}sha256sums")).await; iso_regex .captures_iter(&page) diff --git a/src/linux/debian.rs b/src/linux/debian.rs index 6a92ea0..50a9baf 100644 --- a/src/linux/debian.rs +++ b/src/linux/debian.rs @@ -1,9 +1,8 @@ use crate::{ - store_data::{Config, Distro, Source, WebSource}, + store_data::{ChecksumSeparation, Config, Distro, Source, WebSource}, utils::capture_page, }; use regex::Regex; -use std::collections::HashMap; use std::sync::Arc; const ANTIX_MIRROR: &str = "https://sourceforge.net/projects/antix-linux/files/Final/"; @@ -20,6 +19,14 @@ impl Distro for Antix { let releases_regex = Regex::new(r#""name":"antiX-([0-9.]+)""#).unwrap(); let iso_regex = Arc::new(Regex::new(r#""name":"(antiX-[0-9.]+(?:-runit)?(?:-[^_]+)?_x64-([^.]+).iso)".*?"download_url":"(.*?)""#).unwrap()); + let skip_until_sha256 = |cs_data: String| { + cs_data + .lines() + .skip_while(|l| !l.starts_with("sha256")) + .collect::>() + .join("\n") + }; + let futures = releases_regex.captures_iter(&releases).take(3).map(|r| { let release = r[1].to_string(); let mirror = format!("{ANTIX_MIRROR}antiX-{release}/"); @@ -29,17 +36,10 @@ impl Distro for Antix { let iso_regex = iso_regex.clone(); async move { - let main_checksums = capture_page(&checksum_mirror).await; - let runit_checksums = capture_page(&runit_checksum_mirror).await; - let mut checksums = main_checksums - .iter() - .chain(runit_checksums.iter()) - .flat_map(|cs| { - cs.lines() - .skip_while(|l| !l.starts_with("sha256")) - .filter_map(|l| l.split_once(" ").map(|(a, b)| (b.to_string(), a.to_string()))) - }) - .collect::>(); + let main_checksums = capture_page(&checksum_mirror).await.map(skip_until_sha256).unwrap_or_default(); + let runit_checksums = capture_page(&runit_checksum_mirror).await.map(skip_until_sha256); + let checksums = main_checksums + "\n" + &runit_checksums.unwrap_or_default(); + let mut checksums = ChecksumSeparation::Whitespace.build_with_data(&checksums).await; let page = capture_page(&mirror).await?; let iso_regex = iso_regex.clone(); @@ -75,3 +75,14 @@ impl Distro for Antix { .into() } } + +pub struct BunsenLabs; +impl Distro for BunsenLabs { + const NAME: &'static str = "bunsenlabs"; + const PRETTY_NAME: &'static str = "BunsenLabs"; + const HOMEPAGE: Option<&'static str> = Some("https://www.bunsenlabs.org/"); + const DESCRIPTION: Option<&'static str> = Some("Light-weight and easily customizable Openbox desktop. The project is a community continuation of CrunchBang Linux."); + async fn generate_configs() -> Option> { + todo!() + } +} diff --git a/src/linux/fedora_redhat.rs b/src/linux/fedora_redhat.rs index 7e75087..0371ef4 100644 --- a/src/linux/fedora_redhat.rs +++ b/src/linux/fedora_redhat.rs @@ -1,9 +1,8 @@ use crate::{ - store_data::{Arch, Config, Distro, Source, WebSource}, + store_data::{Arch, ChecksumSeparation, Config, Distro, Source, WebSource}, utils::capture_page, }; use regex::Regex; -use std::collections::HashMap; use std::sync::Arc; const ALMA_MIRROR: &str = "https://repo.almalinux.org/almalinux/"; @@ -19,7 +18,6 @@ impl Distro for Alma { let releases_regex = Regex::new(r#""#).unwrap()); - let checksum_regex = Arc::new(Regex::new(r#"SHA256 \(([^)]+)\) = ([0-9a-f]+)"#).unwrap()); let futures = releases_regex.captures_iter(&releases).flat_map(|r| { let release = r[1].to_string(); @@ -28,18 +26,11 @@ impl Distro for Alma { .map(|arch| { let release = release.clone(); let iso_regex = iso_regex.clone(); - let checksum_regex = checksum_regex.clone(); let mirror = format!("{ALMA_MIRROR}{release}/isos/{arch}/"); async move { let page = capture_page(&mirror).await?; - let checksum_page = capture_page(&format!("{mirror}CHECKSUM")).await; - let checksums = checksum_page.map(|cs| { - checksum_regex - .captures_iter(&cs) - .map(|c| (c[1].to_string(), c[2].to_string())) - .collect::>() - }); + let checksums = ChecksumSeparation::Sha256Regex.build(&format!("{mirror}CHECKSUM")).await; Some( iso_regex diff --git a/src/store_data.rs b/src/store_data.rs index c513f7b..9d7a0da 100644 --- a/src/store_data.rs +++ b/src/store_data.rs @@ -1,6 +1,9 @@ use crate::utils::all_valid; +use once_cell::sync::Lazy; pub use quickemu::config::Arch; pub use quickget::data_structures::{ArchiveFormat, Config, Disk, Source, WebSource, OS}; +use regex::Regex; +use std::{collections::HashMap, sync::Arc}; pub trait Distro { const NAME: &'static str; @@ -89,3 +92,37 @@ pub fn extract_disk_urls(sources: Option<&[Disk]>) -> Vec { }) .collect() } + +pub static DEFAULT_SHA256_REGEX: Lazy = Lazy::new(|| Regex::new(r#"SHA256 \(([^)]+)\) = ([0-9a-f]+)"#).unwrap()); + +pub enum ChecksumSeparation { + Whitespace, + Sha256Regex, + CustomRegex(Arc, usize, usize), +} + +impl ChecksumSeparation { + pub async fn build(self, url: &str) -> Option> { + let data = crate::utils::capture_page(url).await?; + Some(self.build_with_data(&data).await) + } + pub async fn build_with_data(self, data: &str) -> HashMap { + match self { + Self::Whitespace => data + .lines() + .filter_map(|l| { + l.split_once(' ') + .map(|(hash, file)| (file.trim().to_string(), hash.trim().to_string())) + }) + .collect(), + Self::Sha256Regex => DEFAULT_SHA256_REGEX + .captures_iter(data) + .map(|c| (c[1].to_string(), c[2].to_string())) + .collect(), + Self::CustomRegex(regex, keyindex, valueindex) => regex + .captures_iter(data) + .map(|c| (c[keyindex].to_string(), c[valueindex].to_string())) + .collect(), + } + } +}