please-install 1.2.0

A unified interface package manager for many OSes
Documentation
use serde::{Serialize, Deserialize};

use crate::vendors::Vendor;

#[derive(Clone, Debug, Serialize, Deserialize, Eq, Ord)]
pub struct Package {
    pub name: String,
    pub vendor: Vendor,
    pub version: Option<String>,
    pub repo: Option<String>,
}

impl Package {

    fn ordering_string(&self) -> String {
        format!("{}::{}", self.vendor, self.to_string())
    }

    fn archlinux_ordering_string(&self) -> String {
        format!("{}::{}", self.archlinux_repo_prefix(), self.to_string())
    }

    fn archlinux_repo_prefix(&self) -> String {
        if let Some(repo) = &self.repo {
            match repo.as_str() {
                "core" => "0",
                "extra" => "1",
                "multilib" => "2",
                "extra-testing" => "3",
                "multilib-testing" => "4",
                "chaotic-aur" => "6",
                "aur" => "8",
                _ => "5",

            }.to_string()

        } else {
            "7".to_string()
        }

    }
}

impl PartialEq for Package {
    fn eq(&self, other: &Self) -> bool {
        self.name == other.name && self.vendor == self.vendor
    }
}

impl PartialOrd for Package {
    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
        let vendor1 =
            match self.vendor {
                Vendor::Pacman |
                Vendor::Rua |
                Vendor::Yay => self.archlinux_ordering_string(),
                _ => self.ordering_string(),
            };
        let vendor2 =
            match other.vendor {
                Vendor::Pacman |
                Vendor::Rua |
                Vendor::Yay => self.archlinux_ordering_string(),
                _ => self.ordering_string(),
            };

        vendor1.partial_cmp(&vendor2)
    }
}

impl ToString for Package {
    fn to_string(&self) -> String {
        let mut res = self.name.clone();
        if let Some(repo) = &self.repo {
            res = format!("{}/{}", repo, self.name);
        }
        if let Some(version) = &self.version {
            res.push_str(&self.vendor.version_sep());
            res.push_str(version);
        }
        res
    }
}

impl From<&str> for Package {
    fn from(s: &str) -> Self {
        let mut name: String;
        let mut version = None;
        let mut repo = None;
        match s.rfind('/') {
            Some(idx) => {
                name = s[idx + 1..].to_string();
                let _ = repo.insert(s[..idx].to_string());
            },
            None => name = s.to_string(),
        }
        match name.rfind('@') {
            Some(idx) => {
                let _ = version.insert(name[idx + 1..].to_string());
                name = name[..idx].to_string();
            },
            None => (),
        }
        if version.is_none() {
            match name.rfind('=') {
                Some(idx) => {
                    let _ = version.insert(name[idx + 1..].to_string());
                    name = name[..idx].to_string();
                },
                None => (),
            }
        }
        if version.is_none() {
            match name.rfind("//") {
                Some(idx) => {
                    let _ = version.insert(name[idx + 2..].to_string());
                    name = name[..idx].to_string();
                },
                None => (),
            }
        }
        Package { name, version, repo, vendor: Vendor::default() }
    }
}

#[derive(Debug, Serialize, Deserialize)]
pub struct PackageFile {
    pub installed: Vec<Package>,
}