2804: Add environement variable `MEILI_CONFIG_FILE_PATH` to define the config file path r=Kerollmops a=choznerol

# Pull Request

## What does this PR do?
Fixes #2800

~This is a draft PR base on the code in #2745. I will `rebase` and mark it ready for review only after #2745 merge.~ Done rebase


## PR checklist
Please check if your PR fulfills the following requirements:
- [x] Does this PR fix an existing issue?
- [x] Have you read the contributing guidelines?
- [x] Have you made sure that the title is accurate and descriptive of the changes?


## Demo

With `config.toml`, `config_copy1.toml` and `config_copy2.toml` present:
> <img width="692" alt="image" src="https://user-images.githubusercontent.com/12410942/192566891-6b3c9d26-736f-4e23-a09b-687fca1cb50d.png">

`MEILI_CONFIG_FILE_PATH` works:
> <img width="773" alt="image" src="https://user-images.githubusercontent.com/12410942/192567023-f751536e-992a-4e90-a176-cb19122248be.png">

`--config-file-path` still works:
> <img width="768" alt="image" src="https://user-images.githubusercontent.com/12410942/192567318-88c80b24-7873-4cec-8d08-16fe4d228055.png">

When both present, `--config-file-path` taks precedence:
> <img width="1214" alt="image" src="https://user-images.githubusercontent.com/12410942/192567477-8a7cffe1-96f0-42a9-a348-6dbec20dc1e7.png">



Co-authored-by: Lawrence Chou <choznerol@protonmail.com>
This commit is contained in:
bors[bot] 2022-10-17 10:40:05 +00:00 committed by GitHub
commit b0749407f3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 73 additions and 23 deletions

10
Cargo.lock generated
View File

@ -2134,6 +2134,7 @@ dependencies = [
"static-files", "static-files",
"sysinfo", "sysinfo",
"tar", "tar",
"temp-env",
"tempfile", "tempfile",
"thiserror", "thiserror",
"time", "time",
@ -3490,6 +3491,15 @@ dependencies = [
"xattr", "xattr",
] ]
[[package]]
name = "temp-env"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a30d48359f77fbb6af3d7b928cc2d092e1dc90b44f397e979ef08ae15733ed65"
dependencies = [
"once_cell",
]
[[package]] [[package]]
name = "tempfile" name = "tempfile"
version = "3.3.0" version = "3.3.0"

View File

@ -91,6 +91,7 @@ manifest-dir-macros = "0.1.16"
maplit = "1.0.2" maplit = "1.0.2"
urlencoding = "2.1.2" urlencoding = "2.1.2"
yaup = "0.2.1" yaup = "0.2.1"
temp-env = "0.3.1"
[features] [features]
default = ["analytics", "meilisearch-lib/default", "mini-dashboard"] default = ["analytics", "meilisearch-lib/default", "mini-dashboard"]

View File

@ -1,3 +1,4 @@
use std::env;
use std::fs; use std::fs;
use std::io::{BufReader, Read}; use std::io::{BufReader, Read};
use std::path::PathBuf; use std::path::PathBuf;
@ -51,6 +52,7 @@ const MEILI_LOG_LEVEL: &str = "MEILI_LOG_LEVEL";
#[cfg(feature = "metrics")] #[cfg(feature = "metrics")]
const MEILI_ENABLE_METRICS_ROUTE: &str = "MEILI_ENABLE_METRICS_ROUTE"; const MEILI_ENABLE_METRICS_ROUTE: &str = "MEILI_ENABLE_METRICS_ROUTE";
const DEFAULT_CONFIG_FILE_PATH: &str = "./config.toml";
const DEFAULT_DB_PATH: &str = "./data.ms"; const DEFAULT_DB_PATH: &str = "./data.ms";
const DEFAULT_HTTP_ADDR: &str = "localhost:7700"; const DEFAULT_HTTP_ADDR: &str = "localhost:7700";
const DEFAULT_ENV: &str = "development"; const DEFAULT_ENV: &str = "development";
@ -261,11 +263,14 @@ impl Opt {
// Parse the args to get the config_file_path. // Parse the args to get the config_file_path.
let mut opts = Opt::parse(); let mut opts = Opt::parse();
let mut config_read_from = None; let mut config_read_from = None;
if let Some(config_file_path) = opts let user_specified_config_file_path = opts
.config_file_path .config_file_path
.clone() .clone()
.or_else(|| Some(PathBuf::from("./config.toml"))) .or_else(|| env::var("MEILI_CONFIG_FILE_PATH").map(PathBuf::from).ok());
{ let config_file_path = user_specified_config_file_path
.clone()
.unwrap_or_else(|| PathBuf::from(DEFAULT_CONFIG_FILE_PATH));
match std::fs::read(&config_file_path) { match std::fs::read(&config_file_path) {
Ok(config) => { Ok(config) => {
// If the file is successfully read, we deserialize it with `toml`. // If the file is successfully read, we deserialize it with `toml`.
@ -281,12 +286,15 @@ impl Opt {
opts = Opt::parse(); opts = Opt::parse();
config_read_from = Some(config_file_path); config_read_from = Some(config_file_path);
} }
Err(e) => {
if let Some(path) = user_specified_config_file_path {
// If we have an error while reading the file defined by the user. // If we have an error while reading the file defined by the user.
Err(_) if opts.config_file_path.is_some() => anyhow::bail!( anyhow::bail!(
"unable to open or read the {:?} configuration file.", "unable to open or read the {:?} configuration file: {}.",
opts.config_file_path.unwrap().display().to_string() path,
), e,
_ => (), )
}
} }
} }
@ -521,10 +529,41 @@ fn default_log_level() -> String {
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use super::*; use super::*;
#[test] #[test]
fn test_valid_opt() { fn test_valid_opt() {
assert!(Opt::try_parse_from(Some("")).is_ok()); assert!(Opt::try_parse_from(Some("")).is_ok());
} }
#[test]
fn test_meilli_config_file_path_valid() {
temp_env::with_vars(
vec![("MEILI_CONFIG_FILE_PATH", Some("../config.toml"))], // Relative path in meilisearch_http package
|| {
assert!(Opt::try_build().is_ok());
},
);
}
#[test]
fn test_meilli_config_file_path_invalid() {
temp_env::with_vars(
vec![("MEILI_CONFIG_FILE_PATH", Some("../configgg.toml"))],
|| {
let possible_error_messages = [
"unable to open or read the \"../configgg.toml\" configuration file: No such file or directory (os error 2).",
"unable to open or read the \"../configgg.toml\" configuration file: The system cannot find the file specified. (os error 2).", // Windows
];
let error_message = Opt::try_build().unwrap_err().to_string();
assert!(
possible_error_messages.contains(&error_message.as_str()),
"Expected onf of {:?}, got {:?}.",
possible_error_messages,
error_message
);
},
);
}
} }