origin_manifest/
distribution.rs1use serde::{Deserialize, Serialize};
8
9#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Serialize, Deserialize)]
11#[serde(rename_all = "kebab-case")]
12pub enum Channel {
13 #[default]
14 Stable,
15 Beta,
16 Nightly,
17}
18
19impl Channel {
20 pub fn as_str(self) -> &'static str {
21 match self {
22 Self::Stable => "stable",
23 Self::Beta => "beta",
24 Self::Nightly => "nightly",
25 }
26 }
27}
28
29#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
36pub enum Target {
37 #[serde(rename = "macos-aarch64")]
38 MacosAarch64,
39 #[serde(rename = "macos-x86_64")]
40 MacosX86_64,
41 #[serde(rename = "windows-x86_64")]
42 WindowsX86_64,
43 #[serde(rename = "linux-x86_64")]
44 LinuxX86_64,
45}
46
47impl Target {
48 pub fn as_str(self) -> &'static str {
49 match self {
50 Self::MacosAarch64 => "macos-aarch64",
51 Self::MacosX86_64 => "macos-x86_64",
52 Self::WindowsX86_64 => "windows-x86_64",
53 Self::LinuxX86_64 => "linux-x86_64",
54 }
55 }
56
57 pub fn needs_signing(self) -> bool {
59 !matches!(self, Self::LinuxX86_64)
60 }
61}
62
63#[derive(Debug, Clone, Serialize, Deserialize)]
64#[serde(default)]
65pub struct DistributionSection {
66 pub channel: Channel,
67 pub targets: Vec<Target>,
68 pub updater: UpdaterSection,
69}
70
71impl Default for DistributionSection {
72 fn default() -> Self {
73 Self {
74 channel: Channel::default(),
75 targets: vec![
76 Target::MacosAarch64,
77 Target::MacosX86_64,
78 Target::WindowsX86_64,
79 Target::LinuxX86_64,
80 ],
81 updater: UpdaterSection::default(),
82 }
83 }
84}
85
86#[derive(Debug, Clone, Default, Serialize, Deserialize)]
92#[serde(default)]
93pub struct UpdaterSection {
94 pub enabled: bool,
95 pub endpoints: Vec<String>,
97}
98
99impl DistributionSection {
100 pub fn targets_needing_signing(&self) -> Vec<Target> {
102 self.targets
103 .iter()
104 .copied()
105 .filter(|target| target.needs_signing())
106 .collect()
107 }
108}
109
110#[cfg(test)]
111mod tests {
112 use super::*;
113
114 #[test]
115 fn the_updater_is_off_until_someone_turns_it_on() {
116 let distribution = DistributionSection::default();
117
118 assert!(!distribution.updater.enabled);
119 assert!(distribution.updater.endpoints.is_empty());
120 }
121
122 #[test]
123 fn linux_is_the_one_target_that_ships_without_signing() {
124 let distribution = DistributionSection::default();
125
126 let needing = distribution.targets_needing_signing();
127
128 assert_eq!(needing.len(), 3);
129 assert!(!needing.contains(&Target::LinuxX86_64));
130 }
131
132 #[test]
135 fn every_target_serialises_exactly_as_it_displays() {
136 for target in [
137 Target::MacosAarch64,
138 Target::MacosX86_64,
139 Target::WindowsX86_64,
140 Target::LinuxX86_64,
141 ] {
142 let serialised = serde_json::to_string(&target).expect("serialise");
143 assert_eq!(
144 serialised.trim_matches('"'),
145 target.as_str(),
146 "a manifest written with `{}` must parse",
147 target.as_str()
148 );
149
150 let parsed: Target = serde_json::from_str(&serialised).expect("round trip");
151 assert_eq!(parsed, target);
152 }
153 }
154
155 #[test]
156 fn a_channel_round_trips_through_the_manifest_format() {
157 let parsed: Channel = toml::from_str::<toml::Table>("value = \"beta\"")
158 .map(|table| table["value"].clone().try_into().unwrap())
159 .unwrap();
160
161 assert_eq!(parsed, Channel::Beta);
162 assert_eq!(parsed.as_str(), "beta");
163 }
164}