mirror of
https://github.com/ClementTsang/bottom
synced 2024-11-22 12:13:06 +00:00
other: clarify config file creation logic/code (#1518)
This commit is contained in:
parent
38c6e70c1e
commit
2c0fb2a723
3 changed files with 60 additions and 28 deletions
|
@ -12,8 +12,8 @@ If no config file argument is given, it will automatically look for a config fil
|
||||||
| Linux | `~/.config/bottom/bottom.toml` <br/> `$XDG_CONFIG_HOME/bottom/bottom.toml` |
|
| Linux | `~/.config/bottom/bottom.toml` <br/> `$XDG_CONFIG_HOME/bottom/bottom.toml` |
|
||||||
| Windows | `C:\Users\<USER>\AppData\Roaming\bottom\bottom.toml` |
|
| Windows | `C:\Users\<USER>\AppData\Roaming\bottom\bottom.toml` |
|
||||||
|
|
||||||
Like if a path is passed with `-C`/`--config`, if a file doesn't exist at the path, bottom will automatically create a
|
If the config file doesn't exist at the path, bottom will automatically try to create a new config file at the location
|
||||||
new, default config file at that location.
|
with default values.
|
||||||
|
|
||||||
## JSON Schema
|
## JSON Schema
|
||||||
|
|
||||||
|
|
18
src/main.rs
18
src/main.rs
|
@ -27,7 +27,6 @@ use std::{
|
||||||
boxed::Box,
|
boxed::Box,
|
||||||
io::{stderr, stdout, Write},
|
io::{stderr, stdout, Write},
|
||||||
panic::{self, PanicInfo},
|
panic::{self, PanicInfo},
|
||||||
path::Path,
|
|
||||||
sync::{
|
sync::{
|
||||||
mpsc::{self, Receiver, Sender},
|
mpsc::{self, Receiver, Sender},
|
||||||
Arc, Condvar, Mutex,
|
Arc, Condvar, Mutex,
|
||||||
|
@ -36,7 +35,6 @@ use std::{
|
||||||
time::{Duration, Instant},
|
time::{Duration, Instant},
|
||||||
};
|
};
|
||||||
|
|
||||||
use anyhow::Context;
|
|
||||||
use app::{layout_manager::UsedWidgets, App, AppConfigFields, DataFilters};
|
use app::{layout_manager::UsedWidgets, App, AppConfigFields, DataFilters};
|
||||||
use crossterm::{
|
use crossterm::{
|
||||||
event::{
|
event::{
|
||||||
|
@ -49,7 +47,7 @@ use crossterm::{
|
||||||
};
|
};
|
||||||
use data_conversion::*;
|
use data_conversion::*;
|
||||||
use event::{handle_key_event_or_break, handle_mouse_event, BottomEvent, CollectionThreadEvent};
|
use event::{handle_key_event_or_break, handle_mouse_event, BottomEvent, CollectionThreadEvent};
|
||||||
use options::{args, get_config_path, get_or_create_config, init_app};
|
use options::{args, get_or_create_config, init_app};
|
||||||
use tui::{backend::CrosstermBackend, Terminal};
|
use tui::{backend::CrosstermBackend, Terminal};
|
||||||
#[allow(unused_imports)]
|
#[allow(unused_imports)]
|
||||||
use utils::logging::*;
|
use utils::logging::*;
|
||||||
|
@ -330,18 +328,8 @@ fn main() -> anyhow::Result<()> {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read from config file.
|
// Read from config file.
|
||||||
let config = {
|
|
||||||
let config_path = get_config_path(args.general.config_location.as_deref());
|
let config = get_or_create_config(args.general.config_location.as_deref())?;
|
||||||
get_or_create_config(config_path.as_deref()).with_context(|| {
|
|
||||||
format!(
|
|
||||||
"Unable to parse or create the config file at: {}",
|
|
||||||
config_path
|
|
||||||
.as_deref()
|
|
||||||
.unwrap_or_else(|| Path::new("<failed locating>"))
|
|
||||||
.display()
|
|
||||||
)
|
|
||||||
})?
|
|
||||||
};
|
|
||||||
|
|
||||||
// Create the "app" and initialize a bunch of stuff.
|
// Create the "app" and initialize a bunch of stuff.
|
||||||
let (mut app, widget_layout, styling) = init_app(args, config)?;
|
let (mut app, widget_layout, styling) = init_app(args, config)?;
|
||||||
|
|
|
@ -68,7 +68,7 @@ macro_rules! is_flag_enabled {
|
||||||
///
|
///
|
||||||
/// For more details on this, see [dirs](https://docs.rs/dirs/latest/dirs/fn.config_dir.html)'
|
/// For more details on this, see [dirs](https://docs.rs/dirs/latest/dirs/fn.config_dir.html)'
|
||||||
/// documentation.
|
/// documentation.
|
||||||
pub fn get_config_path(override_config_path: Option<&Path>) -> Option<PathBuf> {
|
fn get_config_path(override_config_path: Option<&Path>) -> Option<PathBuf> {
|
||||||
const DEFAULT_CONFIG_FILE_PATH: &str = "bottom/bottom.toml";
|
const DEFAULT_CONFIG_FILE_PATH: &str = "bottom/bottom.toml";
|
||||||
|
|
||||||
if let Some(conf_loc) = override_config_path {
|
if let Some(conf_loc) = override_config_path {
|
||||||
|
@ -92,29 +92,73 @@ pub fn get_config_path(override_config_path: Option<&Path>) -> Option<PathBuf> {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the config at `config_path`. If there is no config file at the specified
|
fn create_config_at_path(path: &Path) -> anyhow::Result<Config> {
|
||||||
/// path, it will try to create a new file with the default settings, and return
|
|
||||||
/// the default config. If bottom fails to write a new config, it will silently
|
|
||||||
/// just return the default config.
|
|
||||||
pub fn get_or_create_config(config_path: Option<&Path>) -> OptionResult<Config> {
|
|
||||||
match &config_path {
|
|
||||||
Some(path) => {
|
|
||||||
if let Ok(config_string) = fs::read_to_string(path) {
|
|
||||||
Ok(toml_edit::de::from_str(&config_string)?)
|
|
||||||
} else {
|
|
||||||
if let Some(parent_path) = path.parent() {
|
if let Some(parent_path) = path.parent() {
|
||||||
fs::create_dir_all(parent_path)?;
|
fs::create_dir_all(parent_path)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
fs::File::create(path)?.write_all(CONFIG_TEXT.as_bytes())?;
|
let mut file = fs::File::create(path)?;
|
||||||
|
file.write_all(CONFIG_TEXT.as_bytes())?;
|
||||||
|
|
||||||
Ok(Config::default())
|
Ok(Config::default())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get the config at `config_path`. If there is no config file at the specified
|
||||||
|
/// path, it will try to create a new file with the default settings, and return
|
||||||
|
/// the default config.
|
||||||
|
///
|
||||||
|
/// We're going to use the following behaviour on when we'll return an error rather
|
||||||
|
/// than just "silently" continuing on:
|
||||||
|
/// - If the user passed in a path explicitly, then we will be loud and error out.
|
||||||
|
/// - If the user does NOT pass in a path explicitly, then just show a warning,
|
||||||
|
/// but continue. This is in case they do not want to write a default config file at
|
||||||
|
/// the XDG locations, for example.
|
||||||
|
pub fn get_or_create_config(config_path: Option<&Path>) -> anyhow::Result<Config> {
|
||||||
|
let adjusted_config_path = get_config_path(config_path);
|
||||||
|
|
||||||
|
match &adjusted_config_path {
|
||||||
|
Some(path) => {
|
||||||
|
if let Ok(config_string) = fs::read_to_string(path) {
|
||||||
|
Ok(toml_edit::de::from_str(&config_string)?)
|
||||||
|
} else {
|
||||||
|
match create_config_at_path(path) {
|
||||||
|
Ok(cfg) => Ok(cfg),
|
||||||
|
Err(err) => {
|
||||||
|
if config_path.is_some() {
|
||||||
|
Err(err.context(format!(
|
||||||
|
"bottom could not create a new config file at '{}'.",
|
||||||
|
path.display()
|
||||||
|
)))
|
||||||
|
} else {
|
||||||
|
indoc::eprintdoc!(
|
||||||
|
"Note: bottom couldn't create a default config file at '{}', and the \
|
||||||
|
application has fallen back to the default configuration.
|
||||||
|
|
||||||
|
Caused by:
|
||||||
|
{err}
|
||||||
|
",
|
||||||
|
path.display()
|
||||||
|
);
|
||||||
|
|
||||||
|
Ok(Config::default())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
// If we somehow don't have any config path, then just assume the default config
|
// If we somehow don't have any config path, then just assume the default config
|
||||||
// but don't write to any file.
|
// but don't write to any file.
|
||||||
//
|
//
|
||||||
// TODO: Maybe make this "show" an error, but don't crash.
|
// TODO: For now, just print a message to stderr indicating this. In the future,
|
||||||
|
// probably show in-app (too).
|
||||||
|
|
||||||
|
eprintln!(
|
||||||
|
"Note: bottom couldn't find a location to create or read a config file, so \
|
||||||
|
the application has fallen back to the default configuration. \
|
||||||
|
This could be for a variety of reasons, such as issues with file permissions."
|
||||||
|
);
|
||||||
|
|
||||||
Ok(Config::default())
|
Ok(Config::default())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue