Merge branch 'odin' of git.hitchhiker-linux.org:jeang3nie/hpk-package into odin
This commit is contained in:
commit
4cede60a80
@ -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::*,
|
||||
};
|
||||
|
@ -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),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
BIN
test/2.tar
BIN
test/2.tar
Binary file not shown.
Loading…
Reference in New Issue
Block a user