safe_chains/registry/
folder_config.rs1use std::{env, fs};
6
7use serde::Deserialize;
8
9use crate::pathctx::anchor::FolderLevel;
10
11#[derive(Deserialize)]
12struct File {
13 #[serde(default)]
14 unknown_folder: Option<Section>,
15}
16
17#[derive(Deserialize)]
18struct Section {
19 #[serde(default)]
20 writes: Option<String>,
21}
22
23#[derive(Clone, Debug, PartialEq, Eq)]
25pub enum Setting {
26 Unset,
28 Level(FolderLevel),
29 Unreadable(String),
32}
33
34impl Setting {
35 pub fn level(&self) -> FolderLevel {
36 match self {
37 Setting::Unset => FolderLevel::DEFAULT,
38 Setting::Level(l) => *l,
39 Setting::Unreadable(_) => FolderLevel::Reads,
40 }
41 }
42}
43
44pub fn user_setting() -> Setting {
47 if env::var_os("SAFE_CHAINS_NO_LOCAL").is_some() {
48 return Setting::Unset;
49 }
50 let Some(path) = super::custom::find_user_custom() else {
51 return Setting::Unset;
52 };
53 match fs::read_to_string(&path) {
54 Ok(source) => parse(&source),
55 Err(e) => Setting::Unreadable(format!("{}: {e}", path.display())),
56 }
57}
58
59pub(crate) fn parse(source: &str) -> Setting {
60 let file: File = match toml::from_str(source) {
61 Ok(f) => f,
62 Err(e) => return Setting::Unreadable(e.message().to_string()),
63 };
64 match file.unknown_folder.and_then(|s| s.writes) {
65 None => Setting::Unset,
66 Some(name) => FolderLevel::parse(&name).map_or_else(
67 || Setting::Unreadable(format!("unknown_folder.writes = \"{name}\" is not one of {}", FolderLevel::NAMES.join(", "))),
68 Setting::Level,
69 ),
70 }
71}
72
73#[cfg(test)]
74mod tests {
75 use super::*;
76
77 #[test]
78 fn each_level_reads_back() {
79 for name in FolderLevel::NAMES {
80 let level = FolderLevel::parse(name).expect("a listed name parses");
81 assert_eq!(parse(&format!("[unknown_folder]\nwrites = \"{name}\"\n")), Setting::Level(level));
82 }
83 }
84
85 #[test]
86 fn absent_is_the_default_and_unreadable_is_reads() {
87 assert_eq!(parse(""), Setting::Unset);
88 assert_eq!(parse("level = \"editor\"\n[[trusted]]\npath = \"/a\"\nsha256 = \"x\"\n"), Setting::Unset);
89 assert_eq!(parse("[unknown_folder]\n"), Setting::Unset);
90 assert_eq!(Setting::Unset.level(), FolderLevel::Developer);
91 for bad in
92 ["[unknown_folder]\nwrites = \"devloper\"\n", "[unknown_folder]\nwrites = 3\n", "not toml {{{", "unknown_folder = \"reads\"\n"]
93 {
94 let got = parse(bad);
95 assert!(matches!(got, Setting::Unreadable(_)), "{bad}: {got:?}");
96 assert_eq!(got.level(), FolderLevel::Reads, "{bad}");
97 }
98 }
99}