diff --git a/Dockerfile b/Dockerfile index 520b4fb..5d7f50f 100644 --- a/Dockerfile +++ b/Dockerfile @@ -9,7 +9,7 @@ RUN cargo build --release FROM archlinux -RUN pacman -Syu --noconfirm openssl-1.1 tar xz zstd +RUN pacman -Syu --noconfirm openssl-1.1 COPY --from=builder /app/target/release/pacco /pacco diff --git a/src/main.rs b/src/main.rs index 176f2d1..2c20f6d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -51,20 +51,23 @@ async fn launch() -> _ { ..Default::default() }) .mount_assets() - .mount("/", routes![ - routes::index_page, - routes::pkg_route, - routes::push::upload_pkg, - routes::user::login, - routes::user::login_post, - routes::user::account_page, - routes::ui::pkg_ui, - routes::ui::repo_ui, - routes::user::new_api_key, - routes::user::end_session, - routes::user::change_password, - routes::user::change_password_post - ]) + .mount( + "/", + routes![ + routes::index_page, + routes::pkg_route, + routes::push::upload_pkg, + routes::user::login, + routes::user::login_post, + routes::user::account_page, + routes::ui::pkg_ui, + routes::ui::repo_ui, + routes::user::new_api_key, + routes::user::end_session, + routes::user::change_password, + routes::user::change_password_post + ], + ) .manage(config) .manage(shell) } diff --git a/src/pkg/mirror.rs b/src/pkg/mirror.rs index 1f2c678..1c30e2b 100644 --- a/src/pkg/mirror.rs +++ b/src/pkg/mirror.rs @@ -110,7 +110,7 @@ impl MirrorRepository { } // 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) .await; diff --git a/src/pkg/package.rs b/src/pkg/package.rs index cf8fb7a..51d4ccc 100644 --- a/src/pkg/package.rs +++ b/src/pkg/package.rs @@ -1,8 +1,7 @@ use std::{ fs::File, - io::{BufReader, Cursor, Read, Write}, + io::{BufReader, Cursor, Read}, path::{Path, PathBuf}, - process::{Command, Stdio}, }; use based::get_pg; @@ -24,27 +23,17 @@ pub struct Package { pub rel: i32, /// Version of the package pub version: Option, - /// Compression used - pub compression: Compression, } impl Package { /// Create a new package - pub fn new( - repo: &str, - arch: Architecture, - pkg_name: &str, - version: &str, - rel: i32, - compression: Compression, - ) -> Self { + pub fn new(repo: &str, arch: Architecture, pkg_name: &str, version: &str, rel: i32) -> Self { let pkg = Package { repo: repo.to_string(), arch, name: pkg_name.to_string(), rel: rel, version: Some(version.to_string()), - compression, }; std::fs::create_dir_all(pkg.base_path()).unwrap(); @@ -139,38 +128,27 @@ impl Package { /// ``` /// use pacco::pkg::Package; /// - /// let (name, version, rel, arch, compress) = Package::extract_pkg_name("pkg-ver-rel-x86_64.pkg.tar.zst").unwrap(); + /// let (name, version, rel, arch) = Package::extract_pkg_name("pkg-ver-rel-x86_64.pkg.tar.zst").unwrap(); /// assert_eq!(name, "pkg"); /// assert_eq!(version, "ver"); /// assert_eq!(rel, "rel"); /// assert_eq!(arch, pacco::pkg::arch::Architecture::x86_64); - /// assert_eq!(compress, pacco::pkg::package::Compression::Zstd); /// - /// let (name, version, rel, arch, compress) = Package::extract_pkg_name("my-pkg-ver-rel-x86_64.pkg.tar.xz").unwrap(); + /// let (name, version, rel, arch) = Package::extract_pkg_name("my-pkg-ver-rel-x86_64.pkg.tar.zst").unwrap(); /// assert_eq!(name, "my-pkg"); /// assert_eq!(version, "ver"); /// assert_eq!(rel, "rel"); /// 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, Compression)> { + pub fn extract_pkg_name(file_name: &str) -> Option<(String, String, String, Architecture)> { // Extract (assuming the filename is "---.pkg.tar.zst") let file_name = file_name.trim_end_matches(".sig").to_string(); let mut splitted = file_name.split('-').collect::>(); let arch = splitted.pop()?; - - 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"), - }; + assert!(arch.ends_with(".pkg.tar.zst"), "{file_name}"); + let arch = arch.trim_end_matches(".pkg.tar.zst"); let relation = splitted.pop()?; let version = splitted.pop()?; @@ -182,50 +160,29 @@ impl Package { version.to_string(), relation.to_string(), Architecture::parse(arch)?, - compression, )) } /// Parse a pkg filename pub fn from_filename(repo: &str, file_name: &str) -> Package { - let (pkg_name, version, rel, arch, compression) = - Package::extract_pkg_name(file_name).unwrap(); + let (pkg_name, version, rel, arch) = Package::extract_pkg_name(file_name).unwrap(); Self { repo: repo.to_string(), arch, name: pkg_name, rel: rel.parse().unwrap(), version: Some(version.to_string()), - compression, } } /// Find a package with latest version pub fn find(repo: &str, arch: Architecture, pkg_name: &str) -> Option { - 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 { let mut base = Package { repo: repo.to_string(), arch, name: pkg_name.to_string(), rel: 1, version: None, - compression, }; let versions = base.versions(); @@ -440,7 +397,7 @@ impl Package { /// Build a pkg filename from the packages values pub fn file_name(&self) -> String { format!( - "{}-{}-{}-{}.pkg.tar.{}", + "{}-{}-{}-{}.pkg.tar.zst", self.name, if let Some(ver) = &self.version { ver.to_string() @@ -450,14 +407,9 @@ impl Package { }, self.rel, 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 pub fn versions(&self) -> Vec { let dir_path = self.base_path(); @@ -466,8 +418,8 @@ impl Package { if let Ok(entries) = std::fs::read_dir(dir_path) { for entry in entries.filter_map(Result::ok) { let file_name = entry.file_name().into_string().unwrap_or_default(); - if file_name.starts_with(&self.name) && Package::has_pkg_ext(&file_name) { - let (_, version, rel, _, _) = Package::extract_pkg_name(&file_name).unwrap(); + if file_name.starts_with(&self.name) && file_name.ends_with(".pkg.tar.zst") { + let (_, version, rel, _) = Package::extract_pkg_name(&file_name).unwrap(); versions.push(format!("{version}-{rel}")); } } @@ -526,63 +478,50 @@ pub fn repo_add(db_file: &str, pkg_file: &str) { } pub fn read_file_tar(tar: &Path, file_path: &str) -> Option { - let output = Command::new("tar") - .arg("-xO") // Extract to stdout (-O) - .arg("-f") - .arg(tar) - .arg(file_path) - .output() - .ok()?; + let file = File::open(tar).ok()?; + let decoder = Decoder::new(BufReader::new(file)).ok()?; + let mut archive = Archive::new(decoder); - if output.status.success() { - Some(String::from_utf8(output.stdout).ok()?.to_string()) - } else { - None + for entry in archive.entries().ok()? { + let mut entry = entry.ok()?; + if entry.path().ok()?.to_str()? == file_path { + let mut file_content = String::new(); + entry.read_to_string(&mut file_content).ok()?; + return Some(file_content); + } } + + None } pub fn read_file_tar_raw(tar_data: &[u8], file_path: &str) -> Option { - let mut output = Command::new("tar") - .arg("-xO") // Extract to stdout (-O) - .arg("-f") - .arg("-") // Indicate that the file input comes from stdin - .arg(file_path) - .stdin(Stdio::piped()) // Open a pipe to provide the tar data - .spawn() - .ok()?; + let decoder = Decoder::new(Cursor::new(tar_data)).ok()?; + let mut archive = Archive::new(decoder); - if let Some(stdin) = output.stdin.as_mut() { - stdin.write_all(tar_data).ok()?; - stdin.flush().ok()?; + for entry in archive.entries().ok()? { + let mut entry = entry.ok()?; + if entry.path().ok()?.to_str()? == file_path { + let mut file_content = String::new(); + entry.read_to_string(&mut file_content).ok()?; + return Some(file_content); + } } - let output = output.wait_with_output().ok()?; - - if output.status.success() { - Some(String::from_utf8(output.stdout).ok()?.to_string()) - } else { - None - } + None } pub fn list_tar_file(tar: &Path) -> Option> { - let output = Command::new("tar") - .arg("-tf") // List the contents of the tar file - .arg(tar) - .output() - .ok()?; + let file = File::open(tar).ok()?; + let decoder = Decoder::new(BufReader::new(file)).ok()?; + let mut archive = Archive::new(decoder); + let mut paths = Vec::new(); - if output.status.success() { - let output_str = String::from_utf8(output.stdout).ok()?; - let paths = output_str - .lines() - .map(|line| line.to_string()) - .collect::>(); - - Some(paths) - } else { - None + for entry in archive.entries().ok()? { + let entry = entry.ok()?; + paths.push(entry.path().ok()?.to_string_lossy().into_owned()); } + + Some(paths) } #[derive(Debug, Clone, FromRow)] @@ -623,28 +562,3 @@ impl PackageMetaInfo for Package { .execute(get_pg!()).await.unwrap(); } } - -#[derive(Debug, Clone, PartialEq)] -pub enum Compression { - Zstd, - Xz, -} - -impl Compression { - pub fn from_filename(name: &str) -> Option { - 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", - } - } -} diff --git a/src/pkg/repo.rs b/src/pkg/repo.rs index 7cadf2d..5afc2eb 100644 --- a/src/pkg/repo.rs +++ b/src/pkg/repo.rs @@ -140,15 +140,8 @@ impl Repository { pub fn get_pkg(&self, pkg_name: &str) -> Option { // Find package - 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(), - compress, - ); + let (name, version, rel, arch) = Package::extract_pkg_name(pkg_name).unwrap(); + let pkg = Package::new(&self.name, arch, &name, &version, rel.parse().unwrap()); // Return if exists if pkg.exists() { Some(pkg) } else { None } diff --git a/src/routes/mod.rs b/src/routes/mod.rs index 914bbc5..a022786 100644 --- a/src/routes/mod.rs +++ b/src/routes/mod.rs @@ -9,8 +9,8 @@ use pacco::pkg::package::PackageMetaInfo; use rocket::http::{ContentType, Status}; use rocket::{State, get}; +use pacco::pkg::Repository; use pacco::pkg::arch::Architecture; -use pacco::pkg::{Package, Repository}; use crate::config::Config; @@ -103,14 +103,14 @@ pub async fn pkg_route( .await .unwrap(); - if Package::has_pkg_ext(&pkg_name) { + if pkg_name.ends_with("pkg.tar.zst") { pkg.increase_download_count().await; return DataResponse::new_file( &pkg.pkg_content_path().unwrap(), "application/tar".to_string(), cache_duration, ); - } else if pkg_name.ends_with("sig") { + } else if pkg_name.ends_with("pkg.tar.zst.sig") { return DataResponse::new( pkg.sig_content().unwrap(), "application/pgp-signature".to_string(), @@ -144,13 +144,13 @@ pub async fn pkg_route( let pkg = repo.get_pkg(pkg_name).unwrap(); - if Package::has_pkg_ext(&pkg_name) { + if pkg_name.ends_with("pkg.tar.zst") { return DataResponse::new_file( &pkg.pkg_content_path().unwrap(), "application/tar".to_string(), cache_duration, ); - } else if pkg_name.ends_with("sig") { + } else if pkg_name.ends_with("pkg.tar.zst.sig") { return DataResponse::new( pkg.sig_content().unwrap(), "application/pgp-signature".to_string(), diff --git a/src/routes/push.rs b/src/routes/push.rs index 42df102..0881e76 100644 --- a/src/routes/push.rs +++ b/src/routes/push.rs @@ -77,10 +77,7 @@ pub async fn upload_pkg( let arch = Architecture::parse(&arch).ok_or_else(|| api_error("Invalid architecture"))?; - 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); + let pkg = Package::new(repo, arch, pkg_name, &version, rel); pkg.save( pkg_file,