use crate::package_manager::{PackageManager, PackageManagerTrait};
use anyhow::Result;
use colored::Colorize;
use itertools::Itertools;
use serde::{Deserialize, Serialize};
use std::{
cmp::Ordering,
iter::{self, IntoIterator},
ops::Deref,
string::String,
};
#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)]
pub struct Package {
source: PackageManager,
name: String,
#[serde(default)]
flags: Vec<String>,
}
impl Package {
pub fn new(source: PackageManager, name: String, flags: Vec<String>) -> Self {
Self {
source,
name,
flags,
}
}
pub fn name(&self) -> &str {
&self.name
}
pub fn full_command(&self) -> String {
self.flags.iter().chain(iter::once(&self.name)).join(" ")
}
#[cfg(not(target_os = "windows"))]
pub fn install_command(&self) -> String {
if self.source.needs_root() {
format!(
"sudo {} {}",
self.source.install_command(),
self.full_command()
)
} else {
format!("{} {}", self.source.install_command(), self.full_command())
}
}
#[cfg(target_os = "windows")]
pub fn install_command(&self) -> String {
format!("{} {}", self.source.install_command(), self.full_command())
}
pub fn color_full_name(&self) -> String {
if self.flags.is_empty() {
format!(
"{} ({})",
self.name.yellow(),
self.source.full_name().green()
)
} else {
format!(
"{} {} ({})",
self.flags.iter().join(" ").dimmed(),
self.name.yellow(),
self.source.full_name().green(),
)
}
}
#[allow(unused)]
pub fn flags(&self) -> &Vec<String> {
&self.flags
}
pub fn is_installed(&self) -> Result<bool> {
self.source.package_is_installed(self)
}
pub fn is_available(&self) -> bool {
self.source.is_available()
}
}
impl Ord for Package {
fn cmp(&self, other: &Self) -> Ordering {
self.full_command().cmp(&other.full_command())
}
}
impl PartialOrd for Package {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Packages(Vec<Package>);
impl Packages {
pub fn empty() -> Self {
Self(vec![])
}
pub fn from_line(line: &str) -> Self {
let lines = line
.split(|c| c == ';' || c == '|' || c == '&' || c == '\r' || c == '\n')
.flat_map(|line| {
PackageManager::from_line_iter(line).map(move |manager| (line, manager))
})
.flat_map(|(line, package_manager)| package_manager.catch(line))
.collect();
Self(lines)
}
pub fn merge(&mut self, other: &mut Packages) {
self.0.append(&mut other.0);
self.0.sort();
self.0.dedup();
}
pub fn filter_saved_packages(&mut self, old: &Packages) {
self.0
.retain(|package| !old.iter().any(|old_package| package == old_package));
}
pub fn dedup(&mut self) {
self.0.dedup();
}
pub fn commit_message(&self) -> String {
match self.0.len() {
0 => panic!("Can't create a commit message for empty changes"),
1 => format!("Emplace - mirror package \"{}\"", self.0[0].full_command()),
n => format!("Emplace - mirror {} packages", n),
}
}
}
impl IntoIterator for Packages {
type Item = Package;
type IntoIter = std::vec::IntoIter<Self::Item>;
fn into_iter(self) -> Self::IntoIter {
self.0.into_iter()
}
}
impl Deref for Packages {
type Target = Vec<Package>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl From<Vec<Package>> for Packages {
fn from(x: Vec<Package>) -> Self {
Packages(x)
}
}