Skip to content

Commit

Permalink
Merge pull request #53 from serpent-os/fix/registry-ordering
Browse files Browse the repository at this point in the history
Use vec instead of btreeset
  • Loading branch information
ikeycode authored Oct 12, 2023
2 parents fd5b914 + 944e2a9 commit 1f083be
Show file tree
Hide file tree
Showing 4 changed files with 73 additions and 47 deletions.
73 changes: 56 additions & 17 deletions moss/src/cli/install.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ use moss::{
};
use stone::read::Payload;
use thiserror::Error;
use tokio::fs;
use tui::{pretty::print_to_columns, MultiProgress, ProgressBar, ProgressStyle, Stylize};

use crate::cli::name_to_provider;
Expand Down Expand Up @@ -76,32 +77,51 @@ pub async fn handle(args: &ArgMatches) -> Result<(), Error> {

// Try stuffing everything into the transaction now
let mut tx = client.registry.transaction()?;
tx.add(input).await?;
tx.add(input.clone()).await?;

// Resolve and map it. Remove any installed items. OK to unwrap here because they're resolved already
let mut results = join_all(
let results = join_all(
tx.finalize()
.iter()
.map(|p| async { client.registry.by_id(p).boxed().next().await.unwrap() }),
)
.await
.into_iter()
.filter(|p| !p.flags.contains(Flags::INSTALLED))
.collect_vec();
.await;

let mut missing = results
.iter()
.filter(|p| !p.flags.contains(Flags::INSTALLED))
.collect_vec();
missing.sort_by_key(|p| p.meta.name.to_string());
missing.dedup_by_key(|p| p.meta.name.to_string());

// If no new packages exist, exit and print
// packages already installed
if missing.is_empty() {
let mut installed = results
.iter()
.filter(|p| p.flags.contains(Flags::INSTALLED) && input.contains(&p.id))
.collect_vec();
installed.sort_by_key(|p| p.meta.name.to_string());
installed.dedup_by_key(|p| p.meta.name.to_string());

if !installed.is_empty() {
println!("The following package(s) are already installed:");
println!();
print_to_columns(&installed);
}

results.sort_by_key(|p| p.meta.name.to_string());
results.dedup_by_key(|p| p.meta.name.to_string());
return Ok(());
}

println!("The following package(s) will be installed:");
println!();
print_to_columns(&results);
print_to_columns(&missing);
println!();

let state_ids = results.iter().map(|p| p.id.clone()).collect_vec();
let multi_progress = MultiProgress::new();

let total_progress = multi_progress.add(
ProgressBar::new(results.len() as u64).with_style(
ProgressBar::new(missing.len() as u64).with_style(
ProgressStyle::with_template("\n|{bar:20.cyan/blue}| {pos}/{len}")
.unwrap()
.progress_chars("■≡=- "),
Expand All @@ -110,7 +130,7 @@ pub async fn handle(args: &ArgMatches) -> Result<(), Error> {
total_progress.tick();

// Download and unpack each package
stream::iter(results.into_iter().map(|package| async {
stream::iter(missing.iter().map(|package| async {
// Setup the progress bar and set as downloading
let progress_bar = multi_progress.insert_before(
&total_progress,
Expand Down Expand Up @@ -186,7 +206,10 @@ pub async fn handle(args: &ArgMatches) -> Result<(), Error> {
}

// Consume the package in the metadb
client.install_db.add(package.id, package.meta).await?;
client
.install_db
.add(package.id.clone(), package.meta.clone())
.await?;

// Write installed line
multi_progress.println(format!(
Expand All @@ -209,10 +232,26 @@ pub async fn handle(args: &ArgMatches) -> Result<(), Error> {
.await?;

// Perfect, record state.
client
.state_db
.add(state_ids.as_slice(), None, None)
.await?;
let previous_state_pkgs = match client.installation.active_state {
Some(id) => client.state_db.get(&id).await?.packages,
None => vec![],
};
let new_state_pkgs = missing
.iter()
.map(|p| p.id.clone())
.chain(previous_state_pkgs)
.collect_vec();
let state = client.state_db.add(&new_state_pkgs, None, None).await?;

// Record state
// TODO: Refactor. This will happen w/ promoting state from staging
// but for now we are adding this to test list installed, etc
{
let usr = client.installation.root.join("usr");
fs::create_dir_all(&usr).await?;
let state_path = usr.join(".stateID");
fs::write(state_path, state.id.to_string()).await?;
}

// Remove progress
multi_progress.clear()?;
Expand Down
2 changes: 1 addition & 1 deletion moss/src/package/render.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ use crate::Package;
const COLUMN_PADDING: usize = 4;

/// Allow display packages in column form
impl ColumnDisplay for Package {
impl<'a> ColumnDisplay for &'a Package {
fn get_display_width(&self) -> usize {
self.meta.name.to_string().len()
+ self.meta.version_identifier.len()
Expand Down
28 changes: 16 additions & 12 deletions moss/src/registry/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,8 @@
//! Defines an encapsulation of "query plugins", including an interface
//! for managing and using them.
use std::collections::BTreeSet;

use futures::{stream, Future, Stream, StreamExt};
use itertools::Itertools;

use crate::package::{self, Package};
use crate::Provider;
Expand All @@ -24,13 +23,13 @@ pub mod transaction;
#[derive(Debug, Default)]
pub struct Registry {
/// Ordered set of plugins
plugins: BTreeSet<plugin::PriorityOrdered>,
plugins: Vec<Plugin>,
}

impl Registry {
/// Add a [`Plugin`] to the [`Registry`]
pub fn add_plugin(&mut self, plugin: Plugin) {
self.plugins.insert(plugin::PriorityOrdered(plugin));
self.plugins.push(plugin);
}

fn query<'a: 'b, 'b, F, I>(
Expand All @@ -41,14 +40,19 @@ impl Registry {
F: Future<Output = I>,
I: IntoIterator<Item = Package>,
{
stream::iter(self.plugins.iter().map(move |p| {
stream::once(async move {
let packages = query(&p.0).await;

stream::iter(packages)
})
.flatten()
}))
stream::iter(
self.plugins
.iter()
.sorted_by(|a, b| a.priority().cmp(&b.priority()).reverse())
.map(move |p| {
stream::once(async move {
let packages = query(p).await;

stream::iter(packages)
})
.flatten()
}),
)
.flatten()
}

Expand Down
17 changes: 0 additions & 17 deletions moss/src/registry/plugin/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -124,23 +124,6 @@ impl Plugin {
}
}

/// Defines a [`Plugin`] ordering based on "priority", sorted
/// highest to lowest
#[derive(Debug, PartialEq, Eq)]
pub(super) struct PriorityOrdered(pub Plugin);

impl PartialOrd for PriorityOrdered {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
Some(self.cmp(other))
}
}

impl Ord for PriorityOrdered {
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
self.0.priority().cmp(&other.0.priority()).reverse()
}
}

#[cfg(test)]
pub mod test {
use std::path::PathBuf;
Expand Down

0 comments on commit 1f083be

Please sign in to comment.