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 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::*,
|
||||||
};
|
};
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
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;
|
||||||
@ -33,7 +33,10 @@ 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!(
|
||||||
|
f,
|
||||||
|
"{}",
|
||||||
|
match self {
|
||||||
Self::armv7l => "armv7l",
|
Self::armv7l => "armv7l",
|
||||||
Self::aarch64 => "aarch64",
|
Self::aarch64 => "aarch64",
|
||||||
Self::i486 => "i486",
|
Self::i486 => "i486",
|
||||||
@ -42,7 +45,8 @@ impl fmt::Display for Arch {
|
|||||||
Self::riscv64 => "riscv64",
|
Self::riscv64 => "riscv64",
|
||||||
Self::x86_64 => "x86_64",
|
Self::x86_64 => "x86_64",
|
||||||
Self::any => "any",
|
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),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
@ -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;
|
||||||
|
@ -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());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -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