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
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
use super::ini::IniManifest;
use crate::error::*;
use crate::unity::urls::DownloadURL;
use crate::unity::{Component, Module, Modules, ModulesMap, Version};
use reqwest::Url;
use std::collections::hash_map::Iter;
use std::fs::File;
use std::io::{self, Read, Write};
use std::ops::{Deref, DerefMut};
use std::path::Path;

#[derive(Debug)]
pub struct Manifest<'a> {
    version: &'a Version,
    base_url: DownloadURL,
    modules: ModulesMap,
    editor: Module,
}

impl<'a> Manifest<'a> {
    pub fn load(version: &'a Version) -> Result<Manifest<'a>> {
        let mut components = IniManifest::load(version)?;
        let editor = components
            .remove(&Component::Editor)
            .ok_or(UvmErrorKind::ManifestReadError)?;
        let editor = Module::from(((Component::Editor, editor), version));

        let modules: ModulesMap = Self::get_modules(components, version);
        let base_url = DownloadURL::new(&version)?;

        Ok(Manifest {
            version,
            base_url,
            modules,
            editor,
        })
    }

    pub fn read_manifest_version_from_path<P: AsRef<Path>>(manifest_path: P) -> Result<Version> {
        IniManifest::read_manifest_version_from_path(manifest_path)
    }

    pub fn read_manifest_version<R: Read>(reader: R) -> Result<Version> {
        IniManifest::read_manifest_version(reader)
    }

    pub fn from_reader<R: Read>(version: &'a Version, manifest: R) -> Result<Manifest<'a>> {
        let base_url = DownloadURL::new(&version)?;
        let mut components = IniManifest::from_reader(version, manifest)?;
        let editor = components
            .remove(&Component::Editor)
            .ok_or(UvmErrorKind::ManifestReadError)?;
        let editor = Module::from(((Component::Editor, editor), version));
        let modules: ModulesMap = Self::get_modules(components, version);

        Ok(Manifest {
            version,
            base_url,
            modules,
            editor,
        })
    }

    pub fn new<P: AsRef<Path>>(version: &'a Version, manifest_path: P) -> Result<Manifest<'a>> {
        let manifest = File::open(manifest_path)?;
        Self::from_reader(version, manifest)
    }

    fn get_modules(components: IniManifest, version: &Version) -> ModulesMap {
        use crate::unity::version::module::ModuleBuilder;

        let modules = ModuleBuilder::from(components, version);
        modules.into_iter().collect()
    }

    pub fn url(&self, component: Component) -> Option<Url> {
        self.get(&component)
            .and_then(|m| Url::parse(&m.download_url).ok())
    }

    pub fn size(&self, component: Component) -> Option<u64> {
        self.get(&component).map(|m| m.download_size)
    }

    pub fn version(&self) -> &Version {
        self.version
    }

    pub fn iter(&self) -> Iter<'_, Component, Module> {
        self.modules.iter()
    }

    pub fn get(&self, component: &Component) -> Option<&Module> {
        match component {
            Component::Editor => Some(&self.editor),
            _ => self.modules.get(component),
        }
    }

    pub fn get_mut(&mut self, component: &Component) -> Option<&mut Module> {
        match component {
            Component::Editor => Some(&mut self.editor),
            _ => self.modules.get_mut(component),
        }
    }

    pub fn mark_installed_modules<C>(&mut self, components: C)
    where
        C: IntoIterator<Item = Component>,
    {
        for component in components {
            if let Some(m) = self.get_mut(&component) {
                m.selected = true;
            }
        }
    }

    pub fn modules_json(&self) -> io::Result<String> {
        let modules: Vec<&Module> = self.modules_map().values().collect();
        let j = serde_json::to_string_pretty(&modules)?;
        Ok(j)
    }

    pub fn write_modules_json<W: Write>(&self, writer:&mut W) -> io::Result<()> {
        let json = self.modules_json()?;
        write!(writer, "{}", json)?;
        trace!("{}", json);
        Ok(())
    }

    pub fn modules_map(&self) -> &ModulesMap {
        &self.modules
    }

    /// Takes ownership of the `Manifest` and returns the internal `Modules` map.
    pub fn into_modules_map(self) -> ModulesMap {
        self.modules
    }

    pub fn into_modules(self) -> Modules {
        self.modules.into()
    }
}

impl Deref for Manifest<'_> {
    type Target = ModulesMap;

    fn deref(&self) -> &Self::Target {
        self.modules_map()
    }
}

impl DerefMut for Manifest<'_> {
    fn deref_mut(&mut self) -> &mut Self::Target {
        &mut self.modules
    }
}

impl AsRef<Version> for Manifest<'_> {
    fn as_ref(&self) -> &Version {
        self.version
    }
}