system_env/
deps.rs

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
use crate::env::*;
use crate::error::Error;
use crate::pm::*;
use serde::{Deserialize, Serialize};
use std::collections::HashMap;

/// A system dependency name in multiple formats.
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
#[cfg_attr(feature = "schematic", derive(schematic::Schematic))]
#[serde(untagged)]
pub enum DependencyName {
    /// A single package by name.
    Single(String),

    /// A single package by name, but with different names (values)
    /// depending on operating system or package manager (keys).
    SingleMap(HashMap<String, String>),

    /// Multiple packages by name.
    Multiple(Vec<String>),
}

impl Default for DependencyName {
    fn default() -> DependencyName {
        DependencyName::Single(String::new())
    }
}

/// Configuration for one or many system dependencies (packages).
#[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq, Serialize)]
#[cfg_attr(feature = "schematic", derive(schematic::Schematic))]
#[serde(default)]
pub struct DependencyConfig {
    /// Only install on this architecture.
    pub arch: Option<SystemArch>,

    /// The dependency name or name(s) to install.
    pub dep: DependencyName,

    /// Only install with this package manager.
    pub manager: Option<SystemPackageManager>,

    /// Only install on this operating system.
    pub os: Option<SystemOS>,

    /// Install using sudo.
    pub sudo: bool,

    /// The version to install.
    pub version: Option<String>,
}

impl DependencyConfig {
    /// Get a list of package names for the provided OS and package manager.
    pub fn get_package_names(
        &self,
        os: &SystemOS,
        pm: &SystemPackageManager,
    ) -> Result<Vec<String>, Error> {
        match &self.dep {
            DependencyName::Single(name) => Ok(vec![name.to_owned()]),
            DependencyName::SingleMap(map) => map
                .get(&pm.to_string())
                .or_else(|| map.get(&os.to_string()))
                .or_else(|| map.get("*"))
                .map(|name| vec![name.to_owned()])
                .ok_or(Error::MissingName),
            DependencyName::Multiple(list) => Ok(list.clone()),
        }
    }
}

/// Represents a system dependency (one or many packages) to install.
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
#[cfg_attr(feature = "schematic", derive(schematic::Schematic))]
#[serde(untagged)]
pub enum SystemDependency {
    /// A single package by name.
    Name(String),

    /// Multiple packages by name.
    Names(Vec<String>),

    /// Either a single or multiple package, defined as an
    /// explicit configuration object.
    Config(Box<DependencyConfig>),

    /// A single package by name, but with different names (values)
    /// depending on operating system or package manager (keys).
    Map(HashMap<String, String>),
}

impl SystemDependency {
    /// Create a single dependency by name.
    pub fn name(name: &str) -> SystemDependency {
        SystemDependency::Name(name.to_owned())
    }

    /// Create multiple dependencies by name.
    pub fn names<I, V>(names: I) -> SystemDependency
    where
        I: IntoIterator<Item = V>,
        V: AsRef<str>,
    {
        SystemDependency::Names(names.into_iter().map(|n| n.as_ref().to_owned()).collect())
    }

    /// Create a single dependency by name for the target architecture.
    pub fn for_arch(name: &str, arch: SystemArch) -> SystemDependency {
        SystemDependency::Config(Box::new(DependencyConfig {
            arch: Some(arch),
            dep: DependencyName::Single(name.into()),
            ..DependencyConfig::default()
        }))
    }

    /// Create a single dependency by name for the target operating system.
    pub fn for_os(name: &str, os: SystemOS) -> SystemDependency {
        SystemDependency::Config(Box::new(DependencyConfig {
            dep: DependencyName::Single(name.into()),
            os: Some(os),
            ..DependencyConfig::default()
        }))
    }

    /// Create a single dependency by name for the target operating system and architecture.
    pub fn for_os_arch(name: &str, os: SystemOS, arch: SystemArch) -> SystemDependency {
        SystemDependency::Config(Box::new(DependencyConfig {
            arch: Some(arch),
            dep: DependencyName::Single(name.into()),
            os: Some(os),
            ..DependencyConfig::default()
        }))
    }

    /// Convert and expand to a dependency configuration.
    pub fn to_config(self) -> DependencyConfig {
        match self {
            Self::Name(name) => DependencyConfig {
                dep: DependencyName::Single(name),
                ..DependencyConfig::default()
            },
            Self::Names(names) => DependencyConfig {
                dep: DependencyName::Multiple(names),
                ..DependencyConfig::default()
            },
            Self::Map(map) => DependencyConfig {
                dep: DependencyName::SingleMap(map),
                ..DependencyConfig::default()
            },
            Self::Config(config) => *config,
        }
    }
}