Just-config is a configuration library for rust

Overview

Rust Current Version Docs.rs License Apache 2.0

Config Library for Rust

Just-config is a configuration library for rust. It strives for the old Unix mantra "Do one thing and to it well". It's just build to read configuration values from different sources and fuse them into an easy to handle configuration source. Its primary purpose is to be used by a configuration class and populate the different, typed configuration values.

Out of the box it features the following configuration sources:

  • Static (fallbacks, command line)
  • Environment variables
  • Configuration file

It has built in validation support and can accept multiple configuration values per key. It even can limit the number of configuration values that are acceptable for a given configuration key.

Writing your own configuration sources (for example for etcd) is really easy. You only have to implement the get method of the Source trait.

If you just want to use this library, open the documentation, look at the examples and descriptions and start using it by adding the following to the [dependencies] section of your Cargo.toml:

justconfig = "1.0"

Basic example

A a little teaser here is the basic example copied from the documentation.

= conf.get(conf.root().push("tags")).values(..)?; // Read the paths from the config file and allow it to be overriden by // the environment variable. We split everything at `:` to allow passing // multiple paths using an environment variable. When read from the config // file, multiple values can be set without using the `:` delimiter. // Passing 1.. to values() makes sure at least one search path is set. let search_paths: Vec = conf.get(conf.root().push("searchPath")).explode(':').values(1..)?; ">
use justconfig::Config;
use justconfig::ConfPath;
use justconfig::sources::text::ConfigText;
use justconfig::sources::env::Env;
use justconfig::sources::defaults::Defaults;
use justconfig::processors::Explode;
use justconfig::validators::Range;
use justconfig::item::ValueExtractor;
use std::ffi::OsStr;
use std::fs::File;
let mut conf = Config::default();
// Allow some environment variables to override configuration values read
// from the configuration file.
let config_env = Env::new(&[
  (ConfPath::from(&["searchPath"]), OsStr::new("SEARCH_PATH")),
]);
// Open the configuration file
let config_file = File::open("myconfig.conf").expect("Could not open config file.");
conf.add_source(ConfigText::new(config_file, "myconfig.conf").expect("Loading configuration file failed."));
// Read the value `num_frobs` from the configuration file.
// Do not allow to use more than 10 frobs.
let num_frobs: i32 = conf.get(conf.root().push("num_frobs")).max(10).value()?;
// Read a list of tags from the configuration file.
let tag_list: Vec<String> = conf.get(conf.root().push("tags")).values(..)?;
// Read the paths from the config file and allow it to be overriden by
// the environment variable. We split everything at `:` to allow passing
// multiple paths using an environment variable. When read from the config
// file, multiple values can be set without using the `:` delimiter.
// Passing 1.. to values() makes sure at least one search path is set.
let search_paths: Vec<String> = conf.get(conf.root().push("searchPath")).explode(':').values(1..)?;

Changelog

  • Version 0.8.0
    Initial Release

  • Version 0.8.1
    Add some more examples

  • Version 0.9.0
    Breaking change: Added range syntax for configuration values and range validation. All occurrences of values() and between() must be updated. The error handling for validation errors of the between-validator has changes as well.

  • Version 0.9.1
    Added the stack_config function to the text source module. This function makes merging configuration files from multiple source paths easier.

  • Version 0.9.2
    Updated documentation to use intra-doc-links.

  • Version 1.0.0
    Fixed that non existent configuration keys satisfied a 1.. range limit. Now this is correctly detected as an error.
    Updates to documentation to mention stack_config on the library page.

Design rational

If you are interested about the rationale behind the design of this library (and can stand some highly opinionated reasoning) you can read on.

No data types

