diff --git a/src/cli.rs b/src/cli.rs index 797e70e..27bd367 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -178,6 +178,7 @@ pub fn install() -> Command { .help("install packages into a different root") .short('r') .long("root") + .default_value("/") .value_hint(ValueHint::DirPath) .num_args(1), ]) diff --git a/src/hpk.rs b/src/hpk.rs index a324e53..1e54583 100644 --- a/src/hpk.rs +++ b/src/hpk.rs @@ -1,15 +1,17 @@ #![warn(clippy::all, clippy::pedantic)] + mod cli; use { clap::ArgMatches, cli::cli, - hpk::{CreationError, Creator, Dependency, Message, Specs, Version}, + hpk::{CreationError, Creator, Dependency, InstallMessage, Installer, Message, Specs, Version}, indicatif::{ProgressBar, ProgressStyle}, ron::ser::{to_writer_pretty, PrettyConfig}, std::{ env, error::Error, ffi::OsStr, + fmt, fs::File, io::{self, BufWriter, ErrorKind}, path::PathBuf, @@ -107,6 +109,42 @@ fn create(matches: &ArgMatches) -> Result<(), Box> { } } +fn install_local + fmt::Display>( + archive: P, + root: P, +) -> Result<(), Box> { + let (sender, receiver) = mpsc::channel(); + let pb = ProgressBar::new(0); + pb.set_style(ProgressStyle::with_template(TEMPLATE).unwrap()); + pb.println(format!("Installing package {}", archive,)); + let installer = Installer::new_for_file(root, archive)?; + let handle = thread::spawn(move || { + for msg in receiver.iter() { + match msg { + InstallMessage::ArchiveLen(len) => pb.set_length(len.try_into().unwrap()), + InstallMessage::LinkCreated(link) => { + pb.inc(1); + } + InstallMessage::DirectoryCreated(dir) => { + pb.inc(1); + } + InstallMessage::FileInstalled(file) => { + pb.inc(1); + } + _ => {} + } + } + }); + installer.install(sender)?; + match handle.join() { + Ok(hooks) => { + println!("hooks: {hooks:?}"); + Ok(()) + } + Err(_) => Err(io::Error::new(ErrorKind::Other, "Unknown thread error").into()), + } +} + fn init(matches: &ArgMatches) -> Result> { let specsfile = PathBuf::from("package.specs"); let cfg = PrettyConfig::new().struct_names(true); diff --git a/src/installer/mod.rs b/src/installer/mod.rs index a66e56c..c6dfddd 100644 --- a/src/installer/mod.rs +++ b/src/installer/mod.rs @@ -57,37 +57,27 @@ pub struct Installer { /// The filesystem root under which to install this package. /// Normally this is "/". root: PathBuf, - package: Package, reader: T, } impl Installer>> { /// creates a new installer from an archive path - pub fn new_for_file>( - root: P, - package: Package, - archive: P, - ) -> Result { + pub fn new_for_file>(root: P, archive: P) -> Result { 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)) + Ok(Self::new(root, decoder)) } } impl Installer { /// Creates a new installer from an open archive stream - pub fn new>(root: P, package: Package, reader: T) -> Self { + pub fn new>(root: P, reader: T) -> Self { let root = Path::new(&root).to_path_buf(); - Self { - root, - package, - reader, - } + Self { root, reader } } - pub fn install(mut self, sender: Sender) -> Result, InstallError> { - let mut hooks = self.init_hooks(); + pub fn install(self, sender: Sender) -> Result, InstallError> { let reader = Decoder::new(self.reader)?; let mut archive = Archive::read(reader)?; sender.send(InstallMessage::ArchiveRead)?; @@ -95,15 +85,19 @@ impl Installer { Some(node) => node, None => return Err(InstallError::MissingManifest), }; + let mut buf = vec![]; + pr_node.write(&mut buf)?; + let package: Package = ron::de::from_bytes(&buf)?; + let mut hooks = init_hooks(&package, &self.root); let len = archive.nodes.len(); sender.send(InstallMessage::ArchiveLen(len))?; let mut db_pkgdir = crate::get_dbdir(Some(self.root.clone())); - db_pkgdir.push(&self.package.name); + db_pkgdir.push(&package.name); if !db_pkgdir.exists() { fs::create_dir_all(&db_pkgdir)?; } pop_appstream(&mut archive, &db_pkgdir)?; - pop_pinstall(&mut archive, &mut hooks, &self.package.name, &self.root)?; + pop_pinstall(&mut archive, &mut hooks, &package.name, &self.root)?; let mut db_file = db_pkgdir; db_file.push("package.ron"); if db_file.exists() { @@ -113,7 +107,6 @@ impl Installer { let writer = BufWriter::new(fd); pr_node.write(writer)?; let root = &self.root; - let package = &self.package; let hooks = Mutex::new(hooks); let s = sender.clone(); archive @@ -175,21 +168,21 @@ impl Installer { })?; Ok(hooks.into_inner()?) } +} - fn init_hooks(&mut self) -> Vec { - let mut hooks = Vec::::new(); - if let Some(ref users) = self.package.users { - users - .iter() - .for_each(|u| hooks.push((u.clone(), Some(self.root.clone())).into())); - } - if let Some(ref groups) = self.package.groups { - groups - .iter() - .for_each(|g| hooks.push((g.clone(), Some(self.root.clone())).into())); - } - hooks +fn init_hooks(package: &Package, root: &Path) -> Vec { + let mut hooks = Vec::::new(); + if let Some(ref users) = package.users { + users + .iter() + .for_each(|u| hooks.push((u.clone(), Some(root.to_path_buf())).into())); } + if let Some(ref groups) = package.groups { + groups + .iter() + .for_each(|g| hooks.push((g.clone(), Some(root.to_path_buf())).into())); + } + hooks } fn extract_entry( @@ -272,6 +265,7 @@ mod error { use super::InstallMessage; use crate::Hooks; use hpk_package::tar; + use ron::error::SpannedError; use std::{ error::Error, fmt, io, @@ -286,6 +280,7 @@ mod error { pub enum InstallError { Fmt(fmt::Error), IO(io::Error), + RonError(SpannedError), SendError(SendError), Tar(tar::Error), ChecksumMismatch, @@ -307,6 +302,7 @@ mod error { Self::IO(e) => Some(e), Self::Tar(e) => Some(e), Self::SendError(e) => Some(e), + Self::RonError(e) => Some(e), _ => None, } } @@ -342,6 +338,12 @@ mod error { } } + impl From for InstallError { + fn from(value: SpannedError) -> Self { + Self::RonError(value) + } + } + impl From for InstallError { fn from(_value: FromUtf8Error) -> Self { Self::Utf8