support more package compressions

This commit is contained in:
JMARyA 2025-03-28 09:17:24 +01:00
parent 788de4da7d
commit 656df96792
Signed by: jmarya
GPG key ID: 901B2ADDF27C2263
6 changed files with 115 additions and 36 deletions

View file

@ -51,23 +51,20 @@ async fn launch() -> _ {
..Default::default() ..Default::default()
}) })
.mount_assets() .mount_assets()
.mount( .mount("/", routes![
"/", routes::index_page,
routes![ routes::pkg_route,
routes::index_page, routes::push::upload_pkg,
routes::pkg_route, routes::user::login,
routes::push::upload_pkg, routes::user::login_post,
routes::user::login, routes::user::account_page,
routes::user::login_post, routes::ui::pkg_ui,
routes::user::account_page, routes::ui::repo_ui,
routes::ui::pkg_ui, routes::user::new_api_key,
routes::ui::repo_ui, routes::user::end_session,
routes::user::new_api_key, routes::user::change_password,
routes::user::end_session, routes::user::change_password_post
routes::user::change_password, ])
routes::user::change_password_post
],
)
.manage(config) .manage(config)
.manage(shell) .manage(shell)
} }

View file

@ -110,7 +110,7 @@ impl MirrorRepository {
} }
// PKG // PKG
let (name, _, _, arch) = Package::extract_pkg_name(pkg_name).unwrap(); let (name, _, _, arch, _) = Package::extract_pkg_name(pkg_name).unwrap();
self.download_package(pkg_name, &name, arch, mirrorlist) self.download_package(pkg_name, &name, arch, mirrorlist)
.await; .await;

View file

@ -23,17 +23,27 @@ pub struct Package {
pub rel: i32, pub rel: i32,
/// Version of the package /// Version of the package
pub version: Option<String>, pub version: Option<String>,
/// Compression used
pub compression: Compression,
} }
impl Package { impl Package {
/// Create a new package /// Create a new package
pub fn new(repo: &str, arch: Architecture, pkg_name: &str, version: &str, rel: i32) -> Self { pub fn new(
repo: &str,
arch: Architecture,
pkg_name: &str,
version: &str,
rel: i32,
compression: Compression,
) -> Self {
let pkg = Package { let pkg = Package {
repo: repo.to_string(), repo: repo.to_string(),
arch, arch,
name: pkg_name.to_string(), name: pkg_name.to_string(),
rel: rel, rel: rel,
version: Some(version.to_string()), version: Some(version.to_string()),
compression,
}; };
std::fs::create_dir_all(pkg.base_path()).unwrap(); std::fs::create_dir_all(pkg.base_path()).unwrap();
@ -128,27 +138,38 @@ impl Package {
/// ``` /// ```
/// use pacco::pkg::Package; /// use pacco::pkg::Package;
/// ///
/// let (name, version, rel, arch) = Package::extract_pkg_name("pkg-ver-rel-x86_64.pkg.tar.zst").unwrap(); /// let (name, version, rel, arch, compress) = Package::extract_pkg_name("pkg-ver-rel-x86_64.pkg.tar.zst").unwrap();
/// assert_eq!(name, "pkg"); /// assert_eq!(name, "pkg");
/// assert_eq!(version, "ver"); /// assert_eq!(version, "ver");
/// assert_eq!(rel, "rel"); /// assert_eq!(rel, "rel");
/// assert_eq!(arch, pacco::pkg::arch::Architecture::x86_64); /// assert_eq!(arch, pacco::pkg::arch::Architecture::x86_64);
/// assert_eq!(compress, pacco::pkg::package::Compression::Zstd);
/// ///
/// let (name, version, rel, arch) = Package::extract_pkg_name("my-pkg-ver-rel-x86_64.pkg.tar.zst").unwrap(); /// let (name, version, rel, arch, compress) = Package::extract_pkg_name("my-pkg-ver-rel-x86_64.pkg.tar.xz").unwrap();
/// assert_eq!(name, "my-pkg"); /// assert_eq!(name, "my-pkg");
/// assert_eq!(version, "ver"); /// assert_eq!(version, "ver");
/// assert_eq!(rel, "rel"); /// assert_eq!(rel, "rel");
/// assert_eq!(arch, pacco::pkg::arch::Architecture::x86_64); /// assert_eq!(arch, pacco::pkg::arch::Architecture::x86_64);
/// assert_eq!(compress, pacco::pkg::package::Compression::Xz);
/// ``` /// ```
pub fn extract_pkg_name(file_name: &str) -> Option<(String, String, String, Architecture)> { pub fn extract_pkg_name(
file_name: &str,
) -> Option<(String, String, String, Architecture, Compression)> {
// Extract (assuming the filename is "<pkg_name>-<version>-<relation>-<arch>.pkg.tar.zst") // Extract (assuming the filename is "<pkg_name>-<version>-<relation>-<arch>.pkg.tar.zst")
let file_name = file_name.trim_end_matches(".sig").to_string(); let file_name = file_name.trim_end_matches(".sig").to_string();
let mut splitted = file_name.split('-').collect::<Vec<&str>>(); let mut splitted = file_name.split('-').collect::<Vec<&str>>();
let arch = splitted.pop()?; let arch = splitted.pop()?;
assert!(arch.ends_with(".pkg.tar.zst"), "{file_name}");
let arch = arch.trim_end_matches(".pkg.tar.zst"); let compression = Compression::from_filename(arch);
assert!(compression.is_some());
let compression = compression.unwrap();
let arch = match compression {
Compression::Zstd => arch.trim_end_matches(".pkg.tar.zst"),
Compression::Xz => arch.trim_end_matches(".pkg.tar.xz"),
};
let relation = splitted.pop()?; let relation = splitted.pop()?;
let version = splitted.pop()?; let version = splitted.pop()?;
@ -160,29 +181,50 @@ impl Package {
version.to_string(), version.to_string(),
relation.to_string(), relation.to_string(),
Architecture::parse(arch)?, Architecture::parse(arch)?,
compression,
)) ))
} }
/// Parse a pkg filename /// Parse a pkg filename
pub fn from_filename(repo: &str, file_name: &str) -> Package { pub fn from_filename(repo: &str, file_name: &str) -> Package {
let (pkg_name, version, rel, arch) = Package::extract_pkg_name(file_name).unwrap(); let (pkg_name, version, rel, arch, compression) =
Package::extract_pkg_name(file_name).unwrap();
Self { Self {
repo: repo.to_string(), repo: repo.to_string(),
arch, arch,
name: pkg_name, name: pkg_name,
rel: rel.parse().unwrap(), rel: rel.parse().unwrap(),
version: Some(version.to_string()), version: Some(version.to_string()),
compression,
} }
} }
/// Find a package with latest version /// Find a package with latest version
pub fn find(repo: &str, arch: Architecture, pkg_name: &str) -> Option<Self> { pub fn find(repo: &str, arch: Architecture, pkg_name: &str) -> Option<Self> {
if let Some(pkg) = Self::find_compressed(repo, arch.clone(), pkg_name, Compression::Zstd) {
return Some(pkg);
}
if let Some(pkg) = Self::find_compressed(repo, arch, pkg_name, Compression::Xz) {
return Some(pkg);
}
None
}
/// Find a package with latest version
fn find_compressed(
repo: &str,
arch: Architecture,
pkg_name: &str,
compression: Compression,
) -> Option<Self> {
let mut base = Package { let mut base = Package {
repo: repo.to_string(), repo: repo.to_string(),
arch, arch,
name: pkg_name.to_string(), name: pkg_name.to_string(),
rel: 1, rel: 1,
version: None, version: None,
compression,
}; };
let versions = base.versions(); let versions = base.versions();
@ -397,7 +439,7 @@ impl Package {
/// Build a pkg filename from the packages values /// Build a pkg filename from the packages values
pub fn file_name(&self) -> String { pub fn file_name(&self) -> String {
format!( format!(
"{}-{}-{}-{}.pkg.tar.zst", "{}-{}-{}-{}.pkg.tar.{}",
self.name, self.name,
if let Some(ver) = &self.version { if let Some(ver) = &self.version {
ver.to_string() ver.to_string()
@ -407,9 +449,14 @@ impl Package {
}, },
self.rel, self.rel,
self.arch.to_string(), self.arch.to_string(),
self.compression.extension()
) )
} }
pub fn has_pkg_ext(filename: &str) -> bool {
filename.ends_with(".pkg.tar.zst") || filename.ends_with(".pkg.tar.xz")
}
/// Get all versions of the package /// Get all versions of the package
pub fn versions(&self) -> Vec<String> { pub fn versions(&self) -> Vec<String> {
let dir_path = self.base_path(); let dir_path = self.base_path();
@ -418,8 +465,8 @@ impl Package {
if let Ok(entries) = std::fs::read_dir(dir_path) { if let Ok(entries) = std::fs::read_dir(dir_path) {
for entry in entries.filter_map(Result::ok) { for entry in entries.filter_map(Result::ok) {
let file_name = entry.file_name().into_string().unwrap_or_default(); let file_name = entry.file_name().into_string().unwrap_or_default();
if file_name.starts_with(&self.name) && file_name.ends_with(".pkg.tar.zst") { if file_name.starts_with(&self.name) && Package::has_pkg_ext(&file_name) {
let (_, version, rel, _) = Package::extract_pkg_name(&file_name).unwrap(); let (_, version, rel, _, _) = Package::extract_pkg_name(&file_name).unwrap();
versions.push(format!("{version}-{rel}")); versions.push(format!("{version}-{rel}"));
} }
} }
@ -562,3 +609,28 @@ impl PackageMetaInfo for Package {
.execute(get_pg!()).await.unwrap(); .execute(get_pg!()).await.unwrap();
} }
} }
#[derive(Debug, Clone, PartialEq)]
pub enum Compression {
Zstd,
Xz,
}
impl Compression {
pub fn from_filename(name: &str) -> Option<Self> {
if name.ends_with("zst") {
Some(Self::Zstd)
} else if name.ends_with("xz") {
Some(Self::Xz)
} else {
None
}
}
pub fn extension(&self) -> &str {
match self {
Compression::Zstd => "zst",
Compression::Xz => "xz",
}
}
}

View file

@ -140,8 +140,15 @@ impl Repository {
pub fn get_pkg(&self, pkg_name: &str) -> Option<Package> { pub fn get_pkg(&self, pkg_name: &str) -> Option<Package> {
// Find package // Find package
let (name, version, rel, arch) = Package::extract_pkg_name(pkg_name).unwrap(); let (name, version, rel, arch, compress) = Package::extract_pkg_name(pkg_name).unwrap();
let pkg = Package::new(&self.name, arch, &name, &version, rel.parse().unwrap()); let pkg = Package::new(
&self.name,
arch,
&name,
&version,
rel.parse().unwrap(),
compress,
);
// Return if exists // Return if exists
if pkg.exists() { Some(pkg) } else { None } if pkg.exists() { Some(pkg) } else { None }

View file

@ -9,8 +9,8 @@ use pacco::pkg::package::PackageMetaInfo;
use rocket::http::{ContentType, Status}; use rocket::http::{ContentType, Status};
use rocket::{State, get}; use rocket::{State, get};
use pacco::pkg::Repository;
use pacco::pkg::arch::Architecture; use pacco::pkg::arch::Architecture;
use pacco::pkg::{Package, Repository};
use crate::config::Config; use crate::config::Config;
@ -103,14 +103,14 @@ pub async fn pkg_route(
.await .await
.unwrap(); .unwrap();
if pkg_name.ends_with("pkg.tar.zst") { if Package::has_pkg_ext(&pkg_name) {
pkg.increase_download_count().await; pkg.increase_download_count().await;
return DataResponse::new_file( return DataResponse::new_file(
&pkg.pkg_content_path().unwrap(), &pkg.pkg_content_path().unwrap(),
"application/tar".to_string(), "application/tar".to_string(),
cache_duration, cache_duration,
); );
} else if pkg_name.ends_with("pkg.tar.zst.sig") { } else if pkg_name.ends_with("sig") {
return DataResponse::new( return DataResponse::new(
pkg.sig_content().unwrap(), pkg.sig_content().unwrap(),
"application/pgp-signature".to_string(), "application/pgp-signature".to_string(),
@ -144,13 +144,13 @@ pub async fn pkg_route(
let pkg = repo.get_pkg(pkg_name).unwrap(); let pkg = repo.get_pkg(pkg_name).unwrap();
if pkg_name.ends_with("pkg.tar.zst") { if Package::has_pkg_ext(&pkg_name) {
return DataResponse::new_file( return DataResponse::new_file(
&pkg.pkg_content_path().unwrap(), &pkg.pkg_content_path().unwrap(),
"application/tar".to_string(), "application/tar".to_string(),
cache_duration, cache_duration,
); );
} else if pkg_name.ends_with("pkg.tar.zst.sig") { } else if pkg_name.ends_with("sig") {
return DataResponse::new( return DataResponse::new(
pkg.sig_content().unwrap(), pkg.sig_content().unwrap(),
"application/pgp-signature".to_string(), "application/pgp-signature".to_string(),

View file

@ -77,7 +77,10 @@ pub async fn upload_pkg(
let arch = Architecture::parse(&arch).ok_or_else(|| api_error("Invalid architecture"))?; let arch = Architecture::parse(&arch).ok_or_else(|| api_error("Invalid architecture"))?;
let pkg = Package::new(repo, arch, pkg_name, &version, rel); let (_, _, _, _, compression) = Package::extract_pkg_name(upload.pkg.name().unwrap())
.ok_or_else(|| api_error("Package has weird filename"))?;
let pkg = Package::new(repo, arch, pkg_name, &version, rel, compression);
pkg.save( pkg.save(
pkg_file, pkg_file,