uefi_run/
args.rs

1use super::*;
2use clap::Parser;
3use std::path::PathBuf;
4
5/// Command line arguments for uefi-run
6#[derive(Parser, Debug, Default, PartialEq)]
7#[clap(
8    version,
9    author,
10    about,
11    trailing_var_arg = true,
12    dont_delimit_trailing_values = true
13)]
14pub struct Args {
15    /// Bios image
16    #[clap(long, short = 'b', default_value = "OVMF.fd")]
17    pub bios_path: String,
18    /// Path to qemu executable
19    #[clap(long, short = 'q', default_value = "qemu-system-x86_64")]
20    pub qemu_path: String,
21    /// Size of the image in MiB
22    #[clap(long, short = 's', default_value_t = 10)]
23    pub size: u64,
24    /// Additional files to be added to the efi image
25    ///
26    /// Additional files to be added to the efi image. If no inner location is provided, it will
27    /// default to the root of the image with the same name as the provided file.
28    #[clap(long, short = 'f')]
29    pub add_file: Vec<String>,
30    /// EFI Executable
31    pub efi_exe: String,
32    /// Additional arguments for qemu
33    pub qemu_args: Vec<String>,
34    /// Load the application as a bootloader instead of in an EFI shell
35    ///
36    /// This effectively skips the 5 second startup delay.
37    #[clap(long, short = 'd')]
38    pub boot: bool,
39}
40
41impl Args {
42    /// Parse `--add-file` arguments into `(outer, inner)` tuples of `PathBuf`
43    pub fn parse_add_file_args(&self) -> impl Iterator<Item = Result<(PathBuf, PathBuf)>> + '_ {
44        self.add_file.iter().map(|file| {
45            // Split the argument to get the inner and outer files
46            file.split_once(':')
47                .map(|(x, y)| Ok((PathBuf::from(x), PathBuf::from(y))))
48                .unwrap_or_else(|| {
49                    let outer = PathBuf::from(&file);
50                    let inner = PathBuf::from(&file)
51                        .file_name()
52                        .ok_or_else(|| Error::msg("Invalid --add-file argument"))?
53                        .into();
54                    Ok((outer, inner))
55                })
56        })
57    }
58}
59
60#[cfg(test)]
61mod tests {
62    use super::*;
63
64    #[test]
65    fn test_parse_add_file_args() {
66        let mut args = Args::default();
67        args.add_file = vec![
68            "/full/path/to/outer:/full/path/to/inner".to_string(),
69            "/full/path/to/outer:inner".to_string(),
70            "outer:inner".to_string(),
71            "/full/path/to/outer".to_string(),
72            "outer".to_string(),
73        ];
74        #[rustfmt::skip]
75        let expected = vec![
76            (PathBuf::from("/full/path/to/outer"), PathBuf::from("/full/path/to/inner")),
77            (PathBuf::from("/full/path/to/outer"), PathBuf::from("inner")),
78            (PathBuf::from("outer"), PathBuf::from("inner")),
79            (PathBuf::from("/full/path/to/outer"), PathBuf::from("outer")),
80            (PathBuf::from("outer"), PathBuf::from("outer")),
81        ];
82        let actual = args
83            .parse_add_file_args()
84            .map(|x| x.unwrap())
85            .collect::<Vec<_>>();
86        assert_eq!(actual, expected);
87    }
88}