1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
use std::path::Path;

pub use gh_crate_meta::*;
pub use quickinstall::*;

use crate::{PkgFmt, PkgMeta};

mod gh_crate_meta;
mod quickinstall;

#[async_trait::async_trait]
pub trait Fetcher {
    /// Create a new fetcher from some data
    async fn new(data: &Data) -> Result<Box<Self>, anyhow::Error>
    where
        Self: Sized;

    /// Fetch a package
    async fn fetch(&self, dst: &Path) -> Result<(), anyhow::Error>;

    /// Check if a package is available for download
    async fn check(&self) -> Result<bool, anyhow::Error>;

    /// Return the package format
    fn pkg_fmt(&self) -> PkgFmt;

    /// A short human-readable name or descriptor for the package source
    fn source_name(&self) -> String;

    /// Should return true if the remote is from a third-party source
    fn is_third_party(&self) -> bool;
}

/// Data required to fetch a package
#[derive(Debug)]
pub struct Data {
    pub name: String,
    pub target: String,
    pub version: String,
    pub repo: Option<String>,
    pub meta: PkgMeta,
}

#[derive(Default)]
pub struct MultiFetcher {
    fetchers: Vec<Box<dyn Fetcher>>,
}

impl MultiFetcher {
    pub fn add(&mut self, fetcher: Box<dyn Fetcher>) {
        self.fetchers.push(fetcher);
    }

    pub async fn first_available(&self) -> Option<&dyn Fetcher> {
        for fetcher in &self.fetchers {
            if fetcher.check().await.unwrap_or(false) {
                return Some(&**fetcher);
            }
        }

        None
    }
}