Use standard paths for a possible config location

Check several possible standard paths when there is no path to the
configuration file given as argument. To find the configuration file
following paths are used. The local directory `./config.toml`, the
user global configuration directory
`$XDG_CONFIG_HOME/whakarite/config.toml` and the system wide
configuration directory `/etc/whakarite/config.toml`. Note that in the
later two cases the directory which contains the `config.toml`
receives its name from the `$CARGO_BIN_NAME` environment variable at
compile time.
This commit is contained in:
finga 2023-01-25 22:11:32 +01:00
parent 21396daf83
commit 0434505b2d
5 changed files with 124 additions and 9 deletions

79
Cargo.lock generated
View file

@ -124,6 +124,26 @@ dependencies = [
"syn", "syn",
] ]
[[package]]
name = "dirs"
version = "4.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ca3aa72a6f96ea37bbc5aa912f6788242832f75369bdfdadcb0e38423f100059"
dependencies = [
"dirs-sys",
]
[[package]]
name = "dirs-sys"
version = "0.3.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1b1d1d91c932ef41c0f2663aa8b0ca0342d444d842c06914aa0a7e352d0bada6"
dependencies = [
"libc",
"redox_users",
"winapi",
]
[[package]] [[package]]
name = "email-encoding" name = "email-encoding"
version = "0.1.3" version = "0.1.3"
@ -218,6 +238,17 @@ dependencies = [
"slab", "slab",
] ]
[[package]]
name = "getrandom"
version = "0.2.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31"
dependencies = [
"cfg-if",
"libc",
"wasi",
]
[[package]] [[package]]
name = "hashbrown" name = "hashbrown"
version = "0.12.3" version = "0.12.3"
@ -632,6 +663,17 @@ dependencies = [
"bitflags", "bitflags",
] ]
[[package]]
name = "redox_users"
version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b"
dependencies = [
"getrandom",
"redox_syscall",
"thiserror",
]
[[package]] [[package]]
name = "remove_dir_all" name = "remove_dir_all"
version = "0.5.3" version = "0.5.3"
@ -805,6 +847,26 @@ dependencies = [
"winapi-util", "winapi-util",
] ]
[[package]]
name = "thiserror"
version = "1.0.38"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6a9cd18aa97d5c45c6603caea1da6628790b37f7a34b6ca89522331c5180fed0"
dependencies = [
"thiserror-impl",
]
[[package]]
name = "thiserror-impl"
version = "1.0.38"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1fb327af4685e4d03fa8cbcf1716380da910eeb2bb8be417e7f9fd3fb164f36f"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]] [[package]]
name = "thread_local" name = "thread_local"
version = "1.1.4" version = "1.1.4"
@ -987,6 +1049,12 @@ version = "0.9.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
[[package]]
name = "wasi"
version = "0.11.0+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
[[package]] [[package]]
name = "whakarite" name = "whakarite"
version = "0.1.0" version = "0.1.0"
@ -995,12 +1063,12 @@ dependencies = [
"clap", "clap",
"diesel", "diesel",
"lettre", "lettre",
"log",
"serde", "serde",
"time", "time",
"toml", "toml",
"tracing", "tracing",
"tracing-subscriber", "tracing-subscriber",
"xdg",
] ]
[[package]] [[package]]
@ -1090,3 +1158,12 @@ name = "windows_x86_64_msvc"
version = "0.42.1" version = "0.42.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "447660ad36a13288b1db4d4248e857b510e8c3a225c822ba4fb748c0aafecffd" checksum = "447660ad36a13288b1db4d4248e857b510e8c3a225c822ba4fb748c0aafecffd"
[[package]]
name = "xdg"
version = "2.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0c4583db5cbd4c4c0303df2d15af80f0539db703fa1c68802d4cbbd2dd0f88f6"
dependencies = [
"dirs",
]

View file

@ -11,7 +11,6 @@ categories = ["utility"]
[dependencies] [dependencies]
anyhow = "1" anyhow = "1"
log = "0.4"
tracing = "0.1" tracing = "0.1"
tracing-subscriber = "0.3" tracing-subscriber = "0.3"
time = "0.3" time = "0.3"
@ -20,3 +19,4 @@ diesel = { version = "2", features = ["postgres", "r2d2", "time"] }
serde = { version = "1", features = ["derive"] } serde = { version = "1", features = ["derive"] }
toml = "0.6" toml = "0.6"
clap = { version = "4", features = ["derive"] } clap = { version = "4", features = ["derive"] }
xdg = "2"

View file

@ -7,7 +7,7 @@ use tracing::Level;
pub struct Args { pub struct Args {
/// Use a custom config file /// Use a custom config file
#[arg(short, long, value_name = "FILE")] #[arg(short, long, value_name = "FILE")]
config: Option<PathBuf>, pub config: Option<PathBuf>,
/// Set a log level /// Set a log level
#[arg(short, long, value_name = "LEVEL", default_value_t = Level::INFO)] #[arg(short, long, value_name = "LEVEL", default_value_t = Level::INFO)]

View file

@ -1,4 +1,7 @@
use anyhow::{bail, Result};
use serde::Deserialize; use serde::Deserialize;
use std::{env, fs, path::PathBuf};
use tracing::{error, info, trace};
fn default_host() -> String { fn default_host() -> String {
"localhost".to_string() "localhost".to_string()
@ -45,3 +48,43 @@ pub struct Config {
/// Database configuration /// Database configuration
pub database: Database, pub database: Database,
} }
impl Config {
fn try_paths() -> Result<(PathBuf, String)> {
let file = "config.toml";
info!(?file, "loading configuration");
if let Ok(config) = fs::read_to_string(&file) {
return Ok((file.into(), config));
}
let user_file =
xdg::BaseDirectories::with_prefix(env!("CARGO_BIN_NAME"))?.get_config_file(file);
info!(file = ?user_file, "loading configuration");
if let Ok(config) = fs::read_to_string(&user_file) {
return Ok((user_file, config));
}
let global_file = format!("/etc/{}/{}", env!("CARGO_BIN_NAME"), file);
info!(file = ?global_file, "loading configuration");
if let Ok(config) = fs::read_to_string(&global_file) {
return Ok((global_file.into(), config));
}
error!("no configuration file found");
bail!("no configuration file found");
}
pub fn load_config(file: Option<PathBuf>) -> Result<Self> {
if let Some(file) = file {
info!(?file, "loading configuration");
let config: Config = toml::from_str(&fs::read_to_string(&file)?)?;
trace!(?file, ?config, "loaded configuration");
Ok(config)
} else {
let (file, config) = Self::try_paths()?;
let config = toml::from_str(&config)?;
trace!(?file, ?config, "loaded configuration");
Ok(config)
}
}
}

View file

@ -71,12 +71,7 @@ fn main() -> Result<()> {
env!("CARGO_PKG_VERSION") env!("CARGO_PKG_VERSION")
); );
let config_path = "./config.toml"; let config = Config::load_config(args.config)?;
let config: Config = toml::from_str(&std::fs::read_to_string(config_path)?)?;
trace!(?config, config_path, "loaded config");
let db_pool = Pool::builder().build(ConnectionManager::<PgConnection>::new(format!( let db_pool = Pool::builder().build(ConnectionManager::<PgConnection>::new(format!(
"postgresql://{}:{}@{}:{}/{}", "postgresql://{}:{}@{}:{}/{}",
config.database.user, config.database.user,