feat(args): add --explain argument for displaying documentation

This commit is contained in:
Orhun Parmaksız 2021-11-15 13:47:05 +03:00
parent 4a22e7cc63
commit 2c0010e362
No known key found for this signature in database
GPG key ID: F83424824B3E4B90
4 changed files with 53 additions and 25 deletions

View file

@ -186,6 +186,22 @@ impl Sysctl {
Ok(Self { parameters })
}
/// Searches and returns the parameter if it exists.
pub fn get_parameter(&mut self, param_name: &str) -> Option<&mut Parameter> {
let parameter = self
.parameters
.iter_mut()
.find(|param| param.name == *param_name);
if parameter.is_none() {
eprintln!(
"{}: cannot stat /proc/{}: No such file or directory",
env!("CARGO_PKG_NAME").split('-').collect::<Vec<_>>()[0],
param_name.replace(".", "/")
)
}
parameter
}
/// Updates the descriptions of the kernel parameters.
pub fn update_docs(&mut self, kernel_docs: &Path) -> Result<()> {
let documents = parse_kernel_docs(kernel_docs)?;

View file

@ -1,4 +1,4 @@
use std::io::{self, Stdout};
use std::io::{self, Stdout, Write};
use systeroid_core::config::Config;
use systeroid_core::error::Result;
use systeroid_core::sysctl::Sysctl;
@ -33,6 +33,21 @@ impl<'a> App<'a> {
.try_for_each(|parameter| parameter.display(&self.config.color, &mut self.stdout))
}
/// Displays the documentation of a parameter.
pub fn display_documentation(&mut self, param_name: &str) -> Result<()> {
if let Some(parameter) = self.sysctl.get_parameter(param_name) {
writeln!(
self.stdout,
"{}",
parameter
.description
.as_deref()
.unwrap_or("No documentation available")
)?;
}
Ok(())
}
/// Updates the parameter if it has the format `name=value`, displays it otherwise.
pub fn process_parameter(&mut self, mut param_name: String) -> Result<()> {
let new_value = if param_name.contains('=') {
@ -46,24 +61,12 @@ impl<'a> App<'a> {
} else {
None
};
match self
.sysctl
.parameters
.iter_mut()
.find(|param| param.name == *param_name)
{
Some(parameter) => {
if let Some(new_value) = new_value {
parameter.update(&new_value, &self.config.color, &mut self.stdout)?;
} else {
parameter.display(&self.config.color, &mut self.stdout)?;
}
if let Some(parameter) = self.sysctl.get_parameter(&param_name) {
if let Some(new_value) = new_value {
parameter.update(&new_value, &self.config.color, &mut self.stdout)?;
} else {
parameter.display(&self.config.color, &mut self.stdout)?;
}
None => eprintln!(
"{}: cannot stat /proc/{}: No such file or directory",
env!("CARGO_PKG_NAME"),
param_name.replace(".", "/")
),
}
Ok(())
}

View file

@ -17,10 +17,10 @@ For more details see {bin}(8)."#;
pub struct Args {
/// Path of the Linux kernel documentation.
pub kernel_docs: Option<PathBuf>,
/// Display all of the kernel parameters.
pub display_all: bool,
/// Disable colored output.
pub no_color: bool,
/// Parameter to explain.
pub param_to_explain: Option<String>,
/// Parameter names.
pub param_names: Vec<String>,
}
@ -35,6 +35,12 @@ impl Args {
opts.optflag("A", "", "alias of -a");
opts.optflag("X", "", "alias of -a");
opts.optflag("", "no-color", "disable colored output");
opts.optopt(
"",
"explain",
"provide a detailed explanation for a variable",
"<var>",
);
opts.optopt(
"d",
"docs",
@ -47,12 +53,13 @@ impl Args {
.map_err(|e| eprintln!("error: {}", e))
.ok()?;
let display_all = matches.opt_present("a")
let required_args_present = matches.opt_present("a")
|| matches.opt_present("A")
|| matches.opt_present("X")
|| !matches.free.is_empty();
|| !matches.free.is_empty()
|| matches.opt_str("explain").is_some();
if matches.opt_present("h") || !display_all {
if matches.opt_present("h") || !required_args_present {
let usage = opts.usage_with_format(|opts| {
HELP_MESSAGE
.replace("{bin}", env!("CARGO_PKG_NAME"))
@ -66,8 +73,8 @@ impl Args {
} else {
Some(Args {
kernel_docs: matches.opt_str("d").map(PathBuf::from),
display_all,
no_color: matches.opt_present("no-color"),
param_to_explain: matches.opt_str("explain"),
param_names: matches.free,
})
}

View file

@ -25,7 +25,9 @@ pub fn run(args: Args) -> Result<()> {
let mut app = App::new(&mut sysctl, &config);
if args.param_names.is_empty() {
if let Some(param) = args.param_to_explain {
app.display_documentation(&param)?;
} else if args.param_names.is_empty() {
app.display_parameters()?;
} else {
for param_name in args.param_names {