Manual do rust-config-tree
English | 中文 | 日本語 | 한국어 | Français | Deutsch | Español | Português | Svenska | Suomi | Nederlands
Este e o manual em portugues do rust-config-tree.
Comece por Introducao, Inicio rapido ou pelos Exemplos executaveis.
Introducao
English | 中文 | 日本語 | 한국어 | Français | Deutsch | Español | Português | Svenska | Suomi | Nederlands
rust-config-tree fornece carregamento reutilizavel de arvores de configuracao
e auxiliares de CLI para aplicacoes Rust que usam arquivos de configuracao em
camadas.
O crate e projetado em torno de uma pequena divisao de responsabilidades:
confiquee dono das definicoes de esquema, padroes de codigo, validacao e geracao de modelos de configuracao.figmente dono do carregamento em tempo de execucao e dos metadados de origem em tempo de execucao.rust-config-treee dono da travessia recursiva de includes, resolucao de caminhos de include, carregamento de.env, descoberta de destinos de modelo e comandos clap reutilizaveis.
O crate e util quando uma aplicacao quer um layout natural de arquivos de configuracao como este:
include:
- config/server.yaml
- config/database.yaml
log:
level: info
Cada arquivo incluido pode usar o mesmo formato de esquema, e caminhos de
include relativos sao resolvidos a partir do arquivo que os declarou. A
configuracao final continua sendo um valor normal de esquema confique.
Principais recursos
- Travessia recursiva de includes com deteccao de ciclos.
- Caminhos de include relativos resolvidos a partir do arquivo declarante.
- Carregamento de
.envantes que provedores de ambiente sejam avaliados. - Variaveis de ambiente declaradas no esquema sem divisao por delimitador.
- Metadados Figment para rastreamento de origem em tempo de execucao.
- Eventos de rastreamento de origem em nivel TRACE por
tracing. - Geracao de JSON Schema Draft 7 para completamento e verificacoes basicas de esquema no editor.
- Validacao de valores de campo no codigo da aplicacao com
#[config(validate = Self::validate)], executada porload_configouconfig-validate. - Geracao de modelos YAML, TOML, JSON e JSON5.
- Diretivas TOML
#:schema, modelines YAML Language Server e campos JSON/JSON5$schemapara modelos gerados. - Divisao opt-in de modelos YAML para secoes marcadas com
x-tree-split. - Subcomandos clap embutidos para modelos de configuracao, JSON Schema e shell completions.
- Uma API de arvore de nivel mais baixo para chamadores que nao usam
confique.
Pontos de entrada publicos
Use estas APIs para a maioria das aplicacoes:
load_config::<S>(path)carrega o esquema final.load_config_with_figment::<S>(path)carrega o esquema e retorna o grafo Figment usado para rastreamento de origem.write_config_templates::<S>(config_path, output_path)grava o modelo raiz e modelos filhos descobertos recursivamente.write_config_schemas::<S>(output_path)grava JSON Schemas Draft 7 raiz e de secao.handle_config_command::<Cli, S>(command, config_path)manipula comandos clap de configuracao embutidos.
Use load_config_tree quando precisar do primitivo de travessia sem confique.
Inicio rapido
English | 中文 | 日本語 | 한국어 | Français | Deutsch | Español | Português | Svenska | Suomi | Nederlands
Adicione o crate e as bibliotecas de esquema/tempo de execucao usadas pela sua aplicacao:
[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"] }
Defina um esquema confique e implemente ConfigSchema para o tipo raiz:
#![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()
}
}
}
Carregue a configuracao:
#![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>>(())
}
Use um arquivo raiz com includes recursivos:
# config.yaml
include:
- config/server.yaml
# config/server.yaml
server:
bind: 0.0.0.0
port: 3000
A precedencia padrao de load_config e:
environment variables
> config files, with later merged files overriding earlier files
> confique code defaults
Quando includes sao carregados pela API de alto nivel, o arquivo raiz tem a maior prioridade entre arquivos. Arquivos incluidos fornecem valores de menor prioridade e podem ser usados para padroes ou arquivos especificos de secao.
Argumentos de linha de comando sao especificos da aplicacao, entao
load_config nao os le automaticamente. Mescle sobrescritas de CLI depois de
build_config_figment quando a aplicacao tiver flags de sobrescrita de
configuracao:
Nomes de flags de CLI sao escolhidos pela aplicacao. Eles nao sao
automaticamente caminhos de configuracao a.b.c. Prefira flags clap normais,
como --server-port, e depois mapeie-as para uma estrutura aninhada de
sobrescrita. O formato serializado aninhado controla a chave de configuracao que
sera sobrescrita.
Somente valores representados no provedor CliOverrides da aplicacao
sobrescrevem a configuracao. Isso e util para parametros alterados com
frequencia em uma unica execucao sem editar o arquivo de configuracao. Valores
estaveis devem permanecer em arquivos de configuracao.
#![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>>(())
}
Com sobrescritas de CLI mescladas dessa forma, a precedencia completa e:
command-line overrides
> environment variables
> config files
> confique code defaults
Esquema de configuracao
English | 中文 | 日本語 | 한국어 | Français | Deutsch | Español | Português | Svenska | Suomi | Nederlands
Esquemas de aplicacao sao tipos normais de configuracao confique. O esquema
raiz deve implementar ConfigSchema para que rust-config-tree possa descobrir
includes recursivos a partir da camada intermediaria do 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 de include
O campo de include pode ter qualquer nome. rust-config-tree so o conhece por
meio de ConfigSchema::include_paths.
Normalmente, o campo deve ter um padrao vazio:
#![allow(unused)]
fn main() {
#[config(default = [])]
include: Vec<PathBuf>,
}
O carregador recebe uma camada parcialmente carregada para cada arquivo. Isso permite descobrir arquivos de configuracao filhos antes que o esquema final seja mesclado e validado.
Secoes aninhadas
Use #[config(nested)] para secoes estruturadas. Secoes aninhadas sempre sao
usadas para carregamento em tempo de execucao. Adicione
#[schemars(extend("x-tree-split" = true))] quando um campo aninhado tambem
deve ser gerado como seu proprio modelo *.yaml e schema
<section>.schema.json:
#![allow(unused)]
fn main() {
#[derive(Debug, Config, JsonSchema)]
struct AppConfig {
#[config(nested)]
#[schemars(extend("x-tree-split" = true))]
server: ServerConfig,
}
}
O formato YAML natural e:
server:
bind: 127.0.0.1
port: 8080
Campos somente de ambiente
Marque um campo folha com #[schemars(extend("x-env-only" = true))] quando seu valor deve vir somente de uma variavel de ambiente e nao deve aparecer em arquivos de configuracao gerados. Modelos YAML e JSON Schemas gerados omitem campos env-only, e objetos pai que ficarem vazios tambem sao removidos.
#![allow(unused)]
fn main() {
#[config(env = "APP_SECRET")]
#[schemars(extend("x-env-only" = true))]
secret: String,
}
Validacao de valores de campo
Os arquivos *.schema.json gerados servem apenas para completamento de IDE e
verificacoes basicas do editor. Eles nao decidem se um valor concreto de campo e
valido para a aplicacao.
A validacao de valores deve ser implementada no codigo com
#[config(validate = Self::validate)]. O validador e executado quando a
configuracao final e carregada por load_config ou verificada por
config-validate.
Sobrescritas de secao de modelo
Quando uma origem de modelo nao tem includes, o crate pode derivar arquivos de
modelo filhos a partir de secoes de esquema aninhadas marcadas com x-tree-split. O caminho padrao de
primeiro nivel e <section>.yaml.
Sobrescreva esse caminho com 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,
}
}
}
}
Carregamento em tempo de execucao
English | 中文 | 日本語 | 한국어 | Français | Deutsch | Español | Português | Svenska | Suomi | Nederlands
O carregamento em tempo de execucao e intencionalmente dividido entre Figment e confique:
figment:
runtime file loading
runtime environment loading
runtime source metadata
confique:
schema metadata
defaults
validation
config templates
A API principal e:
#![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>>(())
}
Use load_config_with_figment quando a aplicacao precisar de metadados de
origem:
#![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>>(())
}
Etapas de carregamento
O carregador de alto nivel executa estas etapas:
- Resolve lexicalmente o caminho da configuracao raiz.
- Carrega o primeiro arquivo
.envencontrado ao subir a partir do diretorio da configuracao raiz. - Carrega cada arquivo de configuracao como uma camada parcial para descobrir includes.
- Constroi um grafo Figment a partir dos arquivos de configuracao descobertos.
- Mescla o
ConfiqueEnvProvidercom prioridade maior que arquivos. - Opcionalmente mescla sobrescritas de CLI especificas da aplicacao.
- Extrai uma camada
confiquedo Figment. - Aplica padroes de codigo do
confique. - Valida e constroi o esquema final.
load_config e load_config_with_figment executam as etapas 1-5 e 7-9. A
etapa 6 e especifica da aplicacao porque este crate nao consegue inferir como
uma flag de CLI mapeia para um campo do esquema.
Formatos de arquivo
O provedor de arquivo em tempo de execucao e selecionado pela extensao do caminho de configuracao:
.yamle.ymlusam YAML..tomlusa TOML..jsone.json5usam JSON.- extensoes desconhecidas ou ausentes usam YAML.
A geracao de modelos ainda usa os renderizadores de modelo do confique para
saida YAML, TOML e compativel com JSON5.
Prioridade de includes
O carregador de alto nivel mescla provedores de arquivo para que arquivos incluidos tenham prioridade menor que o arquivo que os incluiu. O arquivo de configuracao raiz tem a maior prioridade entre arquivos.
Variaveis de ambiente tem prioridade maior que todos os arquivos de
configuracao. Padroes do confique sao usados apenas para valores que nao foram
fornecidos por provedores de tempo de execucao.
Quando sobrescritas de CLI sao mescladas depois de build_config_figment, a
precedencia completa e:
command-line overrides
> environment variables
> config files
> confique code defaults
A sintaxe de linha de comando nao e definida por rust-config-tree. Uma flag
como --server-port pode sobrescrever server.port se a aplicacao mapear esse
valor analisado para um provedor serializado aninhado. Uma sintaxe pontuada
--server.port ou a.b.c so existe se a aplicacao a implementar.
Isso significa que a precedencia de CLI se aplica apenas a chaves presentes no provedor de sobrescrita da aplicacao. Use-a para valores operacionais alterados com frequencia em uma unica execucao. Deixe configuracao duravel em arquivos.
#![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>>(())
}
Variaveis de ambiente
English | 中文 | 日本語 | 한국어 | Français | Deutsch | Español | Português | Svenska | Suomi | Nederlands
Nomes de variaveis de ambiente sao declarados no esquema com 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 le esses nomes de confique::Config::META e constroi um
provedor Figment que mapeia cada variavel de ambiente para seu caminho exato de
campo.
Nao use mapeamento de ambiente Figment baseado em delimitador 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 underscores como separadores de chaves aninhadas. Isso faz
APP_DATABASE_POOL_SIZE virar um caminho como database.pool.size, que entra em
conflito com nomes de campos Rust como pool_size.
Com ConfiqueEnvProvider, esse mapeamento e explicito:
APP_DATABASE_POOL_SIZE -> database.pool_size
Underscores simples continuam fazendo parte do nome da variavel de ambiente. Figment nao tenta adivinhar a regra de aninhamento.
Carregamento dotenv
Antes que provedores de tempo de execucao sejam avaliados, o carregador procura
um arquivo .env subindo a partir do diretorio do arquivo de configuracao raiz.
Variaveis de ambiente existentes no processo sao preservadas. Valores de .env
apenas preenchem variaveis de ambiente ausentes.
Exemplo:
APP_SERVER_PORT=9000
APP_DATABASE_POOL_SIZE=64
Essas variaveis sobrescrevem valores de arquivos de configuracao quando o
esquema declara atributos #[config(env = "...")] correspondentes.
Analise de valores
O provedor de ponte deixa o Figment analisar valores de ambiente. Ele nao chama
os hooks parse_env do confique. Mantenha valores complexos em arquivos de
configuracao a menos que a sintaxe de valores de ambiente do Figment seja uma
boa escolha para o tipo.
Rastreamento de origem
English | 中文 | 日本語 | 한국어 | Français | Deutsch | Español | Português | Svenska | Suomi | Nederlands
Use load_config_with_figment para manter o grafo Figment usado pelo
carregamento em tempo de execucao:
#![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>>(())
}
O valor Figment retornado pode responder perguntas de origem sobre valores em tempo de execucao:
#![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 fornecidos por ConfiqueEnvProvider, a interpolacao retorna o nome
nativo da variavel de ambiente declarado no esquema:
database.pool_size came from APP_DATABASE_POOL_SIZE
Eventos TRACE
O carregador emite eventos de rastreamento de origem com tracing::trace!. Ele
faz isso apenas quando TRACE esta 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 o target rust_config_tree::config e inclui:
config_key: a chave de configuracao pontuada.source: os metadados de origem renderizados.
Valores que vieram apenas de padroes do confique nao tem metadados Figment em
tempo de execucao. Eles sao relatados como
confique default or unset optional field.
Geracao de modelos
English | 中文 | 日本語 | 한국어 | Français | Deutsch | Español | Português | Svenska | Suomi | Nederlands
Modelos sao gerados a partir do mesmo esquema confique usado em tempo de
execucao. confique renderiza o conteudo real do modelo, incluindo comentarios
de documentacao, padroes, campos obrigatorios e nomes declarados de variaveis de
ambiente.
Use 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>>(())
}
Gere JSON Schemas Draft 7 para a configuracao raiz e secoes aninhadas marcadas para divisao:
#![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>>(())
}
Marque um campo aninhado com #[schemars(extend("x-tree-split" = true))]
quando ele deve ser gerado como seu proprio modelo *.yaml e seu proprio
schema <section>.schema.json. Campos aninhados nao marcados permanecem no
modelo pai e no schema pai.
Marque um campo folha com #[schemars(extend("x-env-only" = true))] quando o valor deve vir somente de variaveis de ambiente. Os modelos gerados e os JSON Schemas omitem campos env-only, e objetos pai que ficarem vazios tambem sao removidos.
Os esquemas gerados omitem restricoes required. IDEs ainda podem oferecer
completamento, mas arquivos parciais como log.yaml nao relatam campos
raiz ausentes. O esquema raiz completa apenas campos que pertencem ao arquivo
raiz; campos de secoes divididas sao omitidos ali e completados por seus
proprios esquemas de secao. Campos presentes ainda podem receber verificacoes
basicas do editor, como tipo, enum e propriedades desconhecidas suportadas pelo
esquema gerado. Os *.schema.json gerados nao decidem se um valor concreto de
campo e valido para a aplicacao. A validacao de valores deve ser implementada no
codigo com #[config(validate = Self::validate)]; load_config e
config-validate executam essa validacao em tempo de execucao.
Vincule esses esquemas a partir de modelos TOML, YAML, JSON e JSON5 gerados:
#![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>>(())
}
Modelos raiz TOML e YAML vinculam o esquema raiz e nao completam campos de
secoes filhas. Modelos YAML de secao dividida vinculam seu esquema de secao.
Modelos JSON e JSON5 recebem um campo raiz $schema que o VS Code pode
reconhecer. VS Code json.schemas continua sendo um caminho alternativo de
vinculo.
O formato de saida e inferido a partir do caminho de saida:
.yamle.ymlgeram YAML..tomlgera TOML..jsone.json5geram modelos compativeis com JSON5.- extensoes desconhecidas ou ausentes geram YAML.
Vinculos de esquema
Com um caminho de esquema schemas/myapp.schema.json, modelos raiz gerados usam:
#:schema ./schemas/myapp.schema.json
# yaml-language-server: $schema=./schemas/myapp.schema.json
Modelos de secao gerados vinculam esquemas de secao:
# log.yaml
# yaml-language-server: $schema=./schemas/log.schema.json
Modelos JSON e JSON5 gerados escrevem um campo raiz $schema reconhecido pelo
VS Code. As configuracoes do editor continuam opcionais:
{
"json.schemas": [
{
"fileMatch": [
"/config.json",
"/config.*.json"
],
"url": "./schemas/myapp.schema.json"
}
]
}
Selecao da origem de modelos
A geracao de modelos escolhe sua arvore de origem nesta ordem:
- Caminho de configuracao existente.
- Caminho de modelo de saida existente.
- Caminho de saida tratado como uma nova arvore de modelo vazia.
Isso permite que um projeto atualize modelos a partir dos arquivos de configuracao atuais, atualize um conjunto de modelos existente ou crie um novo conjunto de modelos apenas a partir do esquema.
Arvores de include espelhadas
Se o arquivo de origem declara includes, modelos gerados espelham esses caminhos de include sob o diretorio de saida.
# config.yaml
include:
- server.yaml
Gerar config.example.yaml grava:
config.example.yaml
server.yaml
Destinos de include relativos sao espelhados sob o diretorio pai do arquivo de saida. Destinos de include absolutos permanecem absolutos.
Divisao opt-in de secoes
Quando um arquivo de origem nao tem includes, o crate pode derivar destinos de
include a partir de secoes de esquema aninhadas marcadas com x-tree-split. Para um esquema com uma secao marcada
server, uma origem de modelo raiz vazia pode produzir:
config.example.yaml
server.yaml
O modelo raiz recebe um bloco de include, e server.yaml contem apenas a
secao server. Secoes aninhadas so sao divididas recursivamente quando esses campos tambem carregam x-tree-split.
Completions de IDE
English | 中文 | 日本語 | 한국어 | Français | Deutsch | Español | Português | Svenska | Suomi | Nederlands
JSON Schemas gerados podem ser usados por arquivos de configuracao TOML, YAML,
JSON e JSON5. Eles sao gerados a partir do mesmo tipo Rust usado pelo
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,
}
}
Gere-os com:
#![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>>(())
}
Isso grava o esquema raiz e esquemas de secao, como
schemas/server.schema.json. Esquemas gerados omitem restricoes required para
que o completamento funcione em arquivos de configuracao parciais sem
diagnosticos de campos ausentes. O esquema raiz omite propriedades de secoes
aninhadas, entao o completamento de secoes filhas fica disponivel apenas em
arquivos que vinculam o esquema de secao correspondente.
Campos marcados com x-env-only sao omitidos dos esquemas gerados, entao IDEs nao sugerem secrets ou outros valores que devem vir somente de variaveis de ambiente.
Esquemas de IDE servem para completamento e verificacoes basicas do editor,
como tipo, enum e propriedades desconhecidas suportadas pelo esquema gerado.
Eles nao decidem se um valor concreto de campo e valido para a aplicacao. A
validacao de valores deve ser implementada no codigo com
#[config(validate = Self::validate)] e executada por load_config ou
config-validate. Campos obrigatorios e a validacao final da configuracao
mesclada tambem usam esses caminhos de execucao.
TOML
Arquivos TOML devem vincular o esquema com uma diretiva #:schema no topo do
arquivo:
#:schema ./schemas/myapp.schema.json
[server]
bind = "0.0.0.0"
port = 3000
Nao use um campo raiz $schema = "..." em TOML. Ele vira dado real de
configuracao e pode afetar a desserializacao em tempo de execucao.
write_config_templates_with_schema adiciona a diretiva #:schema
automaticamente para modelos TOML.
YAML
Arquivos YAML devem usar a modeline do YAML Language Server:
# yaml-language-server: $schema=./schemas/myapp.schema.json
server:
bind: 0.0.0.0
port: 3000
write_config_templates_with_schema adiciona essa modeline automaticamente para
modelos YAML. Modelos YAML divididos vinculam seu esquema de secao; por exemplo,
log.yaml vincula ./schemas/log.schema.json.
JSON
Arquivos JSON e JSON5 podem vincular um schema com um campo raiz $schema.
write_config_templates_with_schema o adiciona automaticamente aos modelos
JSON e JSON5 gerados:
{
"$schema": "./schemas/myapp.schema.json"
}
As configuracoes do editor continuam uteis quando o projeto nao quer vinculo dentro do arquivo:
{
"json.schemas": [
{
"fileMatch": [
"/config.json",
"/config.*.json",
"/deploy/*.json"
],
"url": "./schemas/myapp.schema.json"
}
]
}
YAML tambem pode ser vinculado por configuracoes do VS Code:
{
"yaml.schemas": {
"./schemas/myapp.schema.json": [
"config.yaml",
"config.*.yaml",
"deploy/*.yaml"
]
}
}
O layout final e:
schemas/myapp.schema.json:
Somente campos do arquivo raiz
schemas/server.schema.json:
Schema da secao 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:
Integracao de CLI
English | 中文 | 日本語 | 한국어 | Français | Deutsch | Español | Português | Svenska | Suomi | Nederlands
ConfigCommand fornece subcomandos clap reutilizaveis:
config-templateconfig-schemaconfig-validatecompletionsinstall-completionsuninstall-completions
Esses subcomandos embutidos sao separados das flags de sobrescrita de configuracao especificas da aplicacao. Mescle flags de sobrescrita de configuracao como provedores Figment no caminho de carregamento em tempo de execucao.
Flags de sobrescrita de configuracao continuam fazendo parte da CLI da
aplicacao consumidora. Seus nomes nao precisam corresponder a caminhos de
configuracao pontuados. Por exemplo, a aplicacao pode analisar --server-port e
mapeia-lo para a chave aninhada server.port. Somente flags que a aplicacao
mapeia para CliOverrides afetam valores de configuracao.
Achate-o em um enum de comandos da aplicacao:
- Mantenha o tipo
Parserproprio da aplicacao. - Mantenha o enum
Subcommandproprio da aplicacao. - Adicione
#[command(flatten)] Config(ConfigCommand)a esse enum. - Clap expande as variantes achatadas de
ConfigCommandpara o mesmo nivel de comando das variantes proprias da aplicacao. - Faca match da variante
Config(command)e passe-a parahandle_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(())
}
Modelos de configuracao
demo config-template
O comando grava modelos em config/<root_config_name>/. Se --output receber
um caminho, somente o nome do arquivo e usado. Se nenhum nome de arquivo de
saida for fornecido, o comando grava
config/<root_config_name>/<root_config_name>.example.yaml. Adicione
--schema schemas/myapp.schema.json para vincular modelos TOML, YAML, JSON e
JSON5 gerados a JSON Schemas gerados. Modelos YAML divididos vinculam o esquema
de secao correspondente. Modelos JSON e JSON5 recebem um campo $schema
reconhecido pelo VS Code. O comando tambem grava o esquema raiz e esquemas de
secao no caminho de esquema selecionado.
demo config-template --output app_config.example.toml --schema schemas/myapp.schema.json
Gere JSON Schemas raiz e de secao:
demo config-schema
Sem --output, config-schema grava o esquema raiz em
config/<root_config_name>/<root_config_name>.schema.json.
Valide a arvore completa de configuracao em tempo de execucao:
demo config-validate
Esquemas de editor gerados evitam intencionalmente diagnosticos de campos
obrigatorios para arquivos divididos. config-validate carrega includes, aplica
padroes e executa a validacao final do confique, incluindo validadores
declarados com #[config(validate = Self::validate)]. Os *.schema.json
gerados continuam sendo para completamento de IDE e verificacoes basicas do
editor, nao para legalidade de valores de campo. Ele imprime Configuration is ok quando a validacao tem sucesso.
Shell completions
Imprima completions em stdout:
demo completions zsh
Instale completions:
demo install-completions zsh
Desinstale completions:
demo uninstall-completions zsh
O instalador suporta Bash, Elvish, Fish, PowerShell e Zsh. Ele grava o arquivo de completion sob o diretorio home do usuario e atualiza o arquivo de inicializacao do shell para shells que exigem isso.
Antes de alterar um arquivo de inicializacao de shell existente, como
~/.zshrc, ~/.bashrc, um arquivo rc do Elvish ou um perfil do PowerShell, o
comando grava um backup ao lado do arquivo original:
<rc-file>.backup.by.<program-name>.<timestamp>
Exemplos
English | 中文 | 日本語 | 한국어 | Français | Deutsch | Español | Português | Svenska | Suomi | Nederlands
O repositorio inclui exemplos executaveis para carregar arvores de configuracao, sobrescritas de CLI, comandos de configuracao embutidos, geracao de modelos e a API de arvore de nivel mais baixo.
Leia o indice de exemplos do repositorio:
Execute exemplos a partir da raiz do 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 arvore
English | 中文 | 日本語 | 한국어 | Français | Deutsch | Español | Português | Svenska | Suomi | Nederlands
Use a API de arvore de nivel mais baixo quando a aplicacao nao usa confique
ou quando precisa de acesso direto aos resultados da travessia.
#![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>>(())
}
Regras de travessia
O carregador de arvore:
- normaliza caminhos de origem lexicalmente;
- rejeita caminhos de include vazios;
- resolve includes relativos a partir do arquivo que os declarou;
- preserva caminhos de include absolutos;
- detecta ciclos de include recursivos;
- ignora arquivos ja carregados por outro ramo de include.
ConfigTreeOptions pode inverter a travessia de includes irmaos:
#![allow(unused)]
fn main() {
use rust_config_tree::{ConfigTreeOptions, IncludeOrder};
let options = ConfigTreeOptions::default().include_order(IncludeOrder::Reverse);
let _ = options;
}
Auxiliares de caminho
Os auxiliares de caminho sao apenas lexicais. Eles nao resolvem links simbolicos e nao exigem que caminhos existam:
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 o manual com mdBook e GitHub Pages.
Os manuais de cada idioma sao projetos mdBook independentes. Cada idioma tem
seu proprio SUMMARY.md, entao a barra lateral esquerda contem apenas paginas
do idioma atual:
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
...
Construa localmente com:
scripts/publish-pages.sh
O site gerado e gravado em:
target/mdbook
Workflow de publicacao
O workflow em .github/workflows/pages.yml roda em pushes para main e por
acionamento manual. Ele:
- Faz checkout do repositorio.
- Instala mdBook.
- Executa
scripts/publish-pages.sh. - Envia
target/mdbookcomo artefato Pages. - Implanta o artefato no GitHub Pages.
A URL publicada e:
https://developerworks.github.io/rust-config-tree/
Lancamento do crate
Para o fluxo completo de commit, push, deploy do Pages e publicacao do crate:
scripts/release.sh --execute --message "Release 0.1.3"
Use o auxiliar de lancamento do crate a partir da raiz do repositorio:
scripts/publish-crate.sh
O modo padrao executa verificacoes e cargo publish --dry-run. Para publicar no
crates.io depois que as verificacoes passarem. Se a versao atual ja existir no
crates.io, o script incrementa a versao patch automaticamente:
scripts/publish-crate.sh --execute
O uso dos scripts e resumido em scripts/README.md.