Skip to content

Commit

Permalink
More progress
Browse files Browse the repository at this point in the history
  • Loading branch information
hwittenborn committed Aug 21, 2022
1 parent 2d35c50 commit 7a18f2d
Show file tree
Hide file tree
Showing 8 changed files with 198 additions and 33 deletions.
164 changes: 164 additions & 0 deletions src/cache.rs
Original file line number Diff line number Diff line change
Expand Up @@ -385,6 +385,170 @@ impl Cache {
&self.mpr_cache
}

/// Run a transaction.
/// `mpr_pkgs` is the list of MPR packages to install.
pub fn commit(&self, mpr_pkgs: &Vec<String>) {
let mut to_install: Vec<String> = Vec::new();
let mut to_remove: Vec<String> = Vec::new();
let mut to_purge: Vec<String> = Vec::new();
let mut to_upgrade: Vec<String> = Vec::new();
let mut to_downgrade: Vec<String> = Vec::new();

// Report APT packages.
for pkg in self.apt_cache().packages(&PackageSort::default()) {
let pkgname = pkg.name();
let apt_string = format!("{}{}", "apt/".to_string().green(), &pkgname);

if pkg.marked_install() {
to_install.push(apt_string);
} else if pkg.marked_delete() {
to_remove.push(apt_string);
} else if pkg.marked_purge() {
to_purge.push(apt_string);
} else if pkg.marked_upgrade() {
to_upgrade.push(apt_string);
} else if pkg.marked_downgrade() {
to_downgrade.push(apt_string);
}
}

// Report MPR packages.
for pkg in mpr_pkgs {
let mpr_string = format!("{}{}", "mpr/".to_owned().green(), pkg);
to_install.push(mpr_string);
}

// Print out the transaction.
if to_install.is_empty()
&& to_remove.is_empty()
&& to_purge.is_empty()
&& to_upgrade.is_empty()
&& to_downgrade.is_empty()
{
println!("{}", "Nothing to do, quitting.".bold());
quit::with_code(exitcode::OK);
};

if !to_install.is_empty() {
println!("{}", "The following packages will be installed:".bold());
util::format_apt_pkglist(&to_install);
println!();
}

if !to_remove.is_empty() {
println!(
"{}",
format!("The following packages will be {}:", "removed".red()).bold()
);
util::format_apt_pkglist(&to_remove);
println!();
}

if !to_purge.is_empty() {
println!(
"{}",
format!("The following packages (along with their configuration files) will be {}:", "removed".red()).bold()
);
util::format_apt_pkglist(&to_purge);
println!();
}

if !to_upgrade.is_empty() {
println!("{}", "The following packages will be upgraded:".bold());
util::format_apt_pkglist(&to_upgrade);
println!();
}

if !to_downgrade.is_empty() {
println!("{}", "The following packages will be downgraded:".bold());
util::format_apt_pkglist(&to_downgrade);
println!();
}

let (to_install_string, to_install_count) = {
let count = to_install.len();
let string = match count {
0 => "install".green(),
_ => "install".magenta(),
};
(string, count)
};
let (to_remove_string, to_remove_count) = {
let count = to_remove.len();
let string = match count {
0 => "remove".green(),
_ => "remove".magenta(),
};
(string, count)
};
let (to_upgrade_string, to_upgrade_count) = {
let count = to_upgrade.len();
let string = match count {
0 => "upgrade".green(),
_ => "upgrade".magenta(),
};
(string, count)
};
let (to_downgrade_string, to_downgrade_count) = {
let count = to_downgrade.len();
let string = match count {
0 => "downgrade".green(),
_ => "downgrade".magenta(),
};
(string, count)
};

println!("{}", "Review:".bold());

println!(
"{}",
format!("- {} to {}", to_install_count, to_install_string).bold()
);
println!(
"{}",
format!("- {} to {}", to_remove_count, to_remove_string).bold()
);
println!(
"{}",
format!("- {} to {}", to_upgrade_count, to_upgrade_string).bold()
);
println!(
"{}",
format!("- {} to {}", to_downgrade_count, to_downgrade_string).bold()
);

print!("{}", "\nWould you like to continue? [Y/n] ".bold());
io::stdout().flush().unwrap();

let mut resp = String::new();
io::stdin().read_line(&mut resp).unwrap();
resp.pop();

if !util::is_yes(&resp, true) {
println!("{}", "Aborting...".bold());
quit::with_code(exitcode::OK);
}

let mut updater: Box<dyn AcquireProgress> = Box::new(MistAcquireProgress {});
if self.apt_cache().get_archives(&mut updater).is_err() {
message::error("Failed to fetch needed archives\n");
quit::with_code(exitcode::UNAVAILABLE);
}

let mut installer: Box<dyn InstallProgress> = Box::new(MistInstallProgress {});
match self.apt_cache().do_install(&mut installer) {
OrderResult::Completed => (),
OrderResult::Incomplete => {
message::error("`cache.do_install()` returned `OrderResult::Incomplete`, which Mist doesn't know how to handle. Please report this as an issue.\n");
quit::with_code(exitcode::UNAVAILABLE);
}
OrderResult::Failed => {
message::error("There was an issue running the transaction.\n");
quit::with_code(exitcode::UNAVAILABLE);
}
}
}