I don't think that data types in configuration files are a good idea. What do I mean by "data types"? TOML for example distinguishes strings, numbers, dates, etc. They are represented differently within the configuration file. Let's assume you've got a configuration file that reads cache_timeout=42. That's ok, but now the next version of your program should allow the user to disable the cache. You think about it and decide (like many have done before) to use the value 0 as a magic value for disabling the cache. That's fine for now. But after a few versions, you want to add infinite cache timeout. You can't just use "infinite" or some other string, because all old configuration files only have the number in there. You can allow both, strings and numbers but that increases the complexity and it does something else: It makes the configuration file much harder to understand. The infinite value is not a string. It's a special constant (a literal) and putting it between quotation marks conveys the completely wrong message. A string is an arbitrary sequence of characters that can be chosen by the user. Not a single, constant value. By having different data types within your configuration file you've created a restriction for you as a developer and/or a maintenance burden for the user.

I think a better solution is to keep the data type out of the configuration format. cache_timeout=42 is a valid value and cache_timeout=infinite is also valid. Go ahead and add cache_timeout="twenty minutes". It's up to the application to determine the meaning of the value part. If you want to put an exclamation mark in front of your constants: Just do it. The configuration library should not impose any restrictions on you.

Line continuation

Many configuration file format use line continuation on the line that is continued. For example TOML allows to continue a line by ending it with a backslash. This approach has some drawbacks: When writing a multi line value, look-ahead is needed to determine if the current line has to end with a continuation character. This makes automatic writing a multi line value more complicated that it should be. Event for human users this is not very convenient. You have to go up one line and append the continuation character to the previous line to continue it. The LDIF format uses a better solution: Marking continuation on the continuing line. This prevents a security problem as well:

Imagine the following configuration file:

multiline=line1 \
line2 \
line3
critical_value=secure

Now you delete line3 but miss to delete the continuation character on line2. Now the security critical_value is just part of multiline. If the value is security critical but optional you just created a security vulnerability.

Leading white-space

Leading white-space should be left to the user. Making them significant (like in YAML) creates two types of annoyances for the user:

  1. The user should be able to indent its configuration files in any way he finds reasonable. Even unreasonable ways should not be a problem.
  2. Distinguishing the number of white spaces and tabs on a non-working server, in a hurry with not more than basic vi is hard and many administrators will get it wrong at least one time.

And from a security standpoint: A missing white space, that moves your critical configuration value into a section where it does nothing, is a problem as well.

No write support

Configuration files are for the user. He's the only one that should write to a configuration file. Don't mess with it. The configuration file might be part of an automated deployment workflow, that will get upset if you decide to change the contents of the configuration file. If you want to help your user to create the first configuration file, supply an example. If your application has to write to the file, it's not a configuration file anymore. It's a database. Just use a different library and format for that (sqlite, yaml, xml).

There is one exception to this rule. If you're writing a configuration management or deployment solution, you have to write configuration files. But there are good templating engines out there that will get the job done.

No deserialization

Configuration files are parsed, not deserialized. Serialization is the process of turning a complex data structure into a series of tokens (mostly bytes) and later reconstructing the data structure from these tokens later. Configuration information is not a data structure to begin with. Trying to turn it into one turns often out to be a problem in the end. At first serialization libraries look like a good solution. But as your configuration information grows and the number of configuration sources rises it becomes more and more complex.

Different sources have different capabilities in expressing the configuration information. If the information is coming from an environment variable using a separator character for multiple values might be a good choice. For a configuration file simply using multiple entries with the same key might be more intuitive.

Most serialization libraries are not build to give you in depth control over the format you want to parse. And soon you're developing your own parser on top of the chosen library.

If you're searching for a serialization library I recommend you to take a look at serde.

No unsafe code

A configuration file parser by definition is parsing untrusted information. You should not make things worse by using unsafe code. Not using unsafe is no guarantee for safe code, but using it drops many of the guarantees rust gives you. This should only be done with a good reason. And parsing a text file or environment variable is no good reason.

No dependencies

And one last thing: No dependencies. This is a configuration file parser, not an application framework. I think pulling in dependencies and sub dependencies into a project, that only wants to parse some configuration information is rather rude and increases the maintenance burden for the consumer of the configuration library. Every dependency can have security issues that you must track and force updates on your product because of that. Sure, there are libraries that are totally worth it. But I think a configuration library should not do that. It should be simple enough to work without using any dependencies.

You might also like...
This repository is an experimental WebAssembly build of the [ymfm] Yamaha FM sound cores library.
This repository is an experimental WebAssembly build of the [ymfm] Yamaha FM sound cores library.

This repository is an experimental WebAssembly build of the [ymfm] Yamaha FM sound cores library.

An easy to configure wrapper for Rust's clippy

An easy to configure wrapper for Rust's clippy

Easy c̵̰͠r̵̛̠ö̴̪s̶̩̒s̵̭̀-t̶̲͝h̶̯̚r̵̺͐e̷̖̽ḁ̴̍d̶̖̔ ȓ̵͙ė̶͎ḟ̴͙e̸̖͛r̶̖͗ë̶̱́ṉ̵̒ĉ̷̥e̷͚̍ s̷̹͌h̷̲̉a̵̭͋r̷̫̊ḭ̵̊n̷̬͂g̵̦̃ f̶̻̊ơ̵̜ṟ̸̈́ R̵̞̋ù̵̺s̷̖̅ţ̸͗!̸̼͋

Rust S̵̓i̸̓n̵̉ I̴n̴f̶e̸r̵n̷a̴l mutability! Howdy, friendly Rust developer! Ever had a value get m̵̯̅ð̶͊v̴̮̾ê̴̼͘d away right under your nose just when

`haproxy_autconfd` is a daemon that automatically assembles a HAProxy config and restarts HAProxy if the config changes

haproxy_autconfd Welcome to haproxy_autconfd 🎉 haproxy_autconfd is a daemon that automatically assembles a HAProxy config and restarts HAProxy if the

Irx-config - The library provides convenient way to represent/parse configuration from different sources

The irx-config library provides convenient way to represent/parse configuration from different sources. The main goals is to be very easy to use and t

For when you really, really just want to know that your config changed

really-notify This crate is for when you really, really just want to know that your config changed. K8s configmap symlink shenanigans? No problem. Mul

A systemd-boot configuration and boot entry configuration parser library

A systemd-boot configuration and boot entry configuration parser library

A rust layered configuration loader with zero-boilerplate configuration management.

salak A layered configuration loader with zero-boilerplate configuration management. About Features Placeholder Key Convension Cargo Features Default

Kusion Configuration Language (KCL) is an open source configuration language mainly used in Kusion Stack

Kusion Configuration Language (KCL) is an open source configuration language mainly used in Kusion Stack. KCL is a statically typed language for configuration and policy scenarios, based on concepts such as declarative and Object-Oriented Programming (OOP) paradigms.

wireguard tool to manage / generate configuration. Maintain one yaml configuration file to quickly build wireguard network.

wgx wireguard tool to manage / generate configuration. Maintain one yaml configuration file to quickly build wireguard network. Usage wgx --h USAGE:

Bongo Copy Cat wants to be involved in everything you do but instead just imitates you hitting your keyboard all day. After all it's just a cat.
Bongo Copy Cat wants to be involved in everything you do but instead just imitates you hitting your keyboard all day. After all it's just a cat.

Bongo Copy Cat Introduction Bongo Copy Cat wants to be involved in everything you do but instead just imitates you hitting your keyboard all day. Afte

The dead easy way to use config files in your rust project

Configr The dead easy way to use config files in your project This will load a config.toml file if it exists, otherwise it will create the needed fold

Build a config structure from environment variables in Rust without boilerplate

Yasec Yet another stupid environment config (YASEC) creates settings from environment variables. (Envconig-rs fork) Features Nested configuration stru

Your next config manager, written in rust

