Refactoring and transformation of update routine into a state machine
alongside dependency resolution. - In Addition target parameterisation to the arguments parser with --target/-t - Bug fixes to the progress event.
This commit is contained in:
parent
8943e77fed
commit
81482c20f0
4 changed files with 532 additions and 162 deletions
50
src/sync.rs
50
src/sync.rs
|
@ -9,8 +9,9 @@ use crate::constants::{self, LOCATION};
|
||||||
use crate::sync::dl_event::DownloadCallback;
|
use crate::sync::dl_event::DownloadCallback;
|
||||||
use crate::sync::linker::Linker;
|
use crate::sync::linker::Linker;
|
||||||
use crate::sync::progress_event::ProgressCallback;
|
use crate::sync::progress_event::ProgressCallback;
|
||||||
use crate::sync::update::Update;
|
use crate::sync::update::TransactionAggregator;
|
||||||
use crate::utils::{Arguments, test_root, print_help_msg};
|
use crate::sync::update::TransactionType;
|
||||||
|
use crate::utils::{Arguments, arguments::invalid, test_root, print_help_msg};
|
||||||
use crate::config::InsVars;
|
use crate::config::InsVars;
|
||||||
use crate::config::cache::InstanceCache;
|
use crate::config::cache::InstanceCache;
|
||||||
use crate::config::InstanceHandle;
|
use crate::config::InstanceHandle;
|
||||||
|
@ -27,17 +28,21 @@ mod linker;
|
||||||
mod update;
|
mod update;
|
||||||
|
|
||||||
pub fn execute() {
|
pub fn execute() {
|
||||||
let mut sync = false;
|
let mut search = false;
|
||||||
let mut update = false;
|
let mut refresh = false;
|
||||||
let mut explicit = false;
|
let mut upgrade = false;
|
||||||
let mut sync_count = 0;
|
let mut preview = false;
|
||||||
let mut args = Arguments::new().prefix("-S")
|
let mut y_count = 0;
|
||||||
.switch("-y", "--sync", &mut sync).count(&mut sync_count)
|
|
||||||
.switch("-u", "--upgrade", &mut update)
|
let mut args = Arguments::new().prefix("-S").ignore("--sync")
|
||||||
.switch("-e", "--explicit", &mut explicit);
|
.switch("-y", "--refresh", &mut refresh).count(&mut y_count)
|
||||||
|
.switch("-u", "--upgrade", &mut upgrade)
|
||||||
|
.switch("-s", "--search", &mut search)
|
||||||
|
.switch("-p", "--preview", &mut preview);
|
||||||
|
|
||||||
args = args.parse_arguments();
|
args = args.parse_arguments();
|
||||||
let targets = args.get_runtime().clone();
|
let mut targets = args.targets().clone();
|
||||||
|
let runtime = args.get_runtime().clone();
|
||||||
let mut cache: InstanceCache = InstanceCache::new();
|
let mut cache: InstanceCache = InstanceCache::new();
|
||||||
|
|
||||||
if targets.len() > 0 {
|
if targets.len() > 0 {
|
||||||
|
@ -46,14 +51,31 @@ pub fn execute() {
|
||||||
cache.populate();
|
cache.populate();
|
||||||
}
|
}
|
||||||
|
|
||||||
if sync && sync_count == 4 {
|
if refresh && y_count == 4 {
|
||||||
let mut l: Linker = Linker::new();
|
let mut l: Linker = Linker::new();
|
||||||
l.start(cache.registered().len());
|
l.start(cache.registered().len());
|
||||||
linker::wait_on(l.link(&cache, cache.registered(), Vec::new()));
|
linker::wait_on(l.link(&cache, cache.registered(), Vec::new()));
|
||||||
l.finish();
|
l.finish();
|
||||||
|
} else if search {
|
||||||
|
print_help_msg("Functionality is currently unimplemented.");
|
||||||
|
} else if refresh || preview || upgrade {
|
||||||
|
if refresh {
|
||||||
|
synchronize_database(&cache, y_count == 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
if preview && upgrade || upgrade {
|
||||||
|
let mut update: TransactionAggregator = TransactionAggregator::new(TransactionType::UpgradeSync, &cache, preview, y_count > 2);
|
||||||
|
|
||||||
|
if targets.len() > 0 {
|
||||||
|
update.queue(targets.remove(0), runtime);
|
||||||
|
}
|
||||||
|
|
||||||
|
update::update(update, &cache);
|
||||||
|
} else if ! refresh {
|
||||||
|
invalid();
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
if sync { synchronize_database(&cache, sync_count > 1); }
|
invalid();
|
||||||
if update { update::update(Update::new(), &cache); }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -44,13 +44,13 @@ pub fn progress_event(progress: Progress, pkgname: &str, percent: i32, howmany:
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
None => {
|
None => {
|
||||||
let whitespace = whitespace(howmany.to_string().len(), current.to_string().len());
|
let pos = current + 1;
|
||||||
let pos = style(current + 1).bold().white();
|
let total = howmany + 1;
|
||||||
let total = style(howmany + 1).bold().white();
|
|
||||||
let progress_name: String = progress_name(progress,pkgname);
|
let progress_name: String = progress_name(progress,pkgname);
|
||||||
let pb = this.progress.add(ProgressBar::new(progress_u64(percent)));
|
let pb = this.progress.add(ProgressBar::new(100));
|
||||||
|
let whitespace = whitespace(total.to_string().len(), pos.to_string().len());
|
||||||
pb.set_style(this.style.clone());
|
pb.set_style(this.style.clone());
|
||||||
pb.set_message(format!("({}{}/{}) {}", whitespace, pos, total, progress_name));
|
pb.set_message(format!("({}{}/{}) {}", whitespace, style(pos).bold().white(), style(total).bold().white(), progress_name));
|
||||||
this.prbar.insert(progress_ident, pb);
|
this.prbar.insert(progress_ident, pb);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -83,5 +83,5 @@ fn progress_ident(progress: Progress, pkgname: &str) -> String {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn progress_u64(u: i32) -> u64 {
|
fn progress_u64(u: i32) -> u64 {
|
||||||
match u.try_into() { Ok(i) => i, Err(_) => 0 }
|
match u.try_into() { Ok(i) => i, Err(_) => { 0 }}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,12 @@
|
||||||
use console::style;
|
use std::collections::HashMap;
|
||||||
|
use std::process::exit;
|
||||||
|
|
||||||
|
use console::{style, Term};
|
||||||
use alpm::{Alpm,
|
use alpm::{Alpm,
|
||||||
TransFlag,
|
TransFlag,
|
||||||
PrepareResult,
|
PrepareResult,
|
||||||
CommitResult,
|
CommitResult,
|
||||||
FileConflictType};
|
FileConflictType, Package};
|
||||||
|
|
||||||
use crate::{sync, utils::print_error};
|
use crate::{sync, utils::print_error};
|
||||||
use crate::sync::{dl_event, linker};
|
use crate::sync::{dl_event, linker};
|
||||||
|
@ -15,18 +18,35 @@ use crate::utils::prompt::prompt;
|
||||||
use crate::config::cache::InstanceCache;
|
use crate::config::cache::InstanceCache;
|
||||||
use crate::config::InstanceHandle;
|
use crate::config::InstanceHandle;
|
||||||
|
|
||||||
pub struct Update {
|
|
||||||
queried: Vec<String>,
|
pub enum TransactionType {
|
||||||
updated: Vec<String>,
|
Upgrade,
|
||||||
linker: Linker
|
UpgradeSync,
|
||||||
|
Remove,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Update {
|
pub struct TransactionAggregator<'a> {
|
||||||
pub fn new() -> Self {
|
queried: Vec<String>,
|
||||||
|
updated: Vec<String>,
|
||||||
|
pkg_queue: HashMap<String, Vec<String>>,
|
||||||
|
action: TransactionType,
|
||||||
|
linker: Linker,
|
||||||
|
syncdb: bool,
|
||||||
|
preview: bool,
|
||||||
|
cache: &'a InstanceCache
|
||||||
|
}
|
||||||
|
|
||||||
|
impl <'a>TransactionAggregator<'a> {
|
||||||
|
pub fn new(t: TransactionType, icache: &'a InstanceCache, pre: bool, dbsync: bool) -> Self {
|
||||||
Self {
|
Self {
|
||||||
queried: Vec::new(),
|
queried: Vec::new(),
|
||||||
updated: Vec::new(),
|
updated: Vec::new(),
|
||||||
linker: Linker::new()
|
pkg_queue: HashMap::new(),
|
||||||
|
linker: Linker::new(),
|
||||||
|
action: t,
|
||||||
|
preview: pre,
|
||||||
|
syncdb: dbsync,
|
||||||
|
cache: icache,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -38,99 +58,385 @@ impl Update {
|
||||||
&self.updated
|
&self.updated
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn update(&mut self, cache: &InstanceCache, containers: &Vec<String>) {
|
pub fn queue(&mut self, ins: String, install: Vec<String>) {
|
||||||
|
self.pkg_queue.insert(ins, install);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn transaction(&mut self, containers: &Vec<String>) {
|
||||||
for ins in containers.iter() {
|
for ins in containers.iter() {
|
||||||
if self.queried.contains(ins) {
|
if self.queried.contains(ins) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let cache = self.cache;
|
||||||
let inshandle = cache.instances().get(ins).unwrap();
|
let inshandle = cache.instances().get(ins).unwrap();
|
||||||
|
|
||||||
|
self.transaction(inshandle.instance().dependencies());
|
||||||
self.queried.push(ins.clone());
|
self.queried.push(ins.clone());
|
||||||
self.update(cache, inshandle.instance().dependencies());
|
|
||||||
self.update_instance(sync::instantiate_alpm(&inshandle), cache, inshandle, false)
|
let queue = match self.pkg_queue.get(inshandle.vars().instance()) {
|
||||||
.release()
|
Some(some) => some.clone(), None => Vec::new(),
|
||||||
.unwrap();
|
};
|
||||||
|
let alpm = sync::instantiate_alpm(&inshandle);
|
||||||
|
let mut handle = TransactionHandle::new(alpm, queue);
|
||||||
|
let mut act: Transaction = Transaction::new(inshandle, &mut handle);
|
||||||
|
|
||||||
|
loop {
|
||||||
|
if let Some(result) = act.transact(self, self.syncdb) {
|
||||||
|
match result {
|
||||||
|
Ok(_) => handle.release(),
|
||||||
|
Err(_) => handle.release_on_fail()
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update_instance(&mut self, mut handle: Alpm, cache: &InstanceCache, inshandle: &InstanceHandle, dbonly: bool) -> Alpm {
|
fn link_filesystem(&mut self, inshandle: &InstanceHandle) {
|
||||||
let mut flags = TransFlag::NO_DEP_VERSION;
|
if inshandle.instance().container_type() == "ROOT" {
|
||||||
let mut ignored: Vec<String> = Vec::new();
|
return;
|
||||||
let config = inshandle.instance();
|
|
||||||
let deps = config.dependencies();
|
|
||||||
let dep_depth = deps.len();
|
|
||||||
let instance = inshandle.vars().instance();
|
|
||||||
|
|
||||||
if ! dbonly {
|
|
||||||
println!("{} {}",style("::").bold().cyan(), style(format!("Checking {} for updates...", inshandle.vars().instance())).bold());
|
|
||||||
} else {
|
|
||||||
println!("{} {}",style("->").bold().cyan(), style(format!("Synchronizing foreign packages...")));
|
|
||||||
flags = flags | TransFlag::DB_ONLY;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if dep_depth > 0 {
|
|
||||||
let dep_handle = sync::instantiate_alpm(cache.instances().get(&deps[dep_depth-1]).unwrap());
|
|
||||||
ignored = enumerate_ignorelist(&handle, &dep_handle, dbonly);
|
|
||||||
} else if dbonly {
|
|
||||||
return handle;
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Err(_) = out_of_date(&handle, &ignored) {
|
|
||||||
if ! dbonly {
|
|
||||||
println!("{} {} is up-to-date!", style("->").bold().green(), instance);
|
|
||||||
}
|
|
||||||
return handle;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ! dbonly && self.updated
|
|
||||||
.iter()
|
|
||||||
.find(|ins| inshandle
|
|
||||||
.instance()
|
|
||||||
.dependencies()
|
|
||||||
.contains(ins))
|
|
||||||
.is_some() {
|
|
||||||
self.link_filesystem(instance, cache);
|
|
||||||
handle = self.update_instance(handle, cache, inshandle, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
handle.trans_init(flags).unwrap();
|
|
||||||
handle.sync_sysupgrade(false).unwrap();
|
|
||||||
sync_new_packages(&handle, &ignored);
|
|
||||||
|
|
||||||
if ! dbonly {
|
|
||||||
if confirm_transaction(&handle).is_err() {
|
|
||||||
handle.trans_release().unwrap();
|
|
||||||
return handle;
|
|
||||||
}
|
|
||||||
|
|
||||||
handle.set_question_cb(QueryCallback, query_event::questioncb);
|
|
||||||
handle.set_progress_cb(ProgressCallback::new(true), progress_event::progress_event);
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Err(e) = handle.trans_prepare() {
|
|
||||||
handle_erroneous_preparation(e.0, e.1);
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Err(e) = handle.trans_commit() {
|
|
||||||
handle_erroneous_transaction(e.0, e.1);
|
|
||||||
}
|
|
||||||
|
|
||||||
self.updated.push(instance.clone());
|
|
||||||
handle.trans_release().unwrap();
|
|
||||||
handle
|
|
||||||
}
|
|
||||||
|
|
||||||
fn link_filesystem(&mut self, ins: &String, cache: &InstanceCache) {
|
|
||||||
println!("{} {}",style("->").bold().cyan(), style(format!("Synchronizing container filesystem...")));
|
println!("{} {}",style("->").bold().cyan(), style(format!("Synchronizing container filesystem...")));
|
||||||
linker::wait_on(self.linker.link(cache, &vec![ins.clone()], Vec::new()));
|
linker::wait_on(self.linker.link(self.cache, &vec![inshandle.vars().instance().into()], Vec::new()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn update(mut update: Update, cache: &InstanceCache) {
|
enum TransactionState {
|
||||||
update.update(&cache, &cache.containers_base());
|
Prepare,
|
||||||
update.update(&cache, &cache.containers_dep());
|
UpToDate,
|
||||||
|
PrepareForeignDatabase,
|
||||||
|
Commit(bool),
|
||||||
|
Result(Result<(),()>),
|
||||||
|
CommitForeignDb,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Transaction<'a> {
|
||||||
|
inshandle: &'a InstanceHandle,
|
||||||
|
handle: &'a mut TransactionHandle,
|
||||||
|
state: TransactionState
|
||||||
|
}
|
||||||
|
|
||||||
|
impl <'a>Transaction<'a> {
|
||||||
|
pub fn new(ins: &'a InstanceHandle, than: &'a mut TransactionHandle) -> Self {
|
||||||
|
Self {
|
||||||
|
handle: than,
|
||||||
|
inshandle: ins,
|
||||||
|
state: TransactionState::Prepare
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn transact(&mut self, ag: &mut TransactionAggregator, dbonly: bool) -> Option<Result<(),()>> {
|
||||||
|
let instance = self.inshandle.vars().instance();
|
||||||
|
|
||||||
|
match self.state {
|
||||||
|
TransactionState::Prepare => {
|
||||||
|
println!("{} {}",style("::").bold().cyan(), style(format!("Checking {} for updates...", instance)));
|
||||||
|
self.state = self.prepare(ag, dbonly);
|
||||||
|
None?
|
||||||
|
},
|
||||||
|
TransactionState::UpToDate => {
|
||||||
|
println!("{} {} is up-to-date!", style("->").bold().green(), instance);
|
||||||
|
Some(Ok(()))
|
||||||
|
},
|
||||||
|
TransactionState::PrepareForeignDatabase => {
|
||||||
|
ag.link_filesystem(self.inshandle);
|
||||||
|
self.state = self.prepare_db();
|
||||||
|
None?
|
||||||
|
},
|
||||||
|
TransactionState::CommitForeignDb => {
|
||||||
|
if let Err(_) = self.commit(ag,true) {
|
||||||
|
return Some(Err(()));
|
||||||
|
}
|
||||||
|
self.state = TransactionState::Commit(false);
|
||||||
|
None?
|
||||||
|
},
|
||||||
|
TransactionState::Commit(db) => {
|
||||||
|
self.handle.db(db);
|
||||||
|
Some(self.commit(ag,db))
|
||||||
|
},
|
||||||
|
TransactionState::Result(res) => Some(res)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn prepare_db(&mut self) -> TransactionState {
|
||||||
|
println!("{} Synchronizing foreign packages",style("->").bold().cyan());
|
||||||
|
|
||||||
|
let config = self.inshandle.instance();
|
||||||
|
|
||||||
|
if config.dependencies().len() > 0 {
|
||||||
|
self.handle.db(true);
|
||||||
|
} else {
|
||||||
|
return TransactionState::Commit(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Err(_) = self.handle.out_of_date() {
|
||||||
|
return TransactionState::Commit(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
return TransactionState::CommitForeignDb;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn prepare(&mut self, ag: &mut TransactionAggregator, dbonly: bool) -> TransactionState {
|
||||||
|
let deps = self.inshandle.instance().dependencies();
|
||||||
|
let dep_depth = deps.len();
|
||||||
|
|
||||||
|
if dep_depth > 0 {
|
||||||
|
let dep_instance = ag.cache.instances().get(&deps[dep_depth-1]).unwrap();
|
||||||
|
let dep_alpm = sync::instantiate_alpm(dep_instance);
|
||||||
|
self.handle.enumerate_ignorelist(&dep_alpm);
|
||||||
|
} else if dbonly {
|
||||||
|
return TransactionState::UpToDate;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Err(_) = self.handle.out_of_date() {
|
||||||
|
if self.handle.queue.len() == 0 {
|
||||||
|
return TransactionState::UpToDate;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ! dbonly {
|
||||||
|
if let Some(_) = ag.updated
|
||||||
|
.iter()
|
||||||
|
.find(|ins| self.inshandle
|
||||||
|
.instance()
|
||||||
|
.dependencies()
|
||||||
|
.contains(ins)) {
|
||||||
|
return TransactionState::PrepareForeignDatabase;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TransactionState::Commit(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn commit(&mut self, ag: &mut TransactionAggregator, dbonly: bool) -> Result<(),()> {
|
||||||
|
let instance = self.inshandle.vars().instance();
|
||||||
|
let flags = match dbonly {
|
||||||
|
false => TransFlag::NO_DEP_VERSION,
|
||||||
|
true => TransFlag::NO_DEP_VERSION | TransFlag::DB_ONLY
|
||||||
|
};
|
||||||
|
|
||||||
|
self.handle.alpm().trans_init(flags).unwrap();
|
||||||
|
|
||||||
|
match ag.action {
|
||||||
|
TransactionType::UpgradeSync => {
|
||||||
|
self.handle.alpm().sync_sysupgrade(false).unwrap();
|
||||||
|
self.handle.sync_packages();
|
||||||
|
self.handle.resolve_packages();
|
||||||
|
},
|
||||||
|
TransactionType::Upgrade => self.handle.resolve_packages(),
|
||||||
|
TransactionType::Remove => self.handle.resolve_packages(),
|
||||||
|
}
|
||||||
|
|
||||||
|
if ! dbonly {
|
||||||
|
if confirm_transaction(&self.handle.alpm(), ag.preview).is_err() {
|
||||||
|
self.handle.alpm_mut().trans_release().unwrap();
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
self.handle.alpm().set_question_cb(QueryCallback, query_event::questioncb);
|
||||||
|
self.handle.alpm().set_progress_cb(ProgressCallback::new(true), progress_event::progress_event);
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Err(_) = handle_preparation(self.handle.alpm_mut().trans_prepare()) {
|
||||||
|
return Err(())
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Err(_) = handle_transaction(self.handle.alpm_mut().trans_commit()) {
|
||||||
|
return Err(())
|
||||||
|
}
|
||||||
|
|
||||||
|
ag.updated.push(instance.clone());
|
||||||
|
self.handle.alpm_mut().trans_release().unwrap();
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct TransactionHandle {
|
||||||
|
ignore: Vec<String>,
|
||||||
|
ignore_dep: Vec<String>,
|
||||||
|
queue: Vec<String>,
|
||||||
|
dbonly: bool,
|
||||||
|
alpm: Alpm
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TransactionHandle {
|
||||||
|
pub fn new(al: Alpm, q: Vec<String>) -> Self {
|
||||||
|
Self {
|
||||||
|
ignore: Vec::new(),
|
||||||
|
ignore_dep: Vec::new(),
|
||||||
|
dbonly: false,
|
||||||
|
queue: q,
|
||||||
|
alpm: al,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn db(&mut self, dbonly: bool) {
|
||||||
|
self.dbonly = dbonly;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn release_on_fail(mut self) {
|
||||||
|
println!("{} Transaction failed.",style("->").bold().red());
|
||||||
|
self.alpm.trans_release().ok();
|
||||||
|
self.alpm.release().ok();
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn release(mut self) {
|
||||||
|
self.alpm.trans_release().ok();
|
||||||
|
self.alpm.release().unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn alpm_mut(&mut self) -> &mut Alpm {
|
||||||
|
&mut self.alpm
|
||||||
|
}
|
||||||
|
|
||||||
|
fn alpm(&mut self) -> &Alpm {
|
||||||
|
&self.alpm
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fn out_of_date(&mut self) -> Result<(), ()> {
|
||||||
|
let ignored = if self.dbonly {
|
||||||
|
&self.ignore_dep
|
||||||
|
} else {
|
||||||
|
&self.ignore
|
||||||
|
};
|
||||||
|
|
||||||
|
for pkg in self.alpm.localdb().pkgs() {
|
||||||
|
if ignored.contains(&pkg.name().into()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if pkg.sync_new_version(self.alpm.syncdbs()).is_some() {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Err(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn enumerate_ignorelist(&mut self, dep_handle: &Alpm) {
|
||||||
|
for pkg in self.alpm.localdb().pkgs() {
|
||||||
|
if let Ok(_) = dep_handle.localdb().pkg(pkg.name()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
self.ignore_dep.push(pkg.name().into());
|
||||||
|
}
|
||||||
|
|
||||||
|
for pkg in dep_handle.localdb().pkgs() {
|
||||||
|
self.ignore.push(pkg.name().into());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn resolve_packages(&mut self) {
|
||||||
|
let ignor = if self.dbonly {
|
||||||
|
&self.ignore_dep
|
||||||
|
} else {
|
||||||
|
&self.ignore
|
||||||
|
};
|
||||||
|
|
||||||
|
let ignored = ignor.iter().map(|i| i.as_str()) .collect::<Vec<_>>();
|
||||||
|
let queued = self.queue.iter().map(|i| i.as_str()) .collect::<Vec<_>>();
|
||||||
|
let packages = DependencyResolver::new(&self.alpm, &ignored).enumerate(&queued);
|
||||||
|
|
||||||
|
for pkg in packages {
|
||||||
|
self.alpm.trans_add_pkg(pkg).unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn sync_packages(&mut self) {
|
||||||
|
let ignored = if self.dbonly {
|
||||||
|
&self.ignore_dep
|
||||||
|
} else {
|
||||||
|
&self.ignore
|
||||||
|
};
|
||||||
|
|
||||||
|
for pkg in self.alpm.localdb().pkgs() {
|
||||||
|
if ignored.contains(&pkg.name().into()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(pkg) = pkg.sync_new_version(self.alpm.syncdbs()) {
|
||||||
|
self.alpm.trans_add_pkg(pkg).unwrap();
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for pkg in self.alpm.trans_add() {
|
||||||
|
let deps = pkg.depends().iter().map(|p| p.name()).collect::<Vec<&str>>();
|
||||||
|
|
||||||
|
for dep in deps {
|
||||||
|
if let None = get_local_package(&self.alpm, dep) {
|
||||||
|
self.queue.push(dep.into());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct DependencyResolver<'a> {
|
||||||
|
resolved: Vec<&'a str>,
|
||||||
|
packages: Vec<Package<'a>>,
|
||||||
|
ignored: &'a Vec<&'a str>,
|
||||||
|
handle: &'a Alpm,
|
||||||
|
depth: i8,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl <'a>DependencyResolver<'a> {
|
||||||
|
pub fn new(alpm: &'a Alpm, ignorelist: &'a Vec<&'a str>) -> Self {
|
||||||
|
Self {
|
||||||
|
resolved: Vec::new(),
|
||||||
|
packages: Vec::new(),
|
||||||
|
ignored: ignorelist,
|
||||||
|
depth: 0,
|
||||||
|
handle: alpm,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn check_depth(&mut self) {
|
||||||
|
if self.depth == 15 {
|
||||||
|
print_error("Recursion depth exceeded maximum.");
|
||||||
|
exit(2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn enumerate(mut self, packages: &Vec<&'a str>) -> Vec<Package<'a>> {
|
||||||
|
let mut synchronize: Vec<&'a str> = Vec::new();
|
||||||
|
self.check_depth();
|
||||||
|
|
||||||
|
for pkg in packages {
|
||||||
|
if self.resolved.contains(&pkg) || self.ignored.contains(&pkg) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(pkg) = get_package(&self.handle, pkg) {
|
||||||
|
self.resolved.push(pkg.name());
|
||||||
|
self.packages.push(pkg);
|
||||||
|
let deps = pkg.depends().iter().map(|p| p.name()).collect::<Vec<&str>>();
|
||||||
|
|
||||||
|
for dep in deps {
|
||||||
|
if let None = get_local_package(&self.handle, dep) {
|
||||||
|
synchronize.push(dep);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if synchronize.len() > 0 {
|
||||||
|
self.depth += 1;
|
||||||
|
self.enumerate(&synchronize)
|
||||||
|
} else {
|
||||||
|
self.packages
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn update(mut update: TransactionAggregator, cache: &InstanceCache) {
|
||||||
|
update.transaction(&cache.containers_base());
|
||||||
|
update.transaction(&cache.containers_dep());
|
||||||
|
|
||||||
if update.updated().len() > 0 {
|
if update.updated().len() > 0 {
|
||||||
println!("{} {} ",style("::").bold().green(), style("Synchronising container filesystems...").bold());
|
println!("{} {} ",style("::").bold().green(), style("Synchronising container filesystems...").bold());
|
||||||
update.linker().start(cache.registered().len());
|
update.linker().start(cache.registered().len());
|
||||||
|
@ -138,28 +444,35 @@ pub fn update(mut update: Update, cache: &InstanceCache) {
|
||||||
update.linker().finish();
|
update.linker().finish();
|
||||||
}
|
}
|
||||||
|
|
||||||
update.update(&cache, &cache.containers_root());
|
update.transaction(&cache.containers_root());
|
||||||
println!("{} Transaction complete.",style("->").bold().green());
|
println!("{} Transaction complete.",style("->").bold().green());
|
||||||
}
|
}
|
||||||
|
|
||||||
fn confirm_transaction(handle: &Alpm) -> Result<(),()> {
|
fn confirm_transaction(handle: &Alpm, preview: bool) -> Result<(),()> {
|
||||||
println!("{} {} \n",style("::").bold().red(), style("Package changes").bold());
|
let size = Term::size(&Term::stdout());
|
||||||
|
|
||||||
let mut installed_size_old: i64 = 0;
|
let mut installed_size_old: i64 = 0;
|
||||||
let mut installed_size: i64 = 0;
|
let mut installed_size: i64 = 0;
|
||||||
let mut download: i64 = 0;
|
let mut download: i64 = 0;
|
||||||
let mut files_to_download: usize = 0;
|
let mut files_to_download: usize = 0;
|
||||||
|
let preface = format!("Packages ({}) ", handle.trans_add().len());
|
||||||
|
let mut print_string: String = String::new();
|
||||||
|
let line_delimiter = size.1 as isize - preface.len() as isize;
|
||||||
|
let mut current_line_len: isize = 0;
|
||||||
|
|
||||||
|
print!("\n{}", style(format!("{}", preface)).bold());
|
||||||
|
|
||||||
for val in handle.trans_add() {
|
for val in handle.trans_add() {
|
||||||
let pkg_sync = val;
|
let pkg_sync = val;
|
||||||
let pkg;
|
let pkg;
|
||||||
|
|
||||||
if let Ok(p) = handle.localdb().pkg(pkg_sync.name()) {
|
if let Ok(p) = handle.localdb().pkg(pkg_sync.name()) {
|
||||||
pkg = p;
|
pkg = p;
|
||||||
} else {
|
} else {
|
||||||
pkg = pkg_sync;
|
pkg = pkg_sync;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let output = format!("{}-{} ", pkg.name(), style(pkg_sync.version()).dim());
|
||||||
|
|
||||||
installed_size_old += pkg.isize();
|
installed_size_old += pkg.isize();
|
||||||
installed_size += pkg_sync.isize();
|
installed_size += pkg_sync.isize();
|
||||||
download += pkg_sync.download_size();
|
download += pkg_sync.download_size();
|
||||||
|
@ -168,14 +481,29 @@ fn confirm_transaction(handle: &Alpm) -> Result<(),()> {
|
||||||
files_to_download += 1;
|
files_to_download += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
println!("{} {} -> {}", pkg.name(), style(pkg.version()).bold().yellow(), style(pkg_sync.version()).bold().green());
|
current_line_len += print_string.len() as isize;
|
||||||
|
print_string.push_str(&output);
|
||||||
|
|
||||||
|
if current_line_len >= line_delimiter {
|
||||||
|
print!("{}\n", print_string);
|
||||||
|
print_string = " ".repeat(preface.len());
|
||||||
|
current_line_len = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if print_string.len() > 0 {
|
||||||
|
print!("{} \n", print_string);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
let net = installed_size-installed_size_old;
|
let net = installed_size-installed_size_old;
|
||||||
|
|
||||||
println!("\n{}: {}", style("Total Installed Size").bold(), format_unit(installed_size));
|
println!("\n{}: {}", style("Total Installed Size").bold(), format_unit(installed_size));
|
||||||
println!("{}: {}", style("Net Upgrade Size").bold(), format_unit(net));
|
|
||||||
|
if net != 0 {
|
||||||
|
println!("{}: {}", style("Net Upgrade Size").bold(), format_unit(net));
|
||||||
|
}
|
||||||
|
|
||||||
if download > 0 {
|
if download > 0 {
|
||||||
println!("{}: {}", style("Total Download Size").bold(), format_unit(download));
|
println!("{}: {}", style("Total Download Size").bold(), format_unit(download));
|
||||||
handle.set_dl_cb(DownloadCallback::new(download.try_into().unwrap(), files_to_download), dl_event::download_event);
|
handle.set_dl_cb(DownloadCallback::new(download.try_into().unwrap(), files_to_download), dl_event::download_event);
|
||||||
|
@ -183,11 +511,22 @@ fn confirm_transaction(handle: &Alpm) -> Result<(),()> {
|
||||||
}
|
}
|
||||||
|
|
||||||
println!();
|
println!();
|
||||||
prompt("::", style("Proceed with installation?").bold(), true)
|
if preview {
|
||||||
|
Err(())
|
||||||
|
} else {
|
||||||
|
prompt("::", style("Proceed with installation?").bold(), true)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_erroneous_transaction<'a>(result: CommitResult<'a>, error: alpm::Error) {
|
fn handle_transaction<'a>(result: Result<(),(CommitResult<'a>, alpm::Error)>) -> Result<(),()> {
|
||||||
match result {
|
match result {
|
||||||
|
Ok(_) => Ok(()),
|
||||||
|
Err(result) => { handle_erroneous_transaction(result); Err(()) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_erroneous_transaction<'a>(result: (CommitResult<'a>, alpm::Error)) {
|
||||||
|
match result.0 {
|
||||||
CommitResult::FileConflict(file) => {
|
CommitResult::FileConflict(file) => {
|
||||||
print_error("Conflicting files in container filesystem:");
|
print_error("Conflicting files in container filesystem:");
|
||||||
for conflict in file.iter() {
|
for conflict in file.iter() {
|
||||||
|
@ -206,7 +545,7 @@ fn handle_erroneous_transaction<'a>(result: CommitResult<'a>, error: alpm::Error
|
||||||
} else {
|
} else {
|
||||||
println!("{}: '{}' is owned by foreign target", target, file);
|
println!("{}: '{}' is owned by foreign target", target, file);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -217,18 +556,22 @@ fn handle_erroneous_transaction<'a>(result: CommitResult<'a>, error: alpm::Error
|
||||||
pkg_string.push_str(format!("{}, ", pkg).as_str());
|
pkg_string.push_str(format!("{}, ", pkg).as_str());
|
||||||
}
|
}
|
||||||
pkg_string.truncate(pkg_string.len()-2);
|
pkg_string.truncate(pkg_string.len()-2);
|
||||||
|
print_error(format!("Invalid packages: {}", pkg_string));
|
||||||
print_error(format!("Invalid packages found: {}", pkg_string));
|
|
||||||
},
|
},
|
||||||
CommitResult::Ok => print_error(format!("{}", error)) //haha, this should **never** happen
|
CommitResult::Ok => print_error(format!("{}", result.1))
|
||||||
}
|
}
|
||||||
|
|
||||||
println!("{} Transaction failed.", style("->").red());
|
|
||||||
std::process::exit(1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_erroneous_preparation<'a>(result: PrepareResult<'a>, error: alpm::Error) {
|
fn handle_preparation<'a>(result: Result<(), (PrepareResult<'a>, alpm::Error)>) -> Result<(),()> {
|
||||||
match result {
|
match result {
|
||||||
|
Ok(_) => Ok(()),
|
||||||
|
Err(result) => { handle_erroneous_preparation(result); Err(()) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fn handle_erroneous_preparation<'a>(result: (PrepareResult<'a>, alpm::Error)) {
|
||||||
|
match result.0 {
|
||||||
PrepareResult::PkgInvalidArch(list) => {
|
PrepareResult::PkgInvalidArch(list) => {
|
||||||
for package in list.iter() {
|
for package in list.iter() {
|
||||||
print_error(format!("Invalid architecture {} for {}", style(package.arch().unwrap()).bold(), style(package.name()).bold()));
|
print_error(format!("Invalid architecture {} for {}", style(package.arch().unwrap()).bold(), style(package.name()).bold()));
|
||||||
|
@ -244,11 +587,8 @@ fn handle_erroneous_preparation<'a>(result: PrepareResult<'a>, error: alpm::Erro
|
||||||
print_error(format!("Conflict between {} and {}: {}", style(conflict.package1()).bold(), style(conflict.package2()).bold(), conflict.reason()));
|
print_error(format!("Conflict between {} and {}: {}", style(conflict.package1()).bold(), style(conflict.package2()).bold(), conflict.reason()));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
PrepareResult::Ok => print_error(format!("{}", error))
|
PrepareResult::Ok => print_error(format!("{}", result.1))
|
||||||
}
|
}
|
||||||
|
|
||||||
println!("{} Transaction failed.", style("->").red());
|
|
||||||
std::process::exit(1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn unit_suffix<'a>(i: i8) -> &'a str {
|
fn unit_suffix<'a>(i: i8) -> &'a str {
|
||||||
|
@ -280,47 +620,41 @@ fn format_unit(bytes: i64) -> String {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn enumerate_ignorelist(handle: &Alpm, dep_handle: &Alpm, dbonly: bool) -> Vec<String> {
|
fn get_local_package<'a>(handle: &'a Alpm, pkg: &'a str) -> Option<Package<'a>> {
|
||||||
let mut ignored = Vec::new();
|
if let Ok(pkg) = handle.localdb().pkg(pkg) {
|
||||||
|
return Some(pkg);
|
||||||
if dbonly {
|
|
||||||
for pkg in handle.localdb().pkgs() {
|
|
||||||
if let Ok(_) = dep_handle.localdb().pkg(pkg.name()) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
ignored.push(pkg.name().into());
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
for pkg in dep_handle.localdb().pkgs() {
|
for pkgs in handle.localdb().pkgs() {
|
||||||
ignored.push(pkg.name().into());
|
let is_present = pkgs.provides().iter().filter(|d| pkg == d.name()).collect::<Vec<_>>().len() > 0;
|
||||||
|
if is_present {
|
||||||
|
if let Ok(pkg) = handle.localdb().pkg(pkgs.name()) {
|
||||||
|
return Some(pkg);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
None
|
||||||
ignored
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn out_of_date(handle: &Alpm, ignored: &Vec<String>) -> Result<(), ()> {
|
fn get_package<'a>(handle: &'a Alpm, pkg: &'a str) -> Option<Package<'a>> {
|
||||||
for pkg in handle.localdb().pkgs() {
|
for sync in handle.syncdbs() {
|
||||||
if ignored.contains(&pkg.name().into()) {
|
if let Ok(pkg) = sync.pkg(pkg) {
|
||||||
continue;
|
return Some(pkg);
|
||||||
|
} else {
|
||||||
|
for pkgs in sync.pkgs() {
|
||||||
|
let is_present = pkgs.provides().iter().filter(|d| pkg == d.name()).collect::<Vec<_>>().len() > 0;
|
||||||
|
if is_present {
|
||||||
|
return Some(pkgs);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if pkg.sync_new_version(handle.syncdbs()).is_some() {
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
None
|
||||||
Err(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn sync_new_packages(handle: &Alpm, ignored: &Vec<String>) {
|
fn handle_failure(mut handle: Alpm) {
|
||||||
for pkg in handle.localdb().pkgs() {
|
handle.trans_release().ok();
|
||||||
if ignored.contains(&pkg.name().into()) {
|
handle.release().unwrap();
|
||||||
continue;
|
exit(1);
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(pkg) = pkg.sync_new_version(handle.syncdbs()) {
|
|
||||||
handle.trans_add_pkg(pkg).unwrap();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,7 @@ use super::print_help_msg;
|
||||||
pub struct Arguments<'a> {
|
pub struct Arguments<'a> {
|
||||||
prefix: String,
|
prefix: String,
|
||||||
runtime: Vec<String>,
|
runtime: Vec<String>,
|
||||||
|
targets: Vec<String>,
|
||||||
prefixes: HashMap<String, i8>,
|
prefixes: HashMap<String, i8>,
|
||||||
amalgamation: HashMap<String, i8>,
|
amalgamation: HashMap<String, i8>,
|
||||||
bool_map: HashMap<i8, &'a mut bool>,
|
bool_map: HashMap<i8, &'a mut bool>,
|
||||||
|
@ -19,7 +20,8 @@ pub struct Arguments<'a> {
|
||||||
|
|
||||||
impl<'a> Arguments<'a> {
|
impl<'a> Arguments<'a> {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
|
targets: Vec::new(),
|
||||||
prefix: String::new(),
|
prefix: String::new(),
|
||||||
runtime: Vec::new(),
|
runtime: Vec::new(),
|
||||||
prefixes: HashMap::new(),
|
prefixes: HashMap::new(),
|
||||||
|
@ -33,7 +35,15 @@ impl<'a> Arguments<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse_arguments(mut self) -> Arguments<'a> {
|
pub fn parse_arguments(mut self) -> Arguments<'a> {
|
||||||
|
let mut target = false;
|
||||||
|
|
||||||
for string in env::args().skip(1) {
|
for string in env::args().skip(1) {
|
||||||
|
if target {
|
||||||
|
self.targets.push(string);
|
||||||
|
target = false;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
match string {
|
match string {
|
||||||
string if self.prefixes.contains_key(&string) => {
|
string if self.prefixes.contains_key(&string) => {
|
||||||
let key = self.prefixes.get(&string).unwrap();
|
let key = self.prefixes.get(&string).unwrap();
|
||||||
|
@ -60,6 +70,9 @@ impl<'a> Arguments<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
string if string.starts_with("-t") || string.starts_with("--target") => {
|
||||||
|
target = true;
|
||||||
|
},
|
||||||
_ => self.runtime.push(string),
|
_ => self.runtime.push(string),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -116,6 +129,7 @@ impl<'a> Arguments<'a> {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn targets(&self) -> &Vec<String> { &self.targets }
|
||||||
pub fn get_runtime(&self) -> &Vec<String> { &self.runtime }
|
pub fn get_runtime(&self) -> &Vec<String> { &self.runtime }
|
||||||
pub fn get_prefix(&self) -> &String { &self.prefix }
|
pub fn get_prefix(&self) -> &String { &self.prefix }
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue