use std::collections::BTreeMap;
use std::path::Path;
use pmpx_detect::{Candidate, Pins, Preferences};
use pmpx_plugin::{Family, SelectionReason};
use crate::store::PluginSet;
use crate::Event;
use pmpx_project::{GlobalConfig, MergedProjectConfig};
pub use pmpx_detect::{DetectFailure, FamilyScore, Reason, ScoredPlugin, Selection};
struct Dir<'a> {
root: &'a Path,
}
impl pmpx_detect::Presence for Dir<'_> {
fn has(&self, relative: &str) -> bool {
self.root.join(relative).exists()
}
}
pub fn presence(root: &Path) -> impl pmpx_detect::Presence + '_ {
Dir { root }
}
pub fn candidates(set: &PluginSet) -> Vec<Candidate> {
set.plugins
.iter()
.map(|p| Candidate {
crate_name: p.crate_name().to_string(),
name: p.name().to_string(),
family: p
.family
.as_ref()
.map(Family::as_str)
.unwrap_or("")
.to_string(),
strong: p.strong.clone(),
weak: p.weak.clone(),
problem: p.problem().map(str::to_string),
})
.collect()
}
pub fn pins(merged: &MergedProjectConfig) -> Pins {
merged.plugin.clone()
}
pub fn preferences(global: &GlobalConfig) -> Preferences {
Preferences {
family_priority: global.plugin.family_priority.clone(),
priority: global.plugin.priority.clone(),
}
}
pub fn reason_of(reason: Reason) -> SelectionReason {
match reason {
Reason::Scored => SelectionReason::Scored,
Reason::Pinned => SelectionReason::Pinned,
Reason::Explicit => SelectionReason::Explicit,
}
}
pub fn score_all(
set: &PluginSet,
root: &Path,
merged: &MergedProjectConfig,
events: &mut dyn FnMut(Event),
) -> BTreeMap<String, FamilyScore> {
let started = std::time::Instant::now();
let families = pmpx_detect::score_all(&candidates(set), &presence(root), &pins(merged));
events(Event::Phase {
name: "detect.score",
micros: started.elapsed().as_micros(),
detail: format!(
"{} plugins, {} marker names",
set.usable().count(),
set.detect_names().len()
),
});
families
}
pub fn select(
set: &PluginSet,
root: &Path,
merged: &MergedProjectConfig,
global: &GlobalConfig,
explicit: Option<&str>,
events: &mut dyn FnMut(Event),
) -> Result<Selection, DetectFailure> {
let families = score_all(set, root, merged, events);
select_from_scores(set, root, &families, merged, global, explicit, events)
}
pub fn select_from_scores(
set: &PluginSet,
root: &Path,
families: &BTreeMap<String, FamilyScore>,
merged: &MergedProjectConfig,
global: &GlobalConfig,
explicit: Option<&str>,
events: &mut dyn FnMut(Event),
) -> Result<Selection, DetectFailure> {
let started = std::time::Instant::now();
let result = pmpx_detect::select_from_scores(
&candidates(set),
&presence(root),
&pins(merged),
&preferences(global),
explicit,
families,
);
events(Event::Phase {
name: "detect.decide",
micros: started.elapsed().as_micros(),
detail: match &result {
Ok(selection) => format!(
"{} ({}, {} pts)",
selection.name, selection.family, selection.score
),
Err(failure) => format!("nothing selected: {}", failure.message()),
},
});
result
}