qemu_command_builder/args/
boot.rs1use crate::parsers::ARG_BOOT;
2use std::str::FromStr;
3
4use bon::Builder;
5use proptest_derive::Arbitrary;
6use winnow::Result;
7use winnow::ascii::{alphanumeric1, dec_uint};
8use winnow::combinator::opt;
9use winnow::prelude::*;
10use winnow::token::literal;
11
12use crate::common::OnOff;
13use crate::parsers::DELIM_COMMA;
14use crate::shell_string::{ShellString, ShellStringError, shell_string_until_comma};
15use crate::to_command::ToCommand;
16use crate::{pco0, ppo0, qao};
17
18const KEY_ORDER: &str = "order=";
19const KEY_ONCE: &str = "once=";
20const KEY_MENU: &str = "menu=";
21const KEY_SPLASH: &str = "splash=";
22const KEY_SPLASH_TIME: &str = "splash-time=";
23const KEY_REBOOT_TIMEOUT: &str = "reboot-timeout=";
24const KEY_STRICT: &str = "strict=";
25
26#[derive(Debug, Clone, Hash, Ord, PartialOrd, Eq, PartialEq, Builder, Arbitrary)]
56pub struct Boot {
57 order: Option<ShellString>,
58 once: Option<ShellString>,
59 menu: Option<OnOff>,
60 splash: Option<ShellString>,
61 splash_time: Option<u64>,
62 reboot_timeout: Option<u64>,
63 strict: Option<OnOff>,
64}
65
66impl ToCommand for Boot {
67 fn has_args(&self) -> bool {
68 self.order.is_some() || self.once.is_some() || self.menu.is_some() || self.splash.is_some() || self.splash_time.is_some() || self.reboot_timeout.is_some() || self.strict.is_some()
69 }
70
71 fn command(&self) -> String {
72 ARG_BOOT.to_string()
73 }
74 fn to_args(&self) -> Vec<String> {
75 let mut args = vec![];
76
77 if let Some(order) = &self.order {
78 args.push(format!("{}{}", KEY_ORDER, order.as_ref()));
79 }
80 if let Some(once) = &self.once {
81 args.push(format!("{}{}", KEY_ONCE, once.as_ref()));
82 }
83 qao!(&self.menu, args, KEY_MENU);
84 if let Some(splash) = &self.splash {
85 args.push(format!("{}{}", KEY_SPLASH, splash.as_ref()));
86 }
87 qao!(&self.splash_time, args, KEY_SPLASH_TIME);
88 qao!(&self.reboot_timeout, args, KEY_REBOOT_TIMEOUT);
89 qao!(&self.strict, args, KEY_STRICT);
90
91 vec![args.join(DELIM_COMMA)]
92 }
93}
94
95impl FromStr for Boot {
96 type Err = ShellStringError;
97
98 fn from_str(s: &str) -> Result<Self, Self::Err> {
99 let mut value = Self {
100 order: None,
101 once: None,
102 menu: None,
103 splash: None,
104 splash_time: None,
105 reboot_timeout: None,
106 strict: None,
107 };
108 for part in s.split(DELIM_COMMA) {
109 let (key, raw) = part.split_once('=').ok_or_else(|| ShellStringError::new(format!("invalid -boot option: {part}")))?;
110 match key {
111 "order" => value.order = Some(raw.parse::<ShellString>().map_err(ShellStringError::new)?),
112 "once" => value.once = Some(raw.parse::<ShellString>().map_err(ShellStringError::new)?),
113 "menu" => value.menu = Some(raw.parse::<OnOff>().map_err(|_| ShellStringError::new(format!("invalid menu value: {raw}")))?),
114 "splash" => value.splash = Some(raw.parse::<ShellString>().map_err(ShellStringError::new)?),
115 "splash-time" => value.splash_time = Some(raw.parse::<u64>().map_err(|e| ShellStringError::new(e.to_string()))?),
116 "reboot-timeout" => value.reboot_timeout = Some(raw.parse::<u64>().map_err(|e| ShellStringError::new(e.to_string()))?),
117 "strict" => value.strict = Some(raw.parse::<OnOff>().map_err(|_| ShellStringError::new(format!("invalid strict value: {raw}")))?),
118 other => return Err(ShellStringError::new(format!("unsupported -boot option: {other}"))),
119 }
120 }
121 Ok(value)
122 }
123}
124
125pco0!(order, shell_string_until_comma, ShellString, KEY_ORDER);
126pco0!(once, shell_string_until_comma, ShellString, KEY_ONCE);
127pco0!(menu, alphanumeric1, OnOff, KEY_MENU);
128pco0!(splash, shell_string_until_comma, ShellString, KEY_SPLASH);
129ppo0!(splash_time, dec_uint, u64, KEY_SPLASH_TIME);
130ppo0!(reboot_timeout, dec_uint, u64, KEY_REBOOT_TIMEOUT);
131pco0!(strict, alphanumeric1, OnOff, KEY_STRICT);
132
133pub fn boot(s: &mut &str) -> ModalResult<Boot> {
134 let order = opt(order).parse_next(s)?;
135 let once = opt(once).parse_next(s)?;
136 let menu = opt(menu).parse_next(s)?;
137 let splash = opt(splash).parse_next(s)?;
138 let splash_time = opt(splash_time).parse_next(s)?;
139 let reboot_timeout = opt(reboot_timeout).parse_next(s)?;
140 let strict = opt(strict).parse_next(s)?;
141
142 Ok(Boot {
143 order,
144 once,
145 menu,
146 splash,
147 splash_time,
148 reboot_timeout,
149 strict,
150 })
151}