Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

rust-config-tree handleiding

English | 中文 | 日本語 | 한국어 | Français | Deutsch | Español | Português | Svenska | Suomi | Nederlands

Dit is de Nederlandse handleiding voor rust-config-tree.

Begin met Introductie, Snelstart of de uitvoerbare Voorbeelden.

Introductie

English | 中文 | 日本語 | 한국어 | Français | Deutsch | Español | Português | Svenska | Suomi | Nederlands

rust-config-tree biedt herbruikbare configuratieboomlading en CLI-hulpmiddelen voor Rust-toepassingen die gelaagde configuratiebestanden gebruiken.

De crate is ontworpen rond een kleine verdeling van verantwoordelijkheden:

  • confique bezit schemadefinities, codestandaarden, validatie en generatie van configuratiesjablonen.
  • figment bezit runtime laden en runtime bronmetadata.
  • rust-config-tree bezit recursieve include-traversal, oplossen van include-paden, .env laden, ontdekking van sjabloondoelen en herbruikbare clap-opdrachten.

De crate is nuttig wanneer een toepassing een natuurlijke configuratie-indeling zoals deze wil:

include:
  - config/server.yaml
  - config/database.yaml

log:
  level: info

Elk geinclude bestand kan dezelfde schemavorm gebruiken, en relatieve include-paden worden opgelost vanuit het bestand dat ze declareerde. De uiteindelijke configuratie is nog steeds een normale confique-schemawaarde.

Hoofdfuncties

  • Recursieve include-traversal met cycledetectie.
  • Relatieve include-paden opgelost vanuit het declarerende bestand.
  • .env laden voordat omgevingsproviders worden geevalueerd.
  • Door het schema gedeclareerde omgevingsvariabelen zonder delimiter-splitting.
  • Figment-metadata voor runtime brontracking.
  • Brontrackingevents op TRACE-niveau via tracing.
  • Draft 7 JSON Schema-generatie voor editorcompletion en basale schemacontroles.
  • Veldwaardevalidatie in toepassingscode met #[config(validate = Self::validate)], uitgevoerd door load_config of config-validate.
  • YAML-, TOML-, JSON- en JSON5-sjabloongeneratie.
  • TOML #:schema, YAML Language Server-schemamodelines en JSON/JSON5 $schema-velden voor gegenereerde sjablonen.
  • Opt-in YAML-sjabloonsplitsing voor secties gemarkeerd met x-tree-split.
  • Ingebouwde clap-subcommands voor configuratiesjablonen, JSON Schema en shellcompletions.
  • Een lagere tree-API voor callers die geen confique gebruiken.

Publieke entrypoints

Gebruik deze API’s voor de meeste toepassingen:

  • load_config::<S>(path) laadt het uiteindelijke schema.
  • load_config_with_figment::<S>(path) laadt het schema en retourneert de Figment-grafiek die voor brontracking wordt gebruikt.
  • write_config_templates::<S>(config_path, output_path) schrijft het rootsjabloon en recursief ontdekte kindsjablonen.
  • write_config_schemas::<S>(output_path) schrijft root- en sectie-Draft 7 JSON Schemas.
  • handle_config_command::<Cli, S>(command, config_path) verwerkt ingebouwde clap-configuratieopdrachten.

Gebruik load_config_tree wanneer je de traversalprimitive zonder confique nodig hebt.

Snelstart

English | 中文 | 日本語 | 한국어 | Français | Deutsch | Español | Português | Svenska | Suomi | Nederlands

Voeg de crate en de schema/runtime-bibliotheken toe die je toepassing gebruikt:

[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"] }

Definieer een confique-schema en implementeer ConfigSchema voor het roottype:

#![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()
    }
}
}

Laad de configuratie:

#![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>>(())
}

Gebruik een rootbestand met recursieve includes:

# config.yaml
include:
  - config/server.yaml
# config/server.yaml
server:
  bind: 0.0.0.0
  port: 3000

De standaardprioriteit van load_config is:

environment variables
  > config files, with later merged files overriding earlier files
    > confique code defaults

Wanneer includes door de high-level API worden geladen, heeft het rootbestand de hoogste bestandsprioriteit. Geinclude bestanden leveren waarden met lagere prioriteit en kunnen worden gebruikt voor defaults of sectiespecifieke bestanden.

