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 mb_size: u64,
91 },
92}
93
94#[derive(Debug, Subcommand)]
95pub enum EmailForwardCommand {
96 List {
97 domain: String,
98 },
99 Item {
100 domain: String,
101 id: String,
102 },
103 Delete {
104 domain: String,
105 id: String,
106 },
107 Insert {
108 domain: String,
109 local_part: String,
110 forward_to: String,
111 },
112}
113
114#[derive(Debug, Subcommand)]
115pub enum VpsCommand {
116 List,
117 Item { name: String },
118 Start { name: String },
119 Stop { name: String },
120 Reset { name: String },
121 Lock { name: String },
122 Unlock { name: String },
123}
124
125#[derive(Debug, Subcommand)]
126pub enum SubCommand {
127 AvailibilityZones,
128 Comment {
129 text: String,
130 },
131 #[command(subcommand)]
132 Dns(DnsCommand),
133 #[command(subcommand)]
134 Domain(DomainCommand),
135 #[command(subcommand)]
136 EmailBox(EmailBoxCommand),
137 #[command(subcommand)]
138 EmailForward(EmailForwardCommand),
139 #[command(subcommand)]
140 Invoice(InvoiceCommand),
141 Onerror {
142 on_error: OnError,
143 },
144 Ping,
145 #[command(subcommand)]
146 Product(ProductCommand),
147 Sleep {
148 number_of_seconds: u64,
149 },
150 #[command(subcommand)]
151 Vps(VpsCommand),
152}
153
154#[derive(Debug, Parser)]
155#[command(multicall = true)]
156pub struct TransipCommand {
157 #[command(subcommand)]
158 pub command: SubCommand,
159}
160
161fn command_line<S: AsRef<str>>(line: S) -> Result<Vec<String>, clap::Error> {
162 if line.as_ref().trim_start().starts_with("#") {
163 Ok(vec!["comment".to_owned(), line.as_ref().to_owned()])
164 } else {
165 shlex::split(line.as_ref()).ok_or(clap::Error::new(clap::error::ErrorKind::Format))
166 }
167}
168
169impl FromStr for TransipCommand {
170 type Err = Error;
171
172 fn from_str(s: &str) -> Result<Self, Self::Err> {
173 command_line(s).and_then(TransipCommand::try_parse_from)
174 }
175}
176
177#[cfg(test)]
178mod tests {
179 use std::io::{BufRead, BufReader};
180
181 use super::{TransipCommand, command_line};
182 use clap::Parser;
183
184 const COMMANDS: &[u8] = include_bytes!("commands.txt");
185
186 #[test]
187 fn try_command_lines() {
188 let lines = BufReader::new(COMMANDS).lines();
189 for args_option in lines.map_while(Result::ok).map(command_line) {
190 match args_option {
191 Ok(args) => {
192 let result = TransipCommand::try_parse_from(args).unwrap();
193 println!("{:?}", &result.command);
194 }
195 Err(error) => eprintln!("Error parsing line: {error}"),
196 }
197 }
198 }
199}