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
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
use crate::release_channel::Channel;
use crate::{ManifestaError, TResult};

#[derive(Debug)]
pub struct MetaManifest {
    manifests: Vec<ManifestSource>,
}

impl MetaManifest {
    pub(crate) fn try_from_str<T: AsRef<str>>(item: T) -> TResult<Self> {
        let item = item.as_ref();

        let manifests = item
            .lines()
            .map(ManifestSource::try_from_str)
            .collect::<TResult<Vec<_>>>()?;

        Ok(Self { manifests })
    }

    pub fn manifests(&self) -> &[ManifestSource] {
        &self.manifests
    }
}

#[derive(Debug)]
pub struct ManifestSource {
    url: String,
    channel: Channel,
    date: String,
}

impl ManifestSource {
    pub(crate) fn try_from_str<T: AsRef<str>>(item: T) -> TResult<Self> {
        let item = item.as_ref();

        let channel = Self::parse_channel(item)?;
        let date = Self::parse_date(item)?;

        Ok(Self {
            url: format!("https://{}", item),
            channel,
            date,
        })
    }

    pub(crate) fn url(&self) -> &str {
        &self.url
    }

    pub(crate) fn channel(&self) -> Channel {
        self.channel
    }

    pub(crate) fn date(&self) -> &str {
        &self.date
    }

    fn parse_date(input: &str) -> TResult<String> {
        // an input has the following form:
        // `static.rust-lang.org/dist/YYYY-MM-DD/channel-rust-CHANNEL.toml`
        // where YYYY    is the year,
        //   and MM      is the month,
        //   and DD      is the day,
        //   and CHANNEL is one of 'stable' | 'beta' | 'nightly'

        let date = input.get(26..36).ok_or(ManifestaError::ParseManifestDate)?;
        Ok(date.to_string())
    }

    fn parse_channel(input: &str) -> TResult<Channel> {
        Ok(if input.contains("beta") {
            Channel::Beta
        } else if input.contains("nightly") {
            Channel::Nightly
        } else if input.contains("stable") {
            Channel::Stable
        } else {
            return Err(ManifestaError::ParseManifestSource);
        })
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::dl::fetch_meta_manifest;

    #[test]
    fn test_parse_meta_manifest() {
        let meta_file = fetch_meta_manifest().unwrap();
        let buffer = meta_file.load().unwrap();
        let meta_manifest = MetaManifest::try_from_str(String::from_utf8(buffer).unwrap());
        assert!(meta_manifest.is_ok());
    }
}