Commandoregelargumenten zijn toepassingsspecifiek, dus load_config leest ze niet automatisch. Voeg CLI-overrides samen na build_config_figment wanneer de toepassing configuratie-overridevlaggen heeft:

CLI-vlagnamen worden door de toepassing gekozen. Ze zijn niet automatisch a.b.c-configuratiepaden. Geef de voorkeur aan normale clap-vlaggen zoals --server-port en map ze daarna naar een geneste overridestructuur. De geneste geserialiseerde vorm bepaalt welke configuratiesleutel wordt overschreven.

Alleen waarden die in de CliOverrides-provider van de toepassing zijn opgenomen, overschrijven configuratie. Dit is nuttig voor parameters die vaak voor een enkele run worden gewijzigd zonder het configuratiebestand aan te passen. Stabiele waarden horen in configuratiebestanden.

#![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>>(())
}

Met CLI-overrides die zo worden samengevoegd, is de volledige prioriteit:

command-line overrides
  > environment variables
    > config files
      > confique code defaults

Configuratieschema

English | 中文 | 日本語 | 한국어 | Français | Deutsch | Español | Português | Svenska | Suomi | Nederlands

Toepassingsschema’s zijn normale confique-configuratietypen. Het rootschema moet ConfigSchema implementeren zodat rust-config-tree recursieve includes uit de tussenliggende confique-laag kan ontdekken.

#![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()
    }
}
}

Include-veld

Het include-veld mag elke naam hebben. rust-config-tree kent het alleen via ConfigSchema::include_paths.

Het veld heeft normaal een lege default:

#![allow(unused)]
fn main() {
#[config(default = [])]
include: Vec<PathBuf>,
}

De loader ontvangt voor elk bestand een gedeeltelijk geladen laag. Daardoor kan hij kindconfiguratiebestanden ontdekken voordat het uiteindelijke schema wordt samengevoegd en gevalideerd.

Geneste secties

Gebruik #[config(nested)] voor gestructureerde secties. Geneste secties worden altijd gebruikt voor runtime laden. Voeg #[schemars(extend("x-tree-split" = true))] toe wanneer een genest veld ook als eigen *.yaml-sjabloon en <section>.schema.json-schema moet worden gegenereerd:

#![allow(unused)]
fn main() {
#[derive(Debug, Config, JsonSchema)]
struct AppConfig {
    #[config(nested)]
    #[schemars(extend("x-tree-split" = true))]
    server: ServerConfig,
}
}

De natuurlijke YAML-vorm is:

server:
  bind: 127.0.0.1
  port: 8080

Omgevings-only velden

Markeer een leafveld met #[schemars(extend("x-env-only" = true))] wanneer de waarde alleen uit een omgevingsvariabele mag komen en niet in gegenereerde configuratiebestanden mag verschijnen. Gegenereerde YAML-sjablonen en JSON Schemas laten env-only velden weg, en lege bovenliggende objecten die daardoor overblijven worden verwijderd.

#![allow(unused)]
fn main() {
#[config(env = "APP_SECRET")]
#[schemars(extend("x-env-only" = true))]
secret: String,
}

Veldwaardevalidatie

Gegenereerde *.schema.json-bestanden zijn alleen voor IDE-completion en basale editorcontroles. Ze bepalen niet of een concrete veldwaarde geldig is voor de toepassing.

Veldwaardevalidatie moet in code worden geimplementeerd met #[config(validate = Self::validate)]. De validator draait wanneer de uiteindelijke configuratie wordt geladen met load_config of gecontroleerd met config-validate.

Overrides voor sjabloonsecties

Wanneer een sjabloonbron geen includes heeft, kan de crate kind- sjabloonbestanden afleiden uit geneste schemaselecties gemarkeerd met x-tree-split. Het standaardpad op het hoogste niveau is <section>.yaml.

Overschrijf dat pad met 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,
        }
    }
}
}

Runtime laden

English | 中文 | 日本語 | 한국어 | Français | Deutsch | Español | Português | Svenska | Suomi | Nederlands

Runtime laden is bewust verdeeld tussen Figment en confique:

figment:
  runtime file loading
  runtime environment loading
  runtime source metadata

confique:
  schema metadata
  defaults
  validation
  config templates

De hoofd-API is:

#![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>>(())
}

Gebruik load_config_with_figment wanneer de toepassing bronmetadata nodig heeft:

#![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>>(())
}

Laadstappen

De high-level loader voert deze stappen uit:

  1. Los het rootconfiguratiepad lexicaal op.
  2. Laad het eerste .env-bestand dat wordt gevonden door omhoog te lopen vanaf de rootconfiguratiedirectory.
  3. Laad elk configuratiebestand als gedeeltelijke laag om includes te ontdekken.
  4. Bouw een Figment-grafiek uit de ontdekte configuratiebestanden.
  5. Voeg de ConfiqueEnvProvider samen met hogere prioriteit dan bestanden.
  6. Voeg eventueel toepassingsspecifieke CLI-overrides samen.
  7. Extraheer een confique-laag uit Figment.
  8. Pas confique-codestandaarden toe.
  9. Valideer en bouw het uiteindelijke schema.

load_config en load_config_with_figment voeren stappen 1-5 en 7-9 uit. Stap 6 is toepassingsspecifiek omdat deze crate niet kan afleiden hoe een CLI-vlag naar een schemaveld mappt.

Bestandsformaten

De runtimebestandsprovider wordt gekozen uit de extensie van het configuratiepad:

  • .yaml en .yml gebruiken YAML.
  • .toml gebruikt TOML.
  • .json en .json5 gebruiken JSON.
  • onbekende of ontbrekende extensies gebruiken YAML.

Sjabloongeneratie gebruikt nog steeds de template-renderers van confique voor YAML, TOML en JSON5-compatibele uitvoer.

Include-prioriteit

De high-level loader voegt bestandsproviders zo samen dat geinclude bestanden lagere prioriteit hebben dan het bestand dat ze include. Het rootconfiguratie- bestand heeft de hoogste bestandsprioriteit.

Omgevingsvariabelen hebben hogere prioriteit dan alle configuratiebestanden. confique-defaults worden alleen gebruikt voor waarden die niet door runtimeproviders worden geleverd.

Wanneer CLI-overrides na build_config_figment worden samengevoegd, is de volledige prioriteit:

command-line overrides
  > environment variables
    > config files
      > confique code defaults

De commandoregelsyntaxis wordt niet door rust-config-tree gedefinieerd. Een vlag zoals --server-port kan server.port overschrijven als de toepassing die geparsede waarde in een geneste geserialiseerde provider mappt. Een gestippelde syntaxis zoals --server.port of a.b.c bestaat alleen als de toepassing die implementeert.

Dit betekent dat CLI-prioriteit alleen geldt voor sleutels die aanwezig zijn in de overrideprovider van de toepassing. Gebruik dit voor operationele waarden die vaak voor een enkele run worden gewijzigd. Laat duurzame configuratie in bestanden staan.

#![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>>(())
}

Omgevingsvariabelen

English | 中文 | 日本語 | 한국어 | Français | Deutsch | Español | Português | Svenska | Suomi | Nederlands

Namen van omgevingsvariabelen worden in het schema gedeclareerd met 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 leest die namen uit confique::Config::META en bouwt een Figment-provider die elke omgevingsvariabele naar het exacte veldpad mappt.

Gebruik geen delimiter-gebaseerde Figment-omgevingsmapping voor deze crate:

#![allow(unused)]
fn main() {
// Do not use this pattern for rust-config-tree schemas.
Env::prefixed("APP_").split("_")
Env::prefixed("APP_").split("__")
}

split("_") behandelt underscores als scheidingstekens voor geneste sleutels. Daardoor wordt APP_DATABASE_POOL_SIZE een pad zoals database.pool.size, wat botst met Rust-veldnamen zoals pool_size.

Met ConfiqueEnvProvider is deze mapping expliciet:

APP_DATABASE_POOL_SIZE -> database.pool_size

Enkele underscores blijven onderdeel van de naam van de omgevingsvariabele. Figment raadt de nestingregel niet.

Dotenv laden

Voordat runtimeproviders worden geevalueerd, zoekt de loader naar een .env- bestand door omhoog te lopen vanaf de directory van het rootconfiguratiebestand.

