Added package Creator
struct, with create
method to process package
entries fully multithreaded including compressing into the archive, as well as passing messages through an mpsc::channel() interface for use in a background thread in various frontends. Much better suited to task than previous `create_package` function. Untested.
This commit is contained in:
parent
33955fa836
commit
39b8664c9e
@ -1,12 +1,17 @@
|
||||
use {
|
||||
clap_complete::{generate_to, shells},
|
||||
clap_complete_nushell::Nushell,
|
||||
std::{error::Error, fs, ops::Deref, path::{Path, PathBuf}},
|
||||
std::{
|
||||
error::Error,
|
||||
fs,
|
||||
ops::Deref,
|
||||
path::{Path, PathBuf},
|
||||
},
|
||||
};
|
||||
|
||||
static PROGNAME: &str = "hpk";
|
||||
|
||||
fn gencomp(outdir: PathBuf, gen:&str) -> Result<(), Box<dyn Error>> {
|
||||
fn gencomp(outdir: PathBuf, gen: &str) -> Result<(), Box<dyn Error>> {
|
||||
let mut cmd = cli::cli();
|
||||
let path = match gen {
|
||||
"bash" => generate_to(shells::Bash, &mut cmd, PROGNAME, outdir)?,
|
||||
|
@ -17,10 +17,14 @@ fn main() -> Result<(), Box<dyn Error>> {
|
||||
Arg::new("output")
|
||||
.help("the output directory for the installation")
|
||||
.required(true)
|
||||
.num_args(1)
|
||||
.num_args(1),
|
||||
])
|
||||
.get_matches();
|
||||
let outdir = matches.get_one::<String>("output").unwrap().to_string().into();
|
||||
let outdir = matches
|
||||
.get_one::<String>("output")
|
||||
.unwrap()
|
||||
.to_string()
|
||||
.into();
|
||||
let arch = matches.get_one::<String>("arch").map(|x| x.to_string());
|
||||
bootstrap::install(outdir, arch)?;
|
||||
Ok(())
|
||||
|
115
src/creator/mod.rs
Normal file
115
src/creator/mod.rs
Normal file
@ -0,0 +1,115 @@
|
||||
use std::{
|
||||
borrow::BorrowMut,
|
||||
fs::File,
|
||||
io::Write,
|
||||
sync::{
|
||||
atomic::{AtomicUsize, Ordering},
|
||||
mpsc::{self, Receiver},
|
||||
Mutex,
|
||||
},
|
||||
};
|
||||
|
||||
use rayon::prelude::{IntoParallelRefIterator, ParallelIterator};
|
||||
use walkdir::WalkDir;
|
||||
use zstd::Encoder;
|
||||
|
||||
use crate::{Entry, Item, Plist, Package};
|
||||
|
||||
use {
|
||||
crate::Specs,
|
||||
std::{env, error::Error, io, path::Path, sync::mpsc::Sender},
|
||||
walkdir::DirEntry,
|
||||
};
|
||||
|
||||
pub enum Message {
|
||||
Success(String),
|
||||
Failure(String),
|
||||
}
|
||||
|
||||
pub struct Creator {
|
||||
entries: Vec<Result<DirEntry, walkdir::Error>>,
|
||||
specs: Specs,
|
||||
sender: Sender<Message>,
|
||||
receiver: Receiver<Message>,
|
||||
}
|
||||
|
||||
impl Creator {
|
||||
pub fn new(path: &Path, specs: Specs) -> Result<Self, io::Error> {
|
||||
env::set_current_dir(path)?;
|
||||
let entries = WalkDir::new(".").into_iter().collect::<Vec<_>>();
|
||||
let (sender, receiver) = mpsc::channel();
|
||||
Ok(Self {
|
||||
entries,
|
||||
specs,
|
||||
sender,
|
||||
receiver,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn create(self, outdir: &Path) -> Result<(), Box<dyn Error>> {
|
||||
let plist = Mutex::new(Plist::default());
|
||||
let totalsize: AtomicUsize = 0.into();
|
||||
let fullname = format!(
|
||||
"{}-{}_{}",
|
||||
&self.specs.name, self.specs.version, self.specs.release
|
||||
);
|
||||
let mut archive = outdir.to_path_buf();
|
||||
archive.push(&fullname);
|
||||
archive.set_extension("tar.zst");
|
||||
let fd = File::create(&archive)?;
|
||||
let writer = Mutex::new(Encoder::new(fd, 0)?);
|
||||
let sender = Mutex::new(self.sender.clone());
|
||||
self.entries
|
||||
.par_iter()
|
||||
.filter(|x| x.is_ok())
|
||||
.map(|x| x.as_ref().unwrap())
|
||||
.for_each(|x| {
|
||||
let sender = sender.lock().unwrap().clone();
|
||||
if let Ok(item) = Item::try_create(x.path().to_path_buf().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: _,
|
||||
} => path.clone(),
|
||||
Entry::Link { path, target: _ } => path.clone(),
|
||||
Entry::Directory { path, mode: _ } => path.clone(),
|
||||
};
|
||||
plist.lock().unwrap().borrow_mut().entries.push(item.entry);
|
||||
match writer.lock().unwrap().borrow_mut().write_all(&item.data) {
|
||||
Ok(_) => sender
|
||||
.send(Message::Success(format!(
|
||||
"{} added to archive",
|
||||
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("Could not process DirEntry".to_string()))
|
||||
.expect("could not send message");
|
||||
}
|
||||
});
|
||||
let mut package: Package = self.specs.into();
|
||||
package.size = totalsize.into_inner();
|
||||
let node = package.save_ron_and_create_tar_node(outdir)?;
|
||||
let mut writer = writer.into_inner()?;
|
||||
writer.write_all(&node.to_vec()?)?;
|
||||
let _fd = writer.finish()?;
|
||||
self.sender.send(Message::Success(format!("{} saved", archive.display())))?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
use {
|
||||
crate::{Repository, Package, Version},
|
||||
crate::{Package, Repository, Version},
|
||||
serde::{Deserialize, Serialize},
|
||||
std::{collections::HashMap, error::Error},
|
||||
url::Url,
|
||||
|
@ -1,4 +1,5 @@
|
||||
#![warn(clippy::all, clippy::pedantic)]
|
||||
mod creator;
|
||||
mod db;
|
||||
mod hooks;
|
||||
mod item;
|
||||
@ -8,6 +9,7 @@ mod repository;
|
||||
mod version;
|
||||
|
||||
pub use {
|
||||
creator::Creator,
|
||||
db::Database,
|
||||
hooks::Hooks,
|
||||
item::Item,
|
||||
|
@ -92,7 +92,7 @@ impl Package {
|
||||
to_string_pretty(self, cfg)
|
||||
}
|
||||
|
||||
fn save_ron_and_create_tar_node(&self, outdir: &Path) -> Result<Node, Box<dyn Error>> {
|
||||
pub(crate) fn save_ron_and_create_tar_node(&self, outdir: &Path) -> Result<Node, Box<dyn Error>> {
|
||||
if !outdir.exists() {
|
||||
fs::create_dir_all(outdir)?;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user