confy Your next config manager, written in rust Based on uncomfyhalomacro/hmph but written for .ini files instead of json :) Getting started Take a lo

🐙 Loads config and hosts for gh CLI in Rust.

gh-config-rs Loads config and hosts for gh CLI in Rust. Getting started [dependencies] gh-config = "0.2" Usage use std::error::Error; use gh_config::*

An example app in Rust for CircleCI's Dynamic Config demo
An example app in Rust for CircleCI's Dynamic Config demo

circleci-dynamic-config-example An example app in Rust for CircleCI's dynamic config demo. Dynamic config allows you to dynamically generate CircleCI'

FastSSH is a TUI that allows you to quickly connect to your services by navigating through your SSH config.
FastSSH is a TUI that allows you to quickly connect to your services by navigating through your SSH config.

Connect quickly to your services 🚀 FastSSH is a TUI that allows you to quickly connect to your services by navigating through your SSH config. Instal

Most intuitive global cli maker. *(lazy_static + config-rs + clap)

argone Most intuitive global cli maker. *(lazy_static + config-rs + clap) | Examples | Docs | Latest Note | [dependencies] argone = "0.5" Phases Parsi

An ssh config parser for ssh2-rs

ssh2-config Changelog · Get started · Documentation Developed by @veeso Current version: 0.1.0 (04/12/2021) ssh2-config About ssh2-config Exposed attr

Owner
FlashSystems
FlashSystems
Kusion Configuration Language (KCL) is an open source configuration language mainly used in Kusion Stack

Kusion Configuration Language (KCL) is an open source configuration language mainly used in Kusion Stack. KCL is a statically typed language for configuration and policy scenarios, based on concepts such as declarative and Object-Oriented Programming (OOP) paradigms.

KusionStack 264 Dec 30, 2022
Build a config structure from environment variables in Rust without boilerplate

Yasec Yet another stupid environment config (YASEC) creates settings from environment variables. (Envconig-rs fork) Features Nested configuration stru

null 4 Dec 28, 2021
Your next config manager, written in rust

confy Your next config manager, written in rust Based on uncomfyhalomacro/hmph but written for .ini files instead of json :) Getting started Take a lo

Krishna Ramasimha 2 Nov 3, 2021
A Rust library for processing application configuration easily

Configure me A Rust library for processing application configuration easily About This crate aims to help with reading configuration of application fr

Martin Habovštiak 48 Dec 18, 2022
cfg-rs: A Configuration Library for Rust Applications

cfg-rs: A Configuration Library for Rust Applications Major Features One method to get all config objects, see get. Automatic derive config object, se

Daniel YU 20 Dec 16, 2022
⚙️ Layered configuration system for Rust applications (with strong support for 12-factor applications).

config-rs Layered configuration system for Rust applications (with strong support for 12-factor applications). Set defaults Set explicit values (to pr

Ryan Leckey 1.8k Jan 9, 2023
Zap - A simple cross-platform configuration management and orchestration tool

Zap - A simple cross-platform orchestration and configuration management tool. The main goal for Zap is to a simple mechanism for managing groups of com

R. Tyler Croy 50 Oct 29, 2022
Uclicious is a flexible reduced boilerplate configuration framework.

Uclicious What is Uclicious Usage Raw API Derive-driven Validators Type Mapping Supported attributes (#[ucl(..)]) Structure level Field level Addition

Andrey Cherkashin 14 Aug 12, 2022
🌽 A simple and pain-free configuration language.

?? Corn A simple and pain-free configuration language. Corn has been designed using inspiration from JSON and Nix to produce a language that's easy an

Jake Stanger 3 Nov 28, 2022
hosts file parsing, modification library, and some derivatives.

hosts-rs hosts: Hosts file parsing, modification library resolve-github: Use Cloudflare DoH to resolve GitHub domains and generate hosts files github-

zu1k 33 Jul 4, 2022