use std::vec::Vec;
use anyhow::Result;
use crate::app::App;
use crate::db::{Database, PackageInfo};
use crate::install::install_with_package_and_requested_version;
use crate::store::Store;
use crate::ui::Ui;
fn get_upgrades(ui: &Ui, store: &dyn Store, db: &Database) -> Result<Vec<PackageInfo>> {
let mut upgrades = Vec::<PackageInfo>::new();
for info in db.get_installed_packages()? {
let package = match store.get_package(&info.name) {
Ok(x) => x,
Err(x) => {
ui.warn(&format!("Can't check updates for {}: {}", info.name, x));
continue;
}
};
if let Some(available_version) = package.get_version_matching(&info.requested_version) {
if available_version > &info.installed_version {
upgrades.push(info);
}
}
}
Ok(upgrades)
}
pub fn upgrade(app: &App, ui: &Ui) -> Result<()> {
ui.info("Checking upgrades");
let to_upgrade = get_upgrades(&ui.nest(), &*app.store, &app.database)?;
if to_upgrade.is_empty() {
ui.info("No packages to upgrade");
return Ok(());
}
for info in to_upgrade {
ui.info(&format!("Upgrading {}", info.name));
install_with_package_and_requested_version(
app,
&ui.nest(),
&info.name,
&info.requested_version,
)
.unwrap_or_else(|x| {
ui.error(&format!("Error: Failed to upgrade {}: {}", info.name, x));
});
}
Ok(())
}
#[cfg(test)]
mod tests {
use super::*;
use std::collections::{HashMap, HashSet};
use std::path::PathBuf;
use anyhow::anyhow;
use semver::{Version, VersionReq};
use crate::package::Package;
use crate::store::SearchHit;
struct FakeStore {
packages: HashMap<String, Package>,
}
impl FakeStore {
fn new() -> FakeStore {
FakeStore {
packages: HashMap::<String, Package>::new(),
}
}
}
impl Store for FakeStore {
fn setup(&self) -> Result<()> {
Ok(())
}
fn update(&self) -> Result<()> {
Ok(())
}
fn get_package(&self, name: &str) -> Result<Package> {
let pkg = self
.packages
.get(name)
.ok_or_else(|| anyhow!("No such package: {}", name))?;
Ok(pkg.clone())
}
fn search(&self, _query: &str) -> Result<Vec<SearchHit>> {
Ok(vec![])
}
}
#[test]
fn get_upgrades_should_return_an_empty_list_if_nothing_to_do() {
let db = Database::new_in_memory().unwrap();
db.create().unwrap();
let files = HashSet::<PathBuf>::new();
db.add_package("foo", &Version::new(1, 2, 0), &VersionReq::STAR, &files)
.unwrap();
let mut store = FakeStore::new();
let package = Package::from_yaml_str(
"
name: test
description: desc
homepage:
releases:
1.2.0:
any:
url: https://example.com
sha256: 1234
installs: {}
",
)
.unwrap();
store.packages.insert("foo".to_string(), package);
let upgrades = get_upgrades(&Ui::default(), &store, &db).unwrap();
assert_eq!(upgrades, vec![]);
}
#[test]
fn get_upgrades_should_return_an_empty_list_if_upgrade_is_outside_requested_version() {
let db = Database::new_in_memory().unwrap();
db.create().unwrap();
let files = HashSet::<PathBuf>::new();
db.add_package(
"foo",
&Version::new(1, 2, 0),
&VersionReq::parse("1.2.*").unwrap(),
&files,
)
.unwrap();
let mut store = FakeStore::new();
let package = Package::from_yaml_str(
"
name: test
description: desc
homepage:
releases:
1.3.0:
any:
url: https://example.com
sha256: 1234
installs: {}
",
)
.unwrap();
store.packages.insert("foo".to_string(), package);
let upgrades = get_upgrades(&Ui::default(), &store, &db).unwrap();
assert_eq!(upgrades, vec![]);
}
#[test]
fn get_upgrades_should_return_upgrade_list() {
let db = Database::new_in_memory().unwrap();
db.create().unwrap();
let files = HashSet::<PathBuf>::new();
db.add_package("foo", &Version::new(1, 2, 0), &VersionReq::STAR, &files)
.unwrap();
let mut store = FakeStore::new();
let package = Package::from_yaml_str(
"
name: test
description: desc
homepage:
releases:
1.3.0:
any:
url: https://example.com
sha256: 1234
installs: {}
",
)
.unwrap();
store.packages.insert("foo".to_string(), package);
let upgrades = get_upgrades(&Ui::default(), &store, &db).unwrap();
assert_eq!(
upgrades,
vec![PackageInfo {
name: "foo".to_string(),
installed_version: Version::new(1, 2, 0),
requested_version: VersionReq::STAR
}]
);
}
}