pub mod archive;
pub mod container;
pub mod plugin;
use anyhow::anyhow;
use anyhow::Result;
use clap::{crate_version, ArgAction, Parser, Subcommand};
use env_logger::Builder;
use log::LevelFilter;
use nuts_container::{Container, OpenOptions, OpenOptionsBuilder};
use nuts_tool_api::tool::Plugin;
use rpassword::prompt_password;
use crate::backend::{PluginBackend, PluginBackendOpenBuilder};
use crate::cli::archive::ArchiveArgs;
use crate::cli::container::ContainerArgs;
use crate::cli::plugin::PluginArgs;
use crate::config::{ContainerConfig, PluginConfig};
#[derive(Debug, Parser)]
#[clap(name = "nuts", bin_name = "nuts")]
#[clap(version = crate_version!())]
pub struct NutsCli {
#[clap(subcommand)]
command: Commands,
#[clap(short, long, action = ArgAction::Count, global = true)]
verbose: u8,
#[clap(short, long, action = ArgAction::SetTrue, global = true)]
pub quiet: bool,
}
impl NutsCli {
pub fn configure_logging(&self) {
let filter = match self.verbose {
0 => LevelFilter::Off,
1 => LevelFilter::Info,
2 => LevelFilter::Debug,
_ => LevelFilter::Trace,
};
Builder::new().filter_level(filter).init();
}
pub fn run(&self) -> Result<()> {
self.command.run()
}
}
#[derive(Debug, Subcommand)]
pub enum Commands {
Plugin(PluginArgs),
Container(ContainerArgs),
Archive(ArchiveArgs),
}
impl Commands {
pub fn run(&self) -> Result<()> {
match self {
Self::Plugin(args) => args.run(),
Self::Container(args) => args.run(),
Self::Archive(args) => args.run(),
}
}
}
fn open_builder(name: &str, verbose: u8) -> Result<(PluginBackendOpenBuilder, OpenOptions)> {
let container_config = ContainerConfig::load()?;
let plugin_config = PluginConfig::load()?;
let plugin = container_config
.get_plugin(name)
.ok_or_else(|| anyhow!("no such container: {}", name))?;
let exe = plugin_config.path(plugin)?;
let plugin = Plugin::new(&exe);
let plugin_builder = PluginBackendOpenBuilder::new(plugin, name, verbose)?;
let builder = OpenOptionsBuilder::new().with_password_callback(ask_for_password);
let options = builder.build::<PluginBackend>()?;
Ok((plugin_builder, options))
}
fn open_container(name: &str, verbose: u8) -> Result<Container<PluginBackend>> {
let (plugin_builder, options) = open_builder(name, verbose)?;
Container::open(plugin_builder, options).map_err(|err| err.into())
}
pub fn ask_for_password() -> Result<Vec<u8>, String> {
let password = prompt_password("Enter a password: ").map_err(|err| err.to_string())?;
Ok(password.as_bytes().to_vec())
}