Bug fixes for database resolution during composition

- Container::stamp function to set new timestamp with compose_handle.
- Restructured and refactored trans_ready function.
- Fixed bug with progress ticker during an aggregate transaction when
  one or more lines are printed to std[out|err].
- Do not print containers as up-to-date upon completion of container
  composition nor creation in aggregate, nor if a container was
  composed.
- TransactionState::Skip state declared and implemented.
- Check for UpdateSchema(..) instead of Prepare for marking a container
  as updated.
This commit is contained in:
Xavier Moffett 2024-04-21 15:07:13 -04:00
parent 5c3b9bdd5d
commit 03d942ad22
Signed by: Sapphirus
GPG key ID: A6C061B2CEA1A7AC
8 changed files with 60 additions and 47 deletions

View file

@ -105,7 +105,7 @@ pub fn compose_handle<'a>(instance: &'a str, path: Option<&'a str>) -> Result<Co
err!(ConfigError::AlreadyExists(instance.into()))? err!(ConfigError::AlreadyExists(instance.into()))?
} }
Ok(handle(vars)?.create()) Ok(handle(vars)?.stamp().create())
} }
pub fn provide_new_handle<'a>(instance: &'a str, instype: ContainerType, deps: Vec<&'a str>) -> Result<ContainerHandle<'a>> { pub fn provide_new_handle<'a>(instance: &'a str, instype: ContainerType, deps: Vec<&'a str>) -> Result<ContainerHandle<'a>> {

View file

@ -108,6 +108,11 @@ impl<'a> ContainerHandle<'a> {
self self
} }
pub fn stamp(mut self) -> Self {
self.inner.metadata.meta_version = *UNIX_TIMESTAMP;
self
}
pub fn config(&self) -> &ContainerRuntime { pub fn config(&self) -> &ContainerRuntime {
&self.inner.runtime &self.inner.runtime
} }

View file

@ -70,7 +70,7 @@ pub enum SyncError {
InvalidMagicNumber, InvalidMagicNumber,
SignalInterrupt, SignalInterrupt,
AgentVersionMismatch, AgentVersionMismatch,
NothingToDo(bool), NothingToDo,
DependentContainerMissing(String), DependentContainerMissing(String),
RecursionDepthExceeded(isize), RecursionDepthExceeded(isize),
TargetUpstream(String), TargetUpstream(String),
@ -108,7 +108,7 @@ impl Display for SyncError {
Self::SignalInterrupt => write!(fmter, "Signal interrupt was triggered."), Self::SignalInterrupt => write!(fmter, "Signal interrupt was triggered."),
Self::UnableToLocateKeyrings => write!(fmter, "Unable to locate pacman keyrings."), Self::UnableToLocateKeyrings => write!(fmter, "Unable to locate pacman keyrings."),
Self::RepoConfError(path, err) => write!(fmter, "'{}': {}", path, err), Self::RepoConfError(path, err) => write!(fmter, "'{}': {}", path, err),
Self::NothingToDo(_) => write!(fmter, "Nothing to do."), Self::NothingToDo => write!(fmter, "Nothing to do."),
_ => Ok(()), _ => Ok(()),
}?; }?;

View file

@ -54,15 +54,16 @@ pub type Result<T> = crate::Result<T>;
pub static MAGIC_NUMBER: u32 = 663445956; pub static MAGIC_NUMBER: u32 = 663445956;
pub enum TransactionState { pub enum TransactionState {
Complete(bool),
Prepare, Prepare,
UpdateSchema(Option<SchemaState>),
UpToDate, UpToDate,
PrepareForeign(bool), PrepareForeign(bool),
Stage, Stage,
StageForeign, StageForeign,
UpdateSchema(Option<SchemaState>),
Commit(bool), Commit(bool),
CommitForeign, CommitForeign,
Skip,
Complete(bool),
} }
#[derive(Serialize, Deserialize, Copy, Clone)] #[derive(Serialize, Deserialize, Copy, Clone)]
@ -71,12 +72,13 @@ pub enum TransactionType {
Remove(bool, bool, bool), Remove(bool, bool, bool),
} }
#[derive(Serialize, Deserialize, Copy, Clone, Debug, PartialEq, Eq)] #[derive(Serialize, Deserialize, Copy, Clone)]
pub enum TransactionMode { pub enum TransactionMode {
Foreign, Foreign,
Local, Local,
} }
#[derive(Copy, Clone)]
pub enum SyncState { pub enum SyncState {
Required, Required,
NotRequired, NotRequired,
@ -97,19 +99,19 @@ pub trait Transaction {
bitflags! { bitflags! {
pub struct TransactionFlags: u8 { pub struct TransactionFlags: u8 {
const NONE = 0; const NONE = 0;
const TARGET_ONLY = 0b0000001; const TARGET_ONLY = 0b0000001;
const PREVIEW = 0b0000010; const PREVIEW = 0b0000010;
const NO_CONFIRM = 0b0000100; const NO_CONFIRM = 0b0000100;
const FORCE_DATABASE = 0b0001000; const FORCE_DATABASE = 0b0001000;
const DATABASE_ONLY = 0b0010000; const DATABASE_ONLY = 0b0010000;
const CREATE = 0b0100000; const CREATE = 0b0100000;
const FILESYSTEM_SYNC = 0b1000000; const FILESYSTEM_SYNC = 0b1000000;
} }
} }
pub struct TransactionHandle<'a> { pub struct TransactionHandle<'a> {
meta: &'a mut TransactionMetadata<'a>, meta: &'a mut TransactionMetadata<'a>,
fail: bool, state: SyncState,
agent: bool, agent: bool,
config: Option<&'a Global>, config: Option<&'a Global>,
alpm: Option<Alpm>, alpm: Option<Alpm>,
@ -159,7 +161,7 @@ impl TransactionState {
Self::StageForeign => Stage::new(self, ag), Self::StageForeign => Stage::new(self, ag),
Self::Commit(_) => Commit::new(self, ag), Self::Commit(_) => Commit::new(self, ag),
Self::CommitForeign => Commit::new(self, ag), Self::CommitForeign => Commit::new(self, ag),
Self::Complete(_) => unreachable!(), _ => unreachable!(),
} }
} }
@ -248,7 +250,7 @@ impl<'a> TransactionHandle<'a> {
pub fn new(metadata: &'a mut TransactionMetadata<'a>) -> Self { pub fn new(metadata: &'a mut TransactionMetadata<'a>) -> Self {
Self { Self {
meta: metadata, meta: metadata,
fail: true, state: Required,
agent: false, agent: false,
alpm: None, alpm: None,
deps: None, deps: None,
@ -316,11 +318,9 @@ impl<'a> TransactionHandle<'a> {
self.meta self.meta
.queue .queue
.extend(self.meta.foreign_pkgs.iter().map(|p| p.to_owned().into()).collect::<Vec<_>>()); .extend(self.meta.foreign_pkgs.iter().map(|p| p.to_owned().into()).collect::<Vec<_>>());
self.fail = false;
} }
pub fn ignore(&mut self) { pub fn ignore(&mut self) {
let mut fail = self.fail;
let alpm = self.alpm.as_mut().unwrap(); let alpm = self.alpm.as_mut().unwrap();
let config = match self.config { let config = match self.config {
Some(config) => config, Some(config) => config,
@ -355,7 +355,7 @@ impl<'a> TransactionHandle<'a> {
{ {
let new = match package.sync_new_version(alpm.syncdbs()) { let new = match package.sync_new_version(alpm.syncdbs()) {
Some(new) => { Some(new) => {
fail = false; self.state = NotRequired;
match self.agent { match self.agent {
true => break, true => break,
@ -373,8 +373,6 @@ impl<'a> TransactionHandle<'a> {
*BOLD, *RESET, *BOLD_YELLOW, *RESET, *BOLD_GREEN, *RESET *BOLD, *RESET, *BOLD_YELLOW, *RESET, *BOLD_GREEN, *RESET
)); ));
} }
self.fail = fail;
} }
pub fn prepare(&mut self, trans_type: &TransactionType, flags: &TransactionFlags) -> Result<()> { pub fn prepare(&mut self, trans_type: &TransactionType, flags: &TransactionFlags) -> Result<()> {
@ -496,15 +494,19 @@ impl<'a> TransactionHandle<'a> {
Ok(()) Ok(())
} }
pub fn trans_ready(&mut self, trans_type: &TransactionType) -> Result<()> { pub fn trans_ready(&mut self, trans_type: &TransactionType, trans_flags: &TransactionFlags) -> Result<SyncState> {
if match trans_type { if match trans_type {
Upgrade(..) => self.alpm().trans_add().len(), Upgrade(..) => !self.alpm().trans_add().is_empty(),
Remove(..) => self.alpm().trans_remove().len(), Remove(..) => !self.alpm().trans_remove().is_empty(),
} > 0 } {
{ Ok(Required)
Ok(()) } else if trans_flags.intersects(TransactionFlags::CREATE) {
Ok(NotRequired)
} else { } else {
err!(SyncError::NothingToDo(self.fail)) match self.state {
Required => err!(SyncError::NothingToDo),
NotRequired => Ok(NotRequired),
}
} }
} }

View file

@ -71,6 +71,7 @@ pub struct TransactionAggregator<'a> {
action: TransactionType, action: TransactionType,
cache: &'a ContainerCache<'a>, cache: &'a ContainerCache<'a>,
keyring: bool, keyring: bool,
tracted: bool,
logger: &'a mut Logger, logger: &'a mut Logger,
flags: TransactionFlags, flags: TransactionFlags,
targets: Option<Vec<&'a str>>, targets: Option<Vec<&'a str>>,
@ -89,6 +90,7 @@ impl<'a> TransactionAggregator<'a> {
action: action_type, action: action_type,
cache: inscache, cache: inscache,
keyring: false, keyring: false,
tracted: false,
logger: log, logger: log,
flags: TransactionFlags::NONE, flags: TransactionFlags::NONE,
lock: None, lock: None,
@ -249,7 +251,10 @@ impl<'a> TransactionAggregator<'a> {
Ok(result) => { Ok(result) => {
self.signal(&mut handle.alpm)?; self.signal(&mut handle.alpm)?;
if let Complete(updated) = result { if let Skip = result {
handle.release();
return Ok(());
} else if let Complete(updated) = result {
if updated { if updated {
self.updated.insert(inshandle.vars().instance()); self.updated.insert(inshandle.vars().instance());
@ -258,23 +263,24 @@ impl<'a> TransactionAggregator<'a> {
} }
} }
self.tracted = !updated;
handle.release(); handle.release();
return Ok(()); return Ok(());
} else if let Prepare = result { } else if let UpdateSchema(_) = result {
self.updated.insert(inshandle.vars().instance()); self.updated.insert(inshandle.vars().instance());
} }
result result
} }
Err(err) => { Err(err) => {
if let Some(progress) = &self.progress { if let Some(progress) = self.progress.as_ref() {
progress.finish_and_clear(); progress.set_draw_target(ProgressDrawTarget::hidden());
progress.finish();
} }
handle.release(); handle.release();
return match err.downcast::<SyncError>().map_err(|err| error!(SyncError::from(err)))? { return match err.downcast::<SyncError>().map_err(|err| error!(SyncError::from(err)))? {
SyncError::TransactionFailureAgent => exit(err.kind().code()), SyncError::TransactionFailureAgent => exit(err.kind().code()),
SyncError::NothingToDo(bool) => bool.then(|| Err(err)).unwrap_or_else(|| Ok(())),
_ => Err(err), _ => Err(err),
}; };
} }
@ -286,7 +292,8 @@ impl<'a> TransactionAggregator<'a> {
fn print_complete(&mut self, filesystem_sync: bool, target_amount: u64, target: Option<&&str>) { fn print_complete(&mut self, filesystem_sync: bool, target_amount: u64, target: Option<&&str>) {
if let Some(_) = &self.progress { if let Some(_) = &self.progress {
let are_multiple = target_amount > 1; let are_multiple = target_amount > 1;
let container = if filesystem_sync && self.queried.is_empty() { let flagged = self.flags.intersects(TransactionFlags::PREVIEW | TransactionFlags::CREATE);
let container = if filesystem_sync && self.queried.is_empty() || flagged || self.tracted {
None None
} else if are_multiple { } else if are_multiple {
Some("Containers") Some("Containers")

View file

@ -46,6 +46,8 @@ use crate::{
Result, Result,
}; };
use super::SyncState;
pub struct Commit { pub struct Commit {
state: TransactionState, state: TransactionState,
keyring: bool, keyring: bool,
@ -68,13 +70,12 @@ impl Transaction for Commit {
inshandle: &ContainerHandle, inshandle: &ContainerHandle,
) -> Result<TransactionState> { ) -> Result<TransactionState> {
let instance = inshandle.vars().instance(); let instance = inshandle.vars().instance();
let ready = handle.trans_ready(&ag.action());
let state = self.state.as_str(); let state = self.state.as_str();
if let Err(_) = ready { if let SyncState::NotRequired = handle.trans_ready(&ag.action(), ag.flags())? {
match ready_state(handle, ag.action(), &self.state) { match ready_state(handle, ag.action(), &self.state) {
Some(result) => return result, Some(result) => return result,
None => ready?, None => return Ok(TransactionState::Complete(false)),
} }
} }
@ -102,9 +103,7 @@ impl Transaction for Commit {
handle.set_alpm(Some(sync::instantiate_alpm(inshandle))); handle.set_alpm(Some(sync::instantiate_alpm(inshandle)));
handle.apply_configuration(inshandle, ag.flags().intersects(TransactionFlags::CREATE))?; handle.apply_configuration(inshandle, ag.flags().intersects(TransactionFlags::CREATE))?;
ag.logger() ag.logger().log(Info, &format!("container {instance}'s {state} transaction complete"))?;
.log(Info, &format!("container {instance}'s {state} transaction complete"))
.ok();
next_state(handle, ag.action(), &self.state, true) next_state(handle, ag.action(), &self.state, true)
} }
} }
@ -116,11 +115,11 @@ fn confirm(
) -> StdResult<(u64, u64), Result<TransactionState>> { ) -> StdResult<(u64, u64), Result<TransactionState>> {
let database = ag.flags().intersects(TransactionFlags::DATABASE_ONLY | TransactionFlags::FORCE_DATABASE); let database = ag.flags().intersects(TransactionFlags::DATABASE_ONLY | TransactionFlags::FORCE_DATABASE);
let foreign = !handle.get_mode().bool(); let foreign = !handle.get_mode().bool();
let create_foreign = match handle.get_mode() { let create = match handle.get_mode() {
TransactionMode::Foreign => ag.flags().contains(TransactionFlags::CREATE), TransactionMode::Foreign => ag.flags().intersects(TransactionFlags::CREATE),
TransactionMode::Local => false, TransactionMode::Local => false,
}; };
let confirm = foreign || database && !create_foreign; let confirm = foreign || database && !create;
let sum = Summary::new() let sum = Summary::new()
.kind(CONFIG.config().summary(), confirm) .kind(CONFIG.config().summary(), confirm)
.mode(handle.get_mode()) .mode(handle.get_mode())

View file

@ -85,10 +85,10 @@ impl Transaction for Prepare {
if let Upgrade(upgrade, ..) = action { if let Upgrade(upgrade, ..) = action {
if !upgrade && handle.meta.queue.is_empty() { if !upgrade && handle.meta.queue.is_empty() {
err!(SyncError::NothingToDo(true))? err!(SyncError::NothingToDo)?
} }
} else if handle.meta.queue.is_empty() { } else if handle.meta.queue.is_empty() {
err!(SyncError::NothingToDo(true))? err!(SyncError::NothingToDo)?
} }
if handle.meta.queue.is_empty() { if handle.meta.queue.is_empty() {

View file

@ -25,7 +25,7 @@ use crate::{
Transaction, Transaction,
TransactionAggregator, TransactionAggregator,
TransactionHandle, TransactionHandle,
TransactionState::{self, Complete}, TransactionState::{self, Skip},
}, },
Result, Result,
}; };
@ -52,6 +52,6 @@ impl Transaction for UpToDate {
None => println!("{} {} is up-to-date!", *ARROW_GREEN, handle.vars().instance()), None => println!("{} {} is up-to-date!", *ARROW_GREEN, handle.vars().instance()),
} }
Ok(Complete(false)) Ok(Skip)
} }
} }