From 723d697e9085a575c1f6d59baf1e79819452d747 Mon Sep 17 00:00:00 2001 From: Nathan Fisher Date: Thu, 6 Apr 2023 18:31:52 -0400 Subject: [PATCH 1/4] Export `Arch` enum --- src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index 084113d..a8b28de 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -5,7 +5,7 @@ mod version; pub use { deku, - package::{Dependency, Package, Specs}, + package::{Arch, Dependency, Package, Specs}, plist::*, ron, sha2, From 0ab84def2e5e7ac6253c6b5f1ac20ecbf0fe70f8 Mon Sep 17 00:00:00 2001 From: Nathan Fisher Date: Fri, 7 Apr 2023 19:08:23 -0400 Subject: [PATCH 2/4] Make `package::User` and `package::Group` public --- src/lib.rs | 7 +++---- src/package/arch.rs | 30 +++++++++++++++++------------- src/package/mod.rs | 17 ++++++++++------- 3 files changed, 30 insertions(+), 24 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index a8b28de..3381f56 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,13 +1,12 @@ -pub mod tar; mod package; mod plist; +pub mod tar; mod version; pub use { deku, - package::{Arch, Dependency, Package, Specs}, + package::{Arch, Dependency, Package, Specs, User, Group}, plist::*, - ron, - sha2, + ron, sha2, version::*, }; diff --git a/src/package/arch.rs b/src/package/arch.rs index 5f10d1f..59f1c01 100644 --- a/src/package/arch.rs +++ b/src/package/arch.rs @@ -1,10 +1,10 @@ use serde::{Deserialize, Serialize}; -use std::{fmt, str::FromStr, error::Error}; +use std::{error::Error, fmt, str::FromStr}; #[cfg(target_arch = "arm")] pub const HOST_ARCH: Arch = Arch::armv7l; #[cfg(target_arch = "aarch64")] -pub const HOST_ARCH: Arch = Arch::aarch64; +pub const HOST_ARCH: Arch = Arch::aarch64; #[cfg(target_arch = "x86")] pub const HOST_ARCH: Arch = Arch::i486; #[cfg(target_arch = "riscv64")] @@ -33,16 +33,20 @@ impl Default for Arch { impl fmt::Display for Arch { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{}", match self { - Self::armv7l => "armv7l", - Self::aarch64 => "aarch64", - Self::i486 => "i486", - Self::i586 => "i586", - Self::i686 => "i686", - Self::riscv64 => "riscv64", - Self::x86_64 => "x86_64", - Self::any => "any", - }) + write!( + f, + "{}", + match self { + Self::armv7l => "armv7l", + Self::aarch64 => "aarch64", + Self::i486 => "i486", + Self::i586 => "i586", + Self::i686 => "i686", + Self::riscv64 => "riscv64", + Self::x86_64 => "x86_64", + Self::any => "any", + } + ) } } @@ -69,7 +73,7 @@ impl FromStr for Arch { "arm64" | "aarch64" | "armv8" => Ok(Self::aarch64), "riscv" | "riscv64" => Ok(Self::riscv64), "any" => Ok(Self::any), - _ => Err(ParseArchError) + _ => Err(ParseArchError), } } } diff --git a/src/package/mod.rs b/src/package/mod.rs index ffe2a7d..0020cd9 100644 --- a/src/package/mod.rs +++ b/src/package/mod.rs @@ -3,6 +3,7 @@ mod dependency; mod specs; use { + crate::tar::{Node, Owner}, crate::{Plist, Version}, ron::ser::{to_string_pretty, PrettyConfig}, serde::{Deserialize, Serialize}, @@ -13,7 +14,6 @@ use { io::{BufWriter, Write}, path::Path, }, - crate::tar::{Node, Owner}, }; pub use {arch::Arch, dependency::Dependency, specs::Specs}; @@ -88,10 +88,7 @@ impl Package { to_string_pretty(self, cfg) } - pub fn save_ron_and_create_tar_node( - &self, - outdir: &Path, - ) -> Result> { + pub fn save_ron_and_create_tar_node(&self, outdir: &Path) -> Result> { if !outdir.exists() { fs::create_dir_all(outdir)?; } @@ -113,12 +110,18 @@ impl Package { /// Returns the formatted full package name including version and release strings pub fn fullname(&self) -> String { - format!("{}-{}_{}_{}", self.name, self.version, self.release, self.arch) + format!( + "{}-{}_{}_{}", + self.name, self.version, self.release, self.arch + ) } /// Returns the name of the package archive pub fn archive_name(&self) -> String { - format!("{}-{}_{}_{}.tar.zstd", self.name, self.version, self.release, self.arch) + format!( + "{}-{}_{}_{}.tar.zstd", + self.name, self.version, self.release, self.arch + ) } /// Tests whether this package is an update for another From acbdf2d99284b69a48601f3aeb0a56f295872a4c Mon Sep 17 00:00:00 2001 From: Nathan Fisher Date: Fri, 7 Apr 2023 19:11:35 -0400 Subject: [PATCH 3/4] Cargo fmt --- src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index 3381f56..fb56ef0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -5,7 +5,7 @@ mod version; pub use { deku, - package::{Arch, Dependency, Package, Specs, User, Group}, + package::{Arch, Dependency, Group, Package, Specs, User}, plist::*, ron, sha2, version::*, From 32b4f80715faef74d98e20875869de75262db1cc Mon Sep 17 00:00:00 2001 From: Nathan Fisher Date: Sat, 8 Apr 2023 19:10:30 -0400 Subject: [PATCH 4/4] Fix some issues with getting tar header fields; Add some doc tests in tar module; Add some tests for version checks; --- src/tar/header.rs | 142 +++++++++++++++++++++++++++---------------- src/version/rapid.rs | 26 ++++++++ test/2.tar | Bin 10240 -> 10240 bytes 3 files changed, 117 insertions(+), 51 deletions(-) diff --git a/src/tar/header.rs b/src/tar/header.rs index 6e22b78..6c669c2 100644 --- a/src/tar/header.rs +++ b/src/tar/header.rs @@ -117,25 +117,45 @@ impl Default for Header { } impl Header { + /// Gets the filename of this archive member + /// + /// # Example + /// ``` + /// use hpk_package::tar::Header; + /// + /// let header = Header::new("test/1.txt").unwrap(); + /// let filename = header.filename().unwrap(); + /// assert_eq!(filename.as_str(), "1.txt"); + /// ``` pub fn filename(&self) -> Result { let mut s = String::new(); for c in self.fname { - if c != b'\0' { - write!(s, "{c}")?; - } else { + if c == 0 { break; + } else { + write!(s, "{}", char::from(c))?; } } Ok(s) } + /// Gets the Unix mode of this archive member + /// + /// # Example + /// ``` + /// use hpk_package::tar::Header; + /// + /// let header = Header::new("test/1.txt").unwrap(); + /// let mode = header.mode().unwrap(); + /// assert_eq!(mode, 420); + /// ``` pub fn mode(&self) -> Result { let mut s = String::new(); for c in self.mode { - if c != b'\0' { - write!(s, "{c}")?; - } else { + if c == 0 { break; + } else { + write!(s, "{}", char::from(c))?; } } let mode = u32::from_str_radix(&s, 8)?; @@ -145,10 +165,10 @@ impl Header { fn uid(&self) -> Result { let mut s = String::new(); for c in self.mode { - if c != b'\0' { - write!(s, "{c}")?; - } else { + if c == 0 { break; + } else { + write!(s, "{}", char::from(c))?; } } let uid = u32::from_str_radix(&s, 8)?; @@ -158,10 +178,10 @@ impl Header { fn gid(&self) -> Result { let mut s = String::new(); for c in self.mode { - if c != b'\0' { - write!(s, "{c}")?; - } else { + if c == 0 { break; + } else { + write!(s, "{}", char::from(c))?; } } let gid = u32::from_str_radix(&s, 8)?; @@ -171,10 +191,10 @@ impl Header { fn username(&self) -> Result { let mut s = String::new(); for c in self.username { - if c != b'\0' { - write!(s, "{c}")?; - } else { + if c == 0 { break; + } else { + write!(s, "{}", char::from(c))?; } } Ok(s) @@ -183,10 +203,10 @@ impl Header { fn groupname(&self) -> Result { let mut s = String::new(); for c in self.groupname { - if c != b'\0' { - write!(s, "{c}")?; - } else { + if c == 0 { break; + } else { + write!(s, "{}", char::from(c))?; } } Ok(s) @@ -205,25 +225,61 @@ impl Header { }) } - pub fn prefix(&self) -> Result { + /// Gets the path to the file minus it's final component + /// + /// # Example + /// ``` + /// use hpk_package::tar::Header; + /// + /// let header = Header::new("test/1.txt").unwrap(); + /// let prefix = header.prefix().unwrap(); + /// assert_eq!(prefix.as_str(), "test"); + /// ``` + pub fn prefix(&self) -> Option { let mut s = String::new(); for c in self.file_prefix { - if c != b'\0' { - write!(s, "{c}")?; + if c != 0 { + write!(s, "{}", char::from(c)).ok()?; } else { break; } } - Ok(s) + if s.is_empty() { + None + } else { + Some(s) + } + } + + /// Gets the full file path to this archive member. + /// + /// # Example + /// + /// ``` + /// use hpk_package::tar::Header; + /// use std::path::PathBuf; + /// + /// let header = Header::new("test/1.txt").unwrap(); + /// let path = header.file_path().unwrap(); + /// assert_eq!(PathBuf::from("test/1.txt"), path); + /// ``` + pub fn file_path(&self) -> Result { + let mut path = match self.prefix() { + Some(p) => PathBuf::from(&p), + None => PathBuf::new(), + }; + let name = self.filename()?; + path.push(&name); + Ok(path) } pub fn new(filename: &str) -> Result { let mut header = Header::default(); let meta = fs::symlink_metadata(filename)?; - let (filename, prefix) = if filename.len() < 100 { - (filename.to_string(), None) - } else { - // Deal with file names longer than 100 bytes + let (filename, prefix) = { + // Original tar has a maximum file name length of 100 bytes. The ustar + // revision allows storing the path prefix separately, with 100 bytes + // reserved for the file name and 150 bytes for the rest of the path. let path = PathBuf::from(&filename); let name = match path.file_name().and_then(|n| n.to_str()) { Some(n) => n.to_string(), @@ -234,16 +290,8 @@ impl Header { ))) } }; - let dir = match path.parent() { - Some(d) => d, - None => { - return Err(Error::Io(io::Error::new( - io::ErrorKind::Other, - "Cannot get path prefix", - ))) - } - }; - (name, Some(format!("{}", dir.display()))) + let dir = path.parent().map(|x| format!("{}", x.display())); + (name, dir) }; /* Fill in metadata */ @@ -293,10 +341,10 @@ impl Header { owner: Option, ) -> Result { let mut header = Header::default(); - let (filename, prefix) = if filename.len() < 100 { - (filename.to_string(), None) - } else { - // Deal with file names longer than 100 bytes + let (filename, prefix) = { + // Original tar has a maximum file name length of 100 bytes. The ustar + // revision allows storing the path prefix separately, with 100 bytes + // reserved for the file name and 150 bytes for the rest of the path. let path = PathBuf::from(&filename); let name = match path.file_name().and_then(|n| n.to_str()) { Some(n) => n.to_string(), @@ -307,16 +355,8 @@ impl Header { ))) } }; - let dir = match path.parent() { - Some(d) => d, - None => { - return Err(Error::Io(io::Error::new( - io::ErrorKind::Other, - "Cannot get path prefix", - ))) - } - }; - (name, Some(format!("{}", dir.display()))) + let dir = path.parent().map(|x| format!("{}", x.display())); + (name, dir) }; header.fname[..filename.len()].copy_from_slice(filename.as_bytes()); let mode = format!("{:07o}", meta.st_mode()); @@ -431,7 +471,7 @@ fn get_username_for_uid<'a>(uid: u32) -> Result<&'a str, std::str::Utf8Error> { user.to_str() } -pub fn get_groupname_for_gid<'a>(gid: u32) -> Result<&'a str, std::str::Utf8Error> { +fn get_groupname_for_gid<'a>(gid: u32) -> Result<&'a str, std::str::Utf8Error> { let group = unsafe { let gr = libc::getgrgid(gid); let name = (*gr).gr_name; diff --git a/src/version/rapid.rs b/src/version/rapid.rs index 0be2946..e7842fa 100644 --- a/src/version/rapid.rs +++ b/src/version/rapid.rs @@ -165,4 +165,30 @@ mod test { }) ); } + + #[test] + fn rapid_num_eq() { + let rapid = Rapid { major: 42, minor: 0 }; + assert_eq!(rapid, 42); + } + + #[test] + fn rapid_num_gt() { + let rapid = Rapid { major: 1, minor: 42 }; + assert!(rapid > 1); + } + + #[test] + fn rapid_semver_eq() { + let rapid = Rapid { major: 42, minor: 69 }; + let semver = SemVer { major: 42, minor: 69, patch: 0 }; + assert_eq!(rapid, semver); + } + + #[test] + fn rapid_semver_lt() { + let rapid = Rapid { major: 42, minor: 69 }; + let semver = SemVer { major: 42, minor: 69, patch: 1 }; + assert!(rapid < semver); + } } diff --git a/test/2.tar b/test/2.tar index 3e7ac15362f5829b5622aa8d1698d0ed7cab964b..98902ce9c96775fa2ed4c0b8194684c56b3bd9ca 100644 GIT binary patch delta 44 ycmZn&Xb506)GMhdnYb{1Vu}&Ffw`G6gMz_iLB^EHjEoU1C8@