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,7 +1,12 @@
|
|||||||
use {
|
use {
|
||||||
clap_complete::{generate_to, shells},
|
clap_complete::{generate_to, shells},
|
||||||
clap_complete_nushell::Nushell,
|
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";
|
static PROGNAME: &str = "hpk";
|
||||||
|
@ -17,10 +17,14 @@ fn main() -> Result<(), Box<dyn Error>> {
|
|||||||
Arg::new("output")
|
Arg::new("output")
|
||||||
.help("the output directory for the installation")
|
.help("the output directory for the installation")
|
||||||
.required(true)
|
.required(true)
|
||||||
.num_args(1)
|
.num_args(1),
|
||||||
])
|
])
|
||||||
.get_matches();
|
.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());
|
let arch = matches.get_one::<String>("arch").map(|x| x.to_string());
|
||||||
bootstrap::install(outdir, arch)?;
|
bootstrap::install(outdir, arch)?;
|
||||||
Ok(())
|
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 {
|
use {
|
||||||
crate::{Repository, Package, Version},
|
crate::{Package, Repository, Version},
|
||||||
serde::{Deserialize, Serialize},
|
serde::{Deserialize, Serialize},
|
||||||
std::{collections::HashMap, error::Error},
|
std::{collections::HashMap, error::Error},
|
||||||
url::Url,
|
url::Url,
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
#![warn(clippy::all, clippy::pedantic)]
|
#![warn(clippy::all, clippy::pedantic)]
|
||||||
|
mod creator;
|
||||||
mod db;
|
mod db;
|
||||||
mod hooks;
|
mod hooks;
|
||||||
mod item;
|
mod item;
|
||||||
@ -8,6 +9,7 @@ mod repository;
|
|||||||
mod version;
|
mod version;
|
||||||
|
|
||||||
pub use {
|
pub use {
|
||||||
|
creator::Creator,
|
||||||
db::Database,
|
db::Database,
|
||||||
hooks::Hooks,
|
hooks::Hooks,
|
||||||
item::Item,
|
item::Item,
|
||||||
|
@ -92,7 +92,7 @@ impl Package {
|
|||||||
to_string_pretty(self, cfg)
|
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() {
|
if !outdir.exists() {
|
||||||
fs::create_dir_all(outdir)?;
|
fs::create_dir_all(outdir)?;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user