feat(args): add command-line argument parser

This commit is contained in:
Orhun Parmaksız 2021-10-17 21:03:17 +03:00
parent 8ae0acda21
commit 57e334933f
No known key found for this signature in database
GPG key ID: F83424824B3E4B90
5 changed files with 115 additions and 27 deletions

16
Cargo.lock generated
View file

@ -130,6 +130,15 @@ dependencies = [
"typenum",
]
[[package]]
name = "getopts"
version = "0.2.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "14dbbfd5c71d70241ecf9e6f13737f7b5ce823821063188d7e46c41d371eebd5"
dependencies = [
"unicode-width",
]
[[package]]
name = "hermit-abi"
version = "0.1.19"
@ -353,6 +362,7 @@ dependencies = [
name = "systeroid"
version = "0.1.0"
dependencies = [
"getopts",
"rayon",
"systeroid-core",
"systeroid-parser",
@ -407,6 +417,12 @@ version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "56dee185309b50d1f11bfedef0fe6d036842e3fb77413abef29f8f8d1c5d4c1c"
[[package]]
name = "unicode-width"
version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973"
[[package]]
name = "unicode-xid"
version = "0.2.2"

View file

@ -6,6 +6,7 @@ edition = "2021"
[dependencies]
rayon = "1.5.1"
getopts = "0.2.21"
[dependencies.systeroid-parser]
version = "0.1.0"

57
systeroid/src/args.rs Normal file
View file

@ -0,0 +1,57 @@
use getopts::Options;
use std::env;
use std::path::PathBuf;
/// Help message for the arguments.
const HELP_MESSAGE: &str = r#"
Usage:
{bin} [options]
Options:
{usage}
For more details see {bin}(8)."#;
/// Command-line arguments.
#[derive(Debug, Default)]
pub struct Args {
/// Path of the Linux kernel documentation.
pub kernel_docs: Option<PathBuf>,
}
impl Args {
/// Parses the command-line arguments.
pub fn parse() -> Option<Self> {
let mut opts = Options::new();
opts.optflag("h", "help", "display this help and exit");
opts.optflag("V", "version", "output version information and exit");
opts.optopt(
"d",
"kernel-docs",
"set the path of the linux kernel documentation",
"<path>",
);
let matches = opts
.parse(&env::args().collect::<Vec<String>>()[1..])
.map_err(|e| eprintln!("error: {}", e))
.ok()?;
if matches.opt_present("h") {
let usage = opts.usage_with_format(|opts| {
HELP_MESSAGE
.replace("{bin}", env!("CARGO_PKG_NAME"))
.replace("{usage}", &opts.collect::<Vec<String>>().join("\n"))
});
println!("{}", usage);
None
} else if matches.opt_present("V") {
println!("{} {}", env!("CARGO_PKG_NAME"), env!("CARGO_PKG_VERSION"));
None
} else {
Some(Args {
kernel_docs: matches.opt_str("d").map(PathBuf::from),
})
}
}
}

View file

@ -2,8 +2,12 @@
#![warn(missing_docs, clippy::unwrap_used)]
/// Command-line argument parser.
pub mod args;
use crate::args::Args;
use rayon::prelude::*;
use std::path::PathBuf;
use std::io::{Error as IoError, ErrorKind as IoErrorKind};
use std::sync::Mutex;
use systeroid_core::error::{Error, Result};
use systeroid_core::kernel::SysctlSection;
@ -11,29 +15,36 @@ use systeroid_core::reader;
use systeroid_parser::parser::RstParser;
/// Runs `systeroid`.
pub fn run() -> Result<()> {
let kernel_docs = PathBuf::from("/usr/share/doc/linux");
let sysctl_docs = kernel_docs.join("admin-guide").join("sysctl");
pub fn run(args: Args) -> Result<()> {
if let Some(kernel_docs) = args.kernel_docs {
let sysctl_docs = kernel_docs.join("admin-guide").join("sysctl");
if !sysctl_docs.exists() {
return Err(IoError::new(
IoErrorKind::Other,
format!("cannot find sysctl documentation: {:?}", sysctl_docs),
).into());
}
let kernel_parameters = Mutex::new(Vec::new());
SysctlSection::variants().par_iter().try_for_each(|s| {
let mut kernel_parameters = kernel_parameters
let kernel_parameters = Mutex::new(Vec::new());
SysctlSection::variants().par_iter().try_for_each(|s| {
let mut kernel_parameters = kernel_parameters
.lock()
.map_err(|e| Error::ThreadLockError(e.to_string()))?;
let mut parse = |section: SysctlSection| -> Result<()> {
let docs = reader::read_to_string(&sysctl_docs.join(section.as_file()))?;
Ok(kernel_parameters.extend(RstParser::parse_docs(&docs, section)?))
};
parse(*s)
})?;
for param in kernel_parameters
.lock()
.map_err(|e| Error::ThreadLockError(e.to_string()))?;
let mut parse = |section: SysctlSection| -> Result<()> {
let docs = reader::read_to_string(&sysctl_docs.join(section.as_file()))?;
Ok(kernel_parameters.extend(RstParser::parse_docs(&docs, section)?))
};
parse(*s)
})?;
for param in kernel_parameters
.lock()
.map_err(|e| Error::ThreadLockError(e.to_string()))?
.iter()
{
println!("## {}::{}\n", param.section, param.name);
println!("{}\n", param.description);
.map_err(|e| Error::ThreadLockError(e.to_string()))?
.iter()
{
println!("## {}::{}\n", param.section, param.name);
println!("{}\n", param.description);
}
}
Ok(())

View file

@ -1,11 +1,14 @@
use std::process;
use systeroid::args::Args;
fn main() {
match systeroid::run() {
Ok(_) => process::exit(0),
Err(e) => {
eprintln!("{}", e);
process::exit(1)
if let Some(args) = Args::parse() {
match systeroid::run(args) {
Ok(_) => process::exit(0),
Err(e) => {
eprintln!("{}", e);
process::exit(1)
}
}
}
}