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 plist;
pub mod tar;
mod version;
pub use {
deku,
package::{Dependency, Package, Specs},
package::{Arch, Dependency, Group, Package, Specs, User},
plist::*,
ron,
sha2,
ron, sha2,
version::*,
};

View File

@ -1,5 +1,5 @@
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;
@ -33,7 +33,10 @@ impl Default for Arch {
impl fmt::Display for Arch {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", match self {
write!(
f,
"{}",
match self {
Self::armv7l => "armv7l",
Self::aarch64 => "aarch64",
Self::i486 => "i486",
@ -42,7 +45,8 @@ impl fmt::Display for Arch {
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),
}
}
}

View File

@ -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<Node, Box<dyn Error>> {
pub fn save_ron_and_create_tar_node(&self, outdir: &Path) -> Result<Node, Box<dyn Error>> {
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

View File

@ -125,27 +125,38 @@ impl Header {
/// use hpk_package::tar::Header;
///
/// 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> {
let mut s = String::new();
for c in self.fname {
if c != 0 {
write!(s, "{}", char::from(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<u32, Error> {
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)?;
@ -155,10 +166,10 @@ impl Header {
fn uid(&self) -> Result<u32, Error> {
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)?;
@ -168,10 +179,10 @@ impl Header {
fn gid(&self) -> Result<u32, Error> {
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)?;
@ -181,10 +192,10 @@ impl Header {
fn username(&self) -> Result<String, fmt::Error> {
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)
@ -193,10 +204,10 @@ impl Header {
fn groupname(&self) -> Result<String, fmt::Error> {
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)
@ -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();
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)
}
}
pub fn path(&self) -> Result<PathBuf, fmt::Error> {
let mut p = PathBuf::from(&self.prefix()?);
p.push(&self.filename()?);
Ok(p)
/// 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<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> {
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(),
@ -250,16 +291,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 */
@ -309,10 +342,10 @@ impl Header {
owner: Option<Owner>,
) -> Result<Self, Error> {
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(),
@ -323,16 +356,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());
@ -447,7 +472,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;

View File

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