Bug fixes and optimisations applied to package and link synchronization
- InstanceCache populate_from() function. - Functional parity almost reached with pacwrap-bash.
This commit is contained in:
parent
566796d174
commit
68af25e824
11 changed files with 370 additions and 189 deletions
|
@ -15,17 +15,27 @@ pub struct InstanceCache {
|
|||
|
||||
impl InstanceCache {
|
||||
pub fn new() -> Self {
|
||||
let s = Self {
|
||||
Self {
|
||||
instances: HashMap::new(),
|
||||
registered: Vec::new(),
|
||||
containers_base: Vec::new(),
|
||||
containers_dep: Vec::new(),
|
||||
containers_root: Vec::new(),
|
||||
};
|
||||
s.populate()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fn populate(mut self) -> Self {
|
||||
pub fn populate_from(&mut self, containers: &Vec<String>) {
|
||||
for name in containers {
|
||||
if self.map_instance(&name) {
|
||||
self.registered.push(name.clone());
|
||||
let deps = self.instances.get(name).unwrap().instance().dependencies().clone();
|
||||
self.populate_from(&deps);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn populate(&mut self) {
|
||||
if let Ok(dir) = read_dir(format!("{}/root", LOCATION.get_data())) {
|
||||
for f in dir {
|
||||
if let Ok(file) = f {
|
||||
|
@ -36,7 +46,6 @@ impl InstanceCache {
|
|||
}
|
||||
}
|
||||
}
|
||||
self
|
||||
}
|
||||
|
||||
fn map_instance(&mut self, ins: &String) -> bool {
|
||||
|
|
|
@ -32,8 +32,8 @@ pub fn execute() {
|
|||
.prefix("-E")
|
||||
.switch("-r", "--root", &mut root)
|
||||
.switch("-v", "--verbose", &mut verbose)
|
||||
.switch("-c", "--cmd", &mut cmd)
|
||||
.switch("-s", "-shell", &mut shell)
|
||||
.switch("-c", "--command", &mut cmd)
|
||||
.switch("-s", "--shell", &mut shell)
|
||||
.parse_arguments();
|
||||
|
||||
let mut runtime = args.get_runtime().clone();
|
||||
|
|
12
src/main.rs
12
src/main.rs
|
@ -1,7 +1,6 @@
|
|||
use std::env;
|
||||
use std::process::Command;
|
||||
use utils::arguments::Arguments;
|
||||
use utils::print_help_msg;
|
||||
use utils::arguments::{self, Arguments};
|
||||
|
||||
mod config;
|
||||
mod exec;
|
||||
|
@ -40,14 +39,7 @@ fn main() {
|
|||
else if bash_create { execute_pacwrap_bash("pacwrap-create"); }
|
||||
else if bash_proc { execute_pacwrap_bash("pacwrap-ps"); }
|
||||
else if bash_help { execute_pacwrap_bash("pacwrap-man"); }
|
||||
else {
|
||||
let mut ar = String::new();
|
||||
for arg in env::args().skip(1).collect::<Vec<_>>().iter() {
|
||||
ar.push_str(&format!("{} ", &arg));
|
||||
}
|
||||
ar.truncate(ar.len()-1);
|
||||
print_help_msg(&format!("Invalid arguments -- '{}'", ar));
|
||||
}
|
||||
else { arguments::invalid(); }
|
||||
}
|
||||
|
||||
fn print_version() {
|
||||
|
|
49
src/sync.rs
49
src/sync.rs
|
@ -5,17 +5,16 @@ use console::style;
|
|||
use lazy_static::lazy_static;
|
||||
use pacmanconf;
|
||||
|
||||
use crate::{constants, utils};
|
||||
use crate::constants;
|
||||
use crate::sync::dl_event::DownloadCallback;
|
||||
use crate::sync::linker::Linker;
|
||||
use crate::sync::progress_event::ProgressCallback;
|
||||
use crate::sync::update::Update;
|
||||
use crate::utils::{Arguments, test_root};
|
||||
use crate::utils::{Arguments, test_root, print_help_msg};
|
||||
use crate::config::InsVars;
|
||||
use crate::config::cache::InstanceCache;
|
||||
use crate::config::InstanceHandle;
|
||||
|
||||
|
||||
lazy_static! {
|
||||
static ref PACMAN_CONF: pacmanconf::Config = pacmanconf::Config::from_file(format!("{}/pacman/pacman.conf", constants::LOCATION.get_config())).unwrap();
|
||||
}
|
||||
|
@ -32,7 +31,6 @@ pub fn execute() {
|
|||
let mut query = false;
|
||||
let mut explicit = false;
|
||||
let mut sync_count = 0;
|
||||
|
||||
let mut args = Arguments::new().prefix("-S")
|
||||
.switch("-y", "--sync", &mut sync).count(&mut sync_count)
|
||||
.switch("-u", "--upgrade", &mut update)
|
||||
|
@ -41,42 +39,35 @@ pub fn execute() {
|
|||
|
||||
args = args.parse_arguments();
|
||||
let targets = args.get_runtime().clone();
|
||||
let cache: InstanceCache = InstanceCache::new();
|
||||
let mut cache: InstanceCache = InstanceCache::new();
|
||||
|
||||
if sync && sync_count == 4 {
|
||||
link(&cache, cache.registered());
|
||||
if targets.len() > 0 {
|
||||
cache.populate_from(&targets);
|
||||
} else {
|
||||
cache.populate();
|
||||
}
|
||||
|
||||
if sync && sync_count == 4 {
|
||||
let mut l: Linker = Linker::new();
|
||||
l.start(cache.registered().len());
|
||||
linker::wait_on(l.link(&cache, cache.registered(), Vec::new()));
|
||||
l.finish();
|
||||
} else if query {
|
||||
if targets.len() < 1 {
|
||||
utils::print_help_msg("Target not specified.");
|
||||
print_help_msg("Target not specified.");
|
||||
}
|
||||
query_database(targets.get(0).unwrap(), explicit)
|
||||
} else {
|
||||
let mut u: Update = Update::new();
|
||||
|
||||
if sync {
|
||||
synchronize_database(&cache, sync_count > 1);
|
||||
}
|
||||
if update {
|
||||
u.update(&cache, &cache.containers_base());
|
||||
u.update(&cache, &cache.containers_dep());
|
||||
|
||||
if u.updated().len() > 0 {
|
||||
link(&cache, cache.registered());
|
||||
}
|
||||
|
||||
u.update(&cache, &cache.containers_root());
|
||||
}
|
||||
|
||||
println!("{} Transaction complete.",style("->").bold().green());
|
||||
if update {
|
||||
update::update(Update::new(), &cache);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn link(cache: &InstanceCache, containers: &Vec<String>) {
|
||||
let mut l: Linker = Linker::new(containers.len());
|
||||
linker::wait_on(l.link(&cache, containers, Vec::new()));
|
||||
l.finish();
|
||||
}
|
||||
|
||||
fn query_database(instance: &String, explicit: bool) {
|
||||
let instance_vars = InsVars::new(instance);
|
||||
|
||||
|
@ -129,15 +120,13 @@ fn register_remote(mut handle: Alpm) -> Alpm {
|
|||
handle
|
||||
}
|
||||
|
||||
|
||||
|
||||
fn synchronize_database(cache: &InstanceCache, force: bool) {
|
||||
for i in cache.registered().iter() {
|
||||
let ins: &InstanceHandle = cache.instances().get(i).unwrap();
|
||||
if ins.instance().container_type() == "BASE" {
|
||||
let mut handle = instantiate_alpm_syncdb(&ins);
|
||||
|
||||
println!("{} {} ",style("::").bold().green(), style("Synchronising package databases...").bold());
|
||||
println!("{} {} ",style("::").bold().green(), style("Synchronising package databases...").bold());
|
||||
handle.syncdbs_mut().update(force).unwrap();
|
||||
Alpm::release(handle).unwrap();
|
||||
break;
|
||||
|
|
|
@ -2,7 +2,7 @@ use std::collections::HashMap;
|
|||
|
||||
use alpm::{AnyDownloadEvent, DownloadEvent};
|
||||
use indicatif::{MultiProgress, ProgressBar, ProgressStyle};
|
||||
use console::{Term, style};
|
||||
use console::Term;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct DownloadCallback {
|
||||
|
@ -44,7 +44,7 @@ pub fn download_event(filename: &str, download: AnyDownloadEvent, this: &mut Dow
|
|||
let name: Vec<&str> = filename.split(".").collect();
|
||||
let pb = this.progress.add(ProgressBar::new(progress.total.unsigned_abs()));
|
||||
pb.set_style(this.style.clone());
|
||||
pb.set_message(style(name[0].to_string()).bold().to_string());
|
||||
pb.set_message(name[0].to_string());
|
||||
this.prbar.insert(filename.to_string(), pb);
|
||||
}
|
||||
}
|
||||
|
@ -58,7 +58,7 @@ pub fn download_event(filename: &str, download: AnyDownloadEvent, this: &mut Dow
|
|||
let name: Vec<&str> = filename.split(".").collect();
|
||||
let pb = this.progress.add(ProgressBar::new(0));
|
||||
pb.set_style(this.finished.clone());
|
||||
pb.set_message(format!("{} is up-to-date!", style(name[0].to_string()).bold().to_string()));
|
||||
pb.set_message(format!("{} is up-to-date!", name[0].to_string()));
|
||||
pb.finish();
|
||||
this.prbar.insert(filename.to_string(), pb);
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@ use std::sync::mpsc::{Sender, self, Receiver};
|
|||
use std::thread::JoinHandle;
|
||||
|
||||
use indexmap::IndexMap;
|
||||
use indicatif::{ProgressBar, ProgressStyle};
|
||||
use indicatif::{ProgressBar, ProgressStyle, ProgressDrawTarget};
|
||||
use serde::{Serialize, Deserialize};
|
||||
use walkdir::WalkDir;
|
||||
use std::collections::HashMap;
|
||||
|
@ -41,13 +41,15 @@ pub struct Linker {
|
|||
}
|
||||
|
||||
impl Linker {
|
||||
pub fn new(length: usize) -> Self {
|
||||
pub fn new() -> Self {
|
||||
let size = Term::size(&Term::stdout());
|
||||
let width = (size.1 / 2).to_string();
|
||||
let width_str = " {spinner:.green} {msg:<".to_owned()+width.as_str();
|
||||
let style = ProgressStyle::with_template(&(width_str+"} [{wide_bar}] {percent:<3}%"))
|
||||
.unwrap().progress_chars("#-").tick_strings(&[">", "✓"]);
|
||||
let pr = ProgressBar::new(progress_u64(length)).with_style(style);
|
||||
let pr = ProgressBar::new(0).with_style(style);
|
||||
|
||||
pr.set_draw_target(ProgressDrawTarget::hidden());
|
||||
|
||||
Self {
|
||||
progress: pr,
|
||||
|
@ -58,6 +60,13 @@ impl Linker {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn start(&mut self, length: usize) {
|
||||
self.progress.set_draw_target(ProgressDrawTarget::stdout());
|
||||
self.progress.set_message("Synhcronizing containers..");
|
||||
self.progress.set_position(0);
|
||||
self.progress.set_length(progress_u64(length));
|
||||
}
|
||||
|
||||
pub fn finish(&mut self) {
|
||||
self.progress.set_message("Synchronization complete.");
|
||||
self.progress.finish();
|
||||
|
@ -77,7 +86,6 @@ impl Linker {
|
|||
|
||||
pub fn link(&mut self, cache: &InstanceCache, containers: &Vec<String>, mut cached_threads: Vec<JoinHandle<()>>) -> Vec<JoinHandle<()>> {
|
||||
let mut threads: Vec<_> = Vec::new();
|
||||
|
||||
let (tx, rx): (Sender<(String, HardLinkDS)>, Receiver<(String, HardLinkDS)>) = mpsc::channel();
|
||||
|
||||
for ins in containers.iter() {
|
||||
|
@ -132,22 +140,17 @@ impl Linker {
|
|||
if dep_depth == 0 {
|
||||
return None;
|
||||
}
|
||||
|
||||
|
||||
|
||||
let mut map = IndexMap::new();
|
||||
let dephandle = cache.instances().get(&deps[dep_depth-1]).unwrap();
|
||||
let dep = dephandle.vars().instance().clone();
|
||||
|
||||
|
||||
|
||||
let mut map = IndexMap::new();
|
||||
|
||||
|
||||
for dep in deps {
|
||||
let dephandle = cache.instances().get(dep).unwrap();
|
||||
let dephandle = cache.instances().get(dep).unwrap();
|
||||
let ds = match self.hlds.get(dep) {
|
||||
Some(ds) => ds.clone(),
|
||||
None => { HardLinkDS::new() }
|
||||
};
|
||||
//p.push(dephandle.vars().root().clone());
|
||||
map.insert(dephandle.vars().root().clone(), ds);
|
||||
}
|
||||
|
||||
|
@ -171,10 +174,10 @@ impl Linker {
|
|||
let thread = std::thread::Builder::new().name(format!("PR-LINKER")).spawn(move ||{
|
||||
//println!("{} Linking {} against {}", style("->").cyan(), style(instance).bold(), style(&dep).bold());
|
||||
tx.send((dep, link_instance(ds, ds_res, root, map))).unwrap();
|
||||
}).unwrap();
|
||||
}).unwrap();
|
||||
|
||||
Some(thread)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn link_instance(mut ds: HardLinkDS, ds_res: HardLinkDS, root: String, map: IndexMap<String,HardLinkDS>) -> HardLinkDS {
|
||||
|
@ -205,17 +208,7 @@ fn link_instance(mut ds: HardLinkDS, ds_res: HardLinkDS, root: String, map: Inde
|
|||
ds.files.insert(src_tr, (src,metadata.is_dir()));
|
||||
}
|
||||
} else {
|
||||
for file in hpds.1.files.iter() {
|
||||
if let Some(_) = ds.files.get(file.0) {
|
||||
continue
|
||||
}
|
||||
|
||||
let src_tr = file.0.clone();
|
||||
let src = file.1.0.clone();
|
||||
let is_dir = file.1.1;
|
||||
|
||||
ds.files.insert(src_tr, (src,is_dir));
|
||||
}
|
||||
ds.files.extend(hpds.1.files);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -53,11 +53,12 @@ pub fn progress_event(progress: Progress, pkgname: &str, percent: i32, howmany:
|
|||
}
|
||||
}
|
||||
|
||||
let pos = current + 1;
|
||||
let pos = style(current + 1).bold().white();
|
||||
let total = style(howmany + 1).bold().white();
|
||||
let progress_name: String = progress_name(progress,pkgname);
|
||||
let pb = this.progress.add(ProgressBar::new(progress_u64(percent)));
|
||||
pb.set_style(this.style.clone());
|
||||
pb.set_message(format!("({}{}/{}) {}", whitespace, pos, howmany, style(progress_name).bold()));
|
||||
pb.set_message(format!("({}{}/{}) {}", whitespace, pos, total, progress_name));
|
||||
this.prbar.insert(progress_ident, pb);
|
||||
}
|
||||
}
|
||||
|
@ -69,7 +70,12 @@ fn progress_name(progress: Progress, pkgname: &str) -> String {
|
|||
Progress::IntegrityStart => "Checking integrity".into(),
|
||||
Progress::LoadStart => "Loading packages".into(),
|
||||
Progress::ConflictsStart => "Checking conflicts".into(),
|
||||
_ => pkgname.into()
|
||||
Progress::DiskspaceStart => "Checking available diskspace".into(),
|
||||
Progress::UpgradeStart => format!("Upgrading {}", pkgname),
|
||||
Progress::AddStart => format!("Installing {}", pkgname),
|
||||
Progress::RemoveStart => format!("Removing {}", pkgname),
|
||||
Progress::DowngradeStart => format!("Downgrading {}", pkgname),
|
||||
Progress::ReinstallStart => format!("Reinstalling {}", pkgname)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
#![allow(unused_variables)]
|
||||
|
||||
use alpm::{AnyQuestion, Question::*};
|
||||
use console::style;
|
||||
|
||||
use crate::utils::prompt::prompt;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct QueryCallback;
|
||||
|
@ -13,8 +16,24 @@ impl QueryCallback {
|
|||
|
||||
pub fn questioncb(question: AnyQuestion, this: &mut QueryCallback) {
|
||||
match question.question() {
|
||||
Conflict(x) => (),
|
||||
Replace(x) => (),
|
||||
Conflict(mut x) => {
|
||||
let reason = x.conflict().reason();
|
||||
let pkg_a = x.conflict().package1();
|
||||
let pkg_b = x.conflict().package2();
|
||||
|
||||
let prompt_string = format!("Conflict between {} and {}: {}. Remove package?", pkg_a, pkg_b, reason);
|
||||
let prompt = prompt("->", style(&prompt_string), false);
|
||||
if let Ok(_) = prompt {
|
||||
x.set_remove(true);
|
||||
}
|
||||
},
|
||||
Replace(x) => {
|
||||
let prompt_string = format!("Replace package {} with {}?", x.oldpkg().name(), x.newpkg().name());
|
||||
let prompt = prompt("->", style(&prompt_string), false);
|
||||
if let Ok(_) = prompt {
|
||||
x.set_replace(true);
|
||||
}
|
||||
},
|
||||
Corrupted(x) => (),
|
||||
RemovePkgs(x) => (),
|
||||
ImportKey(x) => (),
|
||||
|
|
|
@ -1,32 +1,39 @@
|
|||
#![allow(dead_code)]
|
||||
|
||||
use alpm::{Alpm, PackageReason, Package, TransFlag};
|
||||
use console::style;
|
||||
use alpm::{Alpm,
|
||||
TransFlag,
|
||||
PrepareResult,
|
||||
CommitResult,
|
||||
FileConflictType};
|
||||
|
||||
use crate::sync;
|
||||
use crate::sync::dl_event;
|
||||
use crate::{sync, utils::print_error};
|
||||
use crate::sync::{dl_event, linker};
|
||||
use crate::sync::dl_event::DownloadCallback;
|
||||
use crate::sync::progress_event;
|
||||
use crate::sync::progress_event::ProgressCallback;
|
||||
use crate::sync::linker::Linker;
|
||||
use crate::utils::prompt::prompt;
|
||||
use crate::config::cache::InstanceCache;
|
||||
use crate::config::InstanceHandle;
|
||||
|
||||
|
||||
pub struct Update {
|
||||
queried: Vec<String>,
|
||||
updated: Vec<String>,
|
||||
linker: Linker
|
||||
}
|
||||
|
||||
impl Update {
|
||||
|
||||
impl Update {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
queried: Vec::new(),
|
||||
updated: Vec::new(),
|
||||
linker: Linker::new()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn linker(&mut self) -> &mut Linker {
|
||||
&mut self.linker
|
||||
}
|
||||
|
||||
pub fn updated(&self) -> &Vec<String> {
|
||||
&self.updated
|
||||
}
|
||||
|
@ -38,102 +45,268 @@ impl Update {
|
|||
}
|
||||
|
||||
let inshandle = cache.instances().get(ins).unwrap();
|
||||
|
||||
self.update(cache, inshandle.instance().dependencies());
|
||||
self.update_instance(&cache, inshandle, false);
|
||||
|
||||
self.queried.push(ins.clone());
|
||||
self.update(cache, inshandle.instance().dependencies());
|
||||
self.update_instance(sync::instantiate_alpm(&inshandle), cache, inshandle, false)
|
||||
.release()
|
||||
.unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
fn update_instance(&mut self, cache: &InstanceCache, inshandle: &InstanceHandle, dbonly: bool) {
|
||||
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")));
|
||||
}
|
||||
|
||||
let mut handle = sync::instantiate_alpm(&inshandle);
|
||||
let mut local: Vec<Package> = Vec::new();
|
||||
let mut remote: Vec<Package> = Vec::new();
|
||||
fn update_instance(&mut self, mut handle: Alpm, cache: &InstanceCache, inshandle: &InstanceHandle, dbonly: bool) -> Alpm {
|
||||
let mut flags = TransFlag::NO_DEP_VERSION;
|
||||
let mut ignored: Vec<String> = Vec::new();
|
||||
let config = inshandle.instance();
|
||||
let deps = config.dependencies();
|
||||
let dep_depth = deps.len();
|
||||
let instance = inshandle.vars().instance();
|
||||
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 {
|
||||
if dbonly {
|
||||
flags = flags | TransFlag::DB_ONLY;
|
||||
|
||||
for pkg in handle.localdb().pkgs() {
|
||||
if pkg.reason() != PackageReason::Explicit {
|
||||
continue;
|
||||
}
|
||||
|
||||
ignored.push(pkg.name().into());
|
||||
}
|
||||
} else {
|
||||
let dep_handle = sync::instantiate_alpm(cache.instances().get(&deps[dep_depth-1]).unwrap());
|
||||
|
||||
for pkg in dep_handle.localdb().pkgs() {
|
||||
ignored.push(pkg.name().into());
|
||||
}
|
||||
|
||||
Alpm::release(dep_handle).unwrap();
|
||||
}
|
||||
|
||||
for ignore in ignored.iter() {
|
||||
handle.add_ignorepkg(ignore.as_bytes()).unwrap();
|
||||
}
|
||||
let dep_handle = sync::instantiate_alpm(cache.instances().get(&deps[dep_depth-1]).unwrap());
|
||||
ignored = enumerate_ignorelist(&handle, &dep_handle, dbonly);
|
||||
} else if dbonly {
|
||||
Alpm::release(handle).unwrap();
|
||||
return;
|
||||
return handle;
|
||||
}
|
||||
|
||||
for pkg in handle.localdb().pkgs() {
|
||||
for syncdb in handle.syncdbs() {
|
||||
if let Ok(pkg_remote) = syncdb.pkg(pkg.name()) {
|
||||
if pkg_remote.version() > pkg.version() && ! ignored.contains(&pkg.name().into()) {
|
||||
local.push(pkg);
|
||||
remote.push(pkg_remote);
|
||||
}
|
||||
}
|
||||
if let Err(_) = out_of_date(&handle, &ignored) {
|
||||
if ! dbonly {
|
||||
println!("{} {} is up-to-date!", style("->").bold().green(), instance);
|
||||
}
|
||||
return handle;
|
||||
}
|
||||
|
||||
if local.len() > 0 {
|
||||
if ! dbonly {
|
||||
self.update_instance(&cache, inshandle, true);
|
||||
println!("{} {} \n",style("::").bold().red(), style("Package changes").bold());
|
||||
|
||||
for val in 0..local.len() {
|
||||
let pkg_remote = remote[val];
|
||||
let pkg = local[val];
|
||||
println!("{} {} -> {}", style(pkg.name()).bold(), style(pkg.version()).bold().yellow(), style(pkg_remote.version()).bold().green());
|
||||
} println!();
|
||||
|
||||
if let Err(_) = prompt("Proceed with installation?") {
|
||||
return;
|
||||
}
|
||||
handle.set_progress_cb(ProgressCallback::new(true), progress_event::progress_event);
|
||||
handle.set_dl_cb(DownloadCallback::new(true), dl_event::download_event);
|
||||
}
|
||||
|
||||
handle.trans_init(flags).unwrap();
|
||||
for val in 0..local.len() {
|
||||
handle.trans_add_pkg(remote[val]).unwrap();
|
||||
}
|
||||
|
||||
handle.trans_prepare().unwrap();
|
||||
handle.trans_commit().unwrap();
|
||||
handle.trans_release().unwrap();
|
||||
|
||||
self.updated.push(instance.clone());
|
||||
} else if ! dbonly {
|
||||
println!("{} {} is up-to-date!", style("->").bold().green(), instance);
|
||||
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);
|
||||
}
|
||||
|
||||
Alpm::release(handle).unwrap();
|
||||
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_progress_cb(ProgressCallback::new(true), progress_event::progress_event);
|
||||
handle.set_dl_cb(DownloadCallback::new(true), dl_event::download_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...")));
|
||||
linker::wait_on(self.linker.link(cache, &vec![ins.clone()], Vec::new()));
|
||||
}
|
||||
}
|
||||
|
||||
pub fn update(mut update: Update, cache: &InstanceCache) {
|
||||
update.update(&cache, &cache.containers_base());
|
||||
update.update(&cache, &cache.containers_dep());
|
||||
|
||||
if update.updated().len() > 0 {
|
||||
println!("{} {} ",style("::").bold().green(), style("Synchronising container filesystems...").bold());
|
||||
update.linker().start(cache.registered().len());
|
||||
linker::wait_on(update.linker().link(&cache, cache.registered(), Vec::new()));
|
||||
update.linker().finish();
|
||||
}
|
||||
|
||||
update.update(&cache, &cache.containers_root());
|
||||
println!("{} Transaction complete.",style("->").bold().green());
|
||||
}
|
||||
|
||||
fn confirm_transaction(handle: &Alpm) -> Result<(),()> {
|
||||
println!("{} {} \n",style("::").bold().red(), style("Package changes").bold());
|
||||
|
||||
let mut installed_size_old: i64 = 0;
|
||||
let mut installed_size: i64 = 0;
|
||||
let mut download: i64 = 0;
|
||||
|
||||
for val in handle.trans_add() {
|
||||
let pkg_sync = val;
|
||||
let pkg = handle.localdb().pkg(pkg_sync.name()).unwrap();
|
||||
|
||||
installed_size_old += pkg.isize();
|
||||
installed_size += pkg_sync.isize();
|
||||
download += pkg_sync.download_size();
|
||||
|
||||
println!("{} {} -> {}", pkg.name(), style(pkg.version()).bold().yellow(), style(pkg_sync.version()).bold().green());
|
||||
}
|
||||
|
||||
let net = installed_size-installed_size_old;
|
||||
|
||||
println!("\n{}: {}", style("Total Installed Size").bold(), format_unit(installed_size));
|
||||
println!("{}: {}", style("Net Upgrade Size").bold(), format_unit(net));
|
||||
|
||||
if download > 0 {
|
||||
println!("{}: {}", style("Total Download Size").bold(), format_unit(download));
|
||||
}
|
||||
|
||||
println!();
|
||||
prompt("::", style("Proceed with installation?").bold(), true)
|
||||
}
|
||||
|
||||
fn handle_erroneous_transaction<'a>(result: CommitResult<'a>, error: alpm::Error) {
|
||||
match result {
|
||||
CommitResult::FileConflict(file) => {
|
||||
print_error("Conflicting files in container filesystem:");
|
||||
for conflict in file.iter() {
|
||||
match conflict.conflict_type() {
|
||||
FileConflictType::Filesystem => {
|
||||
let file = conflict.file();
|
||||
let target = conflict.target();
|
||||
println!("{}: '{}' already exists.", target, file);
|
||||
},
|
||||
FileConflictType::Target => {
|
||||
let file = conflict.file();
|
||||
let target = style(conflict.target()).bold().white();
|
||||
if let Some(conflicting) = conflict.conflicting_target() {
|
||||
let conflicting = style(conflicting).bold().white();
|
||||
println!("{}: '{}' is owned by {}", target, file, conflicting);
|
||||
} else {
|
||||
println!("{}: '{}' is owned by foreign target", target, file);
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
},
|
||||
CommitResult::PkgInvalid(p) => {
|
||||
let mut pkg_string = String::new();
|
||||
for pkg in p.iter() {
|
||||
let pkg = style(pkg).bold().white();
|
||||
pkg_string.push_str(format!("{}, ", pkg).as_str());
|
||||
}
|
||||
pkg_string.truncate(pkg_string.len()-2);
|
||||
|
||||
print_error(format!("Invalid packages found: {}", pkg_string));
|
||||
},
|
||||
CommitResult::Ok => print_error(format!("{}", error)) //haha, this should **never** happen
|
||||
}
|
||||
|
||||
println!("{} Transaction failed.", style("->").red());
|
||||
std::process::exit(1);
|
||||
}
|
||||
|
||||
fn handle_erroneous_preparation<'a>(result: PrepareResult<'a>, error: alpm::Error) {
|
||||
match result {
|
||||
PrepareResult::PkgInvalidArch(list) => {
|
||||
for package in list.iter() {
|
||||
print_error(format!("Invalid architecture {} for {}", style(package.arch().unwrap()).bold(), style(package.name()).bold()));
|
||||
}
|
||||
},
|
||||
PrepareResult::UnsatisfiedDeps(list) => {
|
||||
for missing in list.iter() {
|
||||
print_error(format!("Unsatisifed dependency {} for target {}", style(missing.depend()).bold(), style(missing.target()).bold()));
|
||||
}
|
||||
},
|
||||
PrepareResult::ConflictingDeps(list) => {
|
||||
for conflict in list.iter() {
|
||||
print_error(format!("Conflict between {} and {}: {}", style(conflict.package1()).bold(), style(conflict.package2()).bold(), conflict.reason()));
|
||||
}
|
||||
},
|
||||
PrepareResult::Ok => print_error(format!("{}", error))
|
||||
}
|
||||
|
||||
println!("{} Transaction failed.", style("->").red());
|
||||
std::process::exit(1);
|
||||
}
|
||||
|
||||
fn unit_suffix<'a>(i: i8) -> &'a str {
|
||||
match i {
|
||||
0 => "KB",
|
||||
1 => "MB",
|
||||
2 => "GB",
|
||||
3 => "TB",
|
||||
4 => "PB",
|
||||
_ => "B"
|
||||
}
|
||||
}
|
||||
|
||||
fn format_unit(bytes: i64) -> String {
|
||||
let conditional: f64 = if bytes > -1 { 1000.0 } else { -1000.0 };
|
||||
let diviser: f64 = 1000.0;
|
||||
let mut size: f64 = bytes as f64;
|
||||
let mut idx: i8 = -1;
|
||||
|
||||
while if bytes > -1 { size > conditional } else { size < conditional } {
|
||||
size = size / diviser;
|
||||
idx += 1;
|
||||
}
|
||||
|
||||
if idx == -1 {
|
||||
format!("{:.0} {}", size, unit_suffix(idx))
|
||||
} else {
|
||||
format!("{:.2} {}", size, unit_suffix(idx))
|
||||
}
|
||||
}
|
||||
|
||||
fn enumerate_ignorelist(handle: &Alpm, dep_handle: &Alpm, dbonly: bool) -> Vec<String> {
|
||||
let mut ignored = Vec::new();
|
||||
|
||||
if dbonly {
|
||||
for pkg in handle.localdb().pkgs() {
|
||||
if let Ok(_) = dep_handle.localdb().pkg(pkg.name()) {
|
||||
continue;
|
||||
}
|
||||
ignored.push(pkg.name().into());
|
||||
}
|
||||
} else {
|
||||
for pkg in dep_handle.localdb().pkgs() {
|
||||
ignored.push(pkg.name().into());
|
||||
}
|
||||
}
|
||||
|
||||
ignored
|
||||
}
|
||||
|
||||
fn out_of_date(handle: &Alpm, ignored: &Vec<String>) -> Result<(), ()> {
|
||||
for pkg in handle.localdb().pkgs() {
|
||||
if ignored.contains(&pkg.name().into()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if pkg.sync_new_version(handle.syncdbs()).is_some() {
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
|
||||
Err(())
|
||||
}
|
||||
|
||||
fn sync_new_packages(handle: &Alpm, ignored: &Vec<String>) {
|
||||
for pkg in handle.localdb().pkgs() {
|
||||
if ignored.contains(&pkg.name().into()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if let Some(pkg) = pkg.sync_new_version(handle.syncdbs()) {
|
||||
handle.trans_add_pkg(pkg).unwrap();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,6 +3,8 @@ use std::collections::HashMap;
|
|||
|
||||
use crate::utils;
|
||||
|
||||
use super::print_help_msg;
|
||||
|
||||
pub struct Arguments<'a> {
|
||||
prefix: String,
|
||||
runtime: Vec<String>,
|
||||
|
@ -109,3 +111,12 @@ impl<'a> Arguments<'a> {
|
|||
pub fn get_runtime(&self) -> &Vec<String> { &self.runtime }
|
||||
pub fn get_prefix(&self) -> &String { &self.prefix }
|
||||
}
|
||||
|
||||
pub fn invalid() {
|
||||
let mut ar = String::new();
|
||||
for arg in env::args().skip(1).collect::<Vec<_>>().iter() {
|
||||
ar.push_str(&format!("{} ", &arg));
|
||||
}
|
||||
ar.truncate(ar.len()-1);
|
||||
print_help_msg(&format!("Invalid arguments -- '{}'", ar));
|
||||
}
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
#![allow(dead_code)]
|
||||
|
||||
use console::{style, Style};
|
||||
use console::{style, Style, StyledObject};
|
||||
use dialoguer::{theme::ColorfulTheme, Input};
|
||||
|
||||
pub fn prompt(prompt: &str) -> Result<(),()> {
|
||||
if let Ok(value) = create_prompt(prompt, "[Y/n]") {
|
||||
if value.to_lowercase() == "y" || value.is_empty() {
|
||||
pub fn prompt(prefix: &str, prompt: StyledObject<&str>, yn_prompt: bool) -> Result<(),()> {
|
||||
if let Ok(value) = create_prompt(prompt, prefix,
|
||||
if yn_prompt { "[Y/n]" } else { "[N/y]" }) {
|
||||
if value.to_lowercase() == "y" || (yn_prompt && value.is_empty()) {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(())
|
||||
|
@ -15,32 +16,20 @@ pub fn prompt(prompt: &str) -> Result<(),()> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn prompt_no(prompt: &str) -> Result<(),()> {
|
||||
if let Ok(value) = create_prompt(prompt, "[y/N]") {
|
||||
if value.to_lowercase() == "y" {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(())
|
||||
}
|
||||
} else {
|
||||
Err(())
|
||||
}
|
||||
}
|
||||
|
||||
fn create_prompt(message: &str, prompt: &str) -> Result<String, std::io::Error> {
|
||||
fn create_prompt(message: StyledObject<&str>, prefix: &str, prompt: &str) -> Result<String, std::io::Error> {
|
||||
let theme = ColorfulTheme {
|
||||
success_prefix: style("::".to_string()).green().bold(),
|
||||
prompt_prefix: style("::".to_string()).green().bold(),
|
||||
error_prefix: style("::".to_string()).red().bold(),
|
||||
success_prefix: style(prefix.into()).green().bold(),
|
||||
prompt_prefix: style(prefix.into()).green().bold(),
|
||||
error_prefix: style(prefix.into()).red().bold(),
|
||||
prompt_suffix: style(prompt.to_string()).bold(),
|
||||
success_suffix: style(prompt.to_string()).bold(),
|
||||
prompt_style: Style::new().bold(),
|
||||
prompt_style: Style::new(),
|
||||
values_style: Style::new(),
|
||||
..ColorfulTheme::default()
|
||||
};
|
||||
|
||||
return Input::with_theme(&theme)
|
||||
.with_prompt(message)
|
||||
.with_prompt(message.to_string())
|
||||
.allow_empty(true)
|
||||
.interact_text();
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue