1use std::str::FromStr;
2
3pub use clap::error::ErrorKind;
4use clap::{Error, Parser, Subcommand, ValueEnum};
5
6#[derive(Clone, Debug, ValueEnum)]
7#[value(rename_all = "UPPER")]
8pub enum RecordType {
9 A,
10 AAAA,
11 CNAME,
12 MX,
13 NS,
14 TXT,
15 SRV,
16}
17
18#[derive(Clone, Debug, ValueEnum, PartialEq)]
19pub enum OnError {
20 Print,
21 Exit,
22}
23
24#[derive(Clone, Debug, Parser)]
25pub struct DnsEntry {
26 pub domain: String,
27 pub name: String,
28 pub ttl: u32,
29 pub r#type: RecordType,
30 pub content: String,
31}
32
33#[cfg(feature = "propagation")]
34#[derive(Debug, Subcommand)]
35pub enum DnsCommand {
36 AcmeValidationDelete { domain: String },
37 AcmeValidationSet { domain: String, challenge: String },
38 AcmeValidationCheck { domain: String, challenge: String },
39 Delete(DnsEntry),
40 Insert(DnsEntry),
41 List { domain: String },
42}
43
44#[cfg(not(feature = "propagation"))]
45#[derive(Debug, Subcommand)]
46pub enum DnsCommand {
47 AcmeValidationDelete { domain: String },
48 AcmeValidationSet { domain: String, challenge: String },
49 Delete(DnsEntry),
50 Insert(DnsEntry),
51 List { domain: String },
52}
53
54#[derive(Debug, Subcommand)]
55pub enum DomainCommand {
56 List,
57 Item { domain: String },
58}
59
60#[derive(Debug, Subcommand)]
61pub enum InvoiceCommand {
62 List,
63 Item { number: String },
64 Pdf { number: String },
65}
66
67#[derive(Debug, Subcommand)]
68pub enum ProductCommand {
69 List,
70 Elements { name: String },
71}
72
73#[derive(Debug, Subcommand)]
74pub enum EmailBoxCommand {
75 List {
76 domain: String,
77 },
78 Item {
79 domain: String,
80 id: String,
81 },
82 Delete {
83 domain: String,
84 id: String,
85 },
86 Insert {
87 domain: String,
88 username: String,
89 password: String,
90 },
91}
92
93#[derive(Debug, Subcommand)]
94pub enum EmailForwardCommand {
95 List {
96 domain: String,
97 },
98 Item {
99 domain: String,
100 id: String,
101 },
102 Delete {
103 domain: String,
104 id: String,
105 },
106 Insert {
107 domain: String,
108 local_part: String,
109 forward_to: String,
110 },
111}
112
113#[derive(Debug, Subcommand)]
114pub enum VpsCommand {
115 List,
116 Item { name: String },
117 Start { name: String },
118 Stop { name: String },
119 Reset { name: String },
120 Lock { name: String },
121 Unlock { name: String },
122}
123
124#[derive(Debug, Subcommand)]
125pub enum SubCommand {
126 AvailibilityZones,
127 Comment {
128 text: String,
129 },
130 #[command(subcommand)]
131 Dns(DnsCommand),
132 #[command(subcommand)]
133 Domain(DomainCommand),
134 #[command(subcommand)]
135 EmailBox(EmailBoxCommand),
136 #[command(subcommand)]
137 EmailForward(EmailForwardCommand),
138 #[command(subcommand)]
139 Invoice(InvoiceCommand),
140 Onerror {
141 on_error: OnError,
142 },
143 Ping,
144 #[command(subcommand)]
145 Product(ProductCommand),
146 Sleep {
147 number_of_seconds: u64,
148 },
149 #[command(subcommand)]
150 Vps(VpsCommand),
151}
152
153#[derive(Debug, Parser)]
154#[command(multicall = true)]
155pub struct TransipCommand {
156 #[command(subcommand)]
157 pub command: SubCommand,
158}
159
160fn command_line<S: AsRef<str>>(line: S) -> Result<Vec<String>, clap::Error> {
161 if line.as_ref().trim_start().starts_with("#") {
162 Ok(vec!["comment".to_owned(), line.as_ref().to_owned()])
163 } else {
164 shlex::split(line.as_ref()).ok_or(clap::Error::new(clap::error::ErrorKind::Format))
165 }
166}
167
168impl FromStr for TransipCommand {
169 type Err = Error;
170
171 fn from_str(s: &str) -> Result<Self, Self::Err> {
172 command_line(s).and_then(TransipCommand::try_parse_from)
173 }
174}
175
176#[cfg(test)]
177mod tests {
178 use std::io::{BufRead, BufReader};
179
180 use super::{command_line, TransipCommand};
181 use clap::Parser;
182
183 const COMMANDS: &[u8] = include_bytes!("commands.txt");
184
185 #[test]
186 fn try_command_lines() {
187 let lines = BufReader::new(COMMANDS).lines();
188 for args_option in lines.map_while(Result::ok).map(command_line) {
189 match args_option {
190 Ok(args) => {
191 let result = TransipCommand::try_parse_from(args).unwrap();
192 println!("{:?}", &result.command);
193 }
194 Err(error) => eprintln!("Error parsing line: {error}"),
195 }
196 }
197 }
198}