-
-
Notifications
You must be signed in to change notification settings - Fork 476
/
Copy pathset.rs
143 lines (121 loc) · 4.39 KB
/
set.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
use eyre::{Result, bail, eyre};
use toml_edit::DocumentMut;
use crate::config::settings::{SETTINGS_META, SettingsFile, SettingsType};
use crate::{config, duration, file};
/// Add/update a setting
///
/// This modifies the contents of ~/.config/mise/config.toml
#[derive(Debug, clap::Args)]
#[clap(visible_aliases = ["create"], after_long_help = AFTER_LONG_HELP, verbatim_doc_comment)]
pub struct SettingsSet {
/// The setting to set
#[clap()]
pub setting: String,
/// The value to set
pub value: String,
/// Use the local config file instead of the global one
#[clap(long, short)]
pub local: bool,
}
impl SettingsSet {
pub fn run(self) -> Result<()> {
set(&self.setting, &self.value, false, self.local)
}
}
pub fn set(mut key: &str, value: &str, add: bool, local: bool) -> Result<()> {
let meta = SETTINGS_META.get(key);
let is_set_type = meta
.map(|m| matches!(m.type_, SettingsType::ListString | SettingsType::ListPath))
.unwrap_or(false);
let parsed_value = if let Some(meta) = meta {
match meta.type_ {
SettingsType::Bool => parse_bool(value)?,
SettingsType::Integer => parse_i64(value)?,
SettingsType::Duration => parse_duration(value)?,
SettingsType::Url | SettingsType::Path | SettingsType::String => value.into(),
SettingsType::ListString => parse_list_by_comma(value)?,
SettingsType::ListPath => parse_list_by_colon(value)?,
}
} else {
bail!("Unknown setting: {}", key);
};
let path = if local {
config::local_toml_config_path()
} else {
config::global_config_path()
};
file::create_dir_all(path.parent().unwrap())?;
let raw = file::read_to_string(&path).unwrap_or_default();
let mut config: DocumentMut = raw.parse()?;
if !config.contains_key("settings") {
config["settings"] = toml_edit::Item::Table(toml_edit::Table::new());
}
if let Some(mut settings) = config["settings"].as_table_mut() {
if let Some((parent, child)) = key.split_once('.') {
key = child;
settings = settings
.entry(parent)
.or_insert({
let mut t = toml_edit::Table::new();
t.set_implicit(true);
toml_edit::Item::Table(t)
})
.as_table_mut()
.unwrap();
}
let new_value: toml_edit::Value = if add {
if let Some(existing_arr) = settings.get(key).and_then(|item| item.as_array()).cloned()
{
let mut arr = existing_arr;
// Only dedupe if it's a set type
if !is_set_type || !arr.iter().any(|it| it.as_str() == Some(value)) {
arr.push(value);
}
toml_edit::Value::Array(arr)
} else {
parsed_value.clone()
}
} else {
parsed_value.clone()
};
settings.insert(key, new_value.into());
// validate
let _: SettingsFile = toml::from_str(&config.to_string())?;
file::write(&path, config.to_string())?;
}
Ok(())
}
fn parse_list_by_comma(value: &str) -> Result<toml_edit::Value> {
if value.is_empty() || value == "[]" {
return Ok(toml_edit::Array::new().into());
}
Ok(value.split(',').map(|s| s.trim().to_string()).collect())
}
fn parse_list_by_colon(value: &str) -> Result<toml_edit::Value> {
if value.is_empty() || value == "[]" {
return Ok(toml_edit::Array::new().into());
}
Ok(value.split(':').map(|s| s.trim().to_string()).collect())
}
fn parse_bool(value: &str) -> Result<toml_edit::Value> {
match value.to_lowercase().as_str() {
"1" | "true" | "yes" | "y" => Ok(true.into()),
"0" | "false" | "no" | "n" => Ok(false.into()),
_ => Err(eyre!("{} must be true or false", value)),
}
}
fn parse_i64(value: &str) -> Result<toml_edit::Value> {
match value.parse::<i64>() {
Ok(value) => Ok(value.into()),
Err(_) => Err(eyre!("{} must be a number", value)),
}
}
fn parse_duration(value: &str) -> Result<toml_edit::Value> {
duration::parse_duration(value)?;
Ok(value.into())
}
static AFTER_LONG_HELP: &str = color_print::cstr!(
r#"<bold><underline>Examples:</underline></bold>
$ <bold>mise settings idiomatic_version_file=true</bold>
"#
);