Rust provides a simple std::env::Arg
iterator to access command-line arguments passed to a program.
However, most of the time you require more advanced tool for that, which provides --help
and --version
flags out-of-the-box and a convenient way to setup and describe custom options/flags to build your own CLI (command-line interface). For such cases there is the well-known clap
crate in Rust ecosystem.
It has the derive
Cargo feature (formerly, structopt
crate) allowing to define CLI in a declarative and clean way.
For better understanding and familiarity with CLI tools in Rust ecosystem, read through the following articles:
- Rust Book: 12.1. Accepting Command Line Arguments
- Official
std::env::Arg
docs - Official
clap
crate docs - Pavlo Myroniuk: Rust Clap recipes
Rust provides common primitives in std::env
for working with environment variables as strings.
However, most of the time you want to operate with typed data, not with raw strings. Similarly to clap
for CLI, there is the envy
crate in Rust ecosystem, which uses serde
as facade and allows to read data from environment variables in a declarative and clean way (due to serde attributes support).
It's worth mentioning, that clap
crate is able to parse from environment variables too, which is super handy when it comes to backing your CLI with environment variables.
Finally, dotenv
crate should be mentioned. It sets environment variables basing on .env
file contents, which is widely used convention to simplify environment configuration and to omit declaring all the required environment variables by hand each time when running some program. This one is especially useful in development (consider also rs-env
and direnv
for better development experience).
For better understanding and familiarity with environment variables tools in Rust ecosystem, read through the following articles:
- Rust Book: 12.5. Working with Environment Variables
- Official
std::env
docs - Official
envy
crate docs - Official
dotenv
crate docs
For dealing with configurations there is the well-known config
crate in Rust ecosystem, which simplifies creation and usage of hierarchical typed configuration structures in a 12-factor way.
Config
lets you set a set of default parameters and then extend them via merging in configuration from a variety of sources:
- Environment variables
- String literals in well-known formats
- Another
Config
instance- Files: TOML, JSON, YAML, INI, RON, JSON5 and custom ones defined with
Format
trait- Manual, programmatic override (via a
.set
method on theConfig
instance)Additionally,
Config
supports:
- Live watching and re-reading of configuration files
- Deep access into the merged configuration via a path syntax
- Deserialization via
serde
of the configuration or any subset defined via a path
For better understanding and familiarity with config
crate design, concepts, usage, and features, read through the following articles:
Estimated time: 1 day
Write a simple program which prints out its actual configuration. Configuration should be implemented as a typed hierarchical structure, which is able to parse from a specified file and/or environment variables.
The following priority should be applied (in ascending order) when merging:
- Default values declared directly in Rust sources;
- Values read from TOML file;
- Values set by environment variables with
CONF_
prefix.
CLI of the program should look like:
$ cargo run -- --help
step_3_9 0.1.0
Prints its configuration to STDOUT.
USAGE:
step_3_9 [FLAGS] [OPTIONS]
FLAGS:
-d, --debug Enables debug mode
-h, --help Prints help information
-V, --version Prints version information
OPTIONS:
-c, --conf <conf> Path to configuration file [env: CONF_FILE=] [default: config.toml]
After completing everything above, you should be able to answer (and understand why) the following questions: