Add install_local
function to cli app
This commit is contained in:
parent
7fe884cd3e
commit
f479dd28ad
@ -178,6 +178,7 @@ pub fn install() -> Command {
|
|||||||
.help("install packages into a different root")
|
.help("install packages into a different root")
|
||||||
.short('r')
|
.short('r')
|
||||||
.long("root")
|
.long("root")
|
||||||
|
.default_value("/")
|
||||||
.value_hint(ValueHint::DirPath)
|
.value_hint(ValueHint::DirPath)
|
||||||
.num_args(1),
|
.num_args(1),
|
||||||
])
|
])
|
||||||
|
40
src/hpk.rs
40
src/hpk.rs
@ -1,15 +1,17 @@
|
|||||||
#![warn(clippy::all, clippy::pedantic)]
|
#![warn(clippy::all, clippy::pedantic)]
|
||||||
|
|
||||||
mod cli;
|
mod cli;
|
||||||
use {
|
use {
|
||||||
clap::ArgMatches,
|
clap::ArgMatches,
|
||||||
cli::cli,
|
cli::cli,
|
||||||
hpk::{CreationError, Creator, Dependency, Message, Specs, Version},
|
hpk::{CreationError, Creator, Dependency, InstallMessage, Installer, Message, Specs, Version},
|
||||||
indicatif::{ProgressBar, ProgressStyle},
|
indicatif::{ProgressBar, ProgressStyle},
|
||||||
ron::ser::{to_writer_pretty, PrettyConfig},
|
ron::ser::{to_writer_pretty, PrettyConfig},
|
||||||
std::{
|
std::{
|
||||||
env,
|
env,
|
||||||
error::Error,
|
error::Error,
|
||||||
ffi::OsStr,
|
ffi::OsStr,
|
||||||
|
fmt,
|
||||||
fs::File,
|
fs::File,
|
||||||
io::{self, BufWriter, ErrorKind},
|
io::{self, BufWriter, ErrorKind},
|
||||||
path::PathBuf,
|
path::PathBuf,
|
||||||
@ -107,6 +109,42 @@ fn create(matches: &ArgMatches) -> Result<(), Box<dyn Error>> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn install_local<P: AsRef<OsStr> + fmt::Display>(
|
||||||
|
archive: P,
|
||||||
|
root: P,
|
||||||
|
) -> Result<(), Box<dyn Error>> {
|
||||||
|
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<PathBuf, Box<dyn Error>> {
|
fn init(matches: &ArgMatches) -> Result<PathBuf, Box<dyn Error>> {
|
||||||
let specsfile = PathBuf::from("package.specs");
|
let specsfile = PathBuf::from("package.specs");
|
||||||
let cfg = PrettyConfig::new().struct_names(true);
|
let cfg = PrettyConfig::new().struct_names(true);
|
||||||
|
@ -57,37 +57,27 @@ pub struct Installer<T: io::Read> {
|
|||||||
/// The filesystem root under which to install this package.
|
/// The filesystem root under which to install this package.
|
||||||
/// Normally this is "/".
|
/// Normally this is "/".
|
||||||
root: PathBuf,
|
root: PathBuf,
|
||||||
package: Package,
|
|
||||||
reader: T,
|
reader: T,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Installer<Decoder<'_, BufReader<File>>> {
|
impl Installer<Decoder<'_, BufReader<File>>> {
|
||||||
/// creates a new installer from an archive path
|
/// creates a new installer from an archive path
|
||||||
pub fn new_for_file<P: AsRef<OsStr>>(
|
pub fn new_for_file<P: AsRef<OsStr>>(root: P, archive: P) -> Result<Self, io::Error> {
|
||||||
root: P,
|
|
||||||
package: Package,
|
|
||||||
archive: P,
|
|
||||||
) -> Result<Self, io::Error> {
|
|
||||||
let root = Path::new(&root).to_path_buf();
|
let root = Path::new(&root).to_path_buf();
|
||||||
let fd = File::open(Path::new(&archive))?;
|
let fd = File::open(Path::new(&archive))?;
|
||||||
let decoder = Decoder::new(fd)?;
|
let decoder = Decoder::new(fd)?;
|
||||||
Ok(Self::new(root, package, decoder))
|
Ok(Self::new(root, decoder))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: io::Read> Installer<T> {
|
impl<T: io::Read> Installer<T> {
|
||||||
/// Creates a new installer from an open archive stream
|
/// Creates a new installer from an open archive stream
|
||||||
pub fn new<P: AsRef<OsStr>>(root: P, package: Package, reader: T) -> Self {
|
pub fn new<P: AsRef<OsStr>>(root: P, reader: T) -> Self {
|
||||||
let root = Path::new(&root).to_path_buf();
|
let root = Path::new(&root).to_path_buf();
|
||||||
Self {
|
Self { root, reader }
|
||||||
root,
|
|
||||||
package,
|
|
||||||
reader,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn install(mut self, sender: Sender<InstallMessage>) -> Result<Vec<Hooks>, InstallError> {
|
pub fn install(self, sender: Sender<InstallMessage>) -> Result<Vec<Hooks>, InstallError> {
|
||||||
let mut hooks = self.init_hooks();
|
|
||||||
let reader = Decoder::new(self.reader)?;
|
let reader = Decoder::new(self.reader)?;
|
||||||
let mut archive = Archive::read(reader)?;
|
let mut archive = Archive::read(reader)?;
|
||||||
sender.send(InstallMessage::ArchiveRead)?;
|
sender.send(InstallMessage::ArchiveRead)?;
|
||||||
@ -95,15 +85,19 @@ impl<T: io::Read> Installer<T> {
|
|||||||
Some(node) => node,
|
Some(node) => node,
|
||||||
None => return Err(InstallError::MissingManifest),
|
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();
|
let len = archive.nodes.len();
|
||||||
sender.send(InstallMessage::ArchiveLen(len))?;
|
sender.send(InstallMessage::ArchiveLen(len))?;
|
||||||
let mut db_pkgdir = crate::get_dbdir(Some(self.root.clone()));
|
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() {
|
if !db_pkgdir.exists() {
|
||||||
fs::create_dir_all(&db_pkgdir)?;
|
fs::create_dir_all(&db_pkgdir)?;
|
||||||
}
|
}
|
||||||
pop_appstream(&mut archive, &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;
|
let mut db_file = db_pkgdir;
|
||||||
db_file.push("package.ron");
|
db_file.push("package.ron");
|
||||||
if db_file.exists() {
|
if db_file.exists() {
|
||||||
@ -113,7 +107,6 @@ impl<T: io::Read> Installer<T> {
|
|||||||
let writer = BufWriter::new(fd);
|
let writer = BufWriter::new(fd);
|
||||||
pr_node.write(writer)?;
|
pr_node.write(writer)?;
|
||||||
let root = &self.root;
|
let root = &self.root;
|
||||||
let package = &self.package;
|
|
||||||
let hooks = Mutex::new(hooks);
|
let hooks = Mutex::new(hooks);
|
||||||
let s = sender.clone();
|
let s = sender.clone();
|
||||||
archive
|
archive
|
||||||
@ -175,22 +168,22 @@ impl<T: io::Read> Installer<T> {
|
|||||||
})?;
|
})?;
|
||||||
Ok(hooks.into_inner()?)
|
Ok(hooks.into_inner()?)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn init_hooks(&mut self) -> Vec<Hooks> {
|
fn init_hooks(package: &Package, root: &Path) -> Vec<Hooks> {
|
||||||
let mut hooks = Vec::<Hooks>::new();
|
let mut hooks = Vec::<Hooks>::new();
|
||||||
if let Some(ref users) = self.package.users {
|
if let Some(ref users) = package.users {
|
||||||
users
|
users
|
||||||
.iter()
|
.iter()
|
||||||
.for_each(|u| hooks.push((u.clone(), Some(self.root.clone())).into()));
|
.for_each(|u| hooks.push((u.clone(), Some(root.to_path_buf())).into()));
|
||||||
}
|
}
|
||||||
if let Some(ref groups) = self.package.groups {
|
if let Some(ref groups) = package.groups {
|
||||||
groups
|
groups
|
||||||
.iter()
|
.iter()
|
||||||
.for_each(|g| hooks.push((g.clone(), Some(self.root.clone())).into()));
|
.for_each(|g| hooks.push((g.clone(), Some(root.to_path_buf())).into()));
|
||||||
}
|
}
|
||||||
hooks
|
hooks
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
fn extract_entry(
|
fn extract_entry(
|
||||||
entry: &Entry,
|
entry: &Entry,
|
||||||
@ -272,6 +265,7 @@ mod error {
|
|||||||
use super::InstallMessage;
|
use super::InstallMessage;
|
||||||
use crate::Hooks;
|
use crate::Hooks;
|
||||||
use hpk_package::tar;
|
use hpk_package::tar;
|
||||||
|
use ron::error::SpannedError;
|
||||||
use std::{
|
use std::{
|
||||||
error::Error,
|
error::Error,
|
||||||
fmt, io,
|
fmt, io,
|
||||||
@ -286,6 +280,7 @@ mod error {
|
|||||||
pub enum InstallError {
|
pub enum InstallError {
|
||||||
Fmt(fmt::Error),
|
Fmt(fmt::Error),
|
||||||
IO(io::Error),
|
IO(io::Error),
|
||||||
|
RonError(SpannedError),
|
||||||
SendError(SendError<InstallMessage>),
|
SendError(SendError<InstallMessage>),
|
||||||
Tar(tar::Error),
|
Tar(tar::Error),
|
||||||
ChecksumMismatch,
|
ChecksumMismatch,
|
||||||
@ -307,6 +302,7 @@ mod error {
|
|||||||
Self::IO(e) => Some(e),
|
Self::IO(e) => Some(e),
|
||||||
Self::Tar(e) => Some(e),
|
Self::Tar(e) => Some(e),
|
||||||
Self::SendError(e) => Some(e),
|
Self::SendError(e) => Some(e),
|
||||||
|
Self::RonError(e) => Some(e),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -342,6 +338,12 @@ mod error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<SpannedError> for InstallError {
|
||||||
|
fn from(value: SpannedError) -> Self {
|
||||||
|
Self::RonError(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl From<FromUtf8Error> for InstallError {
|
impl From<FromUtf8Error> for InstallError {
|
||||||
fn from(_value: FromUtf8Error) -> Self {
|
fn from(_value: FromUtf8Error) -> Self {
|
||||||
Self::Utf8
|
Self::Utf8
|
||||||
|
Loading…
Reference in New Issue
Block a user