Bestaande procesomgevingsvariabelen blijven behouden. Waarden uit .env vullen alleen ontbrekende omgevingsvariabelen aan.

Voorbeeld:

APP_SERVER_PORT=9000
APP_DATABASE_POOL_SIZE=64

Deze variabelen overschrijven configuratiebestandswaarden wanneer het schema passende #[config(env = "...")]-attributen declareert.

Waarden parsen

De bridgeprovider laat Figment omgevingswaarden parsen. Hij roept de parse_env-hooks van confique niet aan. Houd complexe waarden in configuratiebestanden tenzij de Figment-syntaxis voor omgevingswaarden goed bij het type past.

Brontracking

English | 中文 | 日本語 | 한국어 | Français | Deutsch | Español | Português | Svenska | Suomi | Nederlands

Gebruik load_config_with_figment om de Figment-grafiek te behouden die door runtime laden is gebruikt:

#![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>>(())
}

De geretourneerde Figment-waarde kan bronvragen voor runtimewaarden beantwoorden:

#![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}");
}
}

Voor waarden die door ConfiqueEnvProvider worden geleverd, retourneert interpolatie de native naam van de omgevingsvariabele die in het schema is gedeclareerd:

database.pool_size came from APP_DATABASE_POOL_SIZE

TRACE-events

De loader emitteert brontrackingevents met tracing::trace!. Dit gebeurt alleen wanneer TRACE is ingeschakeld:

#![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>>(())
}

Elk event gebruikt het target rust_config_tree::config en bevat:

  • config_key: de gestippelde configuratiesleutel.
  • source: de gerenderde bronmetadata.

Waarden die alleen uit confique-defaults komen, hebben geen Figment- runtime-metadata. Ze worden gerapporteerd als confique default or unset optional field.

Sjabloongeneratie

English | 中文 | 日本語 | 한국어 | Français | Deutsch | Español | Português | Svenska | Suomi | Nederlands

Sjablonen worden gegenereerd uit hetzelfde confique-schema dat runtime wordt gebruikt. confique rendert de daadwerkelijke sjablooninhoud, inclusief doccomments, defaults, verplichte velden en gedeclareerde omgevingsvariabelen.

Gebruik 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>>(())
}

Genereer Draft 7 JSON Schemas voor de rootconfiguratie en gesplitste geneste secties:

#![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>>(())
}

Markeer een genest veld met #[schemars(extend("x-tree-split" = true))] wanneer het als eigen *.yaml-sjabloon en eigen <section>.schema.json-schema moet worden gegenereerd. Ongemarkeerde geneste velden blijven in het oudersjabloon en het ouderschema.

Markeer een leafveld met #[schemars(extend("x-env-only" = true))] wanneer de waarde alleen uit omgevingsvariabelen mag komen. Gegenereerde sjablonen en JSON Schemas laten env-only velden weg, en lege bovenliggende objecten die daardoor overblijven worden verwijderd.

Gegenereerde schema’s laten required-constraints weg. IDE’s kunnen nog steeds completion bieden, maar gedeeltelijke bestanden zoals log.yaml rapporteren geen ontbrekende rootvelden. Het rootschema vult alleen velden aan die in het rootbestand thuishoren; gesplitste sectievelden worden daar weggelaten en door hun eigen sectieschema’s aangevuld. Aanwezige velden kunnen nog steeds basale editorcontroles krijgen, zoals type-, enum- en onbekende-eigenschapcontroles die door het gegenereerde schema worden ondersteund. Gegenereerde *.schema.json-bestanden bepalen niet of een concrete veldwaarde geldig is voor de toepassing. Veldwaardevalidatie moet in code worden geimplementeerd met #[config(validate = Self::validate)]; load_config en config-validate voeren die runtimevalidatie uit.

Koppel die schema’s vanuit gegenereerde TOML-, YAML-, JSON- en JSON5-sjablonen:

#![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>>(())
}

TOML- en YAML-rootsjablonen koppelen het rootschema en vullen geen velden van gesplitste kindsecties aan. Gesplitste sectie-YAML-sjablonen koppelen hun sectieschema. JSON- en JSON5-sjablonen krijgen een rootveld $schema dat VS Code kan herkennen. VS Code json.schemas blijft een alternatieve koppelingsroute.

