mirror of
https://github.com/orhun/systeroid
synced 2024-10-04 14:39:06 +00:00
Merge pull request #36 from orhun/feat/add_configuration_file
Support configuration
This commit is contained in:
commit
3cec53b7f1
|
@ -4,6 +4,7 @@
|
|||
/target/
|
||||
/.cargo/
|
||||
/assets/
|
||||
/config/
|
||||
|
||||
# Files
|
||||
.editorconfig
|
||||
|
|
74
Cargo.lock
generated
74
Cargo.lock
generated
|
@ -8,6 +8,17 @@ version = "1.0.2"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
|
||||
|
||||
[[package]]
|
||||
name = "ahash"
|
||||
version = "0.7.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47"
|
||||
dependencies = [
|
||||
"getrandom",
|
||||
"once_cell",
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "aho-corasick"
|
||||
version = "0.7.18"
|
||||
|
@ -186,6 +197,15 @@ dependencies = [
|
|||
"once_cell",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dirs"
|
||||
version = "4.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ca3aa72a6f96ea37bbc5aa912f6788242832f75369bdfdadcb0e38423f100059"
|
||||
dependencies = [
|
||||
"dirs-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dirs-next"
|
||||
version = "2.0.0"
|
||||
|
@ -196,6 +216,17 @@ dependencies = [
|
|||
"dirs-sys-next",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dirs-sys"
|
||||
version = "0.3.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1b1d1d91c932ef41c0f2663aa8b0ca0342d444d842c06914aa0a7e352d0bada6"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"redox_users",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dirs-sys-next"
|
||||
version = "0.1.2"
|
||||
|
@ -216,6 +247,12 @@ dependencies = [
|
|||
"libloading",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dlv-list"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0688c2a7f92e427f44895cd63841bff7b29f8d7a1648b9e7e07a4a365b2e1257"
|
||||
|
||||
[[package]]
|
||||
name = "downcast-rs"
|
||||
version = "1.2.0"
|
||||
|
@ -288,6 +325,15 @@ dependencies = [
|
|||
"walkdir",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.12.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
|
||||
dependencies = [
|
||||
"ahash",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hermit-abi"
|
||||
version = "0.1.19"
|
||||
|
@ -491,6 +537,16 @@ version = "1.12.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7709cef83f0c1f58f666e746a08b21e0085f7440fa6a29cc194d68aac97a4225"
|
||||
|
||||
[[package]]
|
||||
name = "ordered-multimap"
|
||||
version = "0.4.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ccd746e37177e1711c20dd619a1620f34f5c8b569c53590a72dedd5344d8924a"
|
||||
dependencies = [
|
||||
"dlv-list",
|
||||
"hashbrown",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "parseit"
|
||||
version = "0.1.0"
|
||||
|
@ -606,6 +662,16 @@ version = "0.6.26"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "49b3de9ec5dc0a3417da371aab17d729997c15010e7fd24ff707773a33bddb64"
|
||||
|
||||
[[package]]
|
||||
name = "rust-ini"
|
||||
version = "0.18.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f6d5f2436026b4f6e79dc829837d467cc7e9a55ee40e750d716713540715a2df"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"ordered-multimap",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ryu"
|
||||
version = "1.0.10"
|
||||
|
@ -735,10 +801,12 @@ name = "systeroid-core"
|
|||
version = "0.1.1"
|
||||
dependencies = [
|
||||
"colored",
|
||||
"dirs",
|
||||
"dirs-next",
|
||||
"lazy_static",
|
||||
"parseit",
|
||||
"rayon",
|
||||
"rust-ini",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"sysctl",
|
||||
|
@ -831,6 +899,12 @@ version = "0.1.9"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973"
|
||||
|
||||
[[package]]
|
||||
name = "version_check"
|
||||
version = "0.9.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
|
||||
|
||||
[[package]]
|
||||
name = "walkdir"
|
||||
version = "2.3.2"
|
||||
|
|
25
README.md
25
README.md
|
@ -93,6 +93,7 @@ Although **systeroid** does not need the parameter section to be specified expli
|
|||
- [Changing the colors](#changing-the-colors)
|
||||
- [Viewing the parameter documentation](#viewing-the-parameter-documentation)
|
||||
- [Setting the refresh rate](#setting-the-refresh-rate)
|
||||
- [Configuration](#configuration)
|
||||
- [Resources](#resources)
|
||||
- [References](#references)
|
||||
- [Logo](#logo)
|
||||
|
@ -215,6 +216,7 @@ systeroid [options] [variable[=value] ...] --load[=<file>]
|
|||
-P, --no-pager do not pipe output into a pager
|
||||
-v, --verbose enable verbose logging
|
||||
--tui show terminal user interface
|
||||
-c, --config <path> set the path of the configuration file
|
||||
-h, --help display this help and exit (-d)
|
||||
-V, --version output version information and exit
|
||||
```
|
||||
|
@ -416,6 +418,7 @@ systeroid-tui [options]
|
|||
set the foreground color [default: white]
|
||||
-n, --no-docs do not show the kernel documentation
|
||||
--deprecated include deprecated variables while listing
|
||||
-c, --config <path> set the path of the configuration file
|
||||
-h, --help display this help and exit
|
||||
-V, --version output version information and exit
|
||||
```
|
||||
|
@ -548,6 +551,28 @@ It is possible to specify a value in milliseconds via `--tick-rate` argument for
|
|||
systeroid-tui --tick-rate 500
|
||||
```
|
||||
|
||||
## Configuration
|
||||
|
||||
**systeroid** can be configured with a configuration file that uses the [INI format](https://en.wikipedia.org/wiki/INI_file). It can be specified via `--config` or `SYSTEROID_CONFIG` environment variable. It can also be placed in one of the following global locations:
|
||||
|
||||
- `$HOME/.config/systeroid/systeroid.conf`
|
||||
- `$HOME/.systeroid/systeroid.conf`
|
||||
|
||||
```sh
|
||||
# set the config path via argument
|
||||
systeroid --config config/systeroid.conf
|
||||
|
||||
# set the config path via env
|
||||
SYSTEROID_CONFIG=config/systeroid.conf systeroid
|
||||
|
||||
# use a global path
|
||||
mkdir -p "$HOME/.config/systeroid"
|
||||
cp config/systeroid.conf "$HOME/.config/systeroid"
|
||||
systeroid
|
||||
```
|
||||
|
||||
See the example [systeroid.conf](./config/systeroid.conf) for the configuration options.
|
||||
|
||||
## Resources
|
||||
|
||||
### References
|
||||
|
|
|
@ -18,7 +18,6 @@ up_to_date_approvals = true
|
|||
delete_merged_branches = true
|
||||
update_base_for_deletes = true
|
||||
use_codeowners = true
|
||||
use_squash_merge = true
|
||||
commit_title = "Merge ${PR_REFS}"
|
||||
timeout_sec = 36000
|
||||
cut_body_after = "<details>"
|
||||
|
|
66
config/systeroid.conf
Normal file
66
config/systeroid.conf
Normal file
|
@ -0,0 +1,66 @@
|
|||
; systeroid ~ configuration file
|
||||
; https://github.com/orhun/systeroid
|
||||
;
|
||||
; Each line either contains a comment or a command line argument grouped under a section.
|
||||
; Run "systeroid --help" or "systeroid-tui --help" to get a list of all possible configuration options.
|
||||
|
||||
[general]
|
||||
; display the deprecated parameters such as base_reachable_time and retrans_time while listing
|
||||
; See https://bugzilla.redhat.com/show_bug.cgi?id=152435
|
||||
display_deprecated = false
|
||||
; path of the Linux kernel documentation
|
||||
; this is distro dependent, systeroid checks the following locations as default:
|
||||
; - /usr/share/doc/linux/
|
||||
; - /usr/share/doc/linux-doc/
|
||||
; - /usr/share/doc/linux-docs/
|
||||
; - /usr/share/doc/kernel-doc-*/Documentation/
|
||||
kernel_docs = "/usr/share/doc/linux"
|
||||
|
||||
[cli]
|
||||
; enable verbose logging
|
||||
verbose = false
|
||||
; ignore unknown variable errors
|
||||
ignore_errors = true
|
||||
; do not print variable after the value is set
|
||||
quiet = false
|
||||
; do not pipe output into a pager
|
||||
; note that the default pager is less(1) and you can change it by using `PAGER` environment variable
|
||||
no_pager = false
|
||||
; display type for the parameter, available options are:
|
||||
; - default: print the parameter name along with its value
|
||||
; - name: print only the name of the parameter
|
||||
; - value: print only the value of the parameter
|
||||
; - binary: print only the value of the parameter without new line
|
||||
display_type = "default"
|
||||
; output type for the list, available options are:
|
||||
; - default: print the output as is
|
||||
; - tree: print the output in a tree-like format
|
||||
; - json: print the output in JSON format
|
||||
output_type = "default"
|
||||
|
||||
[cli.colors]
|
||||
; available colors are defined in https://docs.rs/colored/latest/colored/enum.Color.html
|
||||
; default color for the symbols
|
||||
default_color = "bright black"
|
||||
; section colors
|
||||
section_abi = "red"
|
||||
section_fs = "green"
|
||||
section_kernel = "magenta"
|
||||
section_net = "blue"
|
||||
section_sunrpc = "yellow"
|
||||
section_user = "cyan"
|
||||
section_vm = "bright red"
|
||||
section_unknown = "white"
|
||||
|
||||
[tui]
|
||||
; tick rate of the terminal
|
||||
tick_rate = 250
|
||||
; disable showing the parameter documentation
|
||||
no_docs = true
|
||||
|
||||
[tui.colors]
|
||||
; available colors are defined in https://docs.rs/tui/latest/tui/style/enum.Color.html
|
||||
; terminal foreground color
|
||||
fg_color = "white"
|
||||
; terminal background color
|
||||
bg_color = "black"
|
|
@ -21,3 +21,5 @@ serde = { version = "1.0.140", features = ["derive"] }
|
|||
serde_json = "1.0.82"
|
||||
dirs-next = "2.0.0"
|
||||
parseit = { version = "0.1.0", features = ["gzip"] }
|
||||
rust-ini = "0.18.0"
|
||||
dirs = "4.0.0"
|
||||
|
|
|
@ -1,9 +1,26 @@
|
|||
use crate::sysctl::display::DisplayType;
|
||||
use crate::error::Result;
|
||||
use crate::sysctl::r#type::{DisplayType, OutputType};
|
||||
use crate::sysctl::section::Section;
|
||||
use colored::Color;
|
||||
use ini::Ini;
|
||||
use std::collections::HashMap;
|
||||
use std::path::PathBuf;
|
||||
|
||||
/* Macro for the concise initialization of HashMap */
|
||||
/// Default configuration file.
|
||||
pub const DEFAULT_CONFIG: &str = "systeroid.conf";
|
||||
|
||||
/// Environment variable for setting the path of the configuration file.
|
||||
pub const CONFIG_ENV: &str = "SYSTEROID_CONFIG";
|
||||
|
||||
lazy_static! {
|
||||
/// Default locations for the configuration file.
|
||||
pub static ref DEFAULT_CONFIG_PATHS: Vec<Option<PathBuf>> = vec![
|
||||
dirs::config_dir().map(|p| p.join("systeroid").join(DEFAULT_CONFIG)),
|
||||
dirs_next::home_dir().map(|p| p.join(".systeroid").join(DEFAULT_CONFIG)),
|
||||
];
|
||||
}
|
||||
|
||||
/// Macro for the concise initialization of HashMap
|
||||
macro_rules! map {
|
||||
($( $key: expr => $val: expr ),*) => {{
|
||||
let mut map = ::std::collections::HashMap::new();
|
||||
|
@ -12,47 +29,229 @@ macro_rules! map {
|
|||
}}
|
||||
}
|
||||
|
||||
/// Macro for parsing a boolean value from INI format
|
||||
macro_rules! parse_ini_flag {
|
||||
($self: ident, $config: ident, $section: ident, $name: ident) => {
|
||||
if let Some($name) = $section.get(stringify!($name)) {
|
||||
$self.$config.$name = $name == "true";
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/// Configuration.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Config {
|
||||
/// Whether if the deprecated variables should be included while listing.
|
||||
pub display_deprecated: bool,
|
||||
/// Path of the Linux kernel documentation.
|
||||
pub kernel_docs: Option<PathBuf>,
|
||||
/// CLI configuration.
|
||||
pub cli: CliConfig,
|
||||
/// TUI configuration.
|
||||
pub tui: TuiConfig,
|
||||
}
|
||||
|
||||
/// CLI configuration.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct CliConfig {
|
||||
/// Whether if the verbose logging is enabled.
|
||||
pub verbose: bool,
|
||||
/// Whether if the errors should be ignored.
|
||||
pub ignore_errors: bool,
|
||||
/// Whether if the deprecated variables should be included while listing.
|
||||
pub display_deprecated: bool,
|
||||
/// Whether if the quiet mode is enabled.
|
||||
pub quiet: bool,
|
||||
/// Whether if the pager is disabled.
|
||||
pub no_pager: bool,
|
||||
/// Sections and the corresponding colors.
|
||||
pub section_colors: HashMap<Section, Color>,
|
||||
/// Default color for the output
|
||||
pub default_color: Color,
|
||||
/// Display type of the kernel parameters.
|
||||
pub display_type: DisplayType,
|
||||
/// Output type of the application.
|
||||
pub output_type: OutputType,
|
||||
/// Color configuration.
|
||||
pub color: CliColorConfig,
|
||||
}
|
||||
|
||||
/// CLI color configuration.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct CliColorConfig {
|
||||
/// Default color for the output
|
||||
pub default_color: Color,
|
||||
/// Sections and the corresponding colors.
|
||||
pub section_colors: HashMap<Section, Color>,
|
||||
}
|
||||
|
||||
/// TUI configuration.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct TuiConfig {
|
||||
/// Refresh rate of the terminal.
|
||||
pub tick_rate: u64,
|
||||
/// Do not parse/show Linux kernel documentation.
|
||||
pub no_docs: bool,
|
||||
/// Color configuration.
|
||||
pub color: TuiColorConfig,
|
||||
}
|
||||
|
||||
/// TUI color configuration.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct TuiColorConfig {
|
||||
/// Foreground color.
|
||||
pub fg_color: String,
|
||||
/// Background color.
|
||||
pub bg_color: String,
|
||||
}
|
||||
|
||||
impl Config {
|
||||
/// Parses the configuration file and overrides values.
|
||||
pub fn parse(&mut self, path: Option<PathBuf>) -> Result<()> {
|
||||
let mut config_paths = DEFAULT_CONFIG_PATHS.clone();
|
||||
if path.is_some() {
|
||||
config_paths.insert(0, path);
|
||||
}
|
||||
let mut config_path = None;
|
||||
for path in config_paths.into_iter().flatten() {
|
||||
if path.exists() {
|
||||
config_path = Some(path);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if let Some(path) = config_path {
|
||||
let ini = Ini::load_from_file(path)?;
|
||||
if let Some(general_section) = ini.section(Some("general")) {
|
||||
if let Some(display_deprecated) = general_section.get("display_deprecated") {
|
||||
self.display_deprecated = display_deprecated == "true";
|
||||
}
|
||||
if let Some(kernel_docs) = general_section.get("kernel_docs") {
|
||||
self.kernel_docs = Some(PathBuf::from(kernel_docs));
|
||||
}
|
||||
}
|
||||
if let Some(section) = ini.section(Some("cli")) {
|
||||
parse_ini_flag!(self, cli, section, verbose);
|
||||
parse_ini_flag!(self, cli, section, ignore_errors);
|
||||
parse_ini_flag!(self, cli, section, quiet);
|
||||
parse_ini_flag!(self, cli, section, no_pager);
|
||||
if let Some(display_type) = section.get("display_type").map(DisplayType::from) {
|
||||
self.cli.display_type = display_type;
|
||||
}
|
||||
if let Some(output_type) = section.get("output_type").map(OutputType::from) {
|
||||
self.cli.output_type = output_type;
|
||||
}
|
||||
}
|
||||
if let Some(section) = ini.section(Some("cli.colors")) {
|
||||
if let Some(default_color) = section
|
||||
.get("default_color")
|
||||
.and_then(|v| Color::try_from(v).ok())
|
||||
{
|
||||
self.cli.color.default_color = default_color;
|
||||
}
|
||||
for (key, value) in section.iter() {
|
||||
if key.starts_with("section_") {
|
||||
if let (sysctl_section, Some(color)) = (
|
||||
Section::from(key.trim_start_matches("section_").to_string()),
|
||||
Color::try_from(value).ok(),
|
||||
) {
|
||||
self.cli.color.section_colors.insert(sysctl_section, color);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if let Some(section) = ini.section(Some("tui")) {
|
||||
if let Some(tick_rate) = section.get("tick_rate").and_then(|v| v.parse().ok()) {
|
||||
self.tui.tick_rate = tick_rate;
|
||||
}
|
||||
parse_ini_flag!(self, tui, section, no_docs);
|
||||
}
|
||||
if let Some(section) = ini.section(Some("tui.colors")) {
|
||||
if let Some(fg_color) = section.get("fg_color") {
|
||||
self.tui.color.fg_color = fg_color.to_string();
|
||||
}
|
||||
if let Some(bg_color) = section.get("bg_color") {
|
||||
self.tui.color.bg_color = bg_color.to_string();
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for Config {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
verbose: false,
|
||||
ignore_errors: false,
|
||||
display_deprecated: false,
|
||||
quiet: false,
|
||||
no_pager: false,
|
||||
section_colors: map! {
|
||||
Section::Abi => Color::Red,
|
||||
Section::Fs => Color::Green,
|
||||
Section::Kernel => Color::Magenta,
|
||||
Section::Net => Color::Blue,
|
||||
Section::Sunrpc => Color::Yellow,
|
||||
Section::User => Color::Cyan,
|
||||
Section::Vm => Color::BrightRed,
|
||||
Section::Unknown => Color::White
|
||||
kernel_docs: None,
|
||||
cli: CliConfig {
|
||||
verbose: false,
|
||||
ignore_errors: false,
|
||||
quiet: false,
|
||||
no_pager: false,
|
||||
display_type: DisplayType::Default,
|
||||
output_type: OutputType::Default,
|
||||
color: CliColorConfig {
|
||||
default_color: Color::BrightBlack,
|
||||
section_colors: map! {
|
||||
Section::Abi => Color::Red,
|
||||
Section::Fs => Color::Green,
|
||||
Section::Kernel => Color::Magenta,
|
||||
Section::Net => Color::Blue,
|
||||
Section::Sunrpc => Color::Yellow,
|
||||
Section::User => Color::Cyan,
|
||||
Section::Vm => Color::BrightRed,
|
||||
Section::Unknown => Color::White
|
||||
},
|
||||
},
|
||||
},
|
||||
tui: TuiConfig {
|
||||
tick_rate: 250,
|
||||
no_docs: false,
|
||||
color: TuiColorConfig {
|
||||
fg_color: String::from("white"),
|
||||
bg_color: String::from("black"),
|
||||
},
|
||||
},
|
||||
default_color: Color::BrightBlack,
|
||||
display_type: DisplayType::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
#[test]
|
||||
fn test_config() -> Result<()> {
|
||||
let mut config = Config {
|
||||
display_deprecated: true,
|
||||
..Default::default()
|
||||
};
|
||||
config.cli.display_type = DisplayType::Value;
|
||||
config.cli.color.default_color = Color::Blue;
|
||||
config.cli.color.section_colors = HashMap::new();
|
||||
config.tui.tick_rate = 3000;
|
||||
config.tui.color.fg_color = String::new();
|
||||
let path = PathBuf::from(env!("CARGO_MANIFEST_DIR"))
|
||||
.parent()
|
||||
.expect("parent directory not found")
|
||||
.join("config")
|
||||
.join(DEFAULT_CONFIG);
|
||||
config.parse(Some(path))?;
|
||||
assert_eq!(
|
||||
Config::default().display_deprecated,
|
||||
config.display_deprecated
|
||||
);
|
||||
assert_eq!(
|
||||
Some(PathBuf::from("/usr/share/doc/linux")),
|
||||
config.kernel_docs
|
||||
);
|
||||
assert_eq!(Config::default().cli.display_type, config.cli.display_type);
|
||||
assert_eq!(
|
||||
Config::default().cli.color.default_color,
|
||||
config.cli.color.default_color
|
||||
);
|
||||
assert_eq!(
|
||||
Config::default().cli.color.section_colors,
|
||||
config.cli.color.section_colors
|
||||
);
|
||||
assert_eq!(Config::default().tui.tick_rate, config.tui.tick_rate);
|
||||
assert_eq!(
|
||||
Config::default().tui.color.fg_color,
|
||||
config.tui.color.fg_color
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,6 +24,9 @@ pub enum Error {
|
|||
/// Error that may occur while handling sysctl operations.
|
||||
#[error("sysctl error: `{0}`")]
|
||||
SysctlError(#[from] sysctl::SysctlError),
|
||||
/// Error that may occur while parsing an INI document.
|
||||
#[error("INI parsing error: `{0}`")]
|
||||
IniError(#[from] ini::Error),
|
||||
}
|
||||
|
||||
/// Type alias for the standard [`Result`] type.
|
||||
|
|
|
@ -10,7 +10,7 @@ use parseit::globwalk;
|
|||
use rayon::prelude::*;
|
||||
use std::convert::TryFrom;
|
||||
use std::env;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::path::Path;
|
||||
use std::result::Result as StdResult;
|
||||
use sysctl::{CtlFlags, CtlIter, Sysctl as SysctlImpl};
|
||||
|
||||
|
@ -47,7 +47,7 @@ impl Sysctl {
|
|||
}
|
||||
}
|
||||
Err(e) => {
|
||||
if config.verbose {
|
||||
if config.cli.verbose {
|
||||
eprintln!("{} ({})", e, ctl.name()?);
|
||||
}
|
||||
}
|
||||
|
@ -73,7 +73,7 @@ impl Sysctl {
|
|||
|| param.get_absolute_name() == Some(&query.replace('/', "."))
|
||||
})
|
||||
.collect::<Vec<&Parameter>>();
|
||||
if parameters.is_empty() && !self.config.ignore_errors {
|
||||
if parameters.is_empty() && !self.config.cli.ignore_errors {
|
||||
eprintln!(
|
||||
"{}: cannot stat {}{}: No such file or directory",
|
||||
env!("CARGO_PKG_NAME").split('-').collect::<Vec<_>>()[0],
|
||||
|
@ -85,12 +85,8 @@ impl Sysctl {
|
|||
}
|
||||
|
||||
/// Updates the descriptions of the kernel parameters using the given cached data.
|
||||
pub fn update_docs_from_cache(
|
||||
&mut self,
|
||||
kernel_docs: Option<&PathBuf>,
|
||||
cache: &Cache,
|
||||
) -> Result<()> {
|
||||
let mut kernel_docs_path = if let Some(path) = kernel_docs {
|
||||
pub fn update_docs_from_cache(&mut self, cache: &Cache) -> Result<()> {
|
||||
let mut kernel_docs_path = if let Some(path) = &self.config.kernel_docs {
|
||||
vec![path.to_path_buf()]
|
||||
} else {
|
||||
Vec::new()
|
||||
|
@ -197,7 +193,7 @@ mod tests {
|
|||
);
|
||||
assert!(sysctl.get_parameters("---").is_empty());
|
||||
|
||||
sysctl.update_docs_from_cache(None, &Cache::init()?)?;
|
||||
sysctl.update_docs_from_cache(&Cache::init()?)?;
|
||||
|
||||
let parameter = sysctl
|
||||
.get_parameter("kernel.hostname")
|
||||
|
|
|
@ -1,18 +0,0 @@
|
|||
/// Possible ways of displaying the kernel parameters.
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
pub enum DisplayType {
|
||||
/// Print the kernel parameter name along with its value.
|
||||
Default,
|
||||
/// Print only the name of the parameter.
|
||||
Name,
|
||||
/// Print only the value of the parameter.
|
||||
Value,
|
||||
/// Print only the value of the parameter without new line.
|
||||
Binary,
|
||||
}
|
||||
|
||||
impl Default for DisplayType {
|
||||
fn default() -> Self {
|
||||
Self::Default
|
||||
}
|
||||
}
|
|
@ -4,8 +4,8 @@ pub mod controller;
|
|||
/// Sysctl section.
|
||||
pub mod section;
|
||||
|
||||
/// Sysctl display options.
|
||||
pub mod display;
|
||||
/// Sysctl display/output options.
|
||||
pub mod r#type;
|
||||
|
||||
/// Kernel parameter.
|
||||
pub mod parameter;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use crate::config::Config;
|
||||
use crate::error::Result;
|
||||
use crate::sysctl::display::DisplayType;
|
||||
use crate::sysctl::r#type::DisplayType;
|
||||
use crate::sysctl::section::Section;
|
||||
use colored::*;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
@ -53,9 +53,11 @@ impl Parameter {
|
|||
/// Returns the parameter name with corresponding section colors.
|
||||
pub fn get_colored_name(&self, config: &Config) -> String {
|
||||
let section_color = *(config
|
||||
.cli
|
||||
.color
|
||||
.section_colors
|
||||
.get(&self.section)
|
||||
.unwrap_or(&config.default_color));
|
||||
.unwrap_or(&config.cli.color.default_color));
|
||||
let fields = self.name.split('.').collect::<Vec<&str>>();
|
||||
fields
|
||||
.iter()
|
||||
|
@ -66,7 +68,7 @@ impl Parameter {
|
|||
result,
|
||||
"{}{}",
|
||||
v.color(section_color),
|
||||
".".color(config.default_color)
|
||||
".".color(config.cli.color.default_color)
|
||||
);
|
||||
} else {
|
||||
result += v;
|
||||
|
@ -75,14 +77,16 @@ impl Parameter {
|
|||
})
|
||||
}
|
||||
|
||||
/// Returns the components of the parameter to contruct a [`Tree`].
|
||||
/// Returns the components of the parameter to construct a [`Tree`].
|
||||
///
|
||||
/// [`Tree`]: crate::tree::Tree
|
||||
pub fn get_tree_components(&self, config: &Config) -> Vec<String> {
|
||||
let section_color = *(config
|
||||
.cli
|
||||
.color
|
||||
.section_colors
|
||||
.get(&self.section)
|
||||
.unwrap_or(&config.default_color));
|
||||
.unwrap_or(&config.cli.color.default_color));
|
||||
let mut components = self
|
||||
.name
|
||||
.split('.')
|
||||
|
@ -95,11 +99,11 @@ impl Parameter {
|
|||
.for_each(|(i, component)| {
|
||||
if i != total_components - 1 {
|
||||
*component = component.color(section_color).to_string();
|
||||
} else if config.display_type != DisplayType::Name {
|
||||
} else if config.cli.display_type != DisplayType::Name {
|
||||
*component = format!(
|
||||
"{} {} {}",
|
||||
component,
|
||||
"=".color(config.default_color),
|
||||
"=".color(config.cli.color.default_color),
|
||||
self.value.replace('\n', " ").bold()
|
||||
);
|
||||
}
|
||||
|
@ -109,7 +113,7 @@ impl Parameter {
|
|||
|
||||
/// Prints the kernel parameter to given output.
|
||||
pub fn display_value<Output: Write>(&self, config: &Config, output: &mut Output) -> Result<()> {
|
||||
match config.display_type {
|
||||
match config.cli.display_type {
|
||||
DisplayType::Name => {
|
||||
writeln!(output, "{}", self.get_colored_name(config))?;
|
||||
}
|
||||
|
@ -125,7 +129,7 @@ impl Parameter {
|
|||
output,
|
||||
"{} {} {}",
|
||||
self.get_colored_name(config),
|
||||
"=".color(config.default_color),
|
||||
"=".color(config.cli.color.default_color),
|
||||
value.bold(),
|
||||
)?;
|
||||
}
|
||||
|
@ -187,7 +191,7 @@ impl Parameter {
|
|||
let ctl = Ctl::new(&self.name)?;
|
||||
let new_value = ctl.set_value_string(new_value)?;
|
||||
self.value = new_value;
|
||||
if !config.quiet {
|
||||
if !config.cli.quiet {
|
||||
self.display_value(config, output)?;
|
||||
}
|
||||
Ok(())
|
||||
|
@ -211,10 +215,12 @@ mod tests {
|
|||
assert_eq!(Some("test_param"), parameter.get_absolute_name());
|
||||
|
||||
let mut config = Config {
|
||||
default_color: Color::White,
|
||||
..Default::default()
|
||||
};
|
||||
config.cli.color.default_color = Color::White;
|
||||
*(config
|
||||
.cli
|
||||
.color
|
||||
.section_colors
|
||||
.get_mut(&Section::Kernel)
|
||||
.expect("failed to get color")) = Color::Yellow;
|
||||
|
@ -237,7 +243,7 @@ mod tests {
|
|||
);
|
||||
|
||||
output.clear();
|
||||
config.display_type = DisplayType::Name;
|
||||
config.cli.display_type = DisplayType::Name;
|
||||
parameter.display_value(&config, &mut output)?;
|
||||
assert_eq!(
|
||||
"kernel.fictional.test_param\n",
|
||||
|
@ -245,12 +251,12 @@ mod tests {
|
|||
);
|
||||
|
||||
output.clear();
|
||||
config.display_type = DisplayType::Value;
|
||||
config.cli.display_type = DisplayType::Value;
|
||||
parameter.display_value(&config, &mut output)?;
|
||||
assert_eq!("1\n", String::from_utf8_lossy(&output));
|
||||
|
||||
output.clear();
|
||||
config.display_type = DisplayType::Binary;
|
||||
config.cli.display_type = DisplayType::Binary;
|
||||
parameter.display_value(&config, &mut output)?;
|
||||
assert_eq!("1", String::from_utf8_lossy(&output));
|
||||
|
||||
|
|
73
systeroid-core/src/sysctl/type.rs
Normal file
73
systeroid-core/src/sysctl/type.rs
Normal file
|
@ -0,0 +1,73 @@
|
|||
/// Macro for generating enum type with a Default variant and common implementations.
|
||||
macro_rules! gen_type_property {
|
||||
($name: ident,
|
||||
$($variant: ident,)+
|
||||
) => {
|
||||
/// Enum containing variants.
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||
pub enum $name {
|
||||
/// Default variant.
|
||||
Default,
|
||||
$(
|
||||
/// Variant.
|
||||
$variant
|
||||
),+
|
||||
}
|
||||
|
||||
impl<'a> From<&'a str> for $name {
|
||||
fn from(value: &'a str) -> Self {
|
||||
for section in Self::variants() {
|
||||
if value.to_lowercase() == section.to_string() {
|
||||
return *section;
|
||||
}
|
||||
}
|
||||
Self::Default
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for $name {
|
||||
fn default() -> Self {
|
||||
Self::Default
|
||||
}
|
||||
}
|
||||
|
||||
impl ::std::fmt::Display for $name {
|
||||
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
|
||||
write!(f, "{}", format!("{:?}", self).to_lowercase())
|
||||
}
|
||||
}
|
||||
|
||||
impl $name {
|
||||
/// Returns the variants.
|
||||
pub fn variants() -> &'static [Self] {
|
||||
&[Self::Default, $(Self::$variant),+]
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
gen_type_property!(DisplayType, Name, Value, Binary,);
|
||||
gen_type_property!(OutputType, Tree, Json,);
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
#[test]
|
||||
fn test_gen_type() {
|
||||
gen_type_property!(TestType, One, Two, Three,);
|
||||
assert_eq!(TestType::Two, TestType::from("two"));
|
||||
assert_eq!(TestType::Two, TestType::from("TwO"));
|
||||
assert_eq!(TestType::Default, TestType::from("tw0"));
|
||||
assert_eq!(TestType::Default, TestType::default());
|
||||
assert_eq!("three", &TestType::Three.to_string());
|
||||
assert_eq!("one", &TestType::One.to_string());
|
||||
assert_eq!(
|
||||
&[
|
||||
TestType::Default,
|
||||
TestType::One,
|
||||
TestType::Two,
|
||||
TestType::Three
|
||||
],
|
||||
TestType::variants()
|
||||
);
|
||||
}
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
use crate::style::Colors;
|
||||
use getopts::Options;
|
||||
use std::env;
|
||||
use std::path::PathBuf;
|
||||
use systeroid_core::config::CONFIG_ENV;
|
||||
use systeroid_core::sysctl::section::Section;
|
||||
use systeroid_core::sysctl::KERNEL_DOCS_ENV;
|
||||
|
||||
|
@ -18,6 +18,8 @@ For more details see {bin}(8)."#;
|
|||
/// Command-line arguments.
|
||||
#[derive(Debug, Default)]
|
||||
pub struct Args {
|
||||
/// Location of the configuration file.
|
||||
pub config: Option<PathBuf>,
|
||||
/// Refresh rate of the terminal.
|
||||
pub tick_rate: u64,
|
||||
/// Path of the Linux kernel documentation.
|
||||
|
@ -26,8 +28,10 @@ pub struct Args {
|
|||
pub section: Option<Section>,
|
||||
/// Query to search on startup.
|
||||
pub search_query: Option<String>,
|
||||
/// Background/foreground colors.
|
||||
pub colors: Colors,
|
||||
/// Foreground color.
|
||||
pub fg_color: String,
|
||||
/// Background color.
|
||||
pub bg_color: String,
|
||||
/// Do not parse/show Linux kernel documentation.
|
||||
pub no_docs: bool,
|
||||
/// Whether if the deprecated variables should be included while listing.
|
||||
|
@ -70,6 +74,12 @@ impl Args {
|
|||
"deprecated",
|
||||
"include deprecated variables while listing",
|
||||
);
|
||||
opts.optopt(
|
||||
"c",
|
||||
"config",
|
||||
"set the path of the configuration file",
|
||||
"<path>",
|
||||
);
|
||||
opts.optflag("h", "help", "display this help and exit");
|
||||
opts.optflag("V", "version", "output version information and exit");
|
||||
opts
|
||||
|
@ -106,14 +116,18 @@ impl Args {
|
|||
.map(PathBuf::from),
|
||||
section: matches.opt_str("s").map(Section::from),
|
||||
search_query: matches.opt_str("q"),
|
||||
colors: Colors::new(
|
||||
matches.opt_str("bg-color").as_deref().unwrap_or("black"),
|
||||
matches.opt_str("fg-color").as_deref().unwrap_or("white"),
|
||||
)
|
||||
.map_err(|e| eprintln!("error: `{}`", e))
|
||||
.ok()?,
|
||||
fg_color: matches
|
||||
.opt_str("fg-color")
|
||||
.unwrap_or_else(|| String::from("white")),
|
||||
bg_color: matches
|
||||
.opt_str("bg-color")
|
||||
.unwrap_or_else(|| String::from("black")),
|
||||
no_docs: matches.opt_present("n"),
|
||||
display_deprecated: matches.opt_present("deprecated"),
|
||||
config: matches
|
||||
.opt_str("c")
|
||||
.or_else(|| env::var(CONFIG_ENV).ok())
|
||||
.map(PathBuf::from),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,6 +26,7 @@ use crate::args::Args;
|
|||
use crate::command::Command;
|
||||
use crate::error::Result;
|
||||
use crate::event::{Event, EventHandler};
|
||||
use crate::style::Colors;
|
||||
use systeroid_core::cache::Cache;
|
||||
use systeroid_core::config::Config;
|
||||
use systeroid_core::sysctl::controller::Sysctl;
|
||||
|
@ -34,18 +35,25 @@ use tui::terminal::Terminal;
|
|||
|
||||
/// Runs `systeroid-tui`.
|
||||
pub fn run<B: Backend>(args: Args, backend: B) -> Result<()> {
|
||||
let config = Config {
|
||||
let mut config = Config {
|
||||
display_deprecated: args.display_deprecated,
|
||||
kernel_docs: args.kernel_docs,
|
||||
..Default::default()
|
||||
};
|
||||
config.tui.tick_rate = args.tick_rate;
|
||||
config.tui.no_docs = args.no_docs;
|
||||
config.tui.color.fg_color = args.fg_color;
|
||||
config.tui.color.bg_color = args.bg_color;
|
||||
config.parse(args.config)?;
|
||||
let colors = Colors::new(&config.tui.color.bg_color, &config.tui.color.fg_color)?;
|
||||
let mut sysctl = Sysctl::init(config)?;
|
||||
if !args.no_docs {
|
||||
sysctl.update_docs_from_cache(args.kernel_docs.as_ref(), &Cache::init()?)?;
|
||||
if !sysctl.config.tui.no_docs {
|
||||
sysctl.update_docs_from_cache(&Cache::init()?)?;
|
||||
}
|
||||
let mut terminal = Terminal::new(backend)?;
|
||||
terminal.hide_cursor()?;
|
||||
terminal.clear()?;
|
||||
let event_handler = EventHandler::new(args.tick_rate);
|
||||
let event_handler = EventHandler::new(sysctl.config.tui.tick_rate);
|
||||
let mut app = App::new(&mut sysctl);
|
||||
if let Some(section) = args.section {
|
||||
app.section_list.state.select(Some(
|
||||
|
@ -63,7 +71,7 @@ pub fn run<B: Backend>(args: Args, backend: B) -> Result<()> {
|
|||
app.input = None;
|
||||
}
|
||||
while app.running {
|
||||
terminal.draw(|frame| ui::render(frame, &mut app, &args.colors))?;
|
||||
terminal.draw(|frame| ui::render(frame, &mut app, &colors))?;
|
||||
match event_handler.next()? {
|
||||
Event::KeyPress(key) => {
|
||||
let command = Command::parse(key, app.is_input_mode());
|
||||
|
@ -91,6 +99,8 @@ mod tests {
|
|||
fn test_systeroid_tui() -> Result<()> {
|
||||
let args = Args {
|
||||
tick_rate: 1000,
|
||||
fg_color: String::from("white"),
|
||||
bg_color: String::from("black"),
|
||||
..Args::default()
|
||||
};
|
||||
let backend = TestBackend::new(40, 10);
|
||||
|
|
|
@ -76,13 +76,13 @@ impl FromStr for Color {
|
|||
"magenta" => TuiColor::Magenta,
|
||||
"cyan" => TuiColor::Cyan,
|
||||
"gray" => TuiColor::Gray,
|
||||
"darkgray" => TuiColor::DarkGray,
|
||||
"lightred" => TuiColor::LightRed,
|
||||
"lightgreen" => TuiColor::LightGreen,
|
||||
"lightyellow" => TuiColor::LightYellow,
|
||||
"lightblue" => TuiColor::LightBlue,
|
||||
"lightmagenta" => TuiColor::LightMagenta,
|
||||
"lightcyan" => TuiColor::LightCyan,
|
||||
"darkgray" | "dark gray" => TuiColor::DarkGray,
|
||||
"lightred" | "light red" => TuiColor::LightRed,
|
||||
"lightgreen" | "light green" => TuiColor::LightGreen,
|
||||
"lightyellow" | "light yellow" => TuiColor::LightYellow,
|
||||
"lightblue" | "light blue" => TuiColor::LightBlue,
|
||||
"lightmagenta" | "light magenta" => TuiColor::LightMagenta,
|
||||
"lightcyan" | "light cyan" => TuiColor::LightCyan,
|
||||
"white" => TuiColor::White,
|
||||
_ => {
|
||||
let rgb = Rgb::from_hex_str(&format!("#{}", s))?;
|
||||
|
@ -102,6 +102,8 @@ mod tests {
|
|||
assert_eq!(TuiColor::Gray, Color::from_str("gray")?.get());
|
||||
assert_eq!(TuiColor::Black, Color::from_str("black")?.get());
|
||||
assert_eq!(TuiColor::Green, Color::from_str("green")?.get());
|
||||
assert_eq!(TuiColor::LightRed, Color::from_str("light red")?.get());
|
||||
assert_eq!(TuiColor::LightBlue, Color::from_str("lightblue")?.get());
|
||||
assert_eq!(
|
||||
TuiColor::Rgb(152, 157, 69),
|
||||
Color::from_str("989D45")?.get()
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
use crate::output::OutputType;
|
||||
use std::env;
|
||||
use std::io::{self, BufRead, Write};
|
||||
use std::path::PathBuf;
|
||||
|
@ -9,6 +8,7 @@ use systeroid_core::parseit::reader;
|
|||
use systeroid_core::parseit::regex::Regex;
|
||||
use systeroid_core::sysctl::controller::Sysctl;
|
||||
use systeroid_core::sysctl::parameter::Parameter;
|
||||
use systeroid_core::sysctl::r#type::OutputType;
|
||||
use systeroid_core::sysctl::{DEPRECATED_PARAMS, SYSTEM_PRELOAD};
|
||||
use systeroid_core::tree::{Tree, TreeNode};
|
||||
|
||||
|
@ -19,18 +19,12 @@ pub struct App<'a, Output: Write> {
|
|||
sysctl: &'a mut Sysctl,
|
||||
/// Standard output.
|
||||
output: &'a mut Output,
|
||||
/// Output type.
|
||||
output_type: OutputType,
|
||||
}
|
||||
|
||||
impl<'a, Output: Write> App<'a, Output> {
|
||||
/// Constructs a new instance.
|
||||
pub fn new(sysctl: &'a mut Sysctl, output: &'a mut Output, output_type: OutputType) -> Self {
|
||||
Self {
|
||||
sysctl,
|
||||
output,
|
||||
output_type,
|
||||
}
|
||||
pub fn new(sysctl: &'a mut Sysctl, output: &'a mut Output) -> Self {
|
||||
Self { sysctl, output }
|
||||
}
|
||||
|
||||
/// Prints the given parameters to stdout.
|
||||
|
@ -38,7 +32,7 @@ impl<'a, Output: Write> App<'a, Output> {
|
|||
where
|
||||
I: Iterator<Item = &'b Parameter>,
|
||||
{
|
||||
match self.output_type {
|
||||
match self.sysctl.config.cli.output_type {
|
||||
OutputType::Default => {
|
||||
parameters.try_for_each(|parameter| {
|
||||
parameter.display_value(&self.sysctl.config, self.output)
|
||||
|
@ -54,7 +48,8 @@ impl<'a, Output: Write> App<'a, Output> {
|
|||
.map(|v| v.as_ref()),
|
||||
);
|
||||
});
|
||||
Tree::new(root_node.childs).print(self.output, self.sysctl.config.default_color)?;
|
||||
Tree::new(root_node.childs)
|
||||
.print(self.output, self.sysctl.config.cli.color.default_color)?;
|
||||
}
|
||||
OutputType::Json => {
|
||||
Parameter::display_bulk_json(parameters.collect(), self.output)?;
|
||||
|
@ -81,7 +76,7 @@ impl<'a, Output: Write> App<'a, Output> {
|
|||
|
||||
/// Displays the documentation of a parameter.
|
||||
pub fn display_documentation(&mut self, param_name: &str) -> Result<()> {
|
||||
let no_pager = self.sysctl.config.no_pager;
|
||||
let no_pager = self.sysctl.config.cli.no_pager;
|
||||
for parameter in self.sysctl.get_parameters(param_name) {
|
||||
let mut fallback_to_default = false;
|
||||
if no_pager {
|
||||
|
@ -231,13 +226,12 @@ mod tests {
|
|||
#[test]
|
||||
fn test_app() -> Result<()> {
|
||||
let mut output = Vec::new();
|
||||
let mut sysctl = Sysctl::init(Config {
|
||||
no_pager: true,
|
||||
..Config::default()
|
||||
})?;
|
||||
sysctl.update_docs_from_cache(None, &Cache::init()?)?;
|
||||
let mut config = Config::default();
|
||||
config.cli.no_pager = true;
|
||||
let mut sysctl = Sysctl::init(config)?;
|
||||
sysctl.update_docs_from_cache(&Cache::init()?)?;
|
||||
|
||||
let mut app = App::new(&mut sysctl, &mut output, OutputType::Default);
|
||||
let mut app = App::new(&mut sysctl, &mut output);
|
||||
|
||||
app.display_parameters(Regex::new("kernel|vm").ok(), false)?;
|
||||
let result = String::from_utf8_lossy(app.output);
|
||||
|
@ -245,7 +239,7 @@ mod tests {
|
|||
assert!(result.contains("kernel.version ="));
|
||||
app.output.clear();
|
||||
|
||||
app.output_type = OutputType::Tree;
|
||||
app.sysctl.config.cli.output_type = OutputType::Tree;
|
||||
app.display_parameters(None, false)?;
|
||||
assert!(String::from_utf8_lossy(app.output).contains("─ osrelease ="));
|
||||
app.output.clear();
|
||||
|
@ -255,7 +249,7 @@ mod tests {
|
|||
app.output.clear();
|
||||
|
||||
let param_name = String::from("kernel.version");
|
||||
app.output_type = OutputType::Default;
|
||||
app.sysctl.config.cli.output_type = OutputType::Default;
|
||||
app.process_parameter(param_name.clone(), true, false)?;
|
||||
let result = String::from_utf8_lossy(app.output);
|
||||
assert_eq!(1, result.lines().count());
|
||||
|
@ -263,7 +257,7 @@ mod tests {
|
|||
app.output.clear();
|
||||
|
||||
let param_name = String::from("kernel.version");
|
||||
app.output_type = OutputType::Json;
|
||||
app.sysctl.config.cli.output_type = OutputType::Json;
|
||||
app.process_parameter(param_name.clone(), true, false)?;
|
||||
let result = String::from_utf8_lossy(app.output);
|
||||
assert!(result.contains("\"section\":\"kernel\""));
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
use crate::output::OutputType;
|
||||
use getopts::Options;
|
||||
use std::env;
|
||||
use std::path::PathBuf;
|
||||
use systeroid_core::config::CONFIG_ENV;
|
||||
use systeroid_core::parseit::regex::Regex;
|
||||
use systeroid_core::sysctl::display::DisplayType;
|
||||
use systeroid_core::sysctl::r#type::DisplayType;
|
||||
use systeroid_core::sysctl::r#type::OutputType;
|
||||
use systeroid_core::sysctl::{DEFAULT_PRELOAD, KERNEL_DOCS_ENV};
|
||||
|
||||
/// Help message for the arguments.
|
||||
|
@ -19,6 +20,8 @@ For more details see {bin}(8)."#;
|
|||
/// Command-line arguments.
|
||||
#[derive(Debug, Default)]
|
||||
pub struct Args {
|
||||
/// Location of the configuration file.
|
||||
pub config: Option<PathBuf>,
|
||||
/// Whether if the verbose logging is enabled.
|
||||
pub verbose: bool,
|
||||
/// Whether if the quiet mode is enabled.
|
||||
|
@ -97,6 +100,12 @@ impl Args {
|
|||
opts.optflag("P", "no-pager", "do not pipe output into a pager");
|
||||
opts.optflag("v", "verbose", "enable verbose logging");
|
||||
opts.optflag("", "tui", "show terminal user interface");
|
||||
opts.optopt(
|
||||
"c",
|
||||
"config",
|
||||
"set the path of the configuration file",
|
||||
"<path>",
|
||||
);
|
||||
opts.optflag("h", "help", "display this help and exit (-d)");
|
||||
opts.optflag("V", "version", "output version information and exit");
|
||||
opts
|
||||
|
@ -195,6 +204,10 @@ impl Args {
|
|||
explain: matches.opt_present("E"),
|
||||
output_type,
|
||||
show_tui: matches.opt_present("tui"),
|
||||
config: matches
|
||||
.opt_str("c")
|
||||
.or_else(|| env::var(CONFIG_ENV).ok())
|
||||
.map(PathBuf::from),
|
||||
values: matches.free,
|
||||
})
|
||||
}
|
||||
|
|
|
@ -6,8 +6,6 @@
|
|||
pub mod app;
|
||||
/// Command-line argument parser.
|
||||
pub mod args;
|
||||
/// Application output types.
|
||||
pub mod output;
|
||||
|
||||
use crate::app::App;
|
||||
use crate::args::Args;
|
||||
|
@ -20,20 +18,23 @@ use systeroid_core::sysctl::controller::Sysctl;
|
|||
|
||||
/// Runs `systeroid`.
|
||||
pub fn run<Output: Write>(args: Args, output: &mut Output) -> Result<()> {
|
||||
let config = Config {
|
||||
verbose: args.verbose,
|
||||
ignore_errors: args.ignore_errors,
|
||||
let mut config = Config {
|
||||
display_deprecated: args.display_deprecated,
|
||||
quiet: args.quiet,
|
||||
no_pager: args.no_pager,
|
||||
display_type: args.display_type,
|
||||
kernel_docs: args.kernel_docs,
|
||||
..Default::default()
|
||||
};
|
||||
config.cli.verbose = args.verbose;
|
||||
config.cli.ignore_errors = args.ignore_errors;
|
||||
config.cli.quiet = args.quiet;
|
||||
config.cli.no_pager = args.no_pager;
|
||||
config.cli.display_type = args.display_type;
|
||||
config.cli.output_type = args.output_type;
|
||||
config.parse(args.config)?;
|
||||
let mut sysctl = Sysctl::init(config)?;
|
||||
if args.explain {
|
||||
sysctl.update_docs_from_cache(args.kernel_docs.as_ref(), &Cache::init()?)?;
|
||||
sysctl.update_docs_from_cache(&Cache::init()?)?;
|
||||
}
|
||||
let mut app = App::new(&mut sysctl, output, args.output_type);
|
||||
let mut app = App::new(&mut sysctl, output);
|
||||
|
||||
if args.preload_system_files {
|
||||
app.preload_from_system()?;
|
||||
|
|
|
@ -8,6 +8,9 @@ fn main() {
|
|||
if args.show_tui {
|
||||
let bin = format!("{}-tui", env!("CARGO_PKG_NAME"));
|
||||
let mut command = Command::new(&bin);
|
||||
if let Some(config) = args.config {
|
||||
command.arg("--config").arg(config);
|
||||
}
|
||||
if let Some(kernel_docs) = args.kernel_docs {
|
||||
command.arg("--docs").arg(kernel_docs);
|
||||
}
|
||||
|
|
|
@ -1,18 +0,0 @@
|
|||
/// Possible output types for the [`App`].
|
||||
///
|
||||
/// [`App`]: crate::app::App
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
pub enum OutputType {
|
||||
/// Print the output as is.
|
||||
Default,
|
||||
/// Print the output in a tree-like format.
|
||||
Tree,
|
||||
/// Print the output in JSON format.
|
||||
Json,
|
||||
}
|
||||
|
||||
impl Default for OutputType {
|
||||
fn default() -> Self {
|
||||
Self::Default
|
||||
}
|
||||
}
|
|
@ -1,7 +1,6 @@
|
|||
use {
|
||||
systeroid::args::Args, systeroid_core::error::Result,
|
||||
systeroid_core::sysctl::display::DisplayType,
|
||||
};
|
||||
use systeroid::args::Args;
|
||||
use systeroid_core::error::Result;
|
||||
use systeroid_core::sysctl::r#type::DisplayType;
|
||||
|
||||
#[cfg_attr(not(feature = "live-tests"), ignore)]
|
||||
#[test]
|
||||
|
|
Loading…
Reference in a new issue