Merge pull request 'Rendre le système de fichier de configuration runtime fonctionnel en dev et en release' (#56) from fix/55_move_env_config_into_consistent_dirs into main

Reviewed-on: #56
Reviewed-by: kosssi <simon@p4pillon.org>

# Détails

- Rajoute une librairie d'utilitaires crates/utils
- Rajoute des fonctions de gestion des fichiers et dossiers de configuration dans la lib utils, dont une fonction de chargement du fichier de config approprié
- Remplace le chargement d'un .env relatif au CARGO_MANIFEST_DIR de la librairie sesam-vitale par la fonction de chargement de config

La fonction de chargement de config génère une hiérarchie d'emplacements de fichiers de config (.env dans : dossier courant, dossier manifest, dossier système) et charge le "plus proche", afin de permettre d'avoir une configuration stable au niveau système, mais de pouvoir la surcharger facilement en local, en particulier lors de phases de développement).
Pourquoi ?

L'usage de CARGO_MANIFEST_DIR pour trouver le fichier de configuration n'était pas viable, car cette variable d'environnement n'existe que lors d'un lancement via cargo run, mais pas lors d'un appel direct à l'executable buildé.
La nouvelle implémentation est maintenant totalement compatible, autant avec des approches de surcharge en développement que pour de installations pérennes sur un système.

# Documentation

Le chemin standard des fichiers de config, spécifique à chaque OS, est obtenu à l'aide de la librairie directories-rs

Closes #55
This commit is contained in:
Florian Briand 2024-08-30 18:29:56 +02:00
commit ca2a0ace71
12 changed files with 105 additions and 12 deletions

2
.gitignore vendored
View File

@ -21,3 +21,5 @@ target/
*.sln
*.sw?
# Ignore .env files
.env

19
Cargo.lock generated
View File

@ -1097,6 +1097,15 @@ dependencies = [
"crypto-common",
]
[[package]]
name = "directories"
version = "5.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a49173b84e034382284f27f1af4dcbbd231ffa358c0fe316541a7337f376a35"
dependencies = [
"dirs-sys 0.4.1",
]
[[package]]
name = "dirs"
version = "4.0.0"
@ -3951,6 +3960,7 @@ dependencies = [
"dotenv",
"libc",
"thiserror",
"utils",
]
[[package]]
@ -5068,6 +5078,15 @@ version = "0.7.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9"
[[package]]
name = "utils"
version = "0.1.0"
dependencies = [
"anyhow",
"directories",
"dotenv",
]
[[package]]
name = "uuid"
version = "0.8.2"

View File

@ -3,5 +3,6 @@ resolver = "2"
members = [
"crates/app",
"crates/sesam-vitale",
"crates/desktop"
"crates/desktop",
"crates/utils",
]

View File

