arcs_ctf_yaml_parser/flag/
mod.rs1use std::{fmt::{Display, Debug}, path::{PathBuf, Path}, str::FromStr, io::ErrorKind};
2
3use serde_yaml::Value as YamlValue;
4
5use crate::structs::{get_type, ValueType};
6
7
8pub fn get_file_flag(path: PathBuf, base_path: &Path) -> Result<Flag, FlagError> {
9 match std::fs::read_to_string(base_path.join(&path)) {
10 Ok(s) => Ok(Flag::File(path, s)),
11 Err(e) => if e.kind() == ErrorKind::NotFound {
12 Err(FlagError::FileMissing(path))
13 } else {
14 Err(FlagError::OsError(path))
15 },
16 }
17}
18
19pub fn get_flag(value: &YamlValue, base_path: &Path) -> Result<Flag, FlagError> {
20 if let Some(flag_str) = value.as_str() {
21 Ok(Flag::String(flag_str.trim().to_string()))
22 } else if let Some(mapping) = value.as_mapping() {
23 if let Some(Some(file)) = mapping.get("file").map(YamlValue::as_str) {
24 if let Ok(path) = PathBuf::from_str(file) {
25 if path.is_relative() {
26 get_file_flag(path, base_path)
27 } else {
28 Err(FlagError::BadPath(file.to_string()))
29 }
30 } else {
31 Err(FlagError::BadPath(file.to_string()))
32 }
33 } else {
34 Err(FlagError::MappingNeedsFile)
35 }
36 } else {
37 Err(FlagError::BadType(get_type(value)))
38 }
39}
40
41#[derive(Clone, PartialEq)]
42pub enum Flag {
43 String(String),
44 File(PathBuf, String),
45}
46impl Flag {
47 pub fn as_str(&self) -> &str {
48 match self {
49 Self::String(s) | Self::File(_, s) => s.trim(),
50 }
51 }
52 pub fn path(&self) -> Option<&std::path::Path> {
53 if let Self::File(p, _) = self {
54 Some(p.as_path())
55 } else { None }
56 }
57}
58
59impl Debug for Flag {
60 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
61 use Flag::{ String, File };
62 match self {
63 String(s) => write!(f, "Flag< {s} >"),
64 File(p, s) => write!(f, "Flag< {s} (@ {}) >", p.display()),
65 }
66 }
67}
68
69
70#[derive(Default, Debug, Clone)]
71pub enum FlagError {
72 BadType(ValueType),
73
74 BadString(String),
75
76 BadPath(String),
77 MappingNeedsFile,
78 FileMissing(PathBuf),
79 OsError(PathBuf),
80
81 #[default]
82 MissingKey,
83}
84
85impl Display for FlagError {
86 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
87 use FlagError::*;
88 match self {
89 BadType(t) => write!(f, "Flag should be a list, not {t}."),
90 BadString(s) => write!(f, "The string {s} is not a valid flag."),
91 BadPath(p) => write!(f, "The string {p} is not a valid path. (hint: If you want to define a flag with a string, use `flag: <input>`)"),
92 MappingNeedsFile => write!(f, "If you are going to define a flag via a file, you need to have `file: <path>` as an entry under `flag`. (<path> must be a string)"),
93 MissingKey => write!(f, "You have to define `categories`."),
94 FileMissing(p) => write!(f, "There is no file at {}.", p.display()),
95 OsError(p) => write!(f, "There was an issue opening the file at {}. Maybe check permissions?", p.display()),
96 }
97 }
98}