Use `try_for_each_with` in Creator::create in order to avoid putting

Sender in a mutex and return errors rather than passing messages
This commit is contained in:
Nathan Fisher 2023-04-12 11:15:13 -04:00
parent be0c8dc6e7
commit d3b5d096e5
5 changed files with 136 additions and 55 deletions

View File

@ -1,11 +1,14 @@
use hpk_package::deku::DekuError;
use {
crate::{Item, Package, Plist, Specs},
hpk_package::Entry,
crate::{Item, ItemError, Package, Plist, Specs},
hpk_package::{tar, Entry},
rayon::prelude::{IntoParallelRefIterator, ParallelIterator},
std::{
borrow::BorrowMut,
env,
error::Error,
fmt,
fs::{self, File},
io::{self, Write},
path::{Path, PathBuf},
@ -19,10 +22,10 @@ use {
zstd::Encoder,
};
#[derive(Debug, Clone)]
pub enum Message {
MemberAdded(String),
Success(String),
Failure(String),
}
/// Creates a package archive
@ -90,51 +93,38 @@ impl Creator {
archive.set_extension("tar.zst");
let fd = File::create(&archive)?;
let writer = Mutex::new(Encoder::new(fd, 0)?);
let sender = Mutex::new(sender);
env::set_current_dir(&self.path)?;
let s = sender.clone();
self.entries
.par_iter()
.filter(|x| x.as_path() != Path::new("."))
.for_each(|x| {
let sender = sender.lock().unwrap().clone();
if let Ok(item) = Item::try_create(x.as_path()) {
if let Entry::File {
path: _,
.try_for_each_with(s, |s, x| {
let item = Item::try_create(x.as_path())?;
if let Entry::File {
path: _,
sha256sum: _,
mode: _,
size,
} = &item.entry
{
totalsize.fetch_add(*size, Ordering::Release);
}
let path = match item.entry.clone() {
Entry::File {
path,
sha256sum: _,
mode: _,
size,
} = &item.entry
{
totalsize.fetch_add(*size, Ordering::Release);
size: _,
}
let path = match item.entry.clone() {
Entry::File {
path,
sha256sum: _,
mode: _,
size: _,
}
| Entry::Link { path, target: _ }
| Entry::Directory { path, mode: _ } => path,
};
plist.lock().unwrap().borrow_mut().entries.push(item.entry);
match writer.lock().unwrap().borrow_mut().write_all(&item.data) {
Ok(_) => sender
.send(Message::MemberAdded(format!("{}", path.display())))
.expect("couldn't send message"),
Err(e) => sender
.send(Message::Failure(format!("{e}")))
.expect("couldn't send message"),
}
} else {
sender
.send(Message::Failure(format!(
"Could not process DirEntry for {}",
x.display()
)))
.expect("could not send message");
}
});
| Entry::Link { path, target: _ }
| Entry::Directory { path, mode: _ } => path,
};
plist.lock().unwrap().borrow_mut().entries.push(item.entry);
writer.lock().unwrap().borrow_mut().write_all(&item.data)?;
s.send(Message::MemberAdded(format!("{}", path.display())))
.expect("couldn't send message");
Ok::<(), CreationError>(())
})?;
let mut package: Package = self.specs.into();
package.size = totalsize.into_inner();
let plist = plist.into_inner()?;
@ -143,9 +133,50 @@ impl Creator {
let mut writer = writer.into_inner()?;
writer.write_all(&node.to_vec()?)?;
let _fd = writer.finish()?;
let sender = sender.into_inner()?;
sender.send(Message::Success(format!("{} saved", archive.display())))?;
env::set_current_dir(d)?;
Ok(())
}
}
#[derive(Debug)]
pub enum CreationError {
Io(io::Error),
Fmt(fmt::Error),
Tar(tar::Error),
Deku(DekuError),
}
impl fmt::Display for CreationError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{self:?}")
}
}
impl Error for CreationError {
fn source(&self) -> Option<&(dyn Error + 'static)> {
match self {
Self::Io(e) => Some(e),
Self::Fmt(e) => Some(e),
Self::Tar(e) => Some(e),
Self::Deku(e) => Some(e),
}
}
}
impl From<io::Error> for CreationError {
fn from(value: io::Error) -> Self {
Self::Io(value)
}
}
impl From<ItemError> for CreationError {
fn from(value: ItemError) -> Self {
match value {
ItemError::Io(e) => Self::Io(e),
ItemError::Fmt(e) => Self::Fmt(e),
ItemError::Tar(e) => Self::Tar(e),
ItemError::Deku(e) => Self::Deku(e),
}
}
}

View File

@ -3,7 +3,7 @@ mod cli;
use {
clap::ArgMatches,
cli::cli,
hpk::{Creator, Dependency, Message, Specs, Version},
hpk::{CreationError, Creator, Dependency, Message, Specs, Version},
indicatif::{ProgressBar, ProgressStyle},
ron::ser::{to_writer_pretty, PrettyConfig},
std::{
@ -93,13 +93,9 @@ fn create(matches: &ArgMatches) -> Result<(), Box<dyn Error>> {
pb.inc(1);
pb.finish_and_clear();
}
Message::Failure(s) => {
eprint!("{s}");
return Err(io::Error::new(io::ErrorKind::Other, s));
}
}
}
Ok(())
Ok::<(), CreationError>(())
});
creator.create(&outdir, sender)?;
match handle.join() {

View File

@ -175,7 +175,11 @@ impl<T: io::Read> Installer<T> {
}
}
fn extract_entry(entry: &Entry, node: &Node, path: PathBuf) -> Result<InstallMessage, InstallError> {
fn extract_entry(
entry: &Entry,
node: &Node,
path: PathBuf,
) -> Result<InstallMessage, InstallError> {
match entry {
Entry::Directory { path: _, mode } => {
DirBuilder::new().mode(*mode).create(&path)?;

View File

@ -1,14 +1,15 @@
use hpk_package::{
deku::DekuError,
sha2::{Digest, Sha256},
tar::{Node, Owner},
tar::{Error as TarError, Node, Owner},
Entry,
};
use std::{
error::Error,
ffi::OsStr,
fmt::Write,
fmt::{self, Write},
fs,
io::Read,
io::{self, Read},
os::unix::fs::MetadataExt,
path::{Path, PathBuf},
};
@ -21,7 +22,7 @@ pub struct Item {
}
impl Item {
pub fn try_create(path: &Path) -> Result<Self, Box<dyn Error>> {
pub fn try_create(path: &Path) -> Result<Self, ItemError> {
let path = fix_path(path);
let meta = fs::metadata(&path)?;
let filename = format!("{}", path.display());
@ -68,6 +69,55 @@ impl Item {
}
}
#[derive(Debug)]
pub enum ItemError {
Io(io::Error),
Fmt(fmt::Error),
Tar(TarError),
Deku(DekuError),
}
impl fmt::Display for ItemError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{self:?}")
}
}
impl Error for ItemError {
fn source(&self) -> Option<&(dyn Error + 'static)> {
match self {
Self::Io(e) => Some(e),
Self::Fmt(e) => Some(e),
Self::Tar(e) => Some(e),
Self::Deku(e) => Some(e),
}
}
}
impl From<io::Error> for ItemError {
fn from(value: io::Error) -> Self {
Self::Io(value)
}
}
impl From<fmt::Error> for ItemError {
fn from(value: fmt::Error) -> Self {
Self::Fmt(value)
}
}
impl From<TarError> for ItemError {
fn from(value: TarError) -> Self {
Self::Tar(value)
}
}
impl From<DekuError> for ItemError {
fn from(value: DekuError) -> Self {
Self::Deku(value)
}
}
fn fix_path(path: &Path) -> PathBuf {
let path = if let Ok(p) = path.strip_prefix("./") {
p

View File

@ -9,12 +9,12 @@ mod repository;
use std::path::PathBuf;
pub use {
creator::{Creator, Message},
creator::{CreationError, Creator, Message},
db::Database,
hooks::{Hooks, Pinstall},
hpk_package::{tar, Arch, Dependency, GitRev, Package, Plist, Rapid, SemVer, Specs, Version},
installer::{InstallError, InstallMessage, Installer},
item::Item,
item::{Item, ItemError},
repository::Repository,
};