Het uitvoerformaat wordt afgeleid uit het uitvoerpad:

  • .yaml en .yml genereren YAML.
  • .toml genereert TOML.
  • .json en .json5 genereren JSON5-compatibele sjablonen.
  • onbekende of ontbrekende extensies genereren YAML.

Schemabindingen

Met een schemapad van schemas/myapp.schema.json gebruiken gegenereerde rootsjablonen:

#:schema ./schemas/myapp.schema.json
# yaml-language-server: $schema=./schemas/myapp.schema.json

Gegenereerde sectiesjablonen koppelen sectieschema’s:

# log.yaml
# yaml-language-server: $schema=./schemas/log.schema.json

Gegenereerde JSON- en JSON5-sjablonen schrijven een rootveld $schema dat VS Code herkent. Editorinstellingen blijven optioneel:

{
  "json.schemas": [
    {
      "fileMatch": [
        "/config.json",
        "/config.*.json"
      ],
      "url": "./schemas/myapp.schema.json"
    }
  ]
}

Selectie van sjabloonbron

Sjabloongeneratie kiest de bronboom in deze volgorde:

  1. Bestaand configuratiepad.
  2. Bestaand uitvoersjabloonpad.
  3. Uitvoerpad behandeld als een nieuwe lege sjabloonboom.

Daardoor kan een project sjablonen bijwerken vanuit huidige configuratiebestanden, een bestaande sjabloonset bijwerken of een nieuwe sjabloonset maken vanuit alleen het schema.

Gespiegelde include-bomen

Als het bronbestand includes declareert, spiegelen gegenereerde sjablonen die include-paden onder de uitvoerdirectory.

# config.yaml
include:
  - server.yaml

Het genereren van config.example.yaml schrijft:

config.example.yaml
server.yaml

Relatieve include-doelen worden gespiegeld onder de parentdirectory van het uitvoerbestand. Absolute include-doelen blijven absoluut.

Opt-in sectiesplitsing

Wanneer een bronbestand geen includes heeft, kan de crate include-doelen afleiden uit geneste schemaselecties gemarkeerd met x-tree-split. Voor een schema met een gemarkeerde server-sectie kan een leeg rootsjabloon bijvoorbeeld produceren:

config.example.yaml
server.yaml

Het rootsjabloon krijgt een include-blok en server.yaml bevat alleen de server-sectie. Geneste secties worden alleen recursief gesplitst wanneer die velden ook x-tree-split dragen.

IDE-completions

English | 中文 | 日本語 | 한국어 | Français | Deutsch | Español | Português | Svenska | Suomi | Nederlands

Gegenereerde JSON Schemas kunnen worden gebruikt door TOML-, YAML-, JSON- en JSON5-configuratiebestanden. Ze worden gegenereerd uit hetzelfde Rust-type dat door confique wordt gebruikt:

#![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,
}
}

Genereer ze met:

#![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>>(())
}

Dit schrijft het rootschema en sectieschema’s zoals schemas/server.schema.json. Gegenereerde schema’s laten required- constraints weg, zodat completion werkt voor gedeeltelijke configuratiebestanden zonder diagnostics voor ontbrekende velden. Het rootschema laat geneste sectie-eigenschappen weg, zodat completion voor kindsecties alleen beschikbaar is in bestanden die het passende sectieschema koppelen.

Velden gemarkeerd met x-env-only worden uit gegenereerde schemas weggelaten, zodat IDEs geen secrets of andere waarden voorstellen die alleen uit omgevingsvariabelen mogen komen.

IDE-schema’s zijn voor completion en basale editorcontroles, zoals type-, enum- en onbekende-eigenschapcontroles die door het gegenereerde schema worden ondersteund. Ze bepalen niet of een concrete veldwaarde geldig is voor de toepassing. Veldwaardevalidatie moet in code worden geimplementeerd met #[config(validate = Self::validate)] en wordt uitgevoerd via load_config of config-validate. Verplichte velden en uiteindelijke samengevoegde configuratievalidatie gebruiken ook die runtimepaden.

TOML

TOML-bestanden moeten het schema koppelen met een #:schema-directive bovenaan het bestand:

#:schema ./schemas/myapp.schema.json

[server]
bind = "0.0.0.0"
port = 3000

Gebruik geen rootveld $schema = "..." in TOML. Het wordt echte configuratiedata en kan runtime-deserialisatie beinvloeden. write_config_templates_with_schema voegt de #:schema-directive automatisch toe voor TOML-sjablonen.

YAML

YAML-bestanden moeten de YAML Language Server-modeline gebruiken:

# yaml-language-server: $schema=./schemas/myapp.schema.json

server:
  bind: 0.0.0.0
  port: 3000

write_config_templates_with_schema voegt deze modeline automatisch toe voor YAML-sjablonen. Gesplitste YAML-sjablonen koppelen hun sectieschema, bijvoorbeeld log.yaml koppelt ./schemas/log.schema.json.

JSON

JSON- en JSON5-bestanden kunnen een schema koppelen met een rootveld $schema. write_config_templates_with_schema voegt dit automatisch toe aan gegenereerde JSON- en JSON5-sjablonen:

{
  "$schema": "./schemas/myapp.schema.json"
}

Editorinstellingen blijven nuttig wanneer een project geen binding in het bestand wil:

{
  "json.schemas": [
    {
      "fileMatch": [
        "/config.json",
        "/config.*.json",
        "/deploy/*.json"
      ],
      "url": "./schemas/myapp.schema.json"
    }
  ]
}

YAML kan ook via VS Code-instellingen worden gekoppeld:

{
  "yaml.schemas": {
    "./schemas/myapp.schema.json": [
      "config.yaml",
      "config.*.yaml",
      "deploy/*.yaml"
    ]
  }
}

De uiteindelijke indeling is:

schemas/myapp.schema.json:
  Alleen velden van het rootbestand

schemas/server.schema.json:
  Schema voor de sectie 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"

Referenties:

CLI-integratie

English | 中文 | 日本語 | 한국어 | Français | Deutsch | Español | Português | Svenska | Suomi | Nederlands

ConfigCommand biedt herbruikbare clap-subcommands:

  • config-template
  • config-schema
  • config-validate
  • completions
  • install-completions
  • uninstall-completions

Deze ingebouwde subcommands staan los van toepassingsspecifieke configuratie- overridevlaggen. Voeg configuratie-overridevlaggen als Figment-providers samen in het runtime-laadpad.

Configuratie-overridevlaggen blijven onderdeel van de CLI van de consumerende toepassing. Hun namen hoeven niet overeen te komen met gestippelde configuratiepaden. De toepassing kan bijvoorbeeld --server-port parsen en naar de geneste configuratiesleutel server.port mappen. Alleen vlaggen die de toepassing in CliOverrides mappt, beinvloeden configuratiewaarden.

Flatten het in een toepassingsopdrachtenenum:

  1. Behoud het eigen Parser-type van de toepassing.
  2. Behoud de eigen Subcommand-enum van de toepassing.
  3. Voeg #[command(flatten)] Config(ConfigCommand) aan die enum toe.
  4. Clap breidt de geflattende ConfigCommand-varianten uit naar hetzelfde opdracht niveau als de eigen varianten van de toepassing.
  5. Match de variant Config(command) en geef die door aan handle_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(())
}

Configuratiesjablonen

demo config-template

De opdracht schrijft sjablonen onder config/<root_config_name>/. Als --output een pad ontvangt, wordt alleen de bestandsnaam gebruikt. Als geen uitvoerbestandsnaam is opgegeven, schrijft de opdracht config/<root_config_name>/<root_config_name>.example.yaml. Voeg --schema schemas/myapp.schema.json toe om gegenereerde TOML-, YAML-, JSON- en JSON5-sjablonen te koppelen aan gegenereerde JSON Schemas. Gesplitste YAML-sjablonen koppelen het passende sectieschema. JSON- en JSON5-sjablonen krijgen een $schema-veld dat VS Code herkent. De opdracht schrijft ook het root- en de sectieschema’s naar het gekozen schemapad.

demo config-template --output app_config.example.toml --schema schemas/myapp.schema.json

Genereer root- en sectie-JSON Schemas:

demo config-schema

Zonder --output schrijft config-schema het rootschema naar config/<root_config_name>/<root_config_name>.schema.json.

Valideer de volledige runtimeconfiguratieboom:

demo config-validate

Gegenereerde editorschema’s vermijden bewust diagnostics voor verplichte velden in gesplitste bestanden. config-validate laadt includes, past defaults toe en voert uiteindelijke confique-validatie uit, inclusief validators die met #[config(validate = Self::validate)] zijn gedeclareerd. Gegenereerde *.schema.json-bestanden blijven voor IDE-completion en basale editorcontroles, niet voor veldwaardelegaliteit. Het print Configuration is ok wanneer de validatie slaagt.

Shellcompletions

Print completions naar stdout:

demo completions zsh

Installeer completions:

demo install-completions zsh

Verwijder completions:

demo uninstall-completions zsh

De installer ondersteunt Bash, Elvish, Fish, PowerShell en Zsh. Hij schrijft het completionbestand onder de home-directory van de gebruiker en werkt het shellstartbestand bij voor shells die dat vereisen.

Voordat een bestaand shellstartbestand zoals ~/.zshrc, ~/.bashrc, een Elvish rc-bestand of een PowerShell-profiel wordt gewijzigd, schrijft de opdracht een backup naast het originele bestand:

<rc-file>.backup.by.<program-name>.<timestamp>

Voorbeelden

English | 中文 | 日本語 | 한국어 | Français | Deutsch | Español | Português | Svenska | Suomi | Nederlands

De repository bevat uitvoerbare voorbeelden voor het laden van configuratiebomen, CLI-overrides, ingebouwde configuratieopdrachten, sjabloongeneratie en de lagere tree-API.

Lees de voorbeeldenindex van de repository:

Voer voorbeelden uit vanuit de repositoryroot:

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

Tree API

English | 中文 | 日本語 | 한국어 | Français | Deutsch | Español | Português | Svenska | Suomi | Nederlands

Gebruik de lagere tree-API wanneer de toepassing geen confique gebruikt, of wanneer directe toegang tot traversalresultaten nodig is.

#![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>>(())
}

Traversalregels

De tree-loader:

  • normaliseert bronpaden lexicaal;
  • weigert lege include-paden;
  • lost relatieve includes op vanuit het bestand dat ze declareerde;
  • behoudt absolute include-paden;
  • detecteert recursieve include-cycli;
  • slaat bestanden over die al via een andere include-tak zijn geladen.

ConfigTreeOptions kan sibling-include-traversal omkeren:

#![allow(unused)]
fn main() {
use rust_config_tree::{ConfigTreeOptions, IncludeOrder};

let options = ConfigTreeOptions::default().include_order(IncludeOrder::Reverse);
let _ = options;
}

Padhulpen

De padhulpen zijn alleen lexicaal. Ze lossen geen symbolische links op en vereisen niet dat paden bestaan:

  • 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

Deze repository publiceert de handleiding met mdBook en GitHub Pages.

Elke taalhandleiding is een zelfstandig mdBook-project. Elke taal heeft een eigen SUMMARY.md, zodat de linkerzijbalk alleen pagina’s voor de huidige taal bevat:

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
    ...
  ko/
  fr/
  de/
  es/
  pt/
  sv/
  fi/
  nl/

Bouw lokaal met:

scripts/publish-pages.sh

De gegenereerde site wordt geschreven naar:

target/mdbook

Publicatieworkflow

De workflow in .github/workflows/pages.yml draait bij pushes naar main en bij handmatige dispatch. Hij:

  1. Checkt de repository uit.
  2. Installeert mdBook.
  3. Draait scripts/publish-pages.sh.
  4. Uploadt target/mdbook als Pages-artefact.
  5. Deployt het artefact naar GitHub Pages.

De gepubliceerde URL is:

https://developerworks.github.io/rust-config-tree/

Crate-release

Voor de volledige flow van commit, push, Pages-deploy en crate-publicatie:

scripts/release.sh --execute --message "Release 0.1.3"

Gebruik de crate-releasehelper vanuit de repositoryroot:

scripts/publish-crate.sh

De standaardmodus voert controles en cargo publish --dry-run uit. Om naar crates.io te publiceren nadat de controles slagen. Als de huidige versie al op crates.io bestaat, verhoogt het script automatisch de patchversie:

scripts/publish-crate.sh --execute

Scriptgebruik wordt samengevat in scripts/README.md.