mirror of
https://github.com/orhun/systeroid
synced 2024-07-21 18:35:03 +00:00
feat(app): add caching mechanism for kernel parameters
This commit is contained in:
parent
81e3fc8fa7
commit
6bbf04a3c1
103
Cargo.lock
generated
103
Cargo.lock
generated
|
@ -110,6 +110,27 @@ dependencies = [
|
|||
"lazy_static",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dirs-next"
|
||||
version = "2.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b98cf8ebf19c3d1b223e151f99a4f9f0690dca41414773390fc824184ac833e1"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"dirs-sys-next",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dirs-sys-next"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"redox_users",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "either"
|
||||
version = "1.6.1"
|
||||
|
@ -131,6 +152,17 @@ dependencies = [
|
|||
"unicode-width",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "getrandom"
|
||||
version = "0.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7fcd999463524c52659517fe2cea98493cfe485d10565e7b0fb07dbba7ad2753"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"wasi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "globset"
|
||||
version = "0.4.8"
|
||||
|
@ -182,6 +214,12 @@ dependencies = [
|
|||
"winapi-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "0.4.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4"
|
||||
|
||||
[[package]]
|
||||
name = "lazy_static"
|
||||
version = "1.4.0"
|
||||
|
@ -277,6 +315,25 @@ dependencies = [
|
|||
"num_cpus",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "redox_syscall"
|
||||
version = "0.2.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8383f39639269cde97d255a32bdb68c047337295414940c68bdd30c2e13203ff"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "redox_users"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "528532f3d801c87aec9def2add9ca802fe569e44a544afe633765267840abe64"
|
||||
dependencies = [
|
||||
"getrandom",
|
||||
"redox_syscall",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex"
|
||||
version = "1.5.4"
|
||||
|
@ -294,6 +351,12 @@ version = "0.6.25"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b"
|
||||
|
||||
[[package]]
|
||||
name = "ryu"
|
||||
version = "1.0.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3c9613b5a66ab9ba26415184cfc41156594925a9cf3a2057e57f31ff145f6568"
|
||||
|
||||
[[package]]
|
||||
name = "same-file"
|
||||
version = "1.0.6"
|
||||
|
@ -309,6 +372,37 @@ version = "1.1.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.130"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f12d06de37cf59146fbdecab66aa99f9fe4f78722e3607577a5375d66bd0c913"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.130"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d7bc1a1ab1961464eae040d96713baa5a724a8152c1222492465b54322ec508b"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.72"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d0ffa0837f2dfa6fb90868c2b5468cad482e175f7dad97e7421951e663f2b527"
|
||||
dependencies = [
|
||||
"itoa",
|
||||
"ryu",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "1.0.78"
|
||||
|
@ -347,8 +441,11 @@ name = "systeroid-core"
|
|||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"colored",
|
||||
"dirs-next",
|
||||
"lazy_static",
|
||||
"rayon",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"sysctl",
|
||||
"systeroid-parser",
|
||||
"thiserror",
|
||||
|
@ -415,6 +512,12 @@ dependencies = [
|
|||
"winapi-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasi"
|
||||
version = "0.10.2+wasi-snapshot-preview1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6"
|
||||
|
||||
[[package]]
|
||||
name = "winapi"
|
||||
version = "0.3.9"
|
||||
|
|
|
@ -10,6 +10,9 @@ thiserror = "1.0.29"
|
|||
lazy_static = "1.4.0"
|
||||
rayon = "1.5.1"
|
||||
colored = "2.0.0"
|
||||
serde = { version = "1.0.130", features = ["derive"] }
|
||||
serde_json = "1.0.69"
|
||||
dirs-next = "2.0.0"
|
||||
|
||||
[dependencies.systeroid-parser]
|
||||
version = "0.1.0"
|
||||
|
|
55
systeroid-core/src/cache.rs
Normal file
55
systeroid-core/src/cache.rs
Normal file
|
@ -0,0 +1,55 @@
|
|||
use crate::error::{Error, Result};
|
||||
use serde::de::DeserializeOwned;
|
||||
use serde::Serialize;
|
||||
use std::fs::{self, File};
|
||||
use std::io::Write;
|
||||
use std::path::PathBuf;
|
||||
use systeroid_parser::reader;
|
||||
|
||||
/// Cache manager for handling the R/W operations of labeled data.
|
||||
#[derive(Debug)]
|
||||
pub struct Cache {
|
||||
/// Cache directory.
|
||||
cache_dir: PathBuf,
|
||||
}
|
||||
|
||||
impl Cache {
|
||||
/// Initializes the cache storage.
|
||||
pub fn init() -> Result<Self> {
|
||||
Ok(Self {
|
||||
cache_dir: dirs_next::cache_dir().ok_or_else(|| {
|
||||
Error::CacheError(String::from("cannot access the cache directory"))
|
||||
})?,
|
||||
})
|
||||
}
|
||||
|
||||
/// Returns the path of given labeled data.
|
||||
fn get_cache_path(&self, label: &str) -> PathBuf {
|
||||
self.cache_dir
|
||||
.join(env!("CARGO_PKG_NAME"))
|
||||
.join(label)
|
||||
.with_extension("json")
|
||||
}
|
||||
|
||||
/// Returns `true` if the labeled data is present in the cache.
|
||||
pub fn exists(&self, label: &str) -> bool {
|
||||
self.get_cache_path(label).exists()
|
||||
}
|
||||
|
||||
/// Reads the given labeled data from the cache.
|
||||
pub fn read<Data: DeserializeOwned>(&self, label: &str) -> Result<Data> {
|
||||
let raw_data = reader::read_to_string(self.get_cache_path(label))?;
|
||||
Ok(serde_json::from_str(&raw_data)?)
|
||||
}
|
||||
|
||||
/// Writes the given data to the cache.
|
||||
pub fn write<Data: ?Sized + Serialize>(&self, data: &Data, label: &str) -> Result<()> {
|
||||
let cache_path = self.get_cache_path(label);
|
||||
if !cache_path.exists() {
|
||||
fs::create_dir_all(self.cache_dir.join(env!("CARGO_PKG_NAME")))?;
|
||||
};
|
||||
let mut file = File::create(&cache_path)?;
|
||||
file.write_all(serde_json::to_string(data)?.as_bytes())?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
|
@ -9,6 +9,12 @@ pub enum Error {
|
|||
/// Error that may occur whenever a lock is acquired.
|
||||
#[error("thread lock error: `{0}`")]
|
||||
ThreadLockError(String),
|
||||
/// Error that may occur when accessing the cached data.
|
||||
#[error("cache error: `{0}`")]
|
||||
CacheError(String),
|
||||
/// Error that may occur while de/serializing JSON data.
|
||||
#[error("JSON de/serialization error: `{0}`")]
|
||||
SerdeJsonError(#[from] serde_json::Error),
|
||||
/// Error that may occur while parsing documents.
|
||||
#[error("parser error: `{0}`")]
|
||||
ParseError(#[from] systeroid_parser::error::Error),
|
||||
|
|
|
@ -19,3 +19,6 @@ pub mod config;
|
|||
|
||||
/// Display options.
|
||||
pub mod display;
|
||||
|
||||
/// Cache manager.
|
||||
pub mod cache;
|
||||
|
|
|
@ -4,6 +4,7 @@ use crate::error::Result;
|
|||
use crate::parsers::parse_kernel_docs;
|
||||
use colored::*;
|
||||
use rayon::prelude::*;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::convert::TryFrom;
|
||||
use std::fmt::{self, Display, Formatter};
|
||||
use std::io::Write;
|
||||
|
@ -12,7 +13,7 @@ use std::result::Result as StdResult;
|
|||
use sysctl::{Ctl, CtlFlags, CtlIter, Sysctl as SysctlImpl};
|
||||
|
||||
/// Sections of the sysctl documentation.
|
||||
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
|
||||
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)]
|
||||
pub enum Section {
|
||||
/// Documentation for `/proc/sys/abi/*`
|
||||
Abi,
|
||||
|
@ -76,7 +77,7 @@ impl Section {
|
|||
}
|
||||
|
||||
/// Representation of a kernel parameter.
|
||||
#[derive(Debug)]
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
pub struct Parameter {
|
||||
/// Name of the kernel parameter.
|
||||
pub name: String,
|
||||
|
@ -260,6 +261,22 @@ impl Sysctl {
|
|||
parameter
|
||||
}
|
||||
|
||||
/// Updates the parameters using the given list.
|
||||
///
|
||||
/// Keeps the original values.
|
||||
pub fn update_params(&mut self, mut parameters: Vec<Parameter>) {
|
||||
parameters.par_iter_mut().for_each(|parameter| {
|
||||
if let Some(param) = self
|
||||
.parameters
|
||||
.par_iter()
|
||||
.find_any(|param| param.name == parameter.name)
|
||||
{
|
||||
parameter.value = param.value.to_string();
|
||||
}
|
||||
});
|
||||
self.parameters = parameters;
|
||||
}
|
||||
|
||||
/// Updates the descriptions of the kernel parameters.
|
||||
pub fn update_docs(&mut self, kernel_docs: &Path) -> Result<()> {
|
||||
let documents = parse_kernel_docs(kernel_docs)?;
|
||||
|
|
|
@ -2,10 +2,14 @@ use std::env;
|
|||
use std::io::{self, Stdout};
|
||||
use std::path::PathBuf;
|
||||
use std::process::{Command, Stdio};
|
||||
use systeroid_core::cache::Cache;
|
||||
use systeroid_core::config::AppConfig;
|
||||
use systeroid_core::error::Result;
|
||||
use systeroid_core::parsers::KERNEL_DOCS_PATH;
|
||||
use systeroid_core::sysctl::Sysctl;
|
||||
use systeroid_core::sysctl::{Parameter, Sysctl};
|
||||
|
||||
/// Label for caching the kernel parameters.
|
||||
const PARAMETERS_CACHE_LABEL: &str = "parameters";
|
||||
|
||||
/// Application controller.
|
||||
#[derive(Debug)]
|
||||
|
@ -14,19 +18,21 @@ pub struct App<'a> {
|
|||
sysctl: &'a mut Sysctl,
|
||||
/// Configuration.
|
||||
config: &'a AppConfig,
|
||||
/// Cache.
|
||||
cache: Cache,
|
||||
/// Standard output.
|
||||
stdout: Stdout,
|
||||
}
|
||||
|
||||
impl<'a> App<'a> {
|
||||
/// Constructs a new instance.
|
||||
pub fn new(sysctl: &'a mut Sysctl, config: &'a AppConfig) -> Self {
|
||||
let stdout = io::stdout();
|
||||
Self {
|
||||
pub fn new(sysctl: &'a mut Sysctl, config: &'a AppConfig) -> Result<Self> {
|
||||
Ok(Self {
|
||||
sysctl,
|
||||
config,
|
||||
stdout,
|
||||
}
|
||||
cache: Cache::init()?,
|
||||
stdout: io::stdout(),
|
||||
})
|
||||
}
|
||||
|
||||
/// Displays all of the available kernel modules.
|
||||
|
@ -39,16 +45,23 @@ impl<'a> App<'a> {
|
|||
|
||||
/// Updates the documentation for kernel parameters.
|
||||
pub fn update_documentation(&mut self, kernel_docs: Option<&PathBuf>) -> Result<()> {
|
||||
if self.cache.exists(PARAMETERS_CACHE_LABEL) && kernel_docs.is_none() {
|
||||
self.sysctl
|
||||
.update_params(self.cache.read::<Vec<Parameter>>(PARAMETERS_CACHE_LABEL)?);
|
||||
return Ok(());
|
||||
}
|
||||
let mut kernel_docs_path = KERNEL_DOCS_PATH.clone();
|
||||
if let Some(path) = kernel_docs {
|
||||
kernel_docs_path.insert(0, path);
|
||||
}
|
||||
if let Some(path) = kernel_docs_path.iter().find(|path| path.exists()) {
|
||||
self.sysctl.update_docs(path)
|
||||
self.sysctl.update_docs(path)?;
|
||||
self.cache
|
||||
.write(&self.sysctl.parameters, PARAMETERS_CACHE_LABEL)?;
|
||||
} else {
|
||||
eprintln!("warning: `Linux kernel documentation cannot be found. Please specify a path via '-d' argument`",);
|
||||
Ok(())
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Displays the documentation of a parameter.
|
||||
|
|
|
@ -21,7 +21,7 @@ pub fn run(args: Args) -> Result<()> {
|
|||
config.app.display_type = args.display_type;
|
||||
config.app.no_color = env::var("NO_COLOR").is_ok();
|
||||
let mut sysctl = Sysctl::init(config.sysctl)?;
|
||||
let mut app = App::new(&mut sysctl, &config.app);
|
||||
let mut app = App::new(&mut sysctl, &config.app)?;
|
||||
|
||||
if let Some(param) = args.param_to_explain {
|
||||
app.update_documentation(args.kernel_docs.as_ref())?;
|
||||
|
|
Loading…
Reference in a new issue