update
This commit is contained in:
parent
d9e9ce628c
commit
7c2540a185
|
|
@ -479,6 +479,7 @@ dependencies = [
|
||||||
"stringlit",
|
"stringlit",
|
||||||
"toml",
|
"toml",
|
||||||
"tui",
|
"tui",
|
||||||
|
"version_operators",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
@ -780,6 +781,12 @@ version = "0.9.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
|
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "version_operators"
|
||||||
|
version = "0.0.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "effa0697dca74a72f99a5a3ee248673c19e02a915ce78667768b0d311d468340"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasi"
|
name = "wasi"
|
||||||
version = "0.11.0+wasi-snapshot-preview1"
|
version = "0.11.0+wasi-snapshot-preview1"
|
||||||
|
|
|
||||||
|
|
@ -21,3 +21,4 @@ serde_yaml = "0.9.34"
|
||||||
stringlit = "2.1.0"
|
stringlit = "2.1.0"
|
||||||
toml = { version = "0.8.12", features = ["indexmap", "preserve_order"] }
|
toml = { version = "0.8.12", features = ["indexmap", "preserve_order"] }
|
||||||
tui = "0.19.0"
|
tui = "0.19.0"
|
||||||
|
version_operators = "0.0.1"
|
||||||
|
|
|
||||||
1
req.yml
1
req.yml
|
|
@ -1,4 +1,5 @@
|
||||||
name: journal-uploader
|
name: journal-uploader
|
||||||
|
version: 1.0.0
|
||||||
description: |-
|
description: |-
|
||||||
The journal-uploader has two main functionalities.
|
The journal-uploader has two main functionalities.
|
||||||
- Take a stream of log messages and filter them depending on their severity
|
- Take a stream of log messages and filter them depending on their severity
|
||||||
|
|
|
||||||
80
src/lib.rs
80
src/lib.rs
|
|
@ -1,6 +1,9 @@
|
||||||
|
use std::fmt;
|
||||||
|
|
||||||
use indexmap::{indexmap, IndexMap};
|
use indexmap::{indexmap, IndexMap};
|
||||||
use schemars::JsonSchema;
|
use schemars::JsonSchema;
|
||||||
use serde::{Deserialize, Serialize, Serializer};
|
use serde::de::{self, Unexpected, Visitor};
|
||||||
|
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
||||||
use stringlit::s;
|
use stringlit::s;
|
||||||
|
|
||||||
pub fn my_trim<S>(v: &str, s: S) -> Result<S::Ok, S::Error>
|
pub fn my_trim<S>(v: &str, s: S) -> Result<S::Ok, S::Error>
|
||||||
|
|
@ -51,9 +54,79 @@ pub struct ConfigDefault {
|
||||||
pub hint: Option<String>,
|
pub hint: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(JsonSchema, Deserialize, Serialize, Debug, Clone, PartialEq, Eq)]
|
||||||
|
pub struct Version {
|
||||||
|
major: u64,
|
||||||
|
minor: u64,
|
||||||
|
patch: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for Version {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
write!(f, "{}.{}.{}", self.major, self.minor, self.patch)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Serialization as before
|
||||||
|
fn serialize_version<S>(version: &Version, serializer: S) -> Result<S::Ok, S::Error>
|
||||||
|
where
|
||||||
|
S: Serializer,
|
||||||
|
{
|
||||||
|
serializer.serialize_str(&version.to_string())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Custom deserialization
|
||||||
|
fn deserialize_version<'de, D>(deserializer: D) -> Result<Version, D::Error>
|
||||||
|
where
|
||||||
|
D: Deserializer<'de>,
|
||||||
|
{
|
||||||
|
struct VersionVisitor;
|
||||||
|
|
||||||
|
impl<'de> Visitor<'de> for VersionVisitor {
|
||||||
|
type Value = Version;
|
||||||
|
|
||||||
|
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
formatter.write_str("a version string in the format 'major.minor.patch'")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_str<E>(self, value: &str) -> Result<Version, E>
|
||||||
|
where
|
||||||
|
E: de::Error,
|
||||||
|
{
|
||||||
|
let parts: Vec<&str> = value.split('.').collect();
|
||||||
|
if parts.len() != 3 {
|
||||||
|
return Err(E::invalid_value(Unexpected::Str(value), &self));
|
||||||
|
}
|
||||||
|
|
||||||
|
let major = parts[0]
|
||||||
|
.parse::<u64>()
|
||||||
|
.map_err(|_| E::invalid_value(Unexpected::Str(value), &self))?;
|
||||||
|
let minor = parts[1]
|
||||||
|
.parse::<u64>()
|
||||||
|
.map_err(|_| E::invalid_value(Unexpected::Str(value), &self))?;
|
||||||
|
let patch = parts[2]
|
||||||
|
.parse::<u64>()
|
||||||
|
.map_err(|_| E::invalid_value(Unexpected::Str(value), &self))?;
|
||||||
|
|
||||||
|
Ok(Version {
|
||||||
|
major,
|
||||||
|
minor,
|
||||||
|
patch,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
deserializer.deserialize_str(VersionVisitor)
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(JsonSchema, Debug, Deserialize, Serialize)]
|
#[derive(JsonSchema, Debug, Deserialize, Serialize)]
|
||||||
pub struct Project {
|
pub struct Project {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
|
#[serde(
|
||||||
|
serialize_with = "serialize_version",
|
||||||
|
deserialize_with = "deserialize_version"
|
||||||
|
)]
|
||||||
|
pub version: Version,
|
||||||
#[serde(serialize_with = "my_trim")]
|
#[serde(serialize_with = "my_trim")]
|
||||||
pub description: String,
|
pub description: String,
|
||||||
#[serde(default, skip_serializing_if = "IndexMap::is_empty")]
|
#[serde(default, skip_serializing_if = "IndexMap::is_empty")]
|
||||||
|
|
@ -67,6 +140,11 @@ pub struct Project {
|
||||||
pub fn demo_project() -> Project {
|
pub fn demo_project() -> Project {
|
||||||
Project {
|
Project {
|
||||||
name: s!("journal-uploader"),
|
name: s!("journal-uploader"),
|
||||||
|
version: Version {
|
||||||
|
major: 1,
|
||||||
|
minor: 0,
|
||||||
|
patch: 0,
|
||||||
|
},
|
||||||
description: s!(r"
|
description: s!(r"
|
||||||
The journal-uploader has two main functionalities.
|
The journal-uploader has two main functionalities.
|
||||||
- Take a stream of log messages and filter them depending on their severity
|
- Take a stream of log messages and filter them depending on their severity
|
||||||
|
|
|
||||||
51
src/main.rs
51
src/main.rs
|
|
@ -110,21 +110,25 @@ fn add_requirements(output: &mut Vec<String>, requirements: &IndexMap<String, Re
|
||||||
for (id, requirement) in requirements {
|
for (id, requirement) in requirements {
|
||||||
output.push(format!(
|
output.push(format!(
|
||||||
"- **_{id}_ - {}:** {}",
|
"- **_{id}_ - {}:** {}",
|
||||||
requirement.name, requirement.description
|
requirement.name.trim(),
|
||||||
|
requirement.description.trim()
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_topics(output: &mut Vec<String>, topics: &IndexMap<String, Topic>, level: usize) {
|
fn add_topics(output: &mut Vec<String>, topics: &IndexMap<String, Topic>, level: usize) {
|
||||||
for (id, topic) in topics {
|
for (id, topic) in topics {
|
||||||
output.push(format!("{} _{id}_ - {}", "#".repeat(level), topic.name));
|
output.push(format!(
|
||||||
|
"{} _{id}_ - {}",
|
||||||
|
"#".repeat(level),
|
||||||
|
topic.name.trim()
|
||||||
|
));
|
||||||
if !topic.requirements.is_empty() {
|
if !topic.requirements.is_empty() {
|
||||||
add_requirements(output, &topic.requirements);
|
add_requirements(output, &topic.requirements);
|
||||||
output.push(nl());
|
output.push(nl());
|
||||||
}
|
}
|
||||||
if !topic.subtopics.is_empty() {
|
if !topic.subtopics.is_empty() {
|
||||||
add_topics(output, &topic.subtopics, level + 1);
|
add_topics(output, &topic.subtopics, level + 1);
|
||||||
output.push(nl());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -132,6 +136,7 @@ fn add_topics(output: &mut Vec<String>, topics: &IndexMap<String, Topic>, level:
|
||||||
#[derive(Parser)]
|
#[derive(Parser)]
|
||||||
enum Command {
|
enum Command {
|
||||||
Schema,
|
Schema,
|
||||||
|
Demo,
|
||||||
#[clap(alias = "md")]
|
#[clap(alias = "md")]
|
||||||
Markdown {
|
Markdown {
|
||||||
requirements: PathBuf,
|
requirements: PathBuf,
|
||||||
|
|
@ -153,6 +158,9 @@ struct Args {
|
||||||
fn main() -> anyhow::Result<()> {
|
fn main() -> anyhow::Result<()> {
|
||||||
let Args { command } = Args::parse();
|
let Args { command } = Args::parse();
|
||||||
match command {
|
match command {
|
||||||
|
Command::Demo => {
|
||||||
|
println!("{}", serde_yaml::to_string(&demo_project())?);
|
||||||
|
}
|
||||||
Command::Schema => {
|
Command::Schema => {
|
||||||
let schema = schema_for!(Project);
|
let schema = schema_for!(Project);
|
||||||
println!("{}", serde_json::to_string_pretty(&schema).unwrap());
|
println!("{}", serde_json::to_string_pretty(&schema).unwrap());
|
||||||
|
|
@ -161,29 +169,34 @@ fn main() -> anyhow::Result<()> {
|
||||||
let project: Project = serde_yaml::from_str(&std::fs::read_to_string(requirements)?)?;
|
let project: Project = serde_yaml::from_str(&std::fs::read_to_string(requirements)?)?;
|
||||||
|
|
||||||
let mut output = vec![
|
let mut output = vec![
|
||||||
format!("# Requirements for {}", project.name),
|
format!("# Requirements for {}", project.name.trim()),
|
||||||
nl(),
|
nl(),
|
||||||
s!("[[_TOC_]]"),
|
s!("[[_TOC_]]"),
|
||||||
nl(),
|
nl(),
|
||||||
WORD_DESCRIPTION.to_string(),
|
WORD_DESCRIPTION.trim().to_string(),
|
||||||
|
nl(),
|
||||||
|
format!("**VERSION: {}**", project.version),
|
||||||
nl(),
|
nl(),
|
||||||
s!("## Description"),
|
s!("## Description"),
|
||||||
project.description,
|
project.description.trim().to_string(),
|
||||||
nl(),
|
nl(),
|
||||||
];
|
];
|
||||||
|
|
||||||
if !project.topics.is_empty() {
|
if !project.topics.is_empty() {
|
||||||
output.push(s!("## Requirements"));
|
output.push(s!("## Requirements"));
|
||||||
add_topics(&mut output, &project.topics, 3);
|
add_topics(&mut output, &project.topics, 3);
|
||||||
output.push(nl());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if !project.definitions.is_empty() {
|
if !project.definitions.is_empty() {
|
||||||
output.push(s!("## Definitions"));
|
output.push(s!("## Definitions"));
|
||||||
for definition in project.definitions {
|
for definition in project.definitions {
|
||||||
output.push(format!("- {}: {}", definition.name, definition.value));
|
output.push(format!(
|
||||||
|
"- {}: {}",
|
||||||
|
definition.name.trim(),
|
||||||
|
definition.value.trim()
|
||||||
|
));
|
||||||
for info in definition.additional_info {
|
for info in definition.additional_info {
|
||||||
output.push(format!(" - {info}"))
|
output.push(format!(" - {}", info.trim()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
output.push(nl());
|
output.push(nl());
|
||||||
|
|
@ -192,24 +205,30 @@ fn main() -> anyhow::Result<()> {
|
||||||
if !project.config_defaults.is_empty() {
|
if !project.config_defaults.is_empty() {
|
||||||
output.push(s!("## Config Defaults"));
|
output.push(s!("## Config Defaults"));
|
||||||
for default in project.config_defaults {
|
for default in project.config_defaults {
|
||||||
output.push(format!("- **{}**", default.name));
|
output.push(format!("- **{}**", default.name.trim()));
|
||||||
output.push(format!(" - Type: {}", default.typ));
|
output.push(format!(" - Type: {}", default.typ.trim()));
|
||||||
if let Some(unit) = default.unit {
|
if let Some(unit) = default.unit {
|
||||||
output.push(format!(" - Unit: {unit}"));
|
output.push(format!(" - Unit: {}", unit.trim()));
|
||||||
}
|
}
|
||||||
if let Some(valid_values) = default.valid_values {
|
if let Some(valid_values) = default.valid_values {
|
||||||
output.push(format!(" - Valid Values: _{}_", valid_values.join(", ")));
|
output.push(format!(
|
||||||
|
" - Valid Values: _{}_",
|
||||||
|
valid_values.join(", ").trim()
|
||||||
|
));
|
||||||
}
|
}
|
||||||
if let Some(default_value) = default.default_value {
|
if let Some(default_value) = default.default_value {
|
||||||
output.push(format!(
|
output.push(format!(
|
||||||
" - Default Value: _{}_{}",
|
" - Default Value: _{}_{}",
|
||||||
default_value,
|
default_value.trim(),
|
||||||
default.hint.map(|h| format!(" {h}")).unwrap_or_default()
|
default
|
||||||
|
.hint
|
||||||
|
.map(|h| format!(" {}", h.trim()))
|
||||||
|
.unwrap_or_default()
|
||||||
));
|
));
|
||||||
} else {
|
} else {
|
||||||
output.push(format!(
|
output.push(format!(
|
||||||
" - **Required**: This value **_MUST_** be provided as a start parameter.{}",
|
" - **Required**: This value **_MUST_** be provided as a start parameter.{}",
|
||||||
default.hint.map(|h| format!(" {h}")).unwrap_or_default()
|
default.hint.map(|h| format!(" {}", h.trim())).unwrap_or_default()
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
output.push(nl());
|
output.push(nl());
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue