feat: prompts, dir structure, etc.
This commit is contained in:
parent
f8f95546fd
commit
3e6b0e2070
7 changed files with 94 additions and 20 deletions
|
@ -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))),
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
|
@ -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")
|
||||||
|
|
|
@ -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(),
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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
19
pkgr/src/util/mod.rs
Normal 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
32
pkgr/src/util/prompts.rs
Normal 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"
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue