seaplane_cli/cli/cmds/restrict/
common.rs1use clap::{builder::PossibleValue, value_parser, Arg, ArgMatches};
2use seaplane::api::shared::v1::{Provider as ProviderModel, Region as RegionModel};
3
4use crate::OutputFormat;
5
6const LONG_DECODE: &str = "Decode the directories before printing them
7
8Binary values will be written directly to standard output (which may do strange
9things to your terminal)";
10
11static LONG_REGION: &str = "A region where the data placement is allowed (See REGION SPEC below)
13
14Multiple items can be passed as a comma separated list, or by using the argument
15multiple times.";
16
17static LONG_PROVIDER: &str = "A provider where the data placement is allowed
18
19Multiple items can be passed as a comma separated list, or by using the argument
20multiple times.";
21
22static LONG_EXCLUDE_PROVIDER: &str = "A provider where the data placement is *NOT* allowed
23
24This will override any values given to --provider
25
26Multiple items can be passed as a comma separated list, or by using the argument
27multiple times.";
28
29static LONG_EXCLUDE_REGION: &str =
30 "A region where the data placement is *NOT* allowed (See REGION SPEC below)
31
32This will override any values given to --region
33
34Multiple items can be passed as a comma separated list, or by using the argument
35multiple times.";
36
37#[derive(Debug, Copy, Clone, PartialEq, Eq, strum::EnumString)]
41#[strum(ascii_case_insensitive, serialize_all = "lowercase")]
42pub enum Provider {
43 Aws,
44 Azure,
45 DigitalOcean,
46 Equinix,
47 Gcp,
48 All,
49}
50
51impl clap::ValueEnum for Provider {
52 fn value_variants<'a>() -> &'a [Self] {
53 use Provider::*;
54 &[Aws, Azure, DigitalOcean, Equinix, Gcp, All]
55 }
56
57 fn to_possible_value<'a>(&self) -> Option<PossibleValue> {
58 use Provider::*;
59 match self {
60 Aws => Some(PossibleValue::new("aws")),
61 Azure => Some(PossibleValue::new("azure")),
62 DigitalOcean => Some(PossibleValue::new("digitalocean")),
63 Equinix => Some(PossibleValue::new("equinix")),
64 Gcp => Some(PossibleValue::new("gcp")),
65 All => Some(PossibleValue::new("all")),
66 }
67 }
68
69 fn from_str(input: &str, _ignore_case: bool) -> Result<Self, String> {
70 input.parse().map_err(|e| format!("{e}"))
73 }
74}
75
76impl Provider {
77 pub fn into_model(&self) -> Option<ProviderModel> {
78 if self == &Provider::All {
79 None
80 } else {
81 Some(self.into())
82 }
83 }
84}
85
86#[allow(clippy::from_over_into)]
87impl<'a> Into<ProviderModel> for &'a Provider {
88 fn into(self) -> ProviderModel {
89 use Provider::*;
90 match self {
91 Aws => ProviderModel::AWS,
92 Azure => ProviderModel::Azure,
93 DigitalOcean => ProviderModel::DigitalOcean,
94 Equinix => ProviderModel::Equinix,
95 Gcp => ProviderModel::GCP,
96 All => {
97 panic!("Provider::All cannot be converted into seaplane::api::shared::v1::Provider")
98 }
99 }
100 }
101}
102
103#[allow(clippy::upper_case_acronyms)]
109#[derive(Debug, Copy, Clone, PartialEq, Eq, strum::EnumString)]
110#[strum(ascii_case_insensitive, serialize_all = "lowercase")]
111pub enum Region {
112 XA,
113 Asia,
114 XC,
115 PRC,
116 PeoplesRepublicOfChina,
117 XE,
118 Europe,
119 EU,
120 XF,
121 Africa,
122 XN,
123 NorthAmerica,
124 NAmerica,
125 XO,
126 Oceania,
127 XQ,
128 Antarctica,
129 XS,
130 SAmerica,
131 SouthAmerica,
132 XU,
133 UK,
134 UnitedKingdom,
135 All,
136}
137
138impl clap::ValueEnum for Region {
139 fn value_variants<'a>() -> &'a [Self] {
140 use Region::*;
141 &[
142 XA, XC, XE, XF, XN, XO, XQ, XS, XU, All,
152 ]
153 }
154
155 fn to_possible_value<'a>(&self) -> Option<PossibleValue> {
156 use Region::*;
157 match self {
158 XA => Some(PossibleValue::new("xa").alias("asia")),
159 Asia => None,
160 XC => Some(PossibleValue::new("xc").aliases([
161 "prc",
162 "china",
163 "peoples-republic-of-china",
164 "peoples_republic_of_china",
165 "peoplesrepublicofchina",
166 ])),
167 PRC => None,
168 PeoplesRepublicOfChina => None,
169 XE => Some(PossibleValue::new("xe").aliases(["europe", "eu"])),
170 Europe => None,
171 EU => None,
172 XF => Some(PossibleValue::new("xf").alias("africa")),
173 Africa => None,
174 XN => Some(PossibleValue::new("xn").aliases([
175 "namerica",
176 "northamerica",
177 "n-america",
178 "north-america",
179 "n_america",
180 "north_america",
181 ])),
182 NorthAmerica => None,
183 NAmerica => None,
184 XO => Some(PossibleValue::new("xo").alias("oceania")),
185 Oceania => None,
186 XQ => Some(PossibleValue::new("xq").alias("antarctica")),
187 Antarctica => None,
188 XS => Some(PossibleValue::new("xs").aliases([
189 "samerica",
190 "southamerica",
191 "s-america",
192 "south-america",
193 "s_america",
194 "south_america",
195 ])),
196 SAmerica => None,
197 SouthAmerica => None,
198 XU => Some(PossibleValue::new("xu").aliases([
199 "uk",
200 "unitedkingdom",
201 "united-kingdom",
202 "united_kingdom",
203 ])),
204 UK => None,
205 UnitedKingdom => None,
206 All => Some(PossibleValue::new("all")),
207 }
208 }
209
210 fn from_str(input: &str, _ignore_case: bool) -> Result<Self, String> {
211 input.parse().map_err(|e| format!("{e}"))
214 }
215}
216
217impl Region {
218 pub fn into_model(&self) -> Option<RegionModel> {
219 if self == &Region::All {
220 None
221 } else {
222 Some(self.into())
223 }
224 }
225}
226
227#[allow(clippy::from_over_into)]
228impl<'a> Into<RegionModel> for &'a Region {
229 fn into(self) -> RegionModel {
230 use Region::*;
231 match self {
232 XA | Asia => RegionModel::XA,
233 XC | PRC | PeoplesRepublicOfChina => RegionModel::XC,
234 XE | Europe | EU => RegionModel::XE,
235 XF | Africa => RegionModel::XF,
236 XN | NorthAmerica | NAmerica => RegionModel::XN,
237 XO | Oceania => RegionModel::XO,
238 XQ | Antarctica => RegionModel::XQ,
239 XS | SAmerica | SouthAmerica => RegionModel::XS,
240 XU | UK | UnitedKingdom => RegionModel::XU,
241 All => panic!("Region::All cannot be converted into seaplane::api::shared::v1::Region"),
242 }
243 }
244}
245
246#[allow(missing_debug_implementations)]
251#[derive(Debug)]
252pub struct SeaplaneRestrictCommonArgMatches<'a>(pub &'a ArgMatches);
253
254pub fn display_args() -> Vec<Arg> {
255 vec![
256 arg!(--format =["FORMAT"=>"table"] global)
257 .help("Change the output format")
258 .value_parser(value_parser!(OutputFormat)),
259 arg!(--decode - ('D'))
260 .help("Decode the directories before printing them")
261 .long_help(LONG_DECODE)
262 .overrides_with("no-decode"),
263 arg!(--("no-decode"))
264 .help("Print directories without decoding them")
265 .overrides_with("decode"),
266 arg!(--("no-header") | ("no-heading") | ("no-headers"))
267 .help("Omit the header when printing with `--format=table`"),
268 ]
269}
270
271pub fn restriction_details() -> Vec<Arg> {
272 vec![
273 arg!(--provider|providers =["PROVIDER"=>"all"]... ignore_case)
274 .display_order(1)
275 .next_line_help(true)
276 .help("A provider where the data placement is allowed (supports comma separated list, or multiple uses)")
277 .long_help(LONG_PROVIDER)
278 .value_parser(value_parser!(Provider)),
279 arg!(--("exclude-provider")|("exclude-providers") =["PROVIDER"]... ignore_case)
280 .display_order(2)
281 .next_line_help(true)
282 .help("A provider where the data placement is *NOT* allowed (supports comma separated list, or multiple uses)")
283 .long_help(LONG_EXCLUDE_PROVIDER)
284 .value_parser(value_parser!(Provider)),
285 arg!(--region|regions =["REGION"=>"all"]... ignore_case)
286 .display_order(1)
287 .next_line_help(true)
288 .help("A region where the data placement is allowed (supports comma separated list, or multiple uses) (See REGION SPEC below)")
289 .long_help(LONG_REGION)
290 .value_parser(value_parser!(Region)),
291 arg!(--("exclude-region")|("exclude-regions") =["REGION"]... ignore_case)
292 .display_order(2)
293 .next_line_help(true)
294 .help("A region where the data placement is *NOT* allowed (supports comma separated list, or multiple uses) (See REGION SPEC below)")
295 .long_help(LONG_EXCLUDE_REGION)
296 .value_parser(value_parser!(Region)),
297 ]
298}
299
300pub fn base64() -> Arg {
301 arg!(--base64 - ('B')).help("The directory is already encoded in URL safe Base64")
302}
303
304pub fn api() -> Arg { arg!(api =["API"] required ).help("The API of the restricted directory") }
305
306pub fn directory() -> Arg {
307 arg!(directory =["DIRECTORY"] required ).help("The restricted directory")
308}