refactor: move schema generation to its own binary, go back to lib-bin (#1630)

* refactor: separate schema generation to its own binary, go back to lib-bin setup

Decided it might be nicer to separate the schema generation bit to its
own binary. This does mean that we have to go back to the lib-bin
system, as otherwise passing shared code is _really_ hard.

* handle versioning

* run fmt
This commit is contained in:
Clement Tsang 2024-11-28 03:05:25 -05:00 committed by GitHub
parent 196d6d18c6
commit 24cb8a417c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
17 changed files with 115 additions and 85 deletions

View File

@ -40,13 +40,24 @@ exclude = [
# The oldest version I've tested that should still build - note this is not an official MSRV!
rust-version = "1.81.0"
[[bin]]
name = "btm"
path = "src/main.rs"
[lib]
test = true
doctest = true
doc = true
[[bin]]
name = "btm"
path = "src/bin/main.rs"
doc = false
[[bin]]
name = "schema"
path = "src/bin/schema.rs"
test = false
doctest = false
doc = false
required-features = ["generate_schema"]
# Compile dependencies with optimizations enabled, even in debug mode.
[profile.dev.package."*"]
opt-level = 3

View File

@ -5,4 +5,4 @@ set -e
cd "$(dirname "$0")";
cd ../..
cargo run --features="generate_schema" -- --generate_schema > schema/nightly/bottom.json
cargo run --bin schema --features="generate_schema" -- $1 > schema/nightly/bottom.json

5
src/bin/main.rs Normal file
View File

@ -0,0 +1,5 @@
use bottom::start_bottom;
fn main() -> anyhow::Result<()> {
start_bottom()
}

73
src/bin/schema.rs Normal file
View File

@ -0,0 +1,73 @@
#![cfg(feature = "generate_schema")]
use bottom::{options::config, widgets};
use clap::Parser;
use itertools::Itertools;
use strum::VariantArray;
#[derive(Parser)]
struct SchemaOptions {
/// The version of the schema.
version: Option<String>,
}
fn generate_schema(schema_options: SchemaOptions) -> anyhow::Result<()> {
let mut schema = schemars::schema_for!(config::Config);
{
// TODO: Maybe make this case insensitive? See https://stackoverflow.com/a/68639341
let proc_columns = schema.definitions.get_mut("ProcColumn").unwrap();
match proc_columns {
schemars::schema::Schema::Object(proc_columns) => {
let enums = proc_columns.enum_values.as_mut().unwrap();
*enums = widgets::ProcColumn::VARIANTS
.iter()
.flat_map(|var| var.get_schema_names())
.sorted()
.map(|v| serde_json::Value::String(v.to_string()))
.dedup()
.collect();
}
_ => anyhow::bail!("missing proc columns definition"),
}
let disk_columns = schema.definitions.get_mut("DiskColumn").unwrap();
match disk_columns {
schemars::schema::Schema::Object(disk_columns) => {
let enums = disk_columns.enum_values.as_mut().unwrap();
*enums = widgets::DiskColumn::VARIANTS
.iter()
.flat_map(|var| var.get_schema_names())
.sorted()
.map(|v| serde_json::Value::String(v.to_string()))
.dedup()
.collect();
}
_ => anyhow::bail!("missing disk columns definition"),
}
}
let metadata = schema.schema.metadata.as_mut().unwrap();
let version = schema_options.version.unwrap_or("nightly".to_string());
metadata.id = Some(format!(
"https://github.com/ClementTsang/bottom/blob/main/schema/{version}/bottom.json"
));
metadata.description = Some(format!(
"https://clementtsang.github.io/bottom/{}/configuration/config-file",
if version == "nightly" {
"nightly"
} else {
"stable"
}
));
println!("{}", serde_json::to_string_pretty(&schema).unwrap());
Ok(())
}
fn main() -> anyhow::Result<()> {
let schema_options = SchemaOptions::parse();
generate_schema(schema_options)?;
Ok(())
}

View File

@ -3,8 +3,7 @@
use std::time::Duration;
use super::ProcessHarvest;
use crate::data_collection::error::CollectionResult;
use crate::data_collection::DataCollector;
use crate::data_collection::{error::CollectionResult, DataCollector};
// TODO: There's a lot of shared code with this and the unix impl.
pub fn sysinfo_process_data(

View File

@ -272,67 +272,13 @@ fn create_collection_thread(
})
}
#[cfg(feature = "generate_schema")]
fn generate_schema() -> anyhow::Result<()> {
let mut schema = schemars::schema_for!(crate::options::config::Config);
{
use itertools::Itertools;
use strum::VariantArray;
// TODO: Maybe make this case insensitive? See https://stackoverflow.com/a/68639341
let proc_columns = schema.definitions.get_mut("ProcColumn").unwrap();
match proc_columns {
schemars::schema::Schema::Object(proc_columns) => {
let enums = proc_columns.enum_values.as_mut().unwrap();
*enums = widgets::ProcColumn::VARIANTS
.iter()
.flat_map(|var| var.get_schema_names())
.sorted()
.map(|v| serde_json::Value::String(v.to_string()))
.dedup()
.collect();
}
_ => anyhow::bail!("missing proc columns definition"),
}
let disk_columns = schema.definitions.get_mut("DiskColumn").unwrap();
match disk_columns {
schemars::schema::Schema::Object(disk_columns) => {
let enums = disk_columns.enum_values.as_mut().unwrap();
*enums = widgets::DiskColumn::VARIANTS
.iter()
.flat_map(|var| var.get_schema_names())
.sorted()
.map(|v| serde_json::Value::String(v.to_string()))
.dedup()
.collect();
}
_ => anyhow::bail!("missing disk columns definition"),
}
}
let metadata = schema.schema.metadata.as_mut().unwrap();
metadata.id = Some(
"https://github.com/ClementTsang/bottom/blob/main/schema/nightly/bottom.json".to_string(),
);
metadata.description =
Some("https://clementtsang.github.io/bottom/nightly/configuration/config-file".to_string());
println!("{}", serde_json::to_string_pretty(&schema).unwrap());
Ok(())
}
fn main() -> anyhow::Result<()> {
/// Main code to call.
#[inline]
pub fn start_bottom() -> anyhow::Result<()> {
// let _profiler = dhat::Profiler::new_heap();
let args = args::get_args();
#[cfg(feature = "generate_schema")]
if args.other.generate_schema {
return generate_schema();
}
#[cfg(feature = "logging")]
{
if let Err(err) = init_logger(

View File

@ -195,6 +195,7 @@ pub fn get_or_create_config(config_path: Option<&Path>) -> anyhow::Result<Config
}
}
/// Initialize the app.
pub(crate) fn init_app(
args: BottomArgs, config: Config,
) -> Result<(App, BottomLayout, ColourPalette)> {
@ -1235,10 +1236,10 @@ mod test {
#[cfg(target_os = "macos")]
#[test]
fn test_get_config_path_macos() {
use super::get_config_path;
use super::DEFAULT_CONFIG_FILE_LOCATION;
use std::path::PathBuf;
use super::{get_config_path, DEFAULT_CONFIG_FILE_LOCATION};
// Case three: no previous config, no XDG var.
// SAFETY: this is the only test that does this
unsafe {

View File

@ -566,10 +566,6 @@ pub struct OtherArgs {
#[arg(short = 'V', long, action = ArgAction::Version, help = "Prints version information.")]
version: (),
#[cfg(feature = "generate_schema")]
#[arg(long, action = ArgAction::SetTrue)]
pub generate_schema: bool,
}
/// Returns a [`BottomArgs`].

View File

@ -18,6 +18,7 @@ use temperature::TempConfig;
pub use self::ignore_list::IgnoreList;
use self::{cpu::CpuConfig, layout::Row, process::ProcessesConfig};
/// Overall config for `bottom`.
#[derive(Clone, Debug, Default, Deserialize)]
#[cfg_attr(
feature = "generate_schema",
@ -65,9 +66,10 @@ mod test {
#[test]
#[cfg(feature = "default")]
fn test_integration_valid_configs() {
use super::Config;
use std::fs;
use super::Config;
for config_path in fs::read_dir("./tests/valid_configs").unwrap() {
let config_path = config_path.unwrap();
let config_path_str = config_path.path().display().to_string();

View File

@ -1,8 +1,7 @@
use serde::Deserialize;
use crate::options::DiskColumn;
use super::IgnoreList;
use crate::options::DiskColumn;
/// Disk configuration.
#[derive(Clone, Debug, Default, Deserialize)]

View File

@ -23,9 +23,8 @@ use tui::style::Style;
use utils::{opt, set_colour, set_colour_list, set_style};
use widgets::WidgetStyle;
use crate::options::{args::BottomArgs, OptionError, OptionResult};
use super::Config;
use crate::options::{args::BottomArgs, OptionError, OptionResult};
#[derive(Clone, Debug, Deserialize, Serialize)]
#[cfg_attr(feature = "generate_schema", derive(schemars::JsonSchema))]

View File

@ -17,4 +17,5 @@ macro_rules! hex {
};
}
pub(super) use {color, hex};
pub(super) use color;
pub(super) use hex;

View File

@ -1,8 +1,7 @@
use tui::style::{Color, Modifier, Style};
use crate::options::config::style::ColourPalette;
use super::color;
use crate::options::config::style::ColourPalette;
impl ColourPalette {
pub(crate) fn default_palette() -> Self {

View File

@ -1,8 +1,7 @@
use tui::style::{Color, Modifier};
use crate::options::config::style::{utils::convert_hex_to_color, ColourPalette};
use super::{color, hex};
use crate::options::config::style::{utils::convert_hex_to_color, ColourPalette};
impl ColourPalette {
pub(crate) fn gruvbox_palette() -> Self {

View File

@ -1,8 +1,7 @@
use tui::style::{Color, Modifier};
use crate::options::config::style::{utils::convert_hex_to_color, ColourPalette};
use super::{color, hex};
use crate::options::config::style::{utils::convert_hex_to_color, ColourPalette};
impl ColourPalette {
pub(crate) fn nord_palette() -> Self {

View File

@ -247,16 +247,18 @@ macro_rules! set_colour_list {
};
}
pub(super) use {opt, set_colour, set_colour_list, set_style};
pub(super) use opt;
pub(super) use set_colour;
pub(super) use set_colour_list;
pub(super) use set_style;
#[cfg(test)]
mod test {
use tui::style::{Modifier, Style};
use crate::options::config::style::{ColorStr, TextStyleConfig};
use super::*;
use crate::options::config::style::{ColorStr, TextStyleConfig};
#[test]
fn general_str_to_colour() {

View File

@ -1,7 +1,6 @@
//! Tests config files that have sometimes caused issues despite being valid.
use std::{io::Read, thread, time::Duration};
#[cfg(feature = "default")]
use std::{io::Write, path::Path};