mirror of
https://github.com/meilisearch/meilisearch.git
synced 2024-11-22 18:17:39 +08:00
Merge #2804
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:
commit
b0749407f3
10
Cargo.lock
generated
10
Cargo.lock
generated
@ -2134,6 +2134,7 @@ dependencies = [
|
||||
"static-files",
|
||||
"sysinfo",
|
||||
"tar",
|
||||
"temp-env",
|
||||
"tempfile",
|
||||
"thiserror",
|
||||
"time",
|
||||
@ -3490,6 +3491,15 @@ dependencies = [
|
||||
"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]]
|
||||
name = "tempfile"
|
||||
version = "3.3.0"
|
||||
|
@ -91,6 +91,7 @@ manifest-dir-macros = "0.1.16"
|
||||
maplit = "1.0.2"
|
||||
urlencoding = "2.1.2"
|
||||
yaup = "0.2.1"
|
||||
temp-env = "0.3.1"
|
||||
|
||||
[features]
|
||||
default = ["analytics", "meilisearch-lib/default", "mini-dashboard"]
|
||||
|
@ -1,3 +1,4 @@
|
||||
use std::env;
|
||||
use std::fs;
|
||||
use std::io::{BufReader, Read};
|
||||
use std::path::PathBuf;
|
||||
@ -51,6 +52,7 @@ const MEILI_LOG_LEVEL: &str = "MEILI_LOG_LEVEL";
|
||||
#[cfg(feature = "metrics")]
|
||||
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_HTTP_ADDR: &str = "localhost:7700";
|
||||
const DEFAULT_ENV: &str = "development";
|
||||
@ -261,32 +263,38 @@ impl Opt {
|
||||
// Parse the args to get the config_file_path.
|
||||
let mut opts = Opt::parse();
|
||||
let mut config_read_from = None;
|
||||
if let Some(config_file_path) = opts
|
||||
let user_specified_config_file_path = opts
|
||||
.config_file_path
|
||||
.clone()
|
||||
.or_else(|| Some(PathBuf::from("./config.toml")))
|
||||
{
|
||||
match std::fs::read(&config_file_path) {
|
||||
Ok(config) => {
|
||||
// If the file is successfully read, we deserialize it with `toml`.
|
||||
let opt_from_config = toml::from_slice::<Opt>(&config)?;
|
||||
// Return an error if config file contains 'config_file_path'
|
||||
// Using that key in the config file doesn't make sense bc it creates a logical loop (config file referencing itself)
|
||||
if opt_from_config.config_file_path.is_some() {
|
||||
anyhow::bail!("`config_file_path` is not supported in config file")
|
||||
}
|
||||
// We inject the values from the toml in the corresponding env vars if needs be. Doing so, we respect the priority toml < env vars < cli args.
|
||||
opt_from_config.export_to_env();
|
||||
// Once injected we parse the cli args once again to take the new env vars into scope.
|
||||
opts = Opt::parse();
|
||||
config_read_from = Some(config_file_path);
|
||||
.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) {
|
||||
Ok(config) => {
|
||||
// If the file is successfully read, we deserialize it with `toml`.
|
||||
let opt_from_config = toml::from_slice::<Opt>(&config)?;
|
||||
// Return an error if config file contains 'config_file_path'
|
||||
// Using that key in the config file doesn't make sense bc it creates a logical loop (config file referencing itself)
|
||||
if opt_from_config.config_file_path.is_some() {
|
||||
anyhow::bail!("`config_file_path` is not supported in config file")
|
||||
}
|
||||
// We inject the values from the toml in the corresponding env vars if needs be. Doing so, we respect the priority toml < env vars < cli args.
|
||||
opt_from_config.export_to_env();
|
||||
// Once injected we parse the cli args once again to take the new env vars into scope.
|
||||
opts = Opt::parse();
|
||||
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.
|
||||
anyhow::bail!(
|
||||
"unable to open or read the {:?} configuration file: {}.",
|
||||
path,
|
||||
e,
|
||||
)
|
||||
}
|
||||
// If we have an error while reading the file defined by the user.
|
||||
Err(_) if opts.config_file_path.is_some() => anyhow::bail!(
|
||||
"unable to open or read the {:?} configuration file.",
|
||||
opts.config_file_path.unwrap().display().to_string()
|
||||
),
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
|
||||
@ -521,10 +529,41 @@ fn default_log_level() -> String {
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_valid_opt() {
|
||||
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
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user