Add method to create an Installer struct from an archive path

This commit is contained in:
Nathan Fisher 2023-04-14 01:03:52 -04:00
parent c36b3b14ab
commit 7fe884cd3e

View File

@ -13,7 +13,7 @@ use {
ffi::OsStr, ffi::OsStr,
fmt::Write as _, fmt::Write as _,
fs::{self, DirBuilder, File}, fs::{self, DirBuilder, File},
io::{self, BufWriter, Write}, io::{self, BufReader, BufWriter, Write},
os::{ os::{
self, self,
unix::{fs::DirBuilderExt, prelude::OpenOptionsExt}, unix::{fs::DirBuilderExt, prelude::OpenOptionsExt},
@ -56,17 +56,31 @@ pub enum InstallMessage {
pub struct Installer<T: io::Read> { pub struct Installer<T: io::Read> {
/// The filesystem root under which to install this package. /// The filesystem root under which to install this package.
/// Normally this is "/". /// Normally this is "/".
path: PathBuf, root: PathBuf,
package: Package, package: Package,
reader: T, reader: T,
} }
impl Installer<Decoder<'_, BufReader<File>>> {
/// creates a new installer from an archive path
pub fn new_for_file<P: AsRef<OsStr>>(
root: P,
package: Package,
archive: P,
) -> Result<Self, io::Error> {
let root = Path::new(&root).to_path_buf();
let fd = File::open(Path::new(&archive))?;
let decoder = Decoder::new(fd)?;
Ok(Self::new(root, package, decoder))
}
}
impl<T: io::Read> Installer<T> { impl<T: io::Read> Installer<T> {
/// Creates a new installer from an open archive. /// Creates a new installer from an open archive stream
pub fn new<P: AsRef<OsStr>>(path: P, package: Package, reader: T) -> Self { pub fn new<P: AsRef<OsStr>>(root: P, package: Package, reader: T) -> Self {
let path = Path::new(&path).to_path_buf(); let root = Path::new(&root).to_path_buf();
Self { Self {
path, root,
package, package,
reader, reader,
} }
@ -83,13 +97,13 @@ impl<T: io::Read> Installer<T> {
}; };
let len = archive.nodes.len(); let len = archive.nodes.len();
sender.send(InstallMessage::ArchiveLen(len))?; sender.send(InstallMessage::ArchiveLen(len))?;
let mut db_pkgdir = crate::get_dbdir(Some(self.path.clone())); let mut db_pkgdir = crate::get_dbdir(Some(self.root.clone()));
db_pkgdir.push(&self.package.name); db_pkgdir.push(&self.package.name);
if !db_pkgdir.exists() { if !db_pkgdir.exists() {
fs::create_dir_all(&db_pkgdir)?; fs::create_dir_all(&db_pkgdir)?;
} }
pop_appstream(&mut archive, &db_pkgdir)?; pop_appstream(&mut archive, &db_pkgdir)?;
pop_pinstall(&mut archive, &mut hooks, &self.package.name, &self.path)?; pop_pinstall(&mut archive, &mut hooks, &self.package.name, &self.root)?;
let mut db_file = db_pkgdir; let mut db_file = db_pkgdir;
db_file.push("package.ron"); db_file.push("package.ron");
if db_file.exists() { if db_file.exists() {
@ -98,64 +112,67 @@ impl<T: io::Read> Installer<T> {
let fd = File::create(&db_file)?; let fd = File::create(&db_file)?;
let writer = BufWriter::new(fd); let writer = BufWriter::new(fd);
pr_node.write(writer)?; pr_node.write(writer)?;
let path = &self.path; let root = &self.root;
let package = &self.package; let package = &self.package;
let hooks = Mutex::new(hooks); let hooks = Mutex::new(hooks);
let s = sender.clone(); let s = sender.clone();
archive.nodes.par_iter().try_for_each_with(s, |sender, node| { archive
let mut path = path.clone(); .nodes
let fpath = node.header.file_path()?; .par_iter()
if let Some(s) = node.header.prefix() { .try_for_each_with(s, |sender, node| {
if s.contains("/share/man/") { let mut path = root.clone();
let mut h = hooks.lock().unwrap(); let fpath = node.header.file_path()?;
if !h.contains(&Hooks::Man) { if let Some(s) = node.header.prefix() {
h.push(Hooks::Man); if s.contains("/share/man/") {
} let mut h = hooks.lock().unwrap();
} else if s.contains("/share/info") { if !h.contains(&Hooks::Man) {
hooks h.push(Hooks::Man);
.lock() }
.unwrap() } else if s.contains("/share/info") {
.push(Hooks::Info(fpath.to_str().unwrap().to_string())) hooks
} else if s.contains("/share/glib-2.0/schemas") { .lock()
let mut h = hooks.lock().unwrap(); .unwrap()
if !h.contains(&Hooks::GlibSchema) { .push(Hooks::Info(fpath.to_str().unwrap().to_string()))
h.push(Hooks::GlibSchema); } else if s.contains("/share/glib-2.0/schemas") {
let mut h = hooks.lock().unwrap();
if !h.contains(&Hooks::GlibSchema) {
h.push(Hooks::GlibSchema);
}
} }
} }
} // Match up a package entry with a tar node
// Match up a package entry with a tar node let entry = package
let entry = package .plist
.plist .entries
.entries .iter()
.iter() .find(|&x| match x {
.find(|&x| match x { Entry::File {
Entry::File { path,
path, sha256sum: _,
sha256sum: _, mode: _,
mode: _, size: _,
size: _, } => path == &fpath,
} => path == &fpath, Entry::Link { path, target: _ } => path == &fpath,
Entry::Link { path, target: _ } => path == &fpath, Entry::Directory { path, mode: _ } => path == &fpath,
Entry::Directory { path, mode: _ } => path == &fpath, })
}) .unwrap();
.unwrap(); path = path.join(&fpath);
path = path.join(&fpath); if let Some(parent) = path.parent() {
if let Some(parent) = path.parent() { if !parent.exists() {
if !parent.exists() { fs::create_dir_all(&parent)?;
fs::create_dir_all(&parent)?; }
} }
} if path.exists() {
if path.exists() { if path.is_dir() {
if path.is_dir() { fs::remove_dir(&path)?;
fs::remove_dir(&path)?; } else if path.is_symlink() || path.is_file() {
} else if path.is_symlink() || path.is_file() { fs::remove_file(&path)?;
fs::remove_file(&path)?; }
} }
} let msg = extract_entry(entry, node, path)?;
let msg = extract_entry(entry, node, path)?; sender.send(msg)?;
sender.send(msg)?; Ok::<(), InstallError>(())
Ok::<(), InstallError>(()) })?;
})?;
Ok(hooks.into_inner()?) Ok(hooks.into_inner()?)
} }
@ -164,12 +181,12 @@ impl<T: io::Read> Installer<T> {
if let Some(ref users) = self.package.users { if let Some(ref users) = self.package.users {
users users
.iter() .iter()
.for_each(|u| hooks.push((u.clone(), Some(self.path.clone())).into())); .for_each(|u| hooks.push((u.clone(), Some(self.root.clone())).into()));
} }
if let Some(ref groups) = self.package.groups { if let Some(ref groups) = self.package.groups {
groups groups
.iter() .iter()
.for_each(|g| hooks.push((g.clone(), Some(self.path.clone())).into())); .for_each(|g| hooks.push((g.clone(), Some(self.root.clone())).into()));
} }
hooks hooks
} }
@ -252,6 +269,7 @@ fn pop_pinstall(
} }
mod error { mod error {
use super::InstallMessage;
use crate::Hooks; use crate::Hooks;
use hpk_package::tar; use hpk_package::tar;
use std::{ use std::{
@ -263,7 +281,6 @@ mod error {
PoisonError, PoisonError,
}, },
}; };
use super::InstallMessage;
#[derive(Debug)] #[derive(Debug)]
pub enum InstallError { pub enum InstallError {