Merge branch 'odin' of git.hitchhiker-linux.org:jeang3nie/hpk-package into odin

This commit is contained in:
Nathan Fisher 2023-04-09 01:36:26 -04:00
commit 4cede60a80
7 changed files with 153 additions and 88 deletions

View File

@ -1,13 +1,12 @@
pub mod tar;
mod package; mod package;
mod plist; mod plist;
pub mod tar;
mod version; mod version;
pub use { pub use {
deku, deku,
package::{Dependency, Package, Specs}, package::{Arch, Dependency, Group, Package, Specs, User},
plist::*, plist::*,
ron, ron, sha2,
sha2,
version::*, version::*,
}; };

View File

@ -1,10 +1,10 @@
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::{fmt, str::FromStr, error::Error}; use std::{error::Error, fmt, str::FromStr};
#[cfg(target_arch = "arm")] #[cfg(target_arch = "arm")]
pub const HOST_ARCH: Arch = Arch::armv7l; pub const HOST_ARCH: Arch = Arch::armv7l;
#[cfg(target_arch = "aarch64")] #[cfg(target_arch = "aarch64")]
pub const HOST_ARCH: Arch = Arch::aarch64; pub const HOST_ARCH: Arch = Arch::aarch64;
#[cfg(target_arch = "x86")] #[cfg(target_arch = "x86")]
pub const HOST_ARCH: Arch = Arch::i486; pub const HOST_ARCH: Arch = Arch::i486;
#[cfg(target_arch = "riscv64")] #[cfg(target_arch = "riscv64")]
@ -33,16 +33,20 @@ impl Default for Arch {
impl fmt::Display for Arch { impl fmt::Display for Arch {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", match self { write!(
Self::armv7l => "armv7l", f,
Self::aarch64 => "aarch64", "{}",
Self::i486 => "i486", match self {
Self::i586 => "i586", Self::armv7l => "armv7l",
Self::i686 => "i686", Self::aarch64 => "aarch64",
Self::riscv64 => "riscv64", Self::i486 => "i486",
Self::x86_64 => "x86_64", Self::i586 => "i586",
Self::any => "any", 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), "arm64" | "aarch64" | "armv8" => Ok(Self::aarch64),
"riscv" | "riscv64" => Ok(Self::riscv64), "riscv" | "riscv64" => Ok(Self::riscv64),
"any" => Ok(Self::any), "any" => Ok(Self::any),
_ => Err(ParseArchError) _ => Err(ParseArchError),
} }
} }
} }

View File

