Compare commits

...

4 Commits

Author SHA1 Message Date
19fdfcdfa5 chore(deps): update rust crate clap to v4.5.29 2025-02-15 01:34:38 +00:00
e19bf14a43
feat: support global variables 2025-02-15 00:10:56 +01:00
074f7caf01
feat: add context 2025-02-14 22:43:49 +01:00
e5053ecabd
fix: typo 2025-02-14 22:29:04 +01:00
5 changed files with 134 additions and 12 deletions

10
Cargo.lock generated
View File

@ -129,9 +129,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]] [[package]]
name = "clap" name = "clap"
version = "4.5.28" version = "4.5.29"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3e77c3243bd94243c03672cb5154667347c457ca271254724f9f393aee1c05ff" checksum = "8acebd8ad879283633b343856142139f2da2317c96b05b4dd6181c61e2480184"
dependencies = [ dependencies = [
"clap_builder", "clap_builder",
"clap_derive", "clap_derive",
@ -139,9 +139,9 @@ dependencies = [
[[package]] [[package]]
name = "clap_builder" name = "clap_builder"
version = "4.5.27" version = "4.5.29"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1b26884eb4b57140e4d2d93652abfa49498b938b3c9179f9fc487b0acc3edad7" checksum = "f6ba32cbda51c7e1dfd49acc1457ba1a7dec5b64fe360e828acb13ca8dc9c2f9"
dependencies = [ dependencies = [
"anstream", "anstream",
"anstyle", "anstyle",
@ -1179,7 +1179,7 @@ version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb"
dependencies = [ dependencies = [
"windows-sys 0.59.0", "windows-sys 0.52.0",
] ]
[[package]] [[package]]

View File

@ -5,7 +5,7 @@ use kdl::KdlDocument;
use rusty_s3::{Bucket, Credentials, S3Action}; use rusty_s3::{Bucket, Credentials, S3Action};
use crate::{ use crate::{
model::{Plan, Project}, model::{Context, Plan, Project},
plan_reconciler::PlanReconciler, plan_reconciler::PlanReconciler,
state::SharedState, state::SharedState,
}; };
@ -70,16 +70,24 @@ pub async fn execute() -> anyhow::Result<()> {
let project: Project = project_doc.try_into()?; let project: Project = project_doc.try_into()?;
tracing::trace!("found a project name: {}", project.name); tracing::trace!("found a project name: {}", project.name);
if let Some(plan_file_path) = PlanReconciler::new() let plan = if let Some(plan_file_path) = PlanReconciler::new()
.reconcile(&project, &project_path) .reconcile(&project, &project_path)
.await? .await?
{ {
let plan_file = tokio::fs::read_to_string(&plan_file_path).await?; let plan_file = tokio::fs::read_to_string(&plan_file_path).await?;
let plan_doc: KdlDocument = plan_file.parse()?; let plan_doc: KdlDocument = plan_file.parse()?;
let project: Plan = plan_doc.try_into()?; let plan: Plan = plan_doc.try_into()?;
tracing::trace!("found a plan name: {}", project.name); tracing::trace!("found a plan name: {}", project.name);
}
Some(plan)
} else {
None
};
let context = Context { project, plan };
tracing::info!("context: {:+?}", context);
} }
Commands::Serve { Commands::Serve {

View File

@ -1,6 +1,12 @@
use std::path::PathBuf; use std::{collections::BTreeMap, fmt::Debug, path::PathBuf};
use kdl::{KdlDocument, KdlNode, KdlValue}; use kdl::{KdlDocument, KdlEntry, KdlNode, KdlValue};
#[derive(Debug, Clone)]
pub struct Context {
pub project: Project,
pub plan: Option<Plan>,
}
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct Plan { pub struct Plan {
@ -60,11 +66,99 @@ impl TryFrom<&KdlNode> for ProjectPlan {
} }
} }
#[derive(Debug, Clone)]
pub enum GlobalVariable {
Map(BTreeMap<String, GlobalVariable>),
String(String),
Float(f64),
Integer(i128),
Bool(bool),
}
impl TryFrom<&KdlDocument> for GlobalVariable {
type Error = anyhow::Error;
fn try_from(value: &KdlDocument) -> Result<Self, Self::Error> {
let nodes = value.nodes();
if nodes.is_empty() {
return Ok(Self::Map(BTreeMap::default()));
}
let mut items = BTreeMap::new();
for node in nodes {
let name = node.name().value();
if let Some(children) = node.children() {
let val: GlobalVariable = children.try_into()?;
items.insert(name.into(), val);
} else if let Some(entry) = node.entries().first() {
items.insert(name.into(), entry.value().try_into()?);
} else {
items.insert(name.into(), GlobalVariable::Map(BTreeMap::default()));
}
}
Ok(GlobalVariable::Map(items))
}
}
impl TryFrom<&KdlValue> for GlobalVariable {
type Error = anyhow::Error;
fn try_from(value: &KdlValue) -> Result<Self, Self::Error> {
if let Some(value) = value.as_string() {
return Ok(Self::String(value.to_string()));
}
if let Some(value) = value.as_integer() {
return Ok(Self::Integer(value));
}
if let Some(value) = value.as_float() {
return Ok(Self::Float(value));
}
if let Some(value) = value.as_bool() {
return Ok(Self::Bool(value));
}
anyhow::bail!("value is not supported by global variables")
}
}
#[derive(Debug, Clone, Default)]
pub struct Global {
items: BTreeMap<String, GlobalVariable>,
}
impl TryFrom<&KdlNode> for Global {
type Error = anyhow::Error;
fn try_from(value: &KdlNode) -> Result<Self, Self::Error> {
let mut global = Global::default();
let Some(item) = value.children() else {
return Ok(global);
};
for node in item.nodes() {
let name = node.name().value();
if let Some(children) = node.children() {
let val: GlobalVariable = children.try_into()?;
global.items.insert(name.into(), val);
} else if let Some(entry) = node.entries().first() {
global.items.insert(name.into(), entry.value().try_into()?);
}
}
Ok(global)
}
}
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct Project { pub struct Project {
pub name: String, pub name: String,
pub description: Option<String>, pub description: Option<String>,
pub plan: Option<ProjectPlan>, pub plan: Option<ProjectPlan>,
pub global: Global,
} }
impl TryFrom<KdlDocument> for Project { impl TryFrom<KdlDocument> for Project {
@ -86,6 +180,12 @@ impl TryFrom<KdlDocument> for Project {
None None
}; };
let global: Option<Global> = if let Some(global) = project_children.get("global") {
Some(global.try_into()?)
} else {
None
};
Ok(Self { Ok(Self {
name: project_children name: project_children
.get_arg("name") .get_arg("name")
@ -102,6 +202,7 @@ impl TryFrom<KdlDocument> for Project {
_ => None, _ => None,
}), }),
plan: project_plan, plan: project_plan,
global: global.unwrap_or_default(),
}) })
} }
} }

View File

@ -49,7 +49,7 @@ impl PlanReconciler {
} }
} }
tracing::info!("recociled project"); tracing::info!("reconciled project");
Ok(Some(plan_dir.join("forest.kdl"))) Ok(Some(plan_dir.join("forest.kdl")))
} }

View File

@ -7,4 +7,17 @@ project {
plan { plan {
local "../plan" local "../plan"
} }
global {
someName "name"
someKey {
someNestedKey "somevalue"
some {
key {
val
val
}
}
}
}
} }