Release 0.4.1 - Compatibility bug and improved error handling.

- Disallow multiple type parameters applied to --create
- Provide the ROOT type in pacwrap-utils replicate function
- Updated help manual.
This commit is contained in:
Xavier Moffett 2023-10-22 07:13:41 -04:00
parent c14f6e0733
commit c0bb7f80d1
10 changed files with 91 additions and 50 deletions

2
Cargo.lock generated
View file

@ -362,7 +362,7 @@ dependencies = [
[[package]]
name = "pacwrap"
version = "0.4.0"
version = "0.4.1"
dependencies = [
"alpm",
"bitflags 2.4.1",

View file

@ -2,7 +2,7 @@
[package]
name = "pacwrap"
version = "0.4.0"
version = "0.4.1"
edition = "2021"
[dependencies]

View file

@ -359,6 +359,7 @@ replicate_instance() {
[[ $type != BASE ]] && depend=$(return_dependency)
case $type in
ROOT) params+="r";;
BASE) params+="b";;
DEP) params+="d";;
LINK) ln -s "$INSTANCE_ROOT_DIR/$depend" "$INSTANCE_ROOT_DIR/$instance"

View file

@ -1,7 +1,7 @@
# Maintainer: Xavier R.M. (sapphirus at azorium dot net)
pkgname=('pacwrap-base-dist')
pkgver=0.4.0
pkgver=0.4.1
pkgrel=1
pkgdesc=""
arch=('any')

View file

@ -10,6 +10,7 @@ use crate::config::{self,
InsVars,
InstanceType,
InstanceHandle};
use crate::utils::print_help_error;
use crate::utils::{arguments::{Arguments, Operand},
handle_process,
env_var};
@ -90,7 +91,7 @@ pub fn compat(mut args: Arguments) {
match args.next().unwrap_or_default() {
Operand::Short('s') | Operand::Long("save") => save_configuration(args.target()),
Operand::Short('l') | Operand::Long("load") => print_configuration(args.target()),
_ => args.invalid_operand()
_ => print_help_error(args.invalid_operand())
}
}

View file

@ -28,7 +28,6 @@ fn main() {
Operand::Short('h') | Operand::Long("help") => manual::help(arguments),
Operand::Short('V') | Operand::Long("version") => manual::print_version(arguments),
Operand::Long("compat") => compat::compat(arguments),
Operand::None => print_help_error("Operation not specified."),
_ => arguments.invalid_operand(),
_ => print_help_error(arguments.invalid_operand()),
}
}

View file

@ -20,13 +20,16 @@ lazy_static! {
pub fn help(mut args: Arguments) {
let help = ascertain_help(&mut args);
for topic in help.0 {
topic.display(help.1);
match help {
Ok(help) => for topic in help.0 {
topic.display(help.1);
}
Err(err) => print_help_error(err),
}
}
fn ascertain_help<'a>(args: &mut Arguments) -> (IndexSet<&'a HelpTopic>, &'a HelpLayout) {
fn ascertain_help<'a>(args: &mut Arguments) -> Result<(IndexSet<&'a HelpTopic>, &'a HelpLayout), String> {
let mut layout = match is_color_terminal() {
true => &HelpLayout::Console, false => &HelpLayout::Dumb,
};
@ -75,8 +78,9 @@ fn ascertain_help<'a>(args: &mut Arguments) -> (IndexSet<&'a HelpTopic>, &'a Hel
| Operand::LongPos("help", "all")
| Operand::Short('a')
| Operand::Long("all") => topic.extend(HELP_ALL.iter()),
Operand::ShortPos('h', topic) | Operand::LongPos("help", topic) => print_help_error(format!("Topic '{topic}' is not available.")),
_ => args.invalid_operand(),
Operand::ShortPos('h', topic)
| Operand::LongPos("help", topic) => Err(format!("Topic '{topic}' is not available."))?,
_ => Err(args.invalid_operand())?,
}
}
@ -84,7 +88,7 @@ fn ascertain_help<'a>(args: &mut Arguments) -> (IndexSet<&'a HelpTopic>, &'a Hel
let start = if more || len == 1 || len > 7 { 0 } else { 1 };
args.set_index(1);
(topic.drain(start..).collect(), layout)
Ok((topic.drain(start..).collect(), layout))
}
fn minimal(args: &mut Arguments) -> bool {
@ -203,7 +207,6 @@ fn default(layout: &HelpLayout) {
println!("# {name} 1 \"{version}-{suffix} ({timestamp})\" {name} \"User Manual\"\n");
}
println!("{head}NAME{reset}
{tab}pacwrap - Command-line application which facilitates the creation, management, and execution of unprivileged,
{tab}Sandboxed containers with bubblewrap and libalpm.
@ -271,6 +274,7 @@ fn meta(layout: &HelpLayout) {
fn sync(layout: &HelpLayout) {
let head = layout.head();
let bold = layout.bold();
let sub = layout.sub();
let sub_text = layout.sub_text();
let reset = layout.reset();
@ -287,6 +291,18 @@ fn sync(layout: &HelpLayout) {
{sub}-f, --filesystem{reset_bold}
{sub_text}Force execution of filesystem synchronization coroutines on all or specified containers.
{sub}-c, --create{reset_bold}
{sub_text}Create a container with the first specified target. Providing a container type argument is also required.
{sub}-b, --base{reset_bold}
{sub_text}Base container type. Specify alongside {bold}-c, --create{reset_bold} to assign container type during creation.
{sub}-d, --slice{reset_bold}
{sub_text}Slice container type. Specify alongside {bold}-c, --create{reset_bold} to to assign container type during creation.
{sub}-r, --root{reset_bold}
{sub_text}Root container type. Specify alongside {bold}-c, --create{reset_bold} to assign container type during creation.
{sub}--dbonly{reset_bold}
{sub_text}Transact on resident containers with a database-only transaction.
@ -294,7 +310,11 @@ fn sync(layout: &HelpLayout) {
{sub_text}Force synchronization of foreign packages on resident container.
{sub}--dbonly{reset_bold}
{sub_text}Override confirmation prompts and confirm all operations.\n");
{sub_text}Override confirmation prompts and confirm all operations.
{sub}-t, --target=TARGET{reset_bold}
{sub_text}Specify a target container for the specified operation.\n");
}
fn process(layout: &HelpLayout) {
@ -346,6 +366,7 @@ fn copyright(layout: &HelpLayout) {
let tab = layout.tab();
println!("{head}COPYRIGHT{reset}
{sub_text}Copyright (C) 2023 - Xavier R.M.
{tab}This program may be freely redistributed under
@ -369,7 +390,7 @@ pub fn print_version(mut args: Arguments) {
ACCCCCCCC#####CCCCC######C######C###CCCCCCCCCP
ACCCCCCCCCCC######CC####CCC####CCCCCCCCCCCCCCP
ACCCCCCCCCCCCCC##CCCCCCCCCCCCCCCCCCCCCCCCCCCCP Website: https://pacwrap.sapphirus.org/
ACCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCP Github: https;//git.sapphirus.org/
ACCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCP Github: https://github.com/sapphirusberyl/pacwrap
ACCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCP
ACCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCP
RPCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCP This program may be freely redistributed under

View file

@ -63,19 +63,24 @@ pub fn synchronize(mut args: Arguments) {
TransactionType::Upgrade(u > 0, y > 0, y > 1)
};
if let Some(instype) = create_type(&mut args) {
if let TransactionType::Upgrade(upgrade, refresh, _) = action {
if ! upgrade {
print_help_error("--upgrade/-u not supplied with --create/-c.");
} else if ! refresh {
print_help_error("--refresh/-y not supplied with --create/-c.");
match create_type(&mut args) {
Ok(option) => if let Some(instype) = option {
if let TransactionType::Upgrade(upgrade, refresh, _) = action {
if ! upgrade {
print_help_error("--upgrade/-u not supplied with --create/-c.");
} else if ! refresh {
print_help_error("--refresh/-y not supplied with --create/-c.");
}
}
}
create(instype, args.targets());
create(instype, args.targets());
},
Err(error) => print_help_error(error),
}
aggregator::upgrade(action, &mut args, &mut cache, &mut logger).aggregate(&mut InstanceCache::new());
match aggregator::upgrade(action, &mut args, &mut cache, &mut logger) {
Ok(ag) => ag.aggregate(&mut InstanceCache::new()), Err(e) => print_help_error(e)
}
}
pub fn remove(mut args: Arguments) {
@ -96,10 +101,12 @@ pub fn remove(mut args: Arguments) {
TransactionType::Remove(recursive > 0 , cascade, recursive > 1)
};
aggregator::remove(action, &mut args, &mut cache, &mut logger).aggregate(&mut InstanceCache::new());
match aggregator::remove(action, &mut args, &mut cache, &mut logger) {
Ok(ag) => ag.aggregate(&mut InstanceCache::new()), Err(e) => print_help_error(e),
}
}
fn create_type(args: &mut Arguments) -> Option<InstanceType> {
fn create_type<'a>(args: &mut Arguments) -> Result<Option<InstanceType>, &'a str> {
let mut instype = None;
let mut create = false;
@ -108,14 +115,28 @@ fn create_type(args: &mut Arguments) -> Option<InstanceType> {
while let Some(arg) = args.next() {
match arg {
Operand::Short('c') | Operand::Long("create") => create = true,
Operand::Short('b') | Operand::Long("base") => instype = Some(InstanceType::BASE),
Operand::Short('d') | Operand::Long("slice") => instype = Some(InstanceType::DEP),
Operand::Short('r') | Operand::Long("root") => instype = Some(InstanceType::ROOT),
Operand::Short('b') | Operand::Long("base") => match instype {
None => instype = Some(InstanceType::BASE),
Some(_) => Err("Multiple container types cannot be assigned to a container.")?,
},
Operand::Short('d') | Operand::Long("slice") => match instype {
None => instype = Some(InstanceType::DEP),
Some(_) => Err("Multiple container types cannot be assigned to a container.")?,
},
Operand::Short('r') | Operand::Long("root") => match instype {
None => instype = Some(InstanceType::ROOT),
Some(_) => Err("Multiple container types cannot be assigned to a container.")?,
},
_ => continue,
}
}
if create { instype } else { None }
match create {
true => match instype {
None => Err("Instance type not specified"), Some(_) => Ok(instype),
},
false => Ok(None)
}
}
pub fn create(instype: InstanceType, mut targets: Vec<&str>) {
@ -199,7 +220,7 @@ pub fn query(mut arguments: Arguments) {
Operand::Short('e') | Operand::Long("explicit") => explicit = true,
Operand::Short('q') | Operand::Long("quiet") => quiet = true,
Operand::LongPos("target", t) | Operand::ShortPos(_, t) => target = t,
_ => arguments.invalid_operand(),
_ => print_help_error(arguments.invalid_operand()),
}
}

View file

@ -11,8 +11,7 @@ use crate::sync::{self,
use crate::config::{InstanceHandle,
InstanceType::ROOT,
cache::InstanceCache};
use crate::utils::{Arguments, print_help_error};
use crate::utils::arguments::Operand;
use crate::utils::{arguments::Operand, Arguments};
use super::{
Transaction,
TransactionHandle,
@ -190,7 +189,7 @@ impl <'a>TransactionAggregator<'a> {
}
}
pub fn remove<'a>(action_type: TransactionType, args: &'a mut Arguments, inscache: &'a mut InstanceCache, log: &'a mut Logger) -> TransactionAggregator<'a> {
pub fn remove<'a>(action_type: TransactionType, args: &'a mut Arguments, inscache: &'a mut InstanceCache, log: &'a mut Logger) -> Result<TransactionAggregator<'a>, String> {
let mut action_flags = TransactionFlags::NONE;
let mut targets = Vec::new();
let mut queue: HashMap<Rc<str>,Vec<Rc<str>>> = HashMap::new();
@ -199,7 +198,7 @@ pub fn remove<'a>(action_type: TransactionType, args: &'a mut Arguments, inscach
args.set_index(1);
if let Operand::None = args.next().unwrap_or_default() {
print_help_error("Operation not specified.");
Err("Operation not specified.")?
}
while let Some(arg) = args.next() {
@ -228,12 +227,12 @@ pub fn remove<'a>(action_type: TransactionType, args: &'a mut Arguments, inscach
None => { queue.insert(current_target.into(), vec!(package.into())); },
}
},
_ => args.invalid_operand(),
_ => Err(args.invalid_operand())?,
}
}
if current_target == "" {
print_help_error("Target not specified");
Err("Target not specified")?
}
let current_target = Some(current_target);
@ -244,7 +243,7 @@ pub fn remove<'a>(action_type: TransactionType, args: &'a mut Arguments, inscach
inscache.populate();
}
TransactionAggregator {
Ok(TransactionAggregator {
queried: Vec::new(),
updated: Vec::new(),
pkg_queue: queue,
@ -255,10 +254,10 @@ pub fn remove<'a>(action_type: TransactionType, args: &'a mut Arguments, inscach
logger: log,
flags: action_flags,
target: current_target,
}
})
}
pub fn upgrade<'a>(action_type: TransactionType, args: &'a mut Arguments, inscache: &'a mut InstanceCache, log: &'a mut Logger) -> TransactionAggregator<'a> {
pub fn upgrade<'a>(action_type: TransactionType, args: &'a mut Arguments, inscache: &'a mut InstanceCache, log: &'a mut Logger) -> Result<TransactionAggregator<'a>, String> {
let mut action_flags = TransactionFlags::NONE;
let mut targets = Vec::new();
let mut queue: HashMap<Rc<str>,Vec<Rc<str>>> = HashMap::new();
@ -269,7 +268,7 @@ pub fn upgrade<'a>(action_type: TransactionType, args: &'a mut Arguments, inscac
args.set_index(2);
if let Operand::None = args.next().unwrap_or_default() {
print_help_error("Operation not specified.");
Err("Operation not specified.")?
}
while let Some(arg) = args.next() {
@ -307,15 +306,14 @@ pub fn upgrade<'a>(action_type: TransactionType, args: &'a mut Arguments, inscac
},
}
},
Operand::None => println!("none"),
_ => args.invalid_operand(),
_ => Err(args.invalid_operand())?,
}
}
let current_target = match target_only {
true => {
if current_target == "" {
print_help_error("Target not specified");
Err("Target not specified")?
}
Some(current_target)
@ -329,7 +327,7 @@ pub fn upgrade<'a>(action_type: TransactionType, args: &'a mut Arguments, inscac
inscache.populate();
}
TransactionAggregator {
Ok(TransactionAggregator {
queried: Vec::new(),
updated: Vec::new(),
pkg_queue: queue,
@ -340,5 +338,5 @@ pub fn upgrade<'a>(action_type: TransactionType, args: &'a mut Arguments, inscac
logger: log,
flags: action_flags,
target: current_target,
}
})
}

View file

@ -105,10 +105,10 @@ impl<'a> Arguments<'a> {
self.cur = index;
}
pub fn invalid_operand(&self) {
pub fn invalid_operand(&self) -> String {
match self.operands.get(self.cur) {
Some(oper) => print_help_error(&format!("Invalid option -- '{}'", oper)),
None => print_help_error(&format!("Operation not specified.")),
Some(oper) => format!("Invalid option -- '{}'", oper),
None => format!("Operation not specified."),
}
}