foreman 1.7.0

Toolchain manager for simple binary tools
mod artifactory;
mod github;
mod gitlab;

use crate::{error::ForemanResult, paths::ForemanPaths};
use artifactory::ArtifactoryProvider;
use github::GithubProvider;
use gitlab::GitlabProvider;
use std::{collections::HashMap, fmt};
use url::Url;

pub trait ToolProviderImpl: fmt::Debug {
    fn get_releases(&self, repo: &str, host: &Url) -> ForemanResult<Vec<Release>>;

    fn download_asset(&self, url: &str) -> ForemanResult<Vec<u8>>;
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum Provider {
    Github,
    Gitlab,
    Artifactory,
}

impl fmt::Display for Provider {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(
            f,
            "{}",
            match self {
                Provider::Github => "GitHub",
                Provider::Gitlab => "GitLab",
                Provider::Artifactory => "Artifactory",
            }
        )
    }
}

#[derive(Debug)]
pub struct ToolProvider {
    providers: HashMap<Provider, Box<dyn ToolProviderImpl>>,
}

impl ToolProvider {
    pub fn new(paths: &ForemanPaths) -> Self {
        let mut providers: HashMap<Provider, Box<dyn ToolProviderImpl>> = HashMap::default();
        providers.insert(
            Provider::Github,
            Box::new(GithubProvider::new(paths.clone())),
        );
        providers.insert(
            Provider::Gitlab,
            Box::new(GitlabProvider::new(paths.clone())),
        );
        providers.insert(
            Provider::Artifactory,
            Box::new(ArtifactoryProvider::new(paths.clone())),
        );
        Self { providers }
    }

    pub fn get(&self, provider: &Provider) -> &dyn ToolProviderImpl {
        self.providers
            .get(provider)
            .unwrap_or_else(|| {
                panic!(
                    "unable to find tool provider implementation for {}",
                    provider
                )
            })
            .as_ref()
    }
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Release {
    pub tag_name: String,
    pub prerelease: bool,
    pub assets: Vec<ReleaseAsset>,
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ReleaseAsset {
    pub url: String,
    pub name: String,
}