Handle CLI arguments
Command Line Interface (CLI) tools often require input parameters to dictate their behavior.
clap
(Command Line Argument Parser) is a feature-rich Rust
library that facilitates the parsing of these arguments in an intuitive manner.
Defining Command Line Arguments
In this snippet, we utilize the clap
library to define an Args
struct, which will be used to
capture and structure the arguments passed to the application:
use clap::Parser;
#[derive(Parser, Debug)]
#[command(version = version(), about = "ratatui template with crossterm and tokio")]
struct Args {
/// App tick rate
#[arg(short, long, default_value_t = 1000)]
app_tick_rate: u64,
}
Here, the Args struct defines one command-line arguments:
app_tick_rate
: Dictates the application’s tick rate.
This is supplied with default values, ensuring that even if the user doesn’t provide this argument, the application can still proceed with its defaults.
Displaying Version Information
One common convention in CLIs is the ability to display version information. Here, the version information is presented as a combination of various parameters, including the Git commit hash.
The version()
function, as seen in the snippet, fetches this information:
pub fn version() -> String {
let author = clap::crate_authors!();
let commit_hash = env!("RATATUI_TEMPLATE_GIT_INFO");
// let current_exe_path = PathBuf::from(clap::crate_name!()).display().to_string();
let config_dir_path = get_config_dir().unwrap().display().to_string();
let data_dir_path = get_data_dir().unwrap().display().to_string();
format!(
"\
{commit_hash}
Authors: {author}
Config directory: {config_dir_path}
Data directory: {data_dir_path}"
)
}
This function uses the get_data_dir()
and get_config_dir()
from
the section on XDG directories.
This function also makes use of an environment variable RATATUI_TEMPLATE_GIT_INFO
to derive the
Git commit hash. The variable can be populated during the build process by build.rs
:
println!("cargo:rustc-env=RATATUI_TEMPLATE_GIT_INFO={}", git_describe);
By invoking the CLI tool with the --version
flag, users will be presented with the version
details, including the authors, commit hash, and the paths to the configuration and data
directories.
The version()
function’s output is just an example. You can easily adjust its content by amending
the string template code above.
Here’s the full build.rs
for your reference:
fn main() {
let git_output = std::process::Command::new("git").args(["rev-parse", "--git-dir"]).output().ok();
let git_dir = git_output.as_ref().and_then(|output| {
std::str::from_utf8(&output.stdout).ok().and_then(|s| s.strip_suffix('\n').or_else(|| s.strip_suffix("\r\n")))
});
// Tell cargo to rebuild if the head or any relevant refs change.
if let Some(git_dir) = git_dir {
let git_path = std::path::Path::new(git_dir);
let refs_path = git_path.join("refs");
if git_path.join("HEAD").exists() {
println!("cargo:rerun-if-changed={}/HEAD", git_dir);
}
if git_path.join("packed-refs").exists() {
println!("cargo:rerun-if-changed={}/packed-refs", git_dir);
}
if refs_path.join("heads").exists() {
println!("cargo:rerun-if-changed={}/refs/heads", git_dir);
}
if refs_path.join("tags").exists() {
println!("cargo:rerun-if-changed={}/refs/tags", git_dir);
}
}
let git_output =
std::process::Command::new("git").args(["describe", "--always", "--tags", "--long", "--dirty"]).output().ok();
let git_info = git_output.as_ref().and_then(|output| std::str::from_utf8(&output.stdout).ok().map(str::trim));
let cargo_pkg_version = env!("CARGO_PKG_VERSION");
// Default git_describe to cargo_pkg_version
let mut git_describe = String::from(cargo_pkg_version);
if let Some(git_info) = git_info {
// If the `git_info` contains `CARGO_PKG_VERSION`, we simply use `git_info` as it is.
// Otherwise, prepend `CARGO_PKG_VERSION` to `git_info`.
if git_info.contains(cargo_pkg_version) {
// Remove the 'g' before the commit sha
let git_info = &git_info.replace('g', "");
git_describe = git_info.to_string();
} else {
git_describe = format!("v{}-{}", cargo_pkg_version, git_info);
}
}
println!("cargo:rustc-env=RATATUI_TEMPLATE_GIT_INFO={}", git_describe);
}