Manuel rust-config-tree
English | 中文 | 日本語 | 한국어 | Français | Deutsch | Español | Português | Svenska | Suomi | Nederlands
Ceci est le manuel francais de rust-config-tree.
Commencez par Introduction, Demarrage rapide ou les Exemples executables.
Introduction
English | 中文 | 日本語 | 한국어 | Français | Deutsch | Español | Português | Svenska | Suomi | Nederlands
rust-config-tree fournit un chargement reutilisable d’arbres de configuration
et des assistants CLI pour les applications Rust qui utilisent des fichiers de
configuration en couches.
La crate est concue autour d’une petite separation des responsabilites :
confiquepossede les definitions de schema, les valeurs par defaut du code, la validation et la generation de modeles de configuration.figmentpossede le chargement d’execution et les metadonnees de source d’execution.rust-config-treepossede la traversee recursive des inclusions, la resolution des chemins d’inclusion, le chargement de.env, la decouverte des cibles de modeles et les commandes clap reutilisables.
La crate est utile lorsqu’une application veut une disposition naturelle des fichiers de configuration comme celle-ci :
include:
- config/server.yaml
- config/database.yaml
log:
level: info
Chaque fichier inclus peut utiliser la meme forme de schema, et les chemins
d’inclusion relatifs sont resolus depuis le fichier qui les a declares. La
configuration finale reste une valeur de schema confique normale.
Fonctionnalites principales
- Traversee recursive des inclusions avec detection des cycles.
- Chemins d’inclusion relatifs resolus depuis le fichier declarant.
- Chargement de
.envavant l’evaluation des fournisseurs d’environnement. - Variables d’environnement declarees par le schema sans separation par delimiteur.
- Metadonnees Figment pour le suivi des sources d’execution.
- Evenements de suivi des sources au niveau TRACE via
tracing. - Generation de schemas JSON Draft 7 pour la completion et les controles de schema de base dans l’editeur.
- Validation des valeurs de champ dans le code applicatif avec
#[config(validate = Self::validate)], executee parload_configouconfig-validate. - Generation de modeles YAML, TOML, JSON et JSON5.
- Directives de schema TOML
#:schema, modelines YAML Language Server et champs JSON/JSON5$schemapour les modeles generes. - Decoupage opt-in des modeles YAML pour les sections marquees
x-tree-split. - Sous-commandes clap integrees pour les modeles de configuration, les schemas JSON et les completions shell.
- API d’arbre de plus bas niveau pour les appelants qui n’utilisent pas
confique.
Points d’entree publics
Utilisez ces API pour la plupart des applications :
load_config::<S>(path)charge le schema final.load_config_with_figment::<S>(path)charge le schema et renvoie le graphe Figment utilise pour le suivi des sources.write_config_templates::<S>(config_path, output_path)ecrit le modele racine et les modeles enfants decouverts recursivement.write_config_schemas::<S>(output_path)ecrit les schemas JSON Draft 7 racine et de section.handle_config_command::<Cli, S>(command, config_path)gere les commandes de configuration clap integrees.
Utilisez load_config_tree lorsque vous avez besoin de la primitive de
traversee sans confique.
Demarrage rapide
English | 中文 | 日本語 | 한국어 | Français | Deutsch | Español | Português | Svenska | Suomi | Nederlands
Ajoutez la crate et les bibliotheques de schema/execution utilisees par votre application :
[dependencies]
rust-config-tree = "0.1"
confique = { version = "0.4", features = ["yaml", "toml", "json5"] }
figment = { version = "0.10", features = ["yaml", "toml", "json", "env"] }
schemars = { version = "1", features = ["derive"] }
serde = { version = "1", features = ["derive"] }
clap = { version = "4", features = ["derive"] }
Definissez un schema confique et implementez ConfigSchema pour le type
racine :
#![allow(unused)]
fn main() {
use std::path::PathBuf;
use confique::Config;
use rust_config_tree::ConfigSchema;
#[derive(Debug, Config)]
struct AppConfig {
#[config(default = [])]
include: Vec<PathBuf>,
#[config(nested)]
server: ServerConfig,
}
#[derive(Debug, Config)]
struct ServerConfig {
#[config(default = "127.0.0.1")]
#[config(env = "APP_SERVER_BIND")]
bind: String,
#[config(default = 8080)]
#[config(env = "APP_SERVER_PORT")]
port: u16,
}
impl ConfigSchema for AppConfig {
fn include_paths(layer: &<Self as Config>::Layer) -> Vec<PathBuf> {
layer.include.clone().unwrap_or_default()
}
}
}
Chargez la configuration :
#![allow(unused)]
fn main() {
use rust_config_tree::load_config;
let config = load_config::<AppConfig>("config.yaml")?;
println!("{config:#?}");
Ok::<(), Box<dyn std::error::Error + Send + Sync>>(())
}
Utilisez un fichier racine avec des inclusions recursives :
# config.yaml
include:
- config/server.yaml
# config/server.yaml
server:
bind: 0.0.0.0
port: 3000
La priorite par defaut de load_config est :
environment variables
> config files, with later merged files overriding earlier files
> confique code defaults
Lorsque les inclusions sont chargees par l’API de haut niveau, le fichier racine a la priorite de fichier la plus elevee. Les fichiers inclus fournissent des valeurs de priorite plus faible et peuvent servir de valeurs par defaut ou de fichiers propres a une section.
Les arguments de ligne de commande sont propres a chaque application, donc
load_config ne les lit pas automatiquement. Fusionnez les remplacements CLI
apres build_config_figment lorsque l’application possede des drapeaux de
remplacement de configuration :
Les noms de drapeaux CLI sont choisis par l’application. Ils ne sont pas
automatiquement des chemins de configuration a.b.c. Preferez des drapeaux
clap normaux comme --server-port, puis mappez-les dans une structure de
remplacement imbriquee. La forme serialisee imbriquee controle la cle de
configuration remplacee.
Seules les valeurs representees dans le fournisseur CliOverrides de
l’application remplacent la configuration. C’est utile pour les parametres
modifies frequemment pour une seule execution sans modifier le fichier de
configuration. Les valeurs stables doivent rester dans les fichiers de
configuration.
#![allow(unused)]
fn main() {
use figment::providers::Serialized;
use serde::Serialize;
use rust_config_tree::{build_config_figment, load_config_from_figment};
#[derive(Debug, Serialize)]
struct CliOverrides {
#[serde(skip_serializing_if = "Option::is_none")]
server: Option<CliServerOverrides>,
}
#[derive(Debug, Serialize)]
struct CliServerOverrides {
#[serde(skip_serializing_if = "Option::is_none")]
port: Option<u16>,
}
let cli_overrides = CliOverrides {
server: Some(CliServerOverrides { port: Some(9000) }),
};
let figment = build_config_figment::<AppConfig>("config.yaml")?
.merge(Serialized::defaults(cli_overrides));
let config = load_config_from_figment::<AppConfig>(&figment)?;
let _ = config;
Ok::<(), Box<dyn std::error::Error + Send + Sync>>(())
}
Avec des remplacements CLI fusionnes ainsi, la priorite complete est :
command-line overrides
> environment variables
> config files
> confique code defaults
Schema de configuration
English | 中文 | 日本語 | 한국어 | Français | Deutsch | Español | Português | Svenska | Suomi | Nederlands
Les schemas d’application sont des types de configuration confique normaux.
Le schema racine doit implementer ConfigSchema afin que rust-config-tree
puisse decouvrir les inclusions recursives depuis la couche intermediaire
confique.
#![allow(unused)]
fn main() {
use std::path::PathBuf;
use confique::Config;
use schemars::JsonSchema;
use rust_config_tree::ConfigSchema;
#[derive(Debug, Config, JsonSchema)]
struct AppConfig {
#[config(default = [])]
include: Vec<PathBuf>,
#[config(nested)]
#[schemars(extend("x-tree-split" = true))]
database: DatabaseConfig,
}
#[derive(Debug, Config, JsonSchema)]
struct DatabaseConfig {
#[config(env = "APP_DATABASE_URL")]
url: String,
#[config(default = 16)]
#[config(env = "APP_DATABASE_POOL_SIZE")]
pool_size: u32,
}
impl ConfigSchema for AppConfig {
fn include_paths(layer: &<Self as Config>::Layer) -> Vec<PathBuf> {
layer.include.clone().unwrap_or_default()
}
}
}
Champ d’inclusion
Le champ d’inclusion peut avoir n’importe quel nom. rust-config-tree ne le
connait qu’au travers de ConfigSchema::include_paths.
Le champ doit normalement avoir une valeur par defaut vide :
#![allow(unused)]
fn main() {
#[config(default = [])]
include: Vec<PathBuf>,
}
Le chargeur recoit une couche partiellement chargee pour chaque fichier. Cela lui permet de decouvrir les fichiers de configuration enfants avant que le schema final soit fusionne et valide.
Sections imbriquees
Utilisez #[config(nested)] pour les sections structurees. Les sections
imbriquees sont toujours utilisees pour le chargement d’execution. Ajoutez
#[schemars(extend("x-tree-split" = true))] lorsqu’un champ imbrique doit aussi
etre genere comme son propre modele *.yaml et schema
<section>.schema.json :
#![allow(unused)]
fn main() {
#[derive(Debug, Config, JsonSchema)]
struct AppConfig {
#[config(nested)]
#[schemars(extend("x-tree-split" = true))]
server: ServerConfig,
}
}
La forme YAML naturelle est :
server:
bind: 127.0.0.1
port: 8080
Champs reserves aux variables d environnement
Marquez un champ feuille avec #[schemars(extend("x-env-only" = true))] lorsque sa valeur doit venir uniquement d une variable d environnement et ne doit pas apparaitre dans les fichiers de configuration generes. Les modeles YAML et schemas JSON generes omettent les champs env-only, et les objets parents devenus vides sont supprimes.
#![allow(unused)]
fn main() {
#[config(env = "APP_SECRET")]
#[schemars(extend("x-env-only" = true))]
secret: String,
}
Validation des valeurs de champ
Les fichiers *.schema.json generes servent uniquement a la completion IDE et
aux controles d’editeur de base. Ils ne decident pas si une valeur de champ
concrete est valide pour l’application.
La validation des valeurs doit etre implementee dans le code avec
#[config(validate = Self::validate)]. Ce validateur s’execute quand la
configuration finale est chargee par load_config ou verifiee par
config-validate.
Remplacements de chemin de section pour les modeles
Lorsqu’une source de modele n’a pas d’inclusions, la crate peut deriver les
fichiers modeles enfants depuis les sections de schema imbriquees marquees x-tree-split. Le chemin de
premier niveau par defaut est <section>.yaml.
Remplacez ce chemin avec template_path_for_section :
#![allow(unused)]
fn main() {
impl ConfigSchema for AppConfig {
fn include_paths(layer: &<Self as Config>::Layer) -> Vec<PathBuf> {
layer.include.clone().unwrap_or_default()
}
fn template_path_for_section(section_path: &[&str]) -> Option<PathBuf> {
match section_path {
["database"] => Some(PathBuf::from("examples/database.yaml")),
_ => None,
}
}
}
}
Chargement d’execution
English | 中文 | 日本語 | 한국어 | Français | Deutsch | Español | Português | Svenska | Suomi | Nederlands
Le chargement d’execution est volontairement separe entre Figment et confique :
figment:
runtime file loading
runtime environment loading
runtime source metadata
confique:
schema metadata
defaults
validation
config templates
L’API principale est :
#![allow(unused)]
fn main() {
use rust_config_tree::load_config;
let config = load_config::<AppConfig>("config.yaml")?;
Ok::<(), Box<dyn std::error::Error + Send + Sync>>(())
}
Utilisez load_config_with_figment lorsque l’application a besoin des
metadonnees de source :
#![allow(unused)]
fn main() {
use rust_config_tree::load_config_with_figment;
let (config, figment) = load_config_with_figment::<AppConfig>("config.yaml")?;
let _ = (config, figment);
Ok::<(), Box<dyn std::error::Error + Send + Sync>>(())
}
Etapes de chargement
Le chargeur de haut niveau effectue ces etapes :
- Resoudre lexicalement le chemin de configuration racine.
- Charger le premier fichier
.envtrouve en remontant depuis le repertoire de configuration racine. - Charger chaque fichier de configuration comme couche partielle pour decouvrir les inclusions.
- Construire un graphe Figment depuis les fichiers de configuration decouverts.
- Fusionner
ConfiqueEnvProvideravec une priorite superieure aux fichiers. - Fusionner eventuellement les remplacements CLI propres a l’application.
- Extraire une couche
confiquedepuis Figment. - Appliquer les valeurs par defaut du code
confique. - Valider et construire le schema final.
load_config et load_config_with_figment effectuent les etapes 1-5 et 7-9.
L’etape 6 est propre a l’application, car cette crate ne peut pas deduire
comment un drapeau CLI correspond a un champ de schema.
Formats de fichier
Le fournisseur de fichier d’execution est choisi depuis l’extension du chemin de configuration :
.yamlet.ymlutilisent YAML..tomlutilise TOML..jsonet.json5utilisent JSON.- les extensions inconnues ou absentes utilisent YAML.
La generation de modeles utilise toujours les renderers de modeles confique
pour les sorties YAML, TOML et compatibles JSON5.
Priorite des inclusions
Le chargeur de haut niveau fusionne les fournisseurs de fichiers de sorte que les fichiers inclus aient une priorite plus faible que le fichier qui les a inclus. Le fichier de configuration racine a la priorite de fichier la plus elevee.
Les variables d’environnement ont une priorite superieure a tous les fichiers de
configuration. Les valeurs par defaut confique ne sont utilisees que pour les
valeurs non fournies par les fournisseurs d’execution.
Lorsque des remplacements CLI sont fusionnes apres build_config_figment, la
priorite complete est :
command-line overrides
> environment variables
> config files
> confique code defaults
La syntaxe de ligne de commande n’est pas definie par rust-config-tree. Un
drapeau comme --server-port peut remplacer server.port si l’application
mappe cette valeur analysee dans un fournisseur serialise imbrique. Une syntaxe
avec points comme --server.port ou a.b.c n’existe que si l’application
l’implemente.
Cela signifie que la priorite CLI ne s’applique qu’aux cles presentes dans le fournisseur de remplacement de l’application. Utilisez-la pour les valeurs operationnelles qui changent souvent pour une seule execution. Laissez la configuration durable dans les fichiers.
#![allow(unused)]
fn main() {
use figment::providers::Serialized;
use serde::Serialize;
use rust_config_tree::{build_config_figment, load_config_from_figment};
#[derive(Debug, Serialize)]
struct CliOverrides {
#[serde(skip_serializing_if = "Option::is_none")]
server: Option<CliServerOverrides>,
}
#[derive(Debug, Serialize)]
struct CliServerOverrides {
#[serde(skip_serializing_if = "Option::is_none")]
port: Option<u16>,
}
let cli_overrides = CliOverrides {
server: Some(CliServerOverrides { port: Some(9000) }),
};
let figment = build_config_figment::<AppConfig>("config.yaml")?
.merge(Serialized::defaults(cli_overrides));
let config = load_config_from_figment::<AppConfig>(&figment)?;
let _ = config;
Ok::<(), Box<dyn std::error::Error + Send + Sync>>(())
}
Variables d’environnement
English | 中文 | 日本語 | 한국어 | Français | Deutsch | Español | Português | Svenska | Suomi | Nederlands
Les noms de variables d’environnement sont declares dans le schema avec
confique :
#![allow(unused)]
fn main() {
#[derive(Debug, Config)]
struct DatabaseConfig {
#[config(env = "APP_DATABASE_URL")]
url: String,
#[config(default = 16)]
#[config(env = "APP_DATABASE_POOL_SIZE")]
pool_size: u32,
}
}
rust-config-tree lit ces noms depuis confique::Config::META et construit un
fournisseur Figment qui associe chaque variable d’environnement a son chemin de
champ exact.
N’utilisez pas le mapping d’environnement Figment base sur des delimiteurs avec cette crate :
#![allow(unused)]
fn main() {
// Do not use this pattern for rust-config-tree schemas.
Env::prefixed("APP_").split("_")
Env::prefixed("APP_").split("__")
}
split("_") traite les underscores comme des separateurs de cles imbriquees.
Cela transforme APP_DATABASE_POOL_SIZE en un chemin comme
database.pool.size, ce qui entre en conflit avec les noms de champs Rust comme
pool_size.
Avec ConfiqueEnvProvider, ce mapping est explicite :
APP_DATABASE_POOL_SIZE -> database.pool_size
Les underscores simples restent une partie du nom de variable d’environnement. Figment ne devine pas la regle d’imbrication.
Chargement dotenv
Avant l’evaluation des fournisseurs d’execution, le chargeur cherche un fichier
.env en remontant depuis le repertoire du fichier de configuration racine.
Les variables d’environnement deja presentes dans le processus sont conservees.
Les valeurs de .env ne remplissent que les variables d’environnement
manquantes.
Exemple :
APP_SERVER_PORT=9000
APP_DATABASE_POOL_SIZE=64
Ces variables remplacent les valeurs des fichiers de configuration lorsque le
schema declare des attributs #[config(env = "...")] correspondants.
Analyse des valeurs
Le fournisseur passerelle laisse Figment analyser les valeurs d’environnement.
Il n’appelle pas les hooks parse_env de confique. Gardez les valeurs
complexes dans les fichiers de configuration sauf si la syntaxe de valeur
d’environnement Figment convient au type.
Suivi des sources
English | 中文 | 日本語 | 한국어 | Français | Deutsch | Español | Português | Svenska | Suomi | Nederlands
Utilisez load_config_with_figment pour conserver le graphe Figment utilise par
le chargement d’execution :
#![allow(unused)]
fn main() {
use rust_config_tree::load_config_with_figment;
let (config, figment) = load_config_with_figment::<AppConfig>("config.yaml")?;
let _ = config;
Ok::<(), Box<dyn std::error::Error + Send + Sync>>(())
}
La valeur Figment renvoyee peut repondre aux questions de source pour les valeurs d’execution :
#![allow(unused)]
fn main() {
if let Some(metadata) = figment.find_metadata("database.pool_size") {
let source = metadata.interpolate(
&figment::Profile::Default,
&["database", "pool_size"],
);
println!("database.pool_size came from {source}");
}
}
Pour les valeurs fournies par ConfiqueEnvProvider, l’interpolation renvoie le
nom natif de la variable d’environnement declaree dans le schema :
database.pool_size came from APP_DATABASE_POOL_SIZE
Evenements TRACE
Le chargeur emet des evenements de suivi des sources avec tracing::trace!. Il
ne le fait que lorsque TRACE est active :
#![allow(unused)]
fn main() {
use rust_config_tree::{load_config_with_figment, trace_config_sources};
let (config, figment) = load_config_with_figment::<AppConfig>("config.yaml")?;
// If the tracing subscriber is initialized after config loading, emit the
// same source events again after installing the subscriber.
trace_config_sources::<AppConfig>(&figment);
let _ = config;
Ok::<(), Box<dyn std::error::Error + Send + Sync>>(())
}
Chaque evenement utilise la cible rust_config_tree::config et inclut :
config_key: la cle de configuration avec points.source: les metadonnees de source rendues.
Les valeurs qui viennent uniquement des valeurs par defaut confique n’ont pas
de metadonnees Figment d’execution. Elles sont signalees comme
confique default or unset optional field.
Generation de modeles
English | 中文 | 日本語 | 한국어 | Français | Deutsch | Español | Português | Svenska | Suomi | Nederlands
Les modeles sont generes depuis le meme schema confique que celui utilise a
l’execution. confique rend le contenu reel du modele, y compris les
commentaires de documentation, les valeurs par defaut, les champs obligatoires
et les noms de variables d’environnement declares.
Utilisez write_config_templates :
#![allow(unused)]
fn main() {
use rust_config_tree::write_config_templates;
write_config_templates::<AppConfig>("config.yaml", "config.example.yaml")?;
Ok::<(), Box<dyn std::error::Error + Send + Sync>>(())
}
Generez des schemas JSON Draft 7 pour la configuration racine et les sections imbriquees :
#![allow(unused)]
fn main() {
use rust_config_tree::write_config_schemas;
write_config_schemas::<AppConfig>("schemas/myapp.schema.json")?;
Ok::<(), Box<dyn std::error::Error + Send + Sync>>(())
}
Marquez un champ imbrique avec #[schemars(extend("x-tree-split" = true))]
lorsqu’il doit etre genere comme son propre modele *.yaml et son propre
schema <section>.schema.json. Les champs imbriques non marques restent dans
le modele parent et le schema parent.
Marquez un champ feuille avec #[schemars(extend("x-env-only" = true))] lorsque la valeur doit venir uniquement de variables d environnement. Les modeles generes et les schemas JSON omettent les champs env-only, et les objets parents devenus vides sont supprimes.
Les schemas generes omettent les contraintes required. Les IDE peuvent
toujours proposer la completion, mais les fichiers partiels comme
log.yaml ne signalent pas de champs racine manquants. Le schema racine
ne complete que les champs qui appartiennent au fichier racine ; les champs de
sections imbriquees y sont omis et sont completes par leurs propres schemas de
section. Les champs presents peuvent encore recevoir des controles d’editeur de
base, comme les types, les enums et les proprietes inconnues pris en charge par
le schema genere. Les *.schema.json generes ne decident pas si une valeur de
champ concrete est valide pour l’application. La validation de valeur doit etre
implementee dans le code avec #[config(validate = Self::validate)] ; load_config
et config-validate executent cette validation d’execution.
Liez ces schemas depuis les modeles TOML, YAML, JSON et JSON5 generes :
#![allow(unused)]
fn main() {
use rust_config_tree::write_config_templates_with_schema;
write_config_templates_with_schema::<AppConfig>(
"config.toml",
"config.example.toml",
"schemas/myapp.schema.json",
)?;
Ok::<(), Box<dyn std::error::Error + Send + Sync>>(())
}
Les modeles racine TOML et YAML lient le schema racine et ne completent pas les
champs des sections enfants. Les modeles YAML de section separee lient leur
schema de section. Les modeles JSON et JSON5 recoivent un champ racine
$schema que VS Code peut reconnaitre. VS Code json.schemas reste une autre
facon de lier le schema.
Le format de sortie est deduit du chemin de sortie :
.yamlet.ymlgenerent du YAML..tomlgenere du TOML..jsonet.json5generent des modeles compatibles JSON5.- les extensions inconnues ou absentes generent du YAML.
Liaisons de schema
Avec un chemin de schema schemas/myapp.schema.json, les modeles racine generes
utilisent :
#:schema ./schemas/myapp.schema.json
# yaml-language-server: $schema=./schemas/myapp.schema.json
Les modeles de section generes lient les schemas de section :
# log.yaml
# yaml-language-server: $schema=./schemas/log.schema.json
Les modeles JSON et JSON5 generes ecrivent un champ racine $schema reconnu
par VS Code. Les parametres d’editeur restent optionnels :
{
"json.schemas": [
{
"fileMatch": [
"/config.json",
"/config.*.json"
],
"url": "./schemas/myapp.schema.json"
}
]
}
Selection de la source des modeles
La generation de modeles choisit son arbre source dans cet ordre :
- Chemin de configuration existant.
- Chemin de modele de sortie existant.
- Chemin de sortie traite comme nouvel arbre de modeles vide.
Cela permet a un projet de mettre a jour les modeles depuis les fichiers de configuration actuels, de mettre a jour un ensemble de modeles existant ou de creer un nouvel ensemble de modeles uniquement depuis le schema.
Arbres d’inclusion miroirs
Si le fichier source declare des inclusions, les modeles generes reproduisent ces chemins d’inclusion sous le repertoire de sortie.
# config.yaml
include:
- server.yaml
Generer config.example.yaml ecrit :
config.example.yaml
server.yaml
Les cibles d’inclusion relatives sont reproduites sous le repertoire parent du fichier de sortie. Les cibles d’inclusion absolues restent absolues.
Decoupage opt-in des sections
Lorsqu’un fichier source n’a pas d’inclusions, la crate peut deriver les cibles
d’inclusion depuis les sections de schema imbriquees marquees x-tree-split. Pour un schema avec une
section server marquee, une source de modele racine vide peut produire :
config.example.yaml
server.yaml
Le modele racine recoit un bloc d’inclusion, et server.yaml ne contient
que la section server. Les sections imbriquees ne sont decoupees recursivement que lorsque ces champs portent aussi x-tree-split.
Completions IDE
English | 中文 | 日本語 | 한국어 | Français | Deutsch | Español | Português | Svenska | Suomi | Nederlands
Les schemas JSON generes peuvent etre utilises par les fichiers de configuration
TOML, YAML, JSON et JSON5. Ils sont generes depuis le meme type Rust que celui
utilise par confique :
#![allow(unused)]
fn main() {
use confique::Config;
use schemars::JsonSchema;
#[derive(Debug, Config, JsonSchema)]
struct AppConfig {
#[config(nested)]
#[schemars(extend("x-tree-split" = true))]
server: ServerConfig,
}
}
Generez-les avec :
#![allow(unused)]
fn main() {
use rust_config_tree::write_config_schemas;
write_config_schemas::<AppConfig>("schemas/myapp.schema.json")?;
Ok::<(), Box<dyn std::error::Error + Send + Sync>>(())
}
Cela ecrit le schema racine et les schemas de section comme
schemas/server.schema.json. Les schemas generes omettent les contraintes
required afin que la completion fonctionne pour les fichiers de configuration
partiels sans diagnostics de champs manquants. Le schema racine omet les
proprietes de sections imbriquees, donc la completion des sections enfants
n’est disponible que dans les fichiers qui lient le schema de section
correspondant.
Les champs marques x-env-only sont omis des schemas generes, donc les IDE ne suggerent pas les secrets ou autres valeurs qui doivent venir uniquement de variables d environnement.
Les schemas IDE servent a la completion et aux controles d’editeur de base,
comme les types, les enums et les controles de proprietes inconnues pris en
charge par le schema genere. Ils ne decident pas si une valeur de champ concrete
est valide pour l’application. La validation de valeur doit etre implementee
dans le code avec #[config(validate = Self::validate)], puis executee par
load_config ou config-validate. Les champs obligatoires et la validation
finale de la configuration fusionnee utilisent aussi ces chemins d’execution.
TOML
Les fichiers TOML doivent lier le schema avec une directive #:schema en haut
du fichier :
#:schema ./schemas/myapp.schema.json
[server]
bind = "0.0.0.0"
port = 3000
N’utilisez pas de champ racine $schema = "..." dans TOML. Il devient une
donnee de configuration reelle et peut affecter la deserialisation d’execution.
write_config_templates_with_schema ajoute automatiquement la directive
#:schema pour les modeles TOML.
YAML
Les fichiers YAML doivent utiliser la modeline YAML Language Server :
# yaml-language-server: $schema=./schemas/myapp.schema.json
server:
bind: 0.0.0.0
port: 3000
write_config_templates_with_schema ajoute automatiquement cette modeline pour
les modeles YAML. Les modeles YAML separes lient leur schema de section, par
exemple log.yaml lie ./schemas/log.schema.json.
JSON
Les fichiers JSON et JSON5 peuvent lier un schema avec un champ racine
$schema. write_config_templates_with_schema l’ajoute automatiquement aux
modeles JSON et JSON5 generes :
{
"$schema": "./schemas/myapp.schema.json"
}
Les parametres de l’editeur restent utiles si un projet ne veut pas de liaison dans le fichier :
{
"json.schemas": [
{
"fileMatch": [
"/config.json",
"/config.*.json",
"/deploy/*.json"
],
"url": "./schemas/myapp.schema.json"
}
]
}
YAML peut aussi etre lie via les parametres VS Code :
{
"yaml.schemas": {
"./schemas/myapp.schema.json": [
"config.yaml",
"config.*.yaml",
"deploy/*.yaml"
]
}
}
La disposition finale est :
schemas/myapp.schema.json:
Champs du fichier racine uniquement
schemas/server.schema.json:
Schema de la section server
config.toml:
#:schema ./schemas/myapp.schema.json
config.yaml:
# yaml-language-server: $schema=./schemas/myapp.schema.json
server.yaml:
# yaml-language-server: $schema=./schemas/server.schema.json
config.json:
"$schema": "./schemas/myapp.schema.json"
References :
Integration CLI
English | 中文 | 日本語 | 한국어 | Français | Deutsch | Español | Português | Svenska | Suomi | Nederlands
ConfigCommand fournit des sous-commandes clap reutilisables :
config-templateconfig-schemaconfig-validatecompletionsinstall-completionsuninstall-completions
Ces sous-commandes integrees sont separees des drapeaux de remplacement de configuration propres a l’application. Fusionnez les drapeaux de remplacement comme fournisseurs Figment dans le chemin de chargement d’execution.
Les drapeaux de remplacement de configuration restent dans la CLI de
l’application consommatrice. Leurs noms n’ont pas besoin de correspondre aux
chemins de configuration avec points. Par exemple, l’application peut analyser
--server-port et le mapper a la cle de configuration imbriquee server.port.
Seuls les drapeaux que l’application mappe dans CliOverrides affectent les
valeurs de configuration.
Aplatissez-le dans une enum de commandes d’application :
- Gardez le type
Parserpropre a l’application. - Gardez l’enum
Subcommandpropre a l’application. - Ajoutez
#[command(flatten)] Config(ConfigCommand)a cette enum. - Clap developpe les variantes
ConfigCommandaplaties au meme niveau de commande que les variantes propres a l’application. - Faites correspondre la variante
Config(command)et passez-la ahandle_config_command.
use std::path::PathBuf;
use clap::{Parser, Subcommand};
use confique::Config;
use schemars::JsonSchema;
use rust_config_tree::{ConfigCommand, ConfigSchema, handle_config_command, load_config};
#[derive(Debug, Config, JsonSchema)]
struct AppConfig {
#[config(default = [])]
include: Vec<PathBuf>,
}
impl ConfigSchema for AppConfig {
fn include_paths(layer: &<Self as Config>::Layer) -> Vec<PathBuf> {
layer.include.clone().unwrap_or_default()
}
}
#[derive(Debug, Parser)]
#[command(name = "demo")]
struct Cli {
#[arg(long, default_value = "config.yaml")]
config: PathBuf,
#[command(subcommand)]
command: Command,
}
#[derive(Debug, Subcommand)]
enum Command {
Run,
#[command(flatten)]
Config(ConfigCommand),
}
fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
let cli = Cli::parse();
match cli.command {
Command::Run => {
let config = load_config::<AppConfig>(&cli.config)?;
println!("{config:#?}");
}
Command::Config(command) => {
handle_config_command::<Cli, AppConfig>(command, &cli.config)?;
}
}
Ok(())
}
Modeles de configuration
demo config-template
La commande ecrit les modeles sous config/<root_config_name>/. Si --output
recoit un chemin, seul le nom de fichier est utilise. Si aucun nom de fichier de
sortie n’est fourni, la commande ecrit
config/<root_config_name>/<root_config_name>.example.yaml. Ajoutez
--schema schemas/myapp.schema.json pour lier les modeles TOML, YAML, JSON et
JSON5 generes aux schemas JSON generes. Les modeles YAML separes lient le
schema de section correspondant. Les modeles JSON et JSON5 recoivent un champ
$schema reconnu par VS Code. La commande ecrit aussi les schemas racine et de
section au chemin de schema choisi.
demo config-template --output app_config.example.toml --schema schemas/myapp.schema.json
Generer les schemas JSON racine et de section :
demo config-schema
Sans --output, config-schema ecrit le schema racine dans
config/<root_config_name>/<root_config_name>.schema.json.
Valider l’arbre complet de configuration d’execution :
demo config-validate
Les schemas d’editeur generes evitent intentionnellement les diagnostics de
champs obligatoires pour les fichiers separes. config-validate charge les
inclusions, applique les valeurs par defaut et lance la validation finale
confique, y compris les validateurs declares avec
#[config(validate = Self::validate)]. Les *.schema.json generes restent
reserves a la completion IDE et aux controles d’editeur de base, pas a la
validation de legalite des valeurs. Elle affiche Configuration is ok lorsque
la validation reussit.
Completions shell
Imprimer les completions sur stdout :
demo completions zsh
Installer les completions :
demo install-completions zsh
Desinstaller les completions :
demo uninstall-completions zsh
L’installateur prend en charge Bash, Elvish, Fish, PowerShell et Zsh. Il ecrit le fichier de completion sous le repertoire home de l’utilisateur et met a jour le fichier de demarrage du shell pour les shells qui l’exigent.
Avant de modifier un fichier de demarrage shell existant comme ~/.zshrc,
~/.bashrc, un fichier rc Elvish ou un profil PowerShell, la commande ecrit
une sauvegarde a cote du fichier original :
<rc-file>.backup.by.<program-name>.<timestamp>
Exemples
English | 中文 | 日本語 | 한국어 | Français | Deutsch | Español | Português | Svenska | Suomi | Nederlands
Le depot inclut des exemples executables pour charger des arbres de configuration, appliquer des remplacements CLI, utiliser les commandes de configuration integrees, generer des modeles et utiliser l’API d’arbre de plus bas niveau.
Lisez l’index des exemples du depot :
Executez les exemples depuis la racine du depot :
cargo run --example basic_loading
cargo run --example cli_overrides -- --server-port 9000
cargo run --example config_commands -- config-template
cargo run --example config_commands -- config-schema
cargo run --example config_commands -- config-validate
cargo run --example generate_templates
cargo run --example tree_api
API d’arbre
English | 中文 | 日本語 | 한국어 | Français | Deutsch | Español | Português | Svenska | Suomi | Nederlands
Utilisez l’API d’arbre de plus bas niveau lorsque l’application n’utilise pas
confique, ou lorsqu’elle a besoin d’un acces direct aux resultats de
traversee.
#![allow(unused)]
fn main() {
use std::{
fs,
io,
path::{Path, PathBuf},
};
use rust_config_tree::{ConfigSource, load_config_tree};
fn load_source(path: &Path) -> io::Result<ConfigSource<String>> {
let content = fs::read_to_string(path)?;
let includes = content
.lines()
.filter_map(|line| line.strip_prefix("include: "))
.map(PathBuf::from)
.collect();
Ok(ConfigSource::new(content, includes))
}
let tree = load_config_tree("config.yaml", load_source)?;
for node in tree.nodes() {
println!("{}", node.path().display());
}
Ok::<(), Box<dyn std::error::Error + Send + Sync>>(())
}
Regles de traversee
Le chargeur d’arbre :
- normalise lexicalement les chemins sources ;
- rejette les chemins d’inclusion vides ;
- resout les inclusions relatives depuis le fichier qui les a declarees ;
- preserve les chemins d’inclusion absolus ;
- detecte les cycles d’inclusion recursifs ;
- ignore les fichiers deja charges par une autre branche d’inclusion.
ConfigTreeOptions peut inverser la traversee des inclusions soeurs :
#![allow(unused)]
fn main() {
use rust_config_tree::{ConfigTreeOptions, IncludeOrder};
let options = ConfigTreeOptions::default().include_order(IncludeOrder::Reverse);
let _ = options;
}
Assistants de chemin
Les assistants de chemin sont uniquement lexicaux. Ils ne resolvent pas les liens symboliques et n’exigent pas que les chemins existent :
absolutize_lexical(path)normalize_lexical(path)resolve_include_path(parent_path, include_path)
GitHub Pages
English | 中文 | 日本語 | 한국어 | Français | Deutsch | Español | Português | Svenska | Suomi | Nederlands
Ce depot publie le manuel avec mdBook et GitHub Pages.
Les manuels de chaque langue sont des projets mdBook independants. Chaque
langue a son propre SUMMARY.md, donc la barre laterale gauche ne contient que
les pages de la langue courante :
manual/
en/
book.toml
SUMMARY.md
introduction.md
quick-start.md
...
zh/
book.toml
SUMMARY.md
introduction.md
quick-start.md
...
ja/
book.toml
SUMMARY.md
introduction.md
quick-start.md
...
Construisez localement avec :
scripts/publish-pages.sh
Le site genere est ecrit dans :
target/mdbook
Workflow de publication
Le workflow dans .github/workflows/pages.yml s’execute lors des pushes vers
main et en declenchement manuel. Il :
- Recupere le depot.
- Installe mdBook.
- Execute
scripts/publish-pages.sh. - Televerse
target/mdbookcomme artefact Pages. - Deploie l’artefact vers GitHub Pages.
L’URL publiee est :
https://developerworks.github.io/rust-config-tree/
Publication de la crate
Pour le flux complet de commit, push, deploiement Pages et publication de la crate :
scripts/release.sh --execute --message "Release 0.1.3"
Utilisez l’assistant de publication de crate depuis la racine du depot :
scripts/publish-crate.sh
Le mode par defaut lance les controles et cargo publish --dry-run. Pour
publier sur crates.io apres la reussite des controles. Si la version courante
existe deja sur crates.io, le script incremente automatiquement la version
patch :
scripts/publish-crate.sh --execute
L’utilisation des scripts est resumee dans scripts/README.md.