@ -7,6 +7,20 @@ Logiciel de Pharmacie libre et open-source.
- `app`: Interface du logiciel, servie par un serveur web propulsé par Axum. Utilisable en mode endpoint ou encapsulé dans le client `desktop`
- `desktop`: Client desktop propulsé par Tauri, encapsulant le serveur web `app`
- `sesam-vitale`: Bibliothèque de gestion des services SESAM-Vitale (Lecture des cartes CPS et Vitale, téléservices ...)
- `utils`: Bibliothèque de fonctions utilitaires
## Installation
### Fichiers de configuration
Certaines librairies nécessitent de définir certaines paramètres de configuration pour fonctionner correctement, en particulier le moteur SESAM-Vitale.
Ces paramètres sont définis dans un fichier de configuration `.env` situé dans un des dossiers suivant (par ordre de priorité) :
- dans le dossier courant (`./.env`)
- dans le dossier du manifeste (par exemple `crates/sesam-vitale/.env`)
- dans le dossier de configuration standard de l'OS (par exemple, sur linux, `~/.config/krys4lide/.env` - [plus d'info](https://github.com/dirs-dev/directories-rs?tab=readme-ov-file#projectdirs))
Des exemples de fichiers de configuration sont disponibles à la racine du projet : `.env.linux.example` et `.env.win.example`.
## Development

View File

@ -4,10 +4,10 @@ version = "0.1.0"
edition = "2021"
[dependencies]
anyhow = "1.0.86"
dotenv = "0.15"
anyhow = "1.0"
libc = "0.2"
thiserror = "1.0.63"
thiserror = "1.0"
utils = { path = "../utils" }
[build-dependencies]
dotenv = "0.15"

View File

@ -1,13 +1,13 @@
extern crate dotenv;
use std::env;
use std::path::PathBuf;
use dotenv::from_path;
fn main() {
// Load the .env.build file for build-time environment variables
let manifest_dir = env::var("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR must be set");
let manifest_path = PathBuf::from(manifest_dir);
dotenv::from_path(manifest_path.join(".env.build")).ok();
from_path(manifest_path.join(".env.build")).ok();
println!("cargo::rerun-if-env-changed=SESAM_FSV_LIB_PATH");
println!("cargo::rerun-if-env-changed=SESAM_FSV_SSVLIB");

View File

@ -1,16 +1,16 @@
/// High level API for the SSV library,
/// based on the low level bindings in libssv.rs.
extern crate dotenv;
use libc::{c_void, size_t};
use std::env;
use std::ffi::CString;
use std::path::PathBuf;
use std::ptr;
use thiserror::Error;
use crate::cps::lire_carte;
use crate::libssv::{SSV_InitLIB2, SSV_LireConfig};
use ::utils::config::load_config;
#[derive(Error, Debug)]
pub enum SSVDemoError {
#[error(transparent)]
@ -66,12 +66,11 @@ fn ssv_lire_config() -> Result<(), SSVDemoError> {
pub fn demo() -> Result<(), SSVDemoError> {
// TODO : this is probably not working on release, because I'm not sure it exists a CARGO_MANIFEST_DIR and so it can find the `.env`
// Maybe we could use a system standard config path to store a config file
let manifest_dir = env::var("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR must be set");
let manifest_path = PathBuf::from(manifest_dir);
dotenv::from_path(manifest_path.join(".env")).ok();
println!("------- Demo for the SSV library --------");
load_config()?;
ssv_init_lib_2()?;
let code_pin = "1234";

9
crates/utils/Cargo.toml Normal file
View File

@ -0,0 +1,9 @@
[package]
name = "utils"
version = "0.1.0"
edition = "2021"
[dependencies]
anyhow = "1.0"
directories = "5.0"
dotenv = "0.15"

View File

@ -0,0 +1,48 @@
use std::{env, path::PathBuf};
use anyhow::{bail, Context, Result};
use directories::ProjectDirs;
use dotenv::from_path;
const CONFIG_FILE_NAME: &str = ".env";
pub fn get_config_dirs() -> Vec<PathBuf> {
let mut config_dirs = vec![
PathBuf::from(""), // Current directory
];
if let Ok(manifest_dir) = env::var("CARGO_MANIFEST_DIR") {
config_dirs.push(PathBuf::from(manifest_dir));
}
if let Some(proj_dirs) = ProjectDirs::from("org", "P4pillon", "Krys4lide") {
config_dirs.push(proj_dirs.config_dir().to_path_buf());
}
config_dirs
}
pub fn get_config_files() -> Result<Vec<PathBuf>> {
let config_dirs = get_config_dirs();
let mut config_files = Vec::new();
for config_dir in config_dirs.iter() {
let config_file = config_dir.join(CONFIG_FILE_NAME);
if config_file.exists() {
config_files.push(config_file);
}
}
if config_files.is_empty() {
bail!(
"No config file {CONFIG_FILE_NAME} found in the following directories: {config_dirs:#?}"
);
}
Ok(config_files)
}
pub fn load_config() -> Result<()> {
let config_files = get_config_files()?;
// Load the first config file found
// TODO: add a verbose log to list all config files found
println!(
"DEBUG: Config files found (1st loaded): {:#?}",
config_files
);
from_path(config_files[0].as_path()).context("Failed to load config file")
}

1
crates/utils/src/lib.rs Normal file
View File

@ -0,0 +1 @@
pub mod config;