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
use std::{collections::BTreeSet, fmt::Display, io::Write};
use seaplane::api::restrict::v1::{RestrictedDirectory as RestrictedDirectoryModel, Restriction};
use serde::Serialize;
use tabwriter::TabWriter;
use super::EncodedString;
use crate::{
context::Ctx,
error::{CliError, Result},
printer::{printer, Output},
};
#[derive(Debug, Clone, Serialize)]
pub struct RestrictedDirectory {
pub directory: EncodedString,
}
impl RestrictedDirectory {
pub fn new<S: Into<String>>(directory: S) -> Self {
Self { directory: EncodedString::new(directory.into()) }
}
pub fn to_model(&self) -> RestrictedDirectoryModel {
RestrictedDirectoryModel::from_encoded(self.directory.to_string())
}
}
impl Output for Restriction {
fn print_json(&self, _ctx: &Ctx) -> Result<()> {
cli_println!("{}", serde_json::to_string(self)?);
Ok(())
}
fn print_table(&self, ctx: &Ctx) -> Result<()> {
let restrict_ctx = ctx.restrict_ctx.get_or_init();
let restrictions = Restrictions::from_model(vec![self.clone()]);
restrictions.impl_print_table(!restrict_ctx.no_header, restrict_ctx.decode)?;
Ok(())
}
}
#[derive(Debug, Default, Clone, Serialize)]
#[serde(transparent)]
pub struct Restrictions {
inner: Vec<Restriction>,
}
impl Restrictions {
pub fn from_model(model: Vec<Restriction>) -> Self { Self { inner: model } }
pub fn iter(&self) -> impl Iterator<Item = &Restriction> { self.inner.iter() }
fn impl_print_table(&self, headers: bool, decode: bool) -> Result<()> {
let mut tw = TabWriter::new(Vec::new());
fn join_set<S: Display>(set: BTreeSet<S>) -> String {
let mut vec = set.iter().map(|s| s.to_string()).collect::<Vec<String>>();
vec.sort();
vec.join(",")
}
if headers {
writeln!(tw, "API\tDIRECTORY\tSTATE\tREGIONS ALLOWED\tREGIONS DENIED\tPROVIDERS ALLOWED\tPROVIDERS DENIED")?;
}
for restriction in self.iter() {
let rd = RestrictedDirectory::new(restriction.directory.encoded());
write!(tw, "{}\t", restriction.api)?;
if decode {
tw.write_all(&rd.directory.decoded()?)?;
} else {
write!(tw, "{}", rd.directory)?;
}
writeln!(
tw,
"\t{}\t[{}]\t[{}]\t[{}]\t[{}]",
restriction.state,
join_set(restriction.details.regions_allowed.clone()),
join_set(restriction.details.regions_denied.clone()),
join_set(restriction.details.providers_allowed.clone()),
join_set(restriction.details.providers_denied.clone())
)?;
}
tw.flush()?;
let mut ptr = printer();
let page = tw
.into_inner()
.map_err(|_| CliError::bail("IO flush error writing restrictions"))?;
ptr.write_all(&page)?;
ptr.flush()?;
Ok(())
}
}
impl Output for Restrictions {
fn print_json(&self, _ctx: &Ctx) -> Result<()> {
cli_println!("{}", serde_json::to_string(self)?);
Ok(())
}
fn print_table(&self, ctx: &Ctx) -> Result<()> {
let restrict_ctx = ctx.restrict_ctx.get_or_init();
self.impl_print_table(!restrict_ctx.no_header, restrict_ctx.decode)
}
}