/// Get a reference to the generated pkglist (contains a combined APT+MPR cache).
/*pub fn pkglist(&self) -> &Vec<CachePackage> {
&self.pkglist
Expand Down
10 changes: 9 additions & 1 deletion src/install.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ pub fn install(args: &clap::ArgMatches) {
quit::with_code(exitcode::USAGE);
}

for pkg in pkglist {
for pkg in &pkglist {
let apt_pkg = cache.get_apt_pkg(pkg);
let mpr_pkg = cache.get_mpr_pkg(pkg);

Expand Down Expand Up @@ -71,4 +71,12 @@ pub fn install(args: &clap::ArgMatches) {

// Get the ordering for MPR package installation.
let mpr_install_order = install_util::order_mpr_packages(&cache, &mpr_pkgs);

// Make sure any new marked APT packages are resolved properly.
if let Err(err) = cache.apt_cache().resolve(true) {
util::handle_errors(&err);
quit::with_code(exitcode::UNAVAILABLE);
}

cache.commit(&mpr_install_order);
}
18 changes: 11 additions & 7 deletions src/install_util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ fn resolve_mpr_package(
// If we've gone over the recursion limit, error out.
if current_recursion > recursion_limit {
message::error(&format!(
"Went over the recursion limit ({}) while resolving MPR dependencies. Try increasing it via the 'APT::pkgPackageManager::MaxLoopCount' config option.",
"Went over the recursion limit ({}) while resolving MPR dependencies. Try increasing it via the 'APT::pkgPackageManager::MaxLoopCount' config option.\n",
recursion_limit
));
quit::with_code(exitcode::SOFTWARE);
Expand All @@ -155,7 +155,6 @@ fn resolve_mpr_package(
MprPackage::get_depends,
MprPackage::get_makedepends,
MprPackage::get_checkdepends,
MprPackage::get_conflicts,
] {
if let Some(mut deps) = dep_func(mpr_pkg, Some(&system_distro), Some(&system_arch)) {
dep_groups.append(&mut deps);
Expand Down Expand Up @@ -189,8 +188,8 @@ fn resolve_mpr_package(
let dep = SplitPackage::new(dep_str);

// Find a version of a package that satisfies our requirements.
let cache_apt_pkg = cache.get_apt_pkg(dep_str);
let mpr_pkg = cache.mpr_cache().packages().get(dep_str);
let cache_apt_pkg = cache.get_apt_pkg(&dep.pkgname);
let mpr_pkg = cache.mpr_cache().packages().get(&dep.pkgname);

// We want to prefer the APT package for any dependencies, so test that first.
if let Some(pkg) = cache_apt_pkg {
Expand All @@ -214,6 +213,7 @@ fn resolve_mpr_package(
break;
} else if apt_pkg.marked_keep() {
apt_pkg.mark_install(true, false).then_some(()).unwrap();
apt_pkg.protect();
good_dep_found = true;
break;
}
Expand Down Expand Up @@ -258,18 +258,22 @@ fn resolve_mpr_package(

/// Order marked MPR packages for installation.
/// This function assumes all packages in `pkglist` actually exist.
pub fn order_mpr_packages(cache: &Cache, pkglist: &Vec<&str>) -> Vec<Vec<String>> {
pub fn order_mpr_packages(cache: &Cache, pkglist: &Vec<&str>) -> Vec<String> {
// The list of MPR packages that we need to install.
let mut mpr_pkglist = Vec::new();

// The maximum recursion limit for calls to `resolve_mpr_package`.
let recursion_limit = Config::new().int("APT::pkgPackageManager::MaxLoopCount", 50);

for pkg in pkglist {
// Append the package itself.
mpr_pkglist.push(pkg.to_string());

// Append its dependencies.
mpr_pkglist.append(&mut resolve_mpr_package(cache, pkg, 1, recursion_limit));
}

// TODO: This list needs ordered before returning it so that MPR packages are installed in the correct way.
todo!("ORDER THIS LIST BRO!");
vec![mpr_pkglist]
message::warning("PLEASE ORDER BEFORE MERGE {:?} THX!\n");
mpr_pkglist
}
2 changes: 1 addition & 1 deletion src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,7 @@ fn main() {
Some(("list", args)) => list::list(args),
Some(("list-comments", args)) => list_comments::list_comments(args),
Some(("quick-list", args)) => quick_list::quick_list(args),
Some(("remove", args)) => util::with_lock(|| remove::remove(args)),
Some(("remove", args)) => remove::remove(args),
Some(("search", args)) => search::search(args),
Some(("update", args)) => update::update(args),
Some(("whoami", args)) => whoami::whoami(args),
Expand Down
7 changes: 0 additions & 7 deletions src/progress.rs
Original file line number Diff line number Diff line change
Expand Up @@ -138,17 +138,10 @@ impl InstallProgress for MistInstallProgress {
percent,
(term_width - PROGRESS_STR_LEN).try_into().unwrap()
)
// `Colorize` annoyingly isn't working under replace via `"#".magenta()`, so manually use the escape codes here.
.replace('#', "\x1b[35m#\x1b[0m")
.bold()
);
io::stdout().flush().unwrap();

// If this is the last change, remove the progress reporting bar.
// if steps_done == total_steps {
// print!("{}", " ".repeat(term_width));
// print!("\x1b[0;{}r", term_height);
// }
// Finally, go back to the previous cursor position.
print!("\x1b8");
io::stdout().flush().unwrap();
Expand Down
14 changes: 13 additions & 1 deletion src/remove.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::{cache::run_transaction, message, util};
use crate::{apt_util, cache::run_transaction, message, util};
use rust_apt::cache::{Cache as AptCache, PackageSort};

pub fn remove(args: &clap::ArgMatches) {
Expand All @@ -13,6 +13,12 @@ pub fn remove(args: &clap::ArgMatches) {
let purge = args.is_present("purge");
let autoremove = args.is_present("autoremove");

// Lock the cache.
if let Err(err) = apt_util::apt_lock() {
util::handle_errors(&err);
quit::with_code(exitcode::UNAVAILABLE);
}

// Remove the user requested packages.
for pkgname in pkglist {
if let Some(pkg) = cache.get(pkgname) {
Expand Down Expand Up @@ -44,5 +50,11 @@ pub fn remove(args: &clap::ArgMatches) {
quit::with_code(exitcode::UNAVAILABLE);
}

// Unlock the cache so our transaction can complete.
if let Err(err) = apt_util::apt_unlock() {
util::handle_errors(&err);
quit::with_code(exitcode::UNAVAILABLE);
}

run_transaction(&cache, purge);
}
15 changes: 0 additions & 15 deletions src/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -196,21 +196,6 @@ pub fn is_yes(resp: &str, default: bool) -> bool {
resp.to_lowercase() == "y" || (resp.is_empty() && default)
}

/// Run a function with the lockfile locked, and abort if there's an error.
pub fn with_lock<F: Fn()>(func: F) {
if let Err(err) = apt_util::apt_lock() {
handle_errors(&err);
quit::with_code(exitcode::UNAVAILABLE);
}

func();

if let Err(err) = apt_util::apt_unlock() {
handle_errors(&err);
quit::with_code(exitcode::UNAVAILABLE);
}
}

/// Print out a question with options and get the result.
/// `multi_allowed` specifies if only a single option can be chosen.
pub fn ask_question(question: &str, options: &Vec<&str>, multi_allowed: bool) -> Vec<String> {
Expand Down
1 change: 0 additions & 1 deletion toast
Submodule toast deleted from 46fad1

0 comments on commit 7a18f2d

Please sign in to comment.