Manual de rust-config-tree
English | 中文 | 日本語 | 한국어 | Français | Deutsch | Español | Português | Svenska | Suomi | Nederlands
Este es el manual en español de rust-config-tree.
Empieza con Introducción, Inicio rápido o los Ejemplos ejecutables.
Introducción
English | 中文 | 日本語 | 한국어 | Français | Deutsch | Español | Português | Svenska | Suomi | Nederlands
rust-config-tree proporciona carga reutilizable de árboles de configuración y
ayudantes de CLI para aplicaciones Rust que usan archivos de configuración por
capas.
El crate está diseñado alrededor de una pequeña división de responsabilidades:
confiqueposee las definiciones de esquema, valores por defecto en código, validación y generación de plantillas de configuración.figmentposee la carga en tiempo de ejecución y los metadatos de origen en tiempo de ejecución.rust-config-treeposee el recorrido recursivo de includes, la resolución de rutas de include, la carga de.env, el descubrimiento de destinos de plantilla y comandos clap reutilizables.
El crate es útil cuando una aplicación quiere una distribución natural de archivos de configuración como esta:
include:
- config/server.yaml
- config/database.yaml
log:
level: info
Cada archivo incluido puede usar la misma forma de esquema, y las rutas de
include relativas se resuelven desde el archivo que las declaró. La
configuración final sigue siendo un valor normal de esquema confique.
Funciones principales
- Recorrido recursivo de includes con detección de ciclos.
- Rutas de include relativas resueltas desde el archivo que las declara.
- Carga de
.envantes de evaluar proveedores de entorno. - Variables de entorno declaradas por esquema sin división por delimitadores.
- Metadatos de Figment para seguimiento de origen en tiempo de ejecución.
- Eventos de seguimiento de origen en nivel TRACE mediante
tracing. - Generación de JSON Schema Draft 7 para completado y comprobaciones básicas de esquema en editores.
- Validación de valores de campo en código de aplicación con
#[config(validate = Self::validate)], ejecutada porload_configoconfig-validate. - Generación de plantillas YAML, TOML, JSON y JSON5.
- Directivas TOML
#:schema, modelines de YAML Language Server y campos JSON/JSON5$schemapara plantillas generadas. - División opt-in de plantillas YAML para secciones marcadas con
x-tree-split. - Subcomandos clap incorporados para plantillas de configuración, JSON Schema y completions de shell.
- Una API de árbol de menor nivel para llamadores que no usan
confique.
Puntos de entrada públicos
Usa estas APIs para la mayoría de aplicaciones:
load_config::<S>(path)carga el esquema final.load_config_with_figment::<S>(path)carga el esquema y devuelve el grafo Figment usado para seguimiento de origen.write_config_templates::<S>(config_path, output_path)escribe la plantilla raíz y las plantillas hijas descubiertas recursivamente.write_config_schemas::<S>(output_path)escribe JSON Schemas Draft 7 raíz y de sección.handle_config_command::<Cli, S>(command, config_path)maneja comandos clap de configuración incorporados.
Usa load_config_tree cuando necesites la primitiva de recorrido sin
confique.
Inicio rápido
English | 中文 | 日本語 | 한국어 | Français | Deutsch | Español | Português | Svenska | Suomi | Nederlands
Añade el crate y las bibliotecas de esquema/tiempo de ejecución que usa tu aplicación:
[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"] }
Define un esquema confique e implementa ConfigSchema para el tipo raíz:
#![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()
}
}
}
Carga la configuración:
#![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>>(())
}
Usa un archivo raíz con includes recursivos:
# config.yaml
include:
- config/server.yaml
# config/server.yaml
server:
bind: 0.0.0.0
port: 3000
La precedencia por defecto de load_config es:
environment variables
> config files, with later merged files overriding earlier files
> confique code defaults
Cuando los includes se cargan mediante la API de alto nivel, el archivo raíz tiene la prioridad de archivo más alta. Los archivos incluidos aportan valores de menor prioridad y pueden usarse para valores por defecto o archivos específicos de sección.
Los argumentos de línea de comandos son específicos de la aplicación, así que
load_config no los lee automáticamente. Fusiona overrides de CLI después de
build_config_figment cuando la aplicación tenga flags de override de
configuración:
Los nombres de flags de CLI los elige la aplicación. No son automáticamente
rutas de configuración a.b.c. Prefiere flags clap normales como
--server-port, luego mapéalas a una estructura de override anidada. La forma
serializada anidada controla la clave de configuración que se sobrescribe.
Solo los valores representados en el proveedor CliOverrides de la aplicación
sobrescriben la configuración. Esto es útil para parámetros que se cambian con
frecuencia para una ejecución sin editar el archivo de configuración. Los
valores estables deberían permanecer en archivos de configuración.
#![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>>(())
}
Con overrides de CLI fusionados de esta forma, la precedencia completa es:
command-line overrides
> environment variables
> config files
> confique code defaults
Esquema de configuración
English | 中文 | 日本語 | 한국어 | Français | Deutsch | Español | Português | Svenska | Suomi | Nederlands
Los esquemas de aplicación son tipos normales de configuración confique. El
esquema raíz debe implementar ConfigSchema para que rust-config-tree pueda
descubrir includes recursivos desde la capa intermedia de 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()
}
}
}
Campo include
El campo include puede tener cualquier nombre. rust-config-tree solo lo
conoce mediante ConfigSchema::include_paths.
Normalmente el campo debería tener un valor por defecto vacío:
#![allow(unused)]
fn main() {
#[config(default = [])]
include: Vec<PathBuf>,
}
El cargador recibe una capa parcialmente cargada para cada archivo. Eso le permite descubrir archivos de configuración hijos antes de fusionar y validar el esquema final.
Secciones anidadas
Usa #[config(nested)] para secciones estructuradas. Las secciones anidadas
siempre se usan para la carga en tiempo de ejecución. Agrega
#[schemars(extend("x-tree-split" = true))] cuando un campo anidado tambien
deba generarse como su propio template *.yaml y 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 forma YAML natural es:
server:
bind: 127.0.0.1
port: 8080
Campos solo de entorno
Marca un campo hoja con #[schemars(extend("x-env-only" = true))] cuando su valor debe venir solo de una variable de entorno y no debe aparecer en archivos de configuración generados. Las plantillas YAML y los JSON Schemas generados omiten los campos env-only, y también se eliminan los objetos padre que queden vacíos.
#![allow(unused)]
fn main() {
#[config(env = "APP_SECRET")]
#[schemars(extend("x-env-only" = true))]
secret: String,
}
Validación de valores de campo
Los archivos *.schema.json generados sirven solo para completado de IDE y
comprobaciones básicas del editor. No deciden si un valor concreto de campo es
válido para la aplicación.
La validación de valores debe implementarse en código con
#[config(validate = Self::validate)]. El validador se ejecuta cuando la
configuración final se carga con load_config o se comprueba con
config-validate.
Overrides de sección de plantilla
Cuando una fuente de plantilla no tiene includes, el crate puede derivar
archivos de plantilla hijos desde secciones anidadas del esquema marcadas con x-tree-split. La ruta de
primer nivel por defecto es <section>.yaml.
Sobrescribe esa ruta con 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,
}
}
}
}
Carga en tiempo de ejecución
English | 中文 | 日本語 | 한국어 | Français | Deutsch | Español | Português | Svenska | Suomi | Nederlands
La carga en tiempo de ejecución se divide deliberadamente entre Figment y confique:
figment:
runtime file loading
runtime environment loading
runtime source metadata
confique:
schema metadata
defaults
validation
config templates
La API principal es:
#![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>>(())
}
Usa load_config_with_figment cuando la aplicación necesita metadatos de
origen:
#![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>>(())
}
Pasos de carga
El cargador de alto nivel realiza estos pasos:
- Resolver léxicamente la ruta de configuración raíz.
- Cargar el primer archivo
.envencontrado al caminar hacia arriba desde el directorio de configuración raíz. - Cargar cada archivo de configuración como una capa parcial para descubrir includes.
- Construir un grafo Figment desde los archivos de configuración descubiertos.
- Fusionar
ConfiqueEnvProvidercon mayor prioridad que los archivos. - Fusionar opcionalmente overrides de CLI específicos de la aplicación.
- Extraer una capa
confiquedesde Figment. - Aplicar valores por defecto de código de
confique. - Validar y construir el esquema final.
load_config y load_config_with_figment realizan los pasos 1-5 y 7-9. El
paso 6 es específico de la aplicación porque este crate no puede inferir cómo
una flag de CLI se mapea a un campo del esquema.
Formatos de archivo
El proveedor de archivos en tiempo de ejecución se selecciona desde la extensión de la ruta de configuración:
.yamly.ymlusan YAML..tomlusa TOML..jsony.json5usan JSON.- extensiones desconocidas o ausentes usan YAML.
La generación de plantillas sigue usando los renderizadores de plantillas de confique para YAML, TOML y salida compatible con JSON5.
Prioridad de includes
El cargador de alto nivel fusiona proveedores de archivo para que los archivos incluidos tengan menor prioridad que el archivo que los incluyó. El archivo de configuración raíz tiene la prioridad de archivo más alta.
Las variables de entorno tienen mayor prioridad que todos los archivos de
configuración. Los valores por defecto de confique solo se usan para valores
que no son suministrados por proveedores de tiempo de ejecución.
Cuando se fusionan overrides de CLI después de build_config_figment, la
precedencia completa es:
command-line overrides
> environment variables
> config files
> confique code defaults
La sintaxis de línea de comandos no la define rust-config-tree. Una flag como
--server-port puede sobrescribir server.port si la aplicación mapea ese
valor parseado a un proveedor serializado anidado. Una sintaxis con puntos como
--server.port o a.b.c solo existe si la aplicación la implementa.
Esto significa que la precedencia de CLI se aplica solo a las claves presentes en el proveedor de overrides de la aplicación. Úsala para valores operativos que se cambian con frecuencia en una sola ejecución. Deja la configuración duradera en archivos.
#![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 de entorno
English | 中文 | 日本語 | 한국어 | Français | Deutsch | Español | Português | Svenska | Suomi | Nederlands
Los nombres de variables de entorno se declaran en el esquema con 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 lee esos nombres desde confique::Config::META y construye
un proveedor Figment que mapea cada variable de entorno a su ruta exacta de
campo.
No uses mapeo de entorno de Figment basado en delimitadores para este crate:
#![allow(unused)]
fn main() {
// Do not use this pattern for rust-config-tree schemas.
Env::prefixed("APP_").split("_")
Env::prefixed("APP_").split("__")
}
split("_") trata los guiones bajos como separadores de claves anidadas. Eso
hace que APP_DATABASE_POOL_SIZE se convierta en una ruta como
database.pool.size, que entra en conflicto con nombres de campos Rust como
pool_size.
Con ConfiqueEnvProvider, este mapeo es explícito:
APP_DATABASE_POOL_SIZE -> database.pool_size
Los guiones bajos simples siguen siendo parte del nombre de variable de entorno. Figment no adivina la regla de anidamiento.
Carga dotenv
Antes de evaluar proveedores en tiempo de ejecución, el cargador busca un
archivo .env caminando hacia arriba desde el directorio del archivo de
configuración raíz.
Las variables de entorno existentes del proceso se conservan. Los valores de
.env solo rellenan variables de entorno ausentes.
Ejemplo:
APP_SERVER_PORT=9000
APP_DATABASE_POOL_SIZE=64
Estas variables sobrescriben valores de archivos de configuración cuando el
esquema declara atributos #[config(env = "...")] coincidentes.
Parseo de valores
El proveedor puente deja que Figment parsee los valores de entorno. No llama a
los hooks parse_env de confique. Mantén valores complejos en archivos de
configuración salvo que la sintaxis de valores de entorno de Figment encaje bien
con el tipo.
Seguimiento de origen
English | 中文 | 日本語 | 한국어 | Français | Deutsch | Español | Português | Svenska | Suomi | Nederlands
Usa load_config_with_figment para conservar el grafo Figment usado por la
carga en tiempo de ejecución:
#![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>>(())
}
El valor Figment devuelto puede responder preguntas de origen para valores en tiempo de ejecución:
#![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}");
}
}
Para valores suministrados por ConfiqueEnvProvider, la interpolación devuelve
el nombre nativo de la variable de entorno declarada en el esquema:
database.pool_size came from APP_DATABASE_POOL_SIZE
Eventos TRACE
El cargador emite eventos de seguimiento de origen con tracing::trace!. Lo
hace solo cuando TRACE está habilitado:
#![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>>(())
}
Cada evento usa el target rust_config_tree::config e incluye:
config_key: la clave de configuración con puntos.source: los metadatos de origen renderizados.
Los valores que provienen solo de valores por defecto de confique no tienen
metadatos de tiempo de ejecución de Figment. Se informan como
confique default or unset optional field.
Generación de plantillas
English | 中文 | 日本語 | 한국어 | Français | Deutsch | Español | Português | Svenska | Suomi | Nederlands
Las plantillas se generan desde el mismo esquema confique usado en tiempo de
ejecución. confique renderiza el contenido real de la plantilla, incluidos
comentarios de documentación, valores por defecto, campos obligatorios y nombres
de variables de entorno declaradas.
Usa 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>>(())
}
Genera JSON Schemas Draft 7 para la configuración raíz y las secciones anidadas:
#![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>>(())
}
Marca un campo anidado con #[schemars(extend("x-tree-split" = true))] cuando
deba generarse como su propia plantilla *.yaml y su propio esquema
<section>.schema.json. Los campos anidados sin marcar permanecen en la
plantilla padre y el esquema padre.
Marca un campo hoja con #[schemars(extend("x-env-only" = true))] cuando el valor debe venir solo de variables de entorno. Las plantillas generadas y los JSON Schemas omiten los campos env-only, y tambien se eliminan los objetos padre que queden vacios.
Los esquemas generados omiten restricciones required. Los IDE todavía pueden
ofrecer completado, pero archivos parciales como log.yaml no informan
campos raíz faltantes. El esquema raíz solo completa campos que pertenecen al
archivo raíz; los campos de secciones divididas se omiten allí y se completan
mediante sus propios esquemas de sección. Los campos presentes siguen siendo
comprobados de forma básica por el editor, por ejemplo tipo, enum y propiedades
desconocidas admitidas por el esquema generado. Los *.schema.json generados no
deciden si un valor concreto de campo es válido para la aplicación. La
validación de valores debe implementarse en código con
#[config(validate = Self::validate)]; load_config y config-validate
ejecutan esa validación en tiempo de ejecución.
Enlaza esos esquemas desde plantillas TOML, YAML, JSON y JSON5 generadas:
#![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>>(())
}
Las plantillas raíz TOML y YAML enlazan el esquema raíz y no completan campos de
secciones hijas. Las plantillas YAML de sección dividida enlazan su esquema de
sección. Las plantillas JSON y JSON5 reciben un campo raíz $schema que
VS Code puede reconocer. VS Code json.schemas sigue siendo una ruta de enlace
alternativa.
El formato de salida se infiere de la ruta de salida:
.yamly.ymlgeneran YAML..tomlgenera TOML..jsony.json5generan plantillas compatibles con JSON5.- extensiones desconocidas o ausentes generan YAML.
Enlaces de esquema
Con una ruta de esquema schemas/myapp.schema.json, las plantillas raíz
generadas usan:
#:schema ./schemas/myapp.schema.json
# yaml-language-server: $schema=./schemas/myapp.schema.json
Las plantillas de sección generadas enlazan esquemas de sección:
# log.yaml
# yaml-language-server: $schema=./schemas/log.schema.json
Las plantillas JSON y JSON5 generadas escriben un campo raíz $schema que
VS Code reconoce. Los ajustes del editor siguen siendo opcionales:
{
"json.schemas": [
{
"fileMatch": [
"/config.json",
"/config.*.json"
],
"url": "./schemas/myapp.schema.json"
}
]
}
Selección de fuente de plantilla
La generación de plantillas elige su árbol fuente en este orden:
- Ruta de configuración existente.
- Ruta de plantilla de salida existente.
- Ruta de salida tratada como un nuevo árbol de plantillas vacío.
Esto permite a un proyecto actualizar plantillas desde archivos de configuración actuales, actualizar un conjunto de plantillas existente o crear un conjunto nuevo solo desde el esquema.
Árboles de includes reflejados
Si el archivo fuente declara includes, las plantillas generadas reflejan esas rutas de include bajo el directorio de salida.
# config.yaml
include:
- server.yaml
Generar config.example.yaml escribe:
config.example.yaml
server.yaml
Los destinos de include relativos se reflejan bajo el directorio padre del archivo de salida. Los destinos de include absolutos siguen siendo absolutos.
División opt-in de secciones
Cuando un archivo fuente no tiene includes, el crate puede derivar destinos de
include desde secciones anidadas del esquema marcadas con x-tree-split. Para un esquema con una sección marcada
server, una fuente de plantilla raíz vacía puede producir:
config.example.yaml
server.yaml
La plantilla raíz recibe un bloque include, y server.yaml contiene solo
la sección server. Las secciones anidadas solo se dividen recursivamente cuando esos campos tambien llevan x-tree-split.
Completado en IDE
English | 中文 | 日本語 | 한국어 | Français | Deutsch | Español | Português | Svenska | Suomi | Nederlands
Los JSON Schemas generados pueden usarse con archivos de configuración TOML,
YAML, JSON y JSON5. Se generan desde el mismo tipo Rust usado por 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,
}
}
Genéralos con:
#![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>>(())
}
Esto escribe el esquema raíz y esquemas de sección como
schemas/server.schema.json. Los esquemas generados omiten restricciones
required para que el completado funcione en archivos de configuración
parciales sin diagnósticos de campos faltantes. El esquema raíz omite propiedades de secciones divididas, por lo que el
completado de secciones hijas solo está disponible en archivos que enlazan el
esquema de sección correspondiente. Las secciones anidadas sin marca permanecen
en el esquema raíz.
Los campos marcados con x-env-only se omiten de los esquemas generados, por lo que los IDE no sugieren secrets u otros valores que deben venir solo de variables de entorno.
Los esquemas del IDE sirven para completado y comprobaciones básicas del
editor, como tipo, enum y propiedades desconocidas admitidas por el esquema
generado. No deciden si un valor concreto de campo es válido para la aplicación.
La validación de valores debe implementarse en código con
#[config(validate = Self::validate)] y ejecutarse mediante load_config o
config-validate. Los campos obligatorios y la validación final de la
configuración fusionada también usan esas rutas de ejecución.
TOML
Los archivos TOML deberían enlazar el esquema con una directiva #:schema al
inicio del archivo:
#:schema ./schemas/myapp.schema.json
[server]
bind = "0.0.0.0"
port = 3000
No uses un campo raíz $schema = "..." en TOML. Se convierte en datos reales
de configuración y puede afectar la deserialización en tiempo de ejecución.
write_config_templates_with_schema añade automáticamente la directiva
#:schema para plantillas TOML.
YAML
Los archivos YAML deberían usar la modeline de YAML Language Server:
# yaml-language-server: $schema=./schemas/myapp.schema.json
server:
bind: 0.0.0.0
port: 3000
write_config_templates_with_schema añade automáticamente esta modeline para
plantillas YAML. Las plantillas YAML divididas enlazan su esquema de sección,
por ejemplo log.yaml enlaza ./schemas/log.schema.json.
JSON
Los archivos JSON y JSON5 pueden enlazar un esquema con un campo raíz
$schema. write_config_templates_with_schema lo agrega automáticamente a las
plantillas JSON y JSON5 generadas:
{
"$schema": "./schemas/myapp.schema.json"
}
Los ajustes del editor siguen siendo útiles si un proyecto no quiere un enlace dentro del archivo:
{
"json.schemas": [
{
"fileMatch": [
"/config.json",
"/config.*.json",
"/deploy/*.json"
],
"url": "./schemas/myapp.schema.json"
}
]
}
YAML también puede enlazarse mediante ajustes de VS Code:
{
"yaml.schemas": {
"./schemas/myapp.schema.json": [
"config.yaml",
"config.*.yaml",
"deploy/*.yaml"
]
}
}
La disposición final es:
schemas/myapp.schema.json:
Solo campos del archivo raíz
schemas/server.schema.json:
Esquema de la sección 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"
Referencias:
Integración CLI
English | 中文 | 日本語 | 한국어 | Français | Deutsch | Español | Português | Svenska | Suomi | Nederlands
ConfigCommand proporciona subcomandos clap reutilizables:
config-templateconfig-schemaconfig-validatecompletionsinstall-completionsuninstall-completions
Estos subcomandos incorporados están separados de las flags de override de configuración específicas de la aplicación. Fusiona flags de override de configuración como proveedores Figment en la ruta de carga en tiempo de ejecución.
Las flags de override de configuración siguen siendo parte de la CLI de la
aplicación consumidora. Sus nombres no necesitan coincidir con rutas de
configuración con puntos. Por ejemplo, la aplicación puede parsear
--server-port y mapearla a la clave de configuración anidada server.port.
Solo las flags que la aplicación mapea dentro de CliOverrides afectan los
valores de configuración.
Aplánalo dentro de un enum de comandos de aplicación:
- Mantén el tipo
Parserpropio de la aplicación. - Mantén el enum
Subcommandpropio de la aplicación. - Añade
#[command(flatten)] Config(ConfigCommand)a ese enum. - Clap expande las variantes aplanadas de
ConfigCommanden el mismo nivel de comandos que las variantes propias de la aplicación. - Haz match de la variante
Config(command)y pásala 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(())
}
Plantillas de configuración
demo config-template
El comando escribe plantillas bajo config/<root_config_name>/. Si --output
recibe una ruta, solo se usa el nombre de archivo. Si no se proporciona un
nombre de archivo de salida, el comando escribe
config/<root_config_name>/<root_config_name>.example.yaml. Añade
--schema schemas/myapp.schema.json para enlazar plantillas TOML, YAML, JSON y
JSON5 generadas a JSON Schemas generados. Las plantillas YAML divididas enlazan
el esquema de sección correspondiente. Las plantillas JSON y JSON5 reciben un
campo $schema que VS Code reconoce. El comando también escribe los esquemas
raíz y de sección en la ruta de esquema seleccionada.
demo config-template --output app_config.example.toml --schema schemas/myapp.schema.json
Genera JSON Schemas raíz y de sección:
demo config-schema
Sin --output, config-schema escribe el esquema raíz en
config/<root_config_name>/<root_config_name>.schema.json.
Valida el árbol completo de configuración en tiempo de ejecución:
demo config-validate
Los esquemas de editor generados evitan deliberadamente diagnósticos de campos
obligatorios para archivos divididos. config-validate carga includes, aplica
valores por defecto y ejecuta la validación final de confique, incluidos los
validadores declarados con #[config(validate = Self::validate)]. Los
*.schema.json generados siguen siendo para completado de IDE y comprobaciones
básicas del editor, no para legalidad de valores de campo. Imprime
Configuration is ok cuando la validación tiene éxito.
Shell completions
Imprime completions a stdout:
demo completions zsh
Instala completions:
demo install-completions zsh
Desinstala completions:
demo uninstall-completions zsh
El instalador admite Bash, Elvish, Fish, PowerShell y Zsh. Escribe el archivo de completion bajo el directorio home del usuario y actualiza el archivo de inicio del shell para shells que lo requieren.
Antes de cambiar un archivo de inicio de shell existente como ~/.zshrc,
~/.bashrc, un archivo rc de Elvish o un perfil de PowerShell, el comando
escribe una copia de seguridad junto al archivo original:
<rc-file>.backup.by.<program-name>.<timestamp>
Ejemplos
English | 中文 | 日本語 | 한국어 | Français | Deutsch | Español | Português | Svenska | Suomi | Nederlands
El repositorio incluye ejemplos ejecutables para cargar árboles de configuración, overrides de CLI, comandos de configuración incorporados, generación de plantillas y la API de árbol de menor nivel.
Lee el índice de ejemplos del repositorio:
Ejecuta ejemplos desde la raíz del repositorio:
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 de árbol
English | 中文 | 日本語 | 한국어 | Français | Deutsch | Español | Português | Svenska | Suomi | Nederlands
Usa la API de árbol de menor nivel cuando la aplicación no use confique o
cuando necesite acceso directo a los resultados del recorrido.
#![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>>(())
}
Reglas de recorrido
El cargador de árbol:
- normaliza rutas fuente léxicamente;
- rechaza rutas de include vacías;
- resuelve includes relativos desde el archivo que los declaró;
- conserva rutas de include absolutas;
- detecta ciclos de include recursivos;
- omite archivos ya cargados mediante otra rama de include.
ConfigTreeOptions puede invertir el recorrido de includes hermanos:
#![allow(unused)]
fn main() {
use rust_config_tree::{ConfigTreeOptions, IncludeOrder};
let options = ConfigTreeOptions::default().include_order(IncludeOrder::Reverse);
let _ = options;
}
Ayudantes de ruta
Los ayudantes de ruta son solo léxicos. No resuelven enlaces simbólicos y no requieren que las rutas existan:
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
Este repositorio publica el manual con mdBook y GitHub Pages.
Los manuales por idioma son proyectos mdBook independientes. Cada idioma tiene
su propio SUMMARY.md, por lo que la barra lateral izquierda solo contiene
páginas del idioma actual:
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
...
Construye localmente con:
scripts/publish-pages.sh
El sitio generado se escribe en:
target/mdbook
Workflow de publicación
El workflow en .github/workflows/pages.yml se ejecuta en pushes a main y en
manual dispatch. Hace lo siguiente:
- Hace checkout del repositorio.
- Instala mdBook.
- Ejecuta
scripts/publish-pages.sh. - Sube
target/mdbookcomo artefacto de Pages. - Despliega el artefacto en GitHub Pages.
La URL publicada es:
https://developerworks.github.io/rust-config-tree/
Release del crate
Para el flujo completo de commit, push, despliegue de Pages y publicación del crate:
scripts/release.sh --execute --message "Release 0.1.3"
Usa el ayudante de release del crate desde la raíz del repositorio:
scripts/publish-crate.sh
El modo por defecto ejecuta comprobaciones y cargo publish --dry-run. Para
publicar en crates.io después de que las comprobaciones pasen. Si la versión
actual ya existe en crates.io, el script incrementa automáticamente la versión
patch:
scripts/publish-crate.sh --execute
El uso de scripts se resume en scripts/README.md.