huber 1.0.11

Huber, simplify GitHub package management
Documentation
use std::cmp::Ordering;
use std::fmt;
use std::fmt::{Display, Formatter};
use std::str::FromStr;

use semver::Version;
use serde::{Deserialize, Serialize};

use crate::model::package::{
    GithubAsset, GithubPackage, Package, PackageDetailType, PackageSource,
};
use crate::semver::VersionCompareTrait;

pub trait SortModelTrait {
    fn sort_by_version(&mut self);
    fn sort_by_name(&mut self);
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ReleaseIndex {
    pub name: String,
    pub version: String,
    pub owner: String,
    pub source: String,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Release {
    pub name: String,
    pub version: String,
    pub current: bool,
    pub package: Package,
    pub executables: Option<Vec<String>>,
    pub kind: Option<ReleaseKind>,
}

unsafe impl Send for Release {}

unsafe impl Sync for Release {}

#[derive(Debug, Copy, Clone, Serialize, Deserialize, Eq, PartialEq)]
pub enum ReleaseKind {
    Draft,
    PreRelease,
    Release,
}

impl Release {
    pub fn compare(&self, pkg: &Release) -> anyhow::Result<Ordering> {
        if Version::parse(&self.version).is_ok() {
            let v1 = Version::from_str(self.version.trim_start_matches("v"))?;
            let v2 = Version::from_str(pkg.version.trim_start_matches("v"))?;

            Ok(v1.cmp(&v2))
        } else {
            Ok(self.version.cmp(&pkg.version))
        }
    }
}

impl Display for Release {
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
        write!(
            f,
            "{} (version: {}, source: {})",
            self.name, self.version, self.package.source
        )
    }
}

impl From<octocrab::models::repos::Release> for Release {
    fn from(r: octocrab::models::repos::Release) -> Self {
        let release_kind = if r.draft {
            ReleaseKind::Draft
        } else if r.prerelease {
            ReleaseKind::PreRelease
        } else {
            ReleaseKind::Release
        };

        Release {
            name: "".to_string(),
            version: r.tag_name.clone(),
            current: false,
            package: Package {
                name: "".to_string(),
                source: PackageSource::Github {
                    owner: "".to_string(),
                    repo: "".to_string(),
                },
                targets: vec![],
                detail: Some(PackageDetailType::Github {
                    package: GithubPackage {
                        url: r.url.into(),
                        html_url: r.html_url.into(),
                        assets_url: r.assets_url.into(),
                        upload_url: r.upload_url,
                        tarball_url: r.tarball_url.map_or("".to_string(), |s| s.to_string()),
                        zipball_url: r.zipball_url.map_or("".to_string(), |s| s.to_string()),
                        id: *r.id,
                        tag_name: r.tag_name.clone(),
                        target_commitish: r.target_commitish,
                        name: r.name.unwrap_or_default(),
                        body: r.body.unwrap_or_default(),
                        draft: r.draft,
                        prerelease: r.prerelease,
                        created_at: r.created_at.map_or("".to_string(), |s| s.to_string()),
                        published_at: r.published_at.map_or("".to_string(), |s| s.to_string()),
                        assets: r.assets.into_iter().map(GithubAsset::from).collect(),
                    },
                }),
                version: Some(r.tag_name.clone()),
                description: None,
                release_kind: Some(release_kind),
            },
            executables: None,
            kind: Some(release_kind),
        }
    }
}

impl SortModelTrait for Vec<Release> {
    fn sort_by_version(&mut self) {
        self.sort_by(|x, y| y.version.cmp_version(&x.version).unwrap());
    }

    fn sort_by_name(&mut self) {
        self.sort_by(|x, y| x.name.cmp(&y.name));
    }
}