@ -3,6 +3,7 @@ mod dependency;
mod specs; mod specs;
use { use {
crate::tar::{Node, Owner},
crate::{Plist, Version}, crate::{Plist, Version},
ron::ser::{to_string_pretty, PrettyConfig}, ron::ser::{to_string_pretty, PrettyConfig},
serde::{Deserialize, Serialize}, serde::{Deserialize, Serialize},
@ -13,7 +14,6 @@ use {
io::{BufWriter, Write}, io::{BufWriter, Write},
path::Path, path::Path,
}, },
crate::tar::{Node, Owner},
}; };
pub use {arch::Arch, dependency::Dependency, specs::Specs}; pub use {arch::Arch, dependency::Dependency, specs::Specs};
@ -88,10 +88,7 @@ impl Package {
to_string_pretty(self, cfg) to_string_pretty(self, cfg)
} }
pub fn save_ron_and_create_tar_node( pub fn save_ron_and_create_tar_node(&self, outdir: &Path) -> Result<Node, Box<dyn Error>> {
&self,
outdir: &Path,
) -> Result<Node, Box<dyn Error>> {
if !outdir.exists() { if !outdir.exists() {
fs::create_dir_all(outdir)?; fs::create_dir_all(outdir)?;
} }
@ -113,12 +110,18 @@ impl Package {
/// Returns the formatted full package name including version and release strings /// Returns the formatted full package name including version and release strings
pub fn fullname(&self) -> String { 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 /// Returns the name of the package archive
pub fn archive_name(&self) -> String { 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 /// Tests whether this package is an update for another

View File

@ -125,27 +125,38 @@ impl Header {
/// use hpk_package::tar::Header; /// use hpk_package::tar::Header;
/// ///
/// let header = Header::new("test/1.txt").unwrap(); /// let header = Header::new("test/1.txt").unwrap();
/// assert_eq!(header.filename().unwrap(), "test/1.txt"); /// let filename = header.filename().unwrap();
/// assert_eq!(filename.as_str(), "1.txt");
/// ``` /// ```
pub fn filename(&self) -> Result<String, fmt::Error> { pub fn filename(&self) -> Result<String, fmt::Error> {
let mut s = String::new(); let mut s = String::new();
for c in self.fname { for c in self.fname {
if c != 0 { if c == 0 {
write!(s, "{}", char::from(c))?;
} else {
break; break;
} else {
write!(s, "{}", char::from(c))?;
} }
} }
Ok(s) 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<u32, Error> { pub fn mode(&self) -> Result<u32, Error> {
let mut s = String::new(); let mut s = String::new();
for c in self.mode { for c in self.mode {
if c != b'\0' { if c == 0 {
write!(s, "{c}")?;
} else {
break; break;
} else {
write!(s, "{}", char::from(c))?;
} }
} }
let mode = u32::from_str_radix(&s, 8)?; let mode = u32::from_str_radix(&s, 8)?;
@ -155,10 +166,10 @@ impl Header {
fn uid(&self) -> Result<u32, Error> { fn uid(&self) -> Result<u32, Error> {
let mut s = String::new(); let mut s = String::new();
for c in self.mode { for c in self.mode {
if c != b'\0' { if c == 0 {
write!(s, "{c}")?;
} else {
break; break;
} else {
write!(s, "{}", char::from(c))?;
} }
} }
let uid = u32::from_str_radix(&s, 8)?; let uid = u32::from_str_radix(&s, 8)?;
@ -168,10 +179,10 @@ impl Header {
fn gid(&self) -> Result<u32, Error> { fn gid(&self) -> Result<u32, Error> {
let mut s = String::new(); let mut s = String::new();
for c in self.mode { for c in self.mode {
if c != b'\0' { if c == 0 {
write!(s, "{c}")?;
} else {
break; break;
} else {
write!(s, "{}", char::from(c))?;
} }
} }
let gid = u32::from_str_radix(&s, 8)?; let gid = u32::from_str_radix(&s, 8)?;
@ -181,10 +192,10 @@ impl Header {
fn username(&self) -> Result<String, fmt::Error> { fn username(&self) -> Result<String, fmt::Error> {
let mut s = String::new(); let mut s = String::new();
for c in self.username { for c in self.username {
if c != b'\0' { if c == 0 {
write!(s, "{c}")?;
} else {
break; break;
} else {
write!(s, "{}", char::from(c))?;
} }
} }
Ok(s) Ok(s)
@ -193,10 +204,10 @@ impl Header {
fn groupname(&self) -> Result<String, fmt::Error> { fn groupname(&self) -> Result<String, fmt::Error> {
let mut s = String::new(); let mut s = String::new();
for c in self.groupname { for c in self.groupname {
if c != b'\0' { if c == 0 {
write!(s, "{c}")?;
} else {
break; break;
} else {
write!(s, "{}", char::from(c))?;
} }
} }
Ok(s) Ok(s)
@ -215,31 +226,61 @@ impl Header {
}) })
} }
pub fn prefix(&self) -> Result<String, fmt::Error> { /// 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<String> {
let mut s = String::new(); let mut s = String::new();
for c in self.file_prefix { for c in self.file_prefix {
if c != b'\0' { if c != 0 {
write!(s, "{c}")?; write!(s, "{}", char::from(c)).ok()?;
} else { } else {
break; break;
} }
} }
Ok(s) if s.is_empty() {
None
} else {
Some(s)
}
} }
pub fn path(&self) -> Result<PathBuf, fmt::Error> { /// Gets the full file path to this archive member.
let mut p = PathBuf::from(&self.prefix()?); ///
p.push(&self.filename()?); /// # Example
Ok(p) ///
/// ```
/// 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<PathBuf, fmt::Error> {
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<Self, Error> { pub fn new(filename: &str) -> Result<Self, Error> {
let mut header = Header::default(); let mut header = Header::default();
let meta = fs::symlink_metadata(filename)?; let meta = fs::symlink_metadata(filename)?;
let (filename, prefix) = if filename.len() < 100 { let (filename, prefix) = {
(filename.to_string(), None) // Original tar has a maximum file name length of 100 bytes. The ustar
} else { // revision allows storing the path prefix separately, with 100 bytes
// Deal with file names longer than 100 bytes // reserved for the file name and 150 bytes for the rest of the path.
let path = PathBuf::from(&filename); let path = PathBuf::from(&filename);
let name = match path.file_name().and_then(|n| n.to_str()) { let name = match path.file_name().and_then(|n| n.to_str()) {
Some(n) => n.to_string(), Some(n) => n.to_string(),
@ -250,16 +291,8 @@ impl Header {
))) )))
} }
}; };
let dir = match path.parent() { let dir = path.parent().map(|x| format!("{}", x.display()));
Some(d) => d, (name, dir)
None => {
return Err(Error::Io(io::Error::new(
io::ErrorKind::Other,
"Cannot get path prefix",
)))
}
};
(name, Some(format!("{}", dir.display())))
}; };
/* Fill in metadata */ /* Fill in metadata */
@ -309,10 +342,10 @@ impl Header {
owner: Option<Owner>, owner: Option<Owner>,
) -> Result<Self, Error> { ) -> Result<Self, Error> {
let mut header = Header::default(); let mut header = Header::default();
let (filename, prefix) = if filename.len() < 100 { let (filename, prefix) = {
(filename.to_string(), None) // Original tar has a maximum file name length of 100 bytes. The ustar
} else { // revision allows storing the path prefix separately, with 100 bytes
// Deal with file names longer than 100 bytes // reserved for the file name and 150 bytes for the rest of the path.
let path = PathBuf::from(&filename); let path = PathBuf::from(&filename);
let name = match path.file_name().and_then(|n| n.to_str()) { let name = match path.file_name().and_then(|n| n.to_str()) {
Some(n) => n.to_string(), Some(n) => n.to_string(),
@ -323,16 +356,8 @@ impl Header {
))) )))
} }
}; };
let dir = match path.parent() { let dir = path.parent().map(|x| format!("{}", x.display()));
Some(d) => d, (name, dir)
None => {
return Err(Error::Io(io::Error::new(
io::ErrorKind::Other,
"Cannot get path prefix",
)))
}
};
(name, Some(format!("{}", dir.display())))
}; };
header.fname[..filename.len()].copy_from_slice(filename.as_bytes()); header.fname[..filename.len()].copy_from_slice(filename.as_bytes());
let mode = format!("{:07o}", meta.st_mode()); let mode = format!("{:07o}", meta.st_mode());
@ -447,7 +472,7 @@ fn get_username_for_uid<'a>(uid: u32) -> Result<&'a str, std::str::Utf8Error> {
user.to_str() 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 group = unsafe {
let gr = libc::getgrgid(gid); let gr = libc::getgrgid(gid);
let name = (*gr).gr_name; let name = (*gr).gr_name;

View File

@ -1,6 +1,7 @@
use std::{ use std::{
fs::File, fs::File,
io::{self, BufReader, Write}, io::{self, BufReader, Write},
path::PathBuf,
}; };
use rayon::prelude::{IntoParallelRefIterator, ParallelIterator}; use rayon::prelude::{IntoParallelRefIterator, ParallelIterator};
@ -156,18 +157,25 @@ impl Archive {
/// ///
/// ``` /// ```
/// use hpk_package::tar::Archive; /// use hpk_package::tar::Archive;
/// let archive = Archive::new("test/1.tar").unwrap(); /// let archive = Archive::new("test/1.txt").unwrap();
/// let node = archive.get("1.txt"); /// let node = archive.get("test/1.txt");
/// assert!(node.is_some()); /// assert!(node.is_some());
/// ``` /// ```
pub fn get(&self, filename: &str) -> Option<Node> { pub fn get(&self, filename: &str) -> Option<Node> {
self.nodes.par_iter().find_any(|x| { self.nodes.par_iter().find_any(|x| {
if let Ok(name) = x.header.filename() { x.header.file_path() == Ok(PathBuf::from(filename))
if &name == filename {
return true;
}
}
false
}).cloned() }).cloned()
} }
} }
#[cfg(test)]
mod test {
use super::*;
#[test]
fn open_get() {
let archive = Archive::open("test/1.tar").unwrap();
let node = archive.get("1.txt");
assert!(node.is_some());
}
}

View File

@ -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);
}
} }

Binary file not shown.