diff --git a/pkgr/src/logging.rs b/pkgr/src/logging.rs index f16df2d..daef3eb 100644 --- a/pkgr/src/logging.rs +++ b/pkgr/src/logging.rs @@ -44,14 +44,12 @@ pub fn setup_logger() -> Result<(), SetLoggerError> { Dispatch::new() .format(|out, message, record| { match record.metadata().target() { - "command:stdout" => { - out.finish(format_args!("{} {}", ">>".cyan(), message.to_string())); - return; - } - "command:stderr" => { - out.finish(format_args!("{} {}", ">>".red(), message.to_string())); - return; - } + // command output logging + "command:stdout" => out.finish(format_args!("{} {}", ">>".cyan(), message.to_string())), + "command:stderr" => out.finish(format_args!("{} {}", ">>".red(), message.to_string())), + // this target means, it's an item and not a log. + "item" => out.finish(format_args!("{} {}", "*".blue(), message.to_string())), + // default logging _ => out.finish(format_args!("{}", format_regular(message.to_string(), record))), } }) diff --git a/pkgr/src/main.rs b/pkgr/src/main.rs index 41f4689..cdad0a0 100644 --- a/pkgr/src/main.rs +++ b/pkgr/src/main.rs @@ -17,6 +17,8 @@ mod tmpfs; mod config; /// custom types used by pkgr mod types; +/// utils +mod util; thread_local! { static CONFIG: config::Config = config::Config::from_path("/etc/pkgr.toml") diff --git a/pkgr/src/package/installer/errors.rs b/pkgr/src/package/installer/errors.rs index 9e86f1b..ad6d22f 100644 --- a/pkgr/src/package/installer/errors.rs +++ b/pkgr/src/package/installer/errors.rs @@ -37,8 +37,8 @@ pub enum InstallError { impl ToString for InstallError { fn to_string(&self) -> String { match self { - InstallError::BuildError(e) => format!("Build error: \n{}", e), - InstallError::BinError(e) => format!("Bin error: \n{}", e), + InstallError::BuildError(e) => format!("{}", e), + InstallError::BinError(e) => format!("{}", e), InstallError::InvalidManifest => "Invalid manifest".to_string(), InstallError::Generic => "Install error".to_string(), } diff --git a/pkgr/src/package/installer/mod.rs b/pkgr/src/package/installer/mod.rs index 52852f5..73d40fa 100644 --- a/pkgr/src/package/installer/mod.rs +++ b/pkgr/src/package/installer/mod.rs @@ -1,3 +1,4 @@ +use std::fs::{remove_dir, remove_dir_all}; use std::process::exit; use log::{debug, error, info, trace}; @@ -11,6 +12,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; pub mod errors; @@ -40,11 +43,14 @@ impl PackageInstaller { if !self.pkgfile.has_data() { return Err(BinError::UnpackError("package has no data".to_string())); } - if std::path::Path::new(&path).exists() { - return Err(BinError::UnpackError(format!( - "path already exists: {}", - path - ))); + let path = std::path::Path::new(&path); + if path.exists() { + trace!("cache already exists.."); + debug!("removing cache dir..."); + match remove_dir_all(path) { + Ok(_) => debug!("removed cache directory"), + Err(e) => return Err(BinError::UnpackError(format!("unable to remove directory ({}): {}", path.to_str().unwrap_or("unknown"), e.to_string()))) + } } tar::Archive::new(self.pkgfile.data.as_slice()) .unpack(&path) @@ -55,14 +61,27 @@ impl PackageInstaller { let mut tmpdir = TempDir::default(); tmpdir.push(&self.manifest.package.name); trace!("extracting package into: {}", tmpdir.to_string()); - match self.extract_to(tmpdir.to_string()) { - Ok(_) => {} - Err(e) => return Err(e), + if let Err(e) = self.extract_to(tmpdir.to_string()) { + 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); + } + if prompt_bool("Continue?", false) { + self.apply_overlay(); + } + } else { + self.apply_overlay(); + } Ok(()) } + fn apply_overlay(&self) { + + } + fn build(&self) -> Result<(), BuildError> { if let None = self.manifest.build.clone() { return Err(BuildError::InvalidManifest); @@ -80,7 +99,7 @@ impl PackageInstaller { match pkg.install(CONFIG.with(|c| { c.build_by_default })) { - Ok(_) => { info!("Installed dependency: \"{}\"", pkg.manifest().package.name) }, + Ok(_) => { info!("Installed dependency: \"{}\"", pkg.manifest().package.name) } Err(_) => { error!("Could not install dependency: \"{}\"", pkg.identifier); exit(1); diff --git a/pkgr/src/tmpfs.rs b/pkgr/src/tmpfs.rs index a9b756d..f1d0599 100644 --- a/pkgr/src/tmpfs.rs +++ b/pkgr/src/tmpfs.rs @@ -1,4 +1,4 @@ -use std::path::PathBuf; +use std::path::{Path, PathBuf}; use crate::CONFIG; @@ -16,6 +16,10 @@ impl TempDir { TempDir { path } } + pub fn path(&self) -> PathBuf { + self.path.clone() + } + pub fn push>(&mut self, path: S) { self.path.push(path.into()); } diff --git a/pkgr/src/util/mod.rs b/pkgr/src/util/mod.rs new file mode 100644 index 0000000..dc3d868 --- /dev/null +++ b/pkgr/src/util/mod.rs @@ -0,0 +1,19 @@ +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 diff --git a/pkgr/src/util/prompts.rs b/pkgr/src/util/prompts.rs new file mode 100644 index 0000000..6c3e11a --- /dev/null +++ b/pkgr/src/util/prompts.rs @@ -0,0 +1,32 @@ +use std::io::Write; +use log::trace; + +pub fn is_noninteractive() -> bool { + if let Ok(v) = std::env::var("PKGR_NON_INTERACTIVE") { + trace!("PKGR_NON_INTERACTIVE={}", v); + match v.as_str() { + "1" => true, + "true" => true, + _ => false + } + } else { false } +} + +pub fn prompt_bool>(prompt: S, default: bool) -> bool { + if is_noninteractive() { return default; } + print!("{} [{}]: ", prompt.into(), if default { "Y/n" } else { "y/N" }); + match std::io::stdout().flush() { + Ok(_) => (), + _ => println!() + }; + + let mut input = String::new(); + std::io::stdin().read_line(&mut input).expect("Failed to read input."); + let answer = input.trim().to_lowercase(); + + if answer.is_empty() { + default + } else { + answer == "y" || answer == "yes" + } +} \ No newline at end of file