Skip to main content

transip_command/
lib.rs

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}