diff --git a/src/db/mod.rs b/src/db/mod.rs new file mode 100644 index 0000000..6a08113 --- /dev/null +++ b/src/db/mod.rs @@ -0,0 +1,64 @@ +use { + crate::{Repository, Package, Version}, + serde::{Deserialize, Serialize}, + std::{collections::HashMap, error::Error}, + url::Url, +}; + +pub struct Update { + pub name: String, + pub version: Version, + pub url: Url, +} + +#[derive(Clone, Debug, Deserialize, Serialize)] +pub struct Database { + pub packages: HashMap, + pub available: HashMap, +} + +impl Database { + pub fn update(&mut self) -> Result<(), Box> { + unimplemented!(); + } + + pub fn get_upgradable(&mut self) -> Result, Box> { + self.update()?; + let mut updates = HashMap::::new(); + for local_package in self.packages.values() { + let name = local_package.name.clone(); + for repo in self.available.values() { + // Check if the remote has a package by this name + if let Some(remote_package) = repo.packages.get(&name) { + // Check if the remote package is an update + if remote_package.is_upgrade(&local_package) { + // Check if we've already pulled in an update from another repo, + // and if so compare versions + if let Some(other_update) = updates.get(&name) { + if remote_package.version > other_update.version { + // The remote version is an update to the already + // pulled in update, so swap it out + let update = Update { + name: name.clone(), + version: remote_package.version, + url: repo.base_url.clone(), + }; + updates.insert(name, update); + } + } else { + // First time we've seen this update, so insert it + // into our hashmap + let update = Update { + name: name.clone(), + version: remote_package.version, + url: repo.base_url, + }; + updates.insert(name, update); + } + } + } + } + } + Ok(updates) + } +} diff --git a/src/lib.rs b/src/lib.rs index 5bbcaf3..eea7492 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,4 +1,5 @@ #![warn(clippy::all, clippy::pedantic)] +mod db; mod hooks; mod item; mod package; @@ -7,9 +8,10 @@ mod repository; mod version; pub use { + db: Database, hooks::Hooks, item::Item, - package::{create as create_package, Dependency, Package, Specs}, + package::{create_package, Dependency, Package, Specs}, plist::*, repository::Repository, tar, diff --git a/src/package/mod.rs b/src/package/mod.rs index b3e1f1b..13877ce 100644 --- a/src/package/mod.rs +++ b/src/package/mod.rs @@ -37,6 +37,7 @@ pub struct Group { } #[derive(Clone, Debug, Default, Serialize, Deserialize, PartialEq)] +/// the metadata associated with a package pub struct Package { /// The name of the package minus all version information pub name: String, @@ -91,7 +92,7 @@ impl Package { to_string_pretty(self, cfg) } - pub fn save_ron_and_create_tar_node(&self, outdir: &Path) -> Result> { + fn save_ron_and_create_tar_node(&self, outdir: &Path) -> Result> { if !outdir.exists() { fs::create_dir_all(outdir)?; } @@ -112,12 +113,35 @@ impl Package { Ok(node) } + /// Returns the formatted full package name including version and release strings pub fn fullname(&self) -> String { format!("{}-{}_{}", self.name, self.version, self.release) } + + /// Tests whether this package is an update for another + pub fn is_upgrade(&self, other: &Self) -> bool { + self.name == other.name && self.version > other.version + } } -pub fn create(path: &Path, specs: Specs, outdir: &Path) -> Result<(), Box> { +/// Creates a package archive given a path to the included files, a package `Specs` +/// file and an output directory +/// +/// ## Usage +/// ``` +/// use std::path::Path; +/// use hpk::Specs; +/// +/// let staging = Path::new("staged"); +/// let outdir = Path::new("package"); +/// let specs = Specs { +/// name: "foo".to_string(), +/// version: "0.42.0".parse().unwrap(), +/// description: "an example package".to_string(), +/// ..Default::default() +/// }; +/// let result = hpk::create_package(&staging, specs, &outdir); +pub fn create_package(path: &Path, specs: Specs, outdir: &Path) -> Result<(), Box> { if !outdir.exists() { fs::create_dir_all(outdir)?; }