Skip to content

Commit

Permalink
feat(libscoop|resolve): added fn select_candidate
Browse files Browse the repository at this point in the history
Signed-off-by: Chawye Hsu <[email protected]>
  • Loading branch information
chawyehsu committed Jul 25, 2023
1 parent a2acb22 commit 0e296ea
Show file tree
Hide file tree
Showing 5 changed files with 69 additions and 58 deletions.
7 changes: 7 additions & 0 deletions crates/libscoop/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,11 +48,18 @@ pub enum Error {
#[error("error")]
InvalidHashValue(String),

/// Throw when receiving an invalid answer from the frontend.
#[error("invalid answer")]
InvalidAnswer,

/// Package not found error, this may occur when doing an explicit lookup
/// for a package and no record with the given query was found.
#[error("Could not find package named '{0}'")]
PackageNotFound(String),

#[error("Found multiple candidates for package named '{0}'")]
PackageMultipleCandidates(String),

/// Thrown when trying to perform (un)hold operation on a package that is
/// not installed.
#[error("package '{0}' is not installed")]
Expand Down
41 changes: 1 addition & 40 deletions crates/libscoop/src/operation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -307,46 +307,7 @@ pub fn package_sync(
}

if pkg.len() > 1 {
// Try to filter out installed ones if possible
pkg = pkg
.into_iter()
.filter(|p| !p.is_strictly_installed())
.collect::<Vec<_>>();
// Luckily, there is no more than one package left
if pkg.len() <= 1 {
continue;
}

if let Some(tx) = emitter.clone() {
println!(
"{}",
pkg.iter().map(|p| p.ident()).collect::<Vec<_>>().join(" ")
);
let question = pkg.iter().map(|p| p.ident()).collect::<Vec<_>>();
if tx.send(Event::SelectPackage(question)).is_ok() {
let rx = session.event_bus().inner_receiver();
while let Ok(answer) = rx.recv() {
if let Event::SelectPackageAnswer(idx) = answer {
println!("{}", idx);
if idx < pkg.len() {
pkg = vec![pkg[idx].clone()];
break;
} else {
return Err(Error::Custom(format!(
"Invalid package index: {}",
idx
)));
}
}
}
}
} else {
// TODO: handle this case smartly
return Err(Error::Custom(format!(
"Found multiple candidates for package named '{}'",
query
)));
}
resolve::select_candidate(session, &mut pkg)?;
}

packages.extend(pkg);
Expand Down
4 changes: 2 additions & 2 deletions crates/libscoop/src/package/mod.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
mod manifest;
pub(super) mod query;
pub(super) mod resolve;
pub mod query;
pub mod resolve;
mod sync;

use lazycell::LazyCell;
Expand Down
68 changes: 53 additions & 15 deletions crates/libscoop/src/package/resolve.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,11 @@
#![allow(dead_code)]

use crate::{
error::Fallible,
event,
internal::dag::DepGraph,
package::{query, QueryOption},
package::{query, Package, QueryOption},
Error, Session,
};

use super::Package;

pub(crate) fn resolve_dependencies(session: &Session, packages: &mut Vec<Package>) -> Fallible<()> {
let mut graph = DepGraph::<String>::new();
let mut to_resolve = packages.clone();
Expand All @@ -32,20 +29,16 @@ pub(crate) fn resolve_dependencies(session: &Session, packages: &mut Vec<Package
let queries = deps.iter().map(|d| d.as_str());

for query in queries {
let dpkg = query::query_synced(session, query, &options)?;
if dpkg.is_empty() {
let mut candidates = query::query_synced(session, query, &options)?;
if candidates.is_empty() {
return Err(Error::PackageNotFound(query.to_owned()));
}
if dpkg.len() > 1 {
// TODO: handle this case smartly
return Err(Error::Custom(format!(
"Found multiple candidates for package named '{}'",
query
)));
if candidates.len() > 1 {
select_candidate(session, &mut candidates)?;
}

if !packages.contains(&dpkg[0]) {
dpkgs.push(dpkg[0].clone());
if !packages.contains(&candidates[0]) {
dpkgs.push(candidates[0].clone());
}
}

Expand Down Expand Up @@ -98,3 +91,48 @@ pub(crate) fn resolve_dependents(session: &Session, packages: &mut Vec<Package>)

Ok(())
}

/// Select one from multiple package candidates, interactively if possible.
pub(crate) fn select_candidate(session: &Session, candidates: &mut Vec<Package>) -> Fallible<()> {
// Try to filter out installed ones if possible
candidates.retain(|p| !p.is_strictly_installed());

// Luckily, there is no more than one package left
if candidates.len() <= 1 {
return Ok(());
}

let name = candidates[0].name().to_owned();

// Sort candidates by package ident, in other words, by alphabetical order
// of bucket name.
candidates.sort_by_key(|p| p.ident());

// Only we can ask user/frontend to select one from multiple candidates
// when the outbound tx is available for us to do an interactive q&a.
if let Some(tx) = session.emitter() {
let question = candidates.iter().map(|p| p.ident()).collect::<Vec<_>>();

if tx.send(event::Event::SelectPackage(question)).is_ok() {
// The unwrap is safe here because we have obtained the outbound tx,
// so the inbound rx must be available.
let rx = session.receiver().unwrap();

while let Ok(answer) = rx.recv() {
if let event::Event::SelectPackageAnswer(idx) = answer {
// bounds check
if idx < candidates.len() {
*candidates = vec![candidates[idx].clone()];

return Ok(());
}

return Err(Error::InvalidAnswer);
}
}
}
}

// TODO: handle this case smartly using pre-defined bucket priority
Err(Error::PackageMultipleCandidates(name))
}
7 changes: 6 additions & 1 deletion crates/libscoop/src/session.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use flume::Sender;
use flume::{Receiver, Sender};
use lazycell::LazyCell;
use std::cell::{Ref, RefCell, RefMut};
use std::path::Path;
Expand Down Expand Up @@ -107,6 +107,11 @@ impl Session {
self.event_bus.borrow().map(|bus| bus.inner_sender())
}

/// Get an inbound receiver to reveive events.
pub(crate) fn receiver(&self) -> Option<&Receiver<Event>> {
self.event_bus.borrow().map(|bus| bus.inner_receiver())
}

/// Set the user agent for the session.
///
/// User agent is used when performing network related operations such as
Expand Down

0 comments on commit 0e296ea

Please sign in to comment.