feat: prompts, dir structure, etc.

This commit is contained in:
Strix 2023-10-14 22:39:48 +02:00
parent fc3ae1e71a
commit 89e62ad9c7
No known key found for this signature in database
GPG key ID: 49B2E37B8915B774
7 changed files with 94 additions and 20 deletions

View file

@ -44,14 +44,12 @@ pub fn setup_logger() -> Result<(), SetLoggerError> {
Dispatch::new() Dispatch::new()
.format(|out, message, record| { .format(|out, message, record| {
match record.metadata().target() { match record.metadata().target() {
"command:stdout" => { // command output logging
out.finish(format_args!("{} {}", ">>".cyan(), message.to_string())); "command:stdout" => out.finish(format_args!("{} {}", ">>".cyan(), message.to_string())),
return; "command:stderr" => out.finish(format_args!("{} {}", ">>".red(), message.to_string())),
} // this target means, it's an item and not a log.
"command:stderr" => { "item" => out.finish(format_args!("{} {}", "*".blue(), message.to_string())),
out.finish(format_args!("{} {}", ">>".red(), message.to_string())); // default logging
return;
}
_ => out.finish(format_args!("{}", format_regular(message.to_string(), record))), _ => out.finish(format_args!("{}", format_regular(message.to_string(), record))),
} }
}) })

View file

@ -17,6 +17,8 @@ mod tmpfs;
mod config; mod config;
/// custom types used by pkgr /// custom types used by pkgr
mod types; mod types;
/// utils
mod util;
thread_local! { thread_local! {
static CONFIG: config::Config = config::Config::from_path("/etc/pkgr.toml") static CONFIG: config::Config = config::Config::from_path("/etc/pkgr.toml")

View file

@ -37,8 +37,8 @@ pub enum InstallError {
impl ToString for InstallError { impl ToString for InstallError {
fn to_string(&self) -> String { fn to_string(&self) -> String {
match self { match self {
InstallError::BuildError(e) => format!("Build error: \n{}", e), InstallError::BuildError(e) => format!("{}", e),
InstallError::BinError(e) => format!("Bin error: \n{}", e), InstallError::BinError(e) => format!("{}", e),
InstallError::InvalidManifest => "Invalid manifest".to_string(), InstallError::InvalidManifest => "Invalid manifest".to_string(),
InstallError::Generic => "Install error".to_string(), InstallError::Generic => "Install error".to_string(),
} }

View file

@ -1,3 +1,4 @@
use std::fs::{remove_dir, remove_dir_all};
use std::process::exit; use std::process::exit;
use log::{debug, error, info, trace}; use log::{debug, error, info, trace};
@ -11,6 +12,8 @@ use crate::package::identifier::{PackageIdentifier, PackageLocator};
use crate::package::Package; use crate::package::Package;
use crate::tmpfs::TempDir; use crate::tmpfs::TempDir;
use crate::types::fetch::TryFetch; use crate::types::fetch::TryFetch;
use crate::util::{visit_dirs};
use crate::util::prompts::prompt_bool;
pub mod errors; pub mod errors;
@ -40,11 +43,14 @@ impl PackageInstaller {
if !self.pkgfile.has_data() { if !self.pkgfile.has_data() {
return Err(BinError::UnpackError("package has no data".to_string())); return Err(BinError::UnpackError("package has no data".to_string()));
} }
if std::path::Path::new(&path).exists() { let path = std::path::Path::new(&path);
return Err(BinError::UnpackError(format!( if path.exists() {
"path already exists: {}", trace!("cache already exists..");
path 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()) tar::Archive::new(self.pkgfile.data.as_slice())
.unpack(&path) .unpack(&path)
@ -55,14 +61,27 @@ impl PackageInstaller {
let mut tmpdir = TempDir::default(); let mut tmpdir = TempDir::default();
tmpdir.push(&self.manifest.package.name); tmpdir.push(&self.manifest.package.name);
trace!("extracting package into: {}", tmpdir.to_string()); trace!("extracting package into: {}", tmpdir.to_string());
match self.extract_to(tmpdir.to_string()) { if let Err(e) = self.extract_to(tmpdir.to_string()) {
Ok(_) => {} return Err(e)
Err(e) => return Err(e),
} }
debug!("extracted package in: {}", tmpdir.to_string()); 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(()) Ok(())
} }
fn apply_overlay(&self) {
}
fn build(&self) -> Result<(), BuildError> { fn build(&self) -> Result<(), BuildError> {
if let None = self.manifest.build.clone() { if let None = self.manifest.build.clone() {
return Err(BuildError::InvalidManifest); return Err(BuildError::InvalidManifest);
@ -80,7 +99,7 @@ impl PackageInstaller {
match pkg.install(CONFIG.with(|c| { match pkg.install(CONFIG.with(|c| {
c.build_by_default c.build_by_default
})) { })) {
Ok(_) => { info!("Installed dependency: \"{}\"", pkg.manifest().package.name) }, Ok(_) => { info!("Installed dependency: \"{}\"", pkg.manifest().package.name) }
Err(_) => { Err(_) => {
error!("Could not install dependency: \"{}\"", pkg.identifier); error!("Could not install dependency: \"{}\"", pkg.identifier);
exit(1); exit(1);

View file

@ -1,4 +1,4 @@
use std::path::PathBuf; use std::path::{Path, PathBuf};
use crate::CONFIG; use crate::CONFIG;
@ -16,6 +16,10 @@ impl TempDir {
TempDir { path } TempDir { path }
} }
pub fn path(&self) -> PathBuf {
self.path.clone()
}
pub fn push<S: Into<String>>(&mut self, path: S) { pub fn push<S: Into<String>>(&mut self, path: S) {
self.path.push(path.into()); self.path.push(path.into());
} }

19
pkgr/src/util/mod.rs Normal file
View file

@ -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(())
}

32
pkgr/src/util/prompts.rs Normal file
View file

@ -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<S: Into<String>>(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"
}
}