feat: can load project files
This commit is contained in:
parent
dca625af31
commit
28a1d09974
@ -1,12 +1,13 @@
|
|||||||
use std::{net::SocketAddr, path::PathBuf};
|
use std::{net::SocketAddr, path::PathBuf};
|
||||||
|
|
||||||
|
use anyhow::Context as AnyContext;
|
||||||
use clap::{FromArgMatches, Parser, Subcommand, crate_authors, crate_description, crate_version};
|
use clap::{FromArgMatches, Parser, Subcommand, crate_authors, crate_description, crate_version};
|
||||||
use colored_json::ToColoredJson;
|
use colored_json::ToColoredJson;
|
||||||
use kdl::KdlDocument;
|
use kdl::KdlDocument;
|
||||||
use rusty_s3::{Bucket, Credentials, S3Action};
|
use rusty_s3::{Bucket, Credentials, S3Action};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
model::{Context, ForestFile, Plan},
|
model::{Context, ForestFile, Plan, Project, WorkspaceProject},
|
||||||
plan_reconciler::PlanReconciler,
|
plan_reconciler::PlanReconciler,
|
||||||
state::SharedState,
|
state::SharedState,
|
||||||
};
|
};
|
||||||
@ -86,11 +87,36 @@ pub async fn execute() -> anyhow::Result<()> {
|
|||||||
tracing::trace!("running as workspace");
|
tracing::trace!("running as workspace");
|
||||||
|
|
||||||
// 1. For each member load the project
|
// 1. For each member load the project
|
||||||
let output = serde_json::to_string_pretty(&workspace)?;
|
|
||||||
|
let mut workspace_members = Vec::new();
|
||||||
|
|
||||||
|
for member in workspace.members {
|
||||||
|
let workspace_member_path = project_path.join(&member.path);
|
||||||
|
|
||||||
|
let project_file_path = workspace_member_path.join("forest.kdl");
|
||||||
|
if !project_file_path.exists() {
|
||||||
|
anyhow::bail!(
|
||||||
|
"no 'forest.kdl' file was found at: {}",
|
||||||
|
workspace_member_path.display().to_string()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
let project_file = tokio::fs::read_to_string(&project_file_path).await?;
|
||||||
|
let doc: KdlDocument = project_file.parse()?;
|
||||||
|
let project: WorkspaceProject = doc.try_into().context(format!(
|
||||||
|
"workspace member: {} failed to parse",
|
||||||
|
&member.path
|
||||||
|
))?;
|
||||||
|
|
||||||
|
workspace_members.push(project);
|
||||||
|
}
|
||||||
|
|
||||||
|
let output = serde_json::to_string_pretty(&workspace_members)?;
|
||||||
println!("{}", output.to_colored_json_auto().unwrap_or(output));
|
println!("{}", output.to_colored_json_auto().unwrap_or(output));
|
||||||
|
|
||||||
// TODO: 1a (optional). Resolve dependencies
|
// TODO: 1a (optional). Resolve dependencies
|
||||||
// 2. Reconcile plans
|
// 2. Reconcile plans
|
||||||
|
|
||||||
// 3. Provide context and aggregated commands for projects
|
// 3. Provide context and aggregated commands for projects
|
||||||
}
|
}
|
||||||
ForestFile::Project(project) => {
|
ForestFile::Project(project) => {
|
||||||
|
@ -13,7 +13,9 @@ pub struct Context {
|
|||||||
#[derive(Debug, Clone, Serialize)]
|
#[derive(Debug, Clone, Serialize)]
|
||||||
pub struct Plan {
|
pub struct Plan {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub templates: Option<Templates>,
|
pub templates: Option<Templates>,
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub scripts: Option<Scripts>,
|
pub scripts: Option<Scripts>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -164,6 +166,12 @@ pub struct Global {
|
|||||||
items: BTreeMap<String, GlobalVariable>,
|
items: BTreeMap<String, GlobalVariable>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Global {
|
||||||
|
fn is_empty(&self) -> bool {
|
||||||
|
self.items.is_empty()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl From<&Global> for minijinja::Value {
|
impl From<&Global> for minijinja::Value {
|
||||||
fn from(value: &Global) -> Self {
|
fn from(value: &Global) -> Self {
|
||||||
Self::from_serialize(&value.items)
|
Self::from_serialize(&value.items)
|
||||||
@ -312,10 +320,16 @@ impl TryFrom<&KdlNode> for Scripts {
|
|||||||
#[derive(Debug, Clone, Serialize)]
|
#[derive(Debug, Clone, Serialize)]
|
||||||
pub struct Project {
|
pub struct Project {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub description: Option<String>,
|
pub description: Option<String>,
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub plan: Option<ProjectPlan>,
|
pub plan: Option<ProjectPlan>,
|
||||||
|
|
||||||
|
#[serde(skip_serializing_if = "Global::is_empty")]
|
||||||
pub global: Global,
|
pub global: Global,
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub templates: Option<Templates>,
|
pub templates: Option<Templates>,
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub scripts: Option<Scripts>,
|
pub scripts: Option<Scripts>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -375,7 +389,7 @@ impl TryFrom<KdlDocument> for Project {
|
|||||||
|
|
||||||
#[derive(Debug, Clone, Serialize)]
|
#[derive(Debug, Clone, Serialize)]
|
||||||
pub struct WorkspaceMember {
|
pub struct WorkspaceMember {
|
||||||
pub name: String,
|
pub path: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TryFrom<&kdl::KdlNode> for WorkspaceMember {
|
impl TryFrom<&kdl::KdlNode> for WorkspaceMember {
|
||||||
@ -383,7 +397,7 @@ impl TryFrom<&kdl::KdlNode> for WorkspaceMember {
|
|||||||
|
|
||||||
fn try_from(value: &kdl::KdlNode) -> Result<Self, Self::Error> {
|
fn try_from(value: &kdl::KdlNode) -> Result<Self, Self::Error> {
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
name: value
|
path: value
|
||||||
.entries()
|
.entries()
|
||||||
.first()
|
.first()
|
||||||
.ok_or(anyhow::anyhow!(
|
.ok_or(anyhow::anyhow!(
|
||||||
@ -399,7 +413,7 @@ impl TryFrom<&kdl::KdlNode> for WorkspaceMember {
|
|||||||
|
|
||||||
#[derive(Debug, Clone, Serialize)]
|
#[derive(Debug, Clone, Serialize)]
|
||||||
pub struct Workspace {
|
pub struct Workspace {
|
||||||
members: Vec<WorkspaceMember>,
|
pub members: Vec<WorkspaceMember>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TryFrom<KdlDocument> for Workspace {
|
impl TryFrom<KdlDocument> for Workspace {
|
||||||
@ -453,3 +467,30 @@ impl TryFrom<KdlDocument> for ForestFile {
|
|||||||
anyhow::bail!("a forest.kdl file must be either a project, workspace or plan")
|
anyhow::bail!("a forest.kdl file must be either a project, workspace or plan")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Serialize)]
|
||||||
|
#[serde(tag = "type")]
|
||||||
|
pub enum WorkspaceProject {
|
||||||
|
Plan(Plan),
|
||||||
|
Project(Project),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TryFrom<KdlDocument> for WorkspaceProject {
|
||||||
|
type Error = anyhow::Error;
|
||||||
|
|
||||||
|
fn try_from(value: KdlDocument) -> Result<Self, Self::Error> {
|
||||||
|
if value.get("plan").is_some() && value.get("project").is_some() {
|
||||||
|
anyhow::bail!("a forest.kdl file cannot contain both a plan and project")
|
||||||
|
}
|
||||||
|
|
||||||
|
if value.get("project").is_some() {
|
||||||
|
return Ok(Self::Project(value.try_into()?));
|
||||||
|
}
|
||||||
|
|
||||||
|
if value.get("plan").is_some() {
|
||||||
|
return Ok(Self::Plan(value.try_into()?));
|
||||||
|
}
|
||||||
|
|
||||||
|
anyhow::bail!("a forest.kdl file must be either a project, workspace or plan")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
workspace {
|
workspace {
|
||||||
members {
|
members {
|
||||||
member "./projects/a"
|
member "projects/a"
|
||||||
member "./projects/b"
|
member "projects/b"
|
||||||
member "./plan/a"
|
member "plan/a"
|
||||||
member "./plan/b"
|
member "plan/b"
|
||||||
member "./components/*"
|
// member "components/*"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,3 @@
|
|||||||
|
plan {
|
||||||
|
name a
|
||||||
|
}
|
@ -0,0 +1,3 @@
|
|||||||
|
plan {
|
||||||
|
name b
|
||||||
|
}
|
@ -0,0 +1,3 @@
|
|||||||
|
project {
|
||||||
|
name a
|
||||||
|
}
|
@ -0,0 +1,3 @@
|
|||||||
|
project {
|
||||||
|
name b
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user