diff --git a/.gitignore b/.gitignore index be024c4..bfa4a4d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ +dist/ **/target **/Cargo.lock *.pkg \ No newline at end of file diff --git a/pkgr/src/package/installer/errors.rs b/pkgr/src/package/installer/errors.rs index ad6d22f..332a06f 100644 --- a/pkgr/src/package/installer/errors.rs +++ b/pkgr/src/package/installer/errors.rs @@ -1,21 +1,26 @@ use std::fmt::Display; +use std::io; #[derive(Debug)] pub enum BinError { UnpackError(String), + IOError(io::Error), + Cancelled, } impl Display for BinError { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { BinError::UnpackError(e) => write!(f, "Unpack error: {}", e), + BinError::IOError(e) => write!(f, "IO error: {}", e), + BinError::Cancelled => write!(f, "Cancelled by user"), } } } #[derive(Debug)] pub enum BuildError { - InvalidManifest, + InvalidManifest(String), } impl Display for BuildError { @@ -30,8 +35,7 @@ impl Display for BuildError { pub enum InstallError { BuildError(BuildError), BinError(BinError), - InvalidManifest, - Generic, + InvalidManifest(String), } impl ToString for InstallError { @@ -39,8 +43,7 @@ impl ToString for InstallError { match self { InstallError::BuildError(e) => format!("{}", e), InstallError::BinError(e) => format!("{}", e), - InstallError::InvalidManifest => "Invalid manifest".to_string(), - InstallError::Generic => "Install error".to_string(), + InstallError::InvalidManifest(s) => format!("{}", s), } } } diff --git a/pkgr/src/package/installer/mod.rs b/pkgr/src/package/installer/mod.rs index 73d40fa..bea639d 100644 --- a/pkgr/src/package/installer/mod.rs +++ b/pkgr/src/package/installer/mod.rs @@ -1,5 +1,8 @@ -use std::fs::{remove_dir, remove_dir_all}; +use std::fs::remove_dir_all; +use std::path::Path; use std::process::exit; +use std::{io, thread}; +use libc::SIGINT; use log::{debug, error, info, trace}; @@ -12,8 +15,8 @@ use crate::package::identifier::{PackageIdentifier, PackageLocator}; use crate::package::Package; use crate::tmpfs::TempDir; use crate::types::fetch::TryFetch; -use crate::util::{visit_dirs}; -use crate::util::prompts::prompt_bool; +use crate::util::fs::{copy_recursively, visit_dirs}; +use crate::util::prompts::{is_noninteractive, prompt_bool}; pub mod errors; @@ -62,29 +65,47 @@ impl PackageInstaller { tmpdir.push(&self.manifest.package.name); trace!("extracting package into: {}", tmpdir.to_string()); if let Err(e) = self.extract_to(tmpdir.to_string()) { - return Err(e) + return Err(e); } debug!("extracted package in: {}", tmpdir.to_string()); - if prompt_bool("See all files?", false) { - if let Err(e) = visit_dirs(tmpdir.path().as_path(), &|d| info!(target: "item", "{}", d.path().to_str().unwrap())) { - error!("Could not show files: {}", e); + { + let mut tmpdir = tmpdir.clone(); + tmpdir.push(&self.manifest.bin.clone().unwrap().root); + if prompt_bool("See all pending installation files?", true) { + if let Err(e) = visit_dirs(tmpdir.path().as_path(), + &|d| { + info!(target: "item", "{}", d.path() + .to_str() + .unwrap() + .replace(&tmpdir.to_string(), "")) + }) + { + error!("Could not show files: {}", e); + } } - if prompt_bool("Continue?", false) { - self.apply_overlay(); - } - } else { - self.apply_overlay(); + } + if !prompt_bool("Continue?", is_noninteractive()) { + return Err(BinError::Cancelled); + } + match self.apply_overlay() { + Ok(_) => Ok(()), + Err(e) => Err(BinError::IOError(e)) + } + } + + fn apply_overlay(&self) -> Result<(), io::Error> { + let mut tmpdir = TempDir::default(); + tmpdir.push(&self.manifest.package.name); + tmpdir.push(&self.manifest.bin.clone().unwrap().root); + if let Err(e) = copy_recursively(&tmpdir.path(), Path::new("/")) { + return Err(e); } Ok(()) } - fn apply_overlay(&self) { - - } - fn build(&self) -> Result<(), BuildError> { if let None = self.manifest.build.clone() { - return Err(BuildError::InvalidManifest); + return Err(BuildError::InvalidManifest(String::from("No build manifest"))); } let build_manifest = self.manifest.build.clone().unwrap(); // TODO: Check dependencies @@ -117,7 +138,7 @@ impl PackageInstaller { if let None = self.manifest.bin { self.install_type = InstallType::Build; if let None = self.manifest.build { - return Err(InstallError::InvalidManifest); + return Err(InstallError::InvalidManifest(String::from("no bin or build manifest"))); } } } @@ -125,7 +146,7 @@ impl PackageInstaller { if let None = self.manifest.build { self.install_type = InstallType::Bin; if let None = self.manifest.bin { - return Err(InstallError::InvalidManifest); + return Err(InstallError::InvalidManifest(String::from("no build or bin manifest"))); } } } diff --git a/pkgr/src/tmpfs.rs b/pkgr/src/tmpfs.rs index f1d0599..e83b860 100644 --- a/pkgr/src/tmpfs.rs +++ b/pkgr/src/tmpfs.rs @@ -2,6 +2,7 @@ use std::path::{Path, PathBuf}; use crate::CONFIG; +#[derive(Clone)] pub struct TempDir { path: PathBuf, } @@ -21,7 +22,11 @@ impl TempDir { } pub fn push>(&mut self, path: S) { - self.path.push(path.into()); + let mut path_str = path.into(); + if path_str.starts_with('/') { + path_str = path_str[1..].to_string(); + } + self.path.push(path_str); } } diff --git a/pkgr/src/util/fs.rs b/pkgr/src/util/fs.rs new file mode 100644 index 0000000..03b5cb2 --- /dev/null +++ b/pkgr/src/util/fs.rs @@ -0,0 +1,40 @@ +use std::path::Path; +use std::fs::DirEntry; +use std::{fs, io}; +use log::trace; + +pub fn visit_dirs(dir: &Path, cb: &dyn Fn(&DirEntry)) -> std::io::Result<()> { + if dir.is_dir() { + for entry in std::fs::read_dir(dir)? { + let entry = entry?; + let path = entry.path(); + if path.is_dir() { + visit_dirs(&path, cb)?; + } else { + cb(&entry); + } + } + } + Ok(()) +} + +pub fn copy_recursively(source: &Path, target: &Path) -> io::Result<()> { + if source.is_file() { + trace!("source: {:?}, target: {:?}", source, target); + fs::copy(source, target)?; + } else if source.is_dir() { + if !target.exists() { + fs::create_dir(target)?; + } + + for entry in fs::read_dir(source)? { + let entry = entry?; + let file_name = entry.file_name(); + let source_path = entry.path(); + let target_path = target.join(&file_name); + + copy_recursively(&source_path, &target_path)?; + } + } + Ok(()) +} \ No newline at end of file diff --git a/pkgr/src/util/mod.rs b/pkgr/src/util/mod.rs index dc3d868..c239775 100644 --- a/pkgr/src/util/mod.rs +++ b/pkgr/src/util/mod.rs @@ -1,19 +1,2 @@ -use std::fs::DirEntry; -use std::path::Path; - pub mod prompts; - -pub fn visit_dirs(dir: &Path, cb: &dyn Fn(&DirEntry)) -> std::io::Result<()> { - if dir.is_dir() { - for entry in std::fs::read_dir(dir)? { - let entry = entry?; - let path = entry.path(); - if path.is_dir() { - visit_dirs(&path, cb)?; - } else { - cb(&entry); - } - } - } - Ok(()) -} \ No newline at end of file +pub mod fs; \ No newline at end of file