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 { use {
crate::{Item, Package, Plist, Specs}, crate::{Item, ItemError, Package, Plist, Specs},
hpk_package::Entry, hpk_package::{tar, Entry},
rayon::prelude::{IntoParallelRefIterator, ParallelIterator}, rayon::prelude::{IntoParallelRefIterator, ParallelIterator},
std::{ std::{
borrow::BorrowMut, borrow::BorrowMut,
env, env,
error::Error, error::Error,
fmt,
fs::{self, File}, fs::{self, File},
io::{self, Write}, io::{self, Write},
path::{Path, PathBuf}, path::{Path, PathBuf},
@ -19,10 +22,10 @@ use {
zstd::Encoder, zstd::Encoder,
}; };
#[derive(Debug, Clone)]
pub enum Message { pub enum Message {
MemberAdded(String), MemberAdded(String),
Success(String), Success(String),
Failure(String),
} }
/// Creates a package archive /// Creates a package archive
@ -90,51 +93,38 @@ impl Creator {
archive.set_extension("tar.zst"); archive.set_extension("tar.zst");
let fd = File::create(&archive)?; let fd = File::create(&archive)?;
let writer = Mutex::new(Encoder::new(fd, 0)?); let writer = Mutex::new(Encoder::new(fd, 0)?);
let sender = Mutex::new(sender);
env::set_current_dir(&self.path)?; env::set_current_dir(&self.path)?;
let s = sender.clone();
self.entries self.entries
.par_iter() .par_iter()
.filter(|x| x.as_path() != Path::new(".")) .filter(|x| x.as_path() != Path::new("."))
.for_each(|x| { .try_for_each_with(s, |s, x| {
let sender = sender.lock().unwrap().clone(); let item = Item::try_create(x.as_path())?;
if let Ok(item) = Item::try_create(x.as_path()) { if let Entry::File {
if let Entry::File { path: _,
path: _, sha256sum: _,
mode: _,
size,
} = &item.entry
{
totalsize.fetch_add(*size, Ordering::Release);
}
let path = match item.entry.clone() {
Entry::File {
path,
sha256sum: _, sha256sum: _,
mode: _, mode: _,
size, size: _,
} = &item.entry
{
totalsize.fetch_add(*size, Ordering::Release);
} }
let path = match item.entry.clone() { | Entry::Link { path, target: _ }
Entry::File { | Entry::Directory { path, mode: _ } => path,
path, };
sha256sum: _, plist.lock().unwrap().borrow_mut().entries.push(item.entry);
mode: _, writer.lock().unwrap().borrow_mut().write_all(&item.data)?;
size: _, s.send(Message::MemberAdded(format!("{}", path.display())))
} .expect("couldn't send message");
| Entry::Link { path, target: _ } Ok::<(), CreationError>(())
| 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");
}
});
let mut package: Package = self.specs.into(); let mut package: Package = self.specs.into();
package.size = totalsize.into_inner(); package.size = totalsize.into_inner();
let plist = plist.into_inner()?; let plist = plist.into_inner()?;
@ -143,9 +133,50 @@ impl Creator {
let mut writer = writer.into_inner()?; let mut writer = writer.into_inner()?;
writer.write_all(&node.to_vec()?)?; writer.write_all(&node.to_vec()?)?;
let _fd = writer.finish()?; let _fd = writer.finish()?;
let sender = sender.into_inner()?;
sender.send(Message::Success(format!("{} saved", archive.display())))?; sender.send(Message::Success(format!("{} saved", archive.display())))?;
env::set_current_dir(d)?; env::set_current_dir(d)?;
Ok(()) 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 { use {
clap::ArgMatches, clap::ArgMatches,
cli::cli, cli::cli,
hpk::{Creator, Dependency, Message, Specs, Version}, hpk::{CreationError, Creator, Dependency, Message, Specs, Version},
indicatif::{ProgressBar, ProgressStyle}, indicatif::{ProgressBar, ProgressStyle},
ron::ser::{to_writer_pretty, PrettyConfig}, ron::ser::{to_writer_pretty, PrettyConfig},
std::{ std::{
@ -93,13 +93,9 @@ fn create(matches: &ArgMatches) -> Result<(), Box<dyn Error>> {
pb.inc(1); pb.inc(1);
pb.finish_and_clear(); 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)?; creator.create(&outdir, sender)?;
match handle.join() { 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 { match entry {
Entry::Directory { path: _, mode } => { Entry::Directory { path: _, mode } => {
DirBuilder::new().mode(*mode).create(&path)?; DirBuilder::new().mode(*mode).create(&path)?;

View File

@ -1,14 +1,15 @@
use hpk_package::{ use hpk_package::{
deku::DekuError,
sha2::{Digest, Sha256}, sha2::{Digest, Sha256},
tar::{Node, Owner}, tar::{Error as TarError, Node, Owner},
Entry, Entry,
}; };
use std::{ use std::{
error::Error, error::Error,
ffi::OsStr, ffi::OsStr,
fmt::Write, fmt::{self, Write},
fs, fs,
io::Read, io::{self, Read},
os::unix::fs::MetadataExt, os::unix::fs::MetadataExt,
path::{Path, PathBuf}, path::{Path, PathBuf},
}; };
@ -21,7 +22,7 @@ pub struct Item {
} }
impl 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 path = fix_path(path);
let meta = fs::metadata(&path)?; let meta = fs::metadata(&path)?;
let filename = format!("{}", path.display()); 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 { fn fix_path(path: &Path) -> PathBuf {
let path = if let Ok(p) = path.strip_prefix("./") { let path = if let Ok(p) = path.strip_prefix("./") {
p p

View File

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