feat: implement basic workspace
This commit is contained in:
parent
f98b48667c
commit
bd927840d6
2
.env
2
.env
@ -3,3 +3,5 @@ FOREST_S3_BUCKET=forest
|
|||||||
FOREST_S3_REGION=eu-west-1
|
FOREST_S3_REGION=eu-west-1
|
||||||
FOREST_S3_USER=forestadmin
|
FOREST_S3_USER=forestadmin
|
||||||
FOREST_S3_PASSWORD=forestadmin
|
FOREST_S3_PASSWORD=forestadmin
|
||||||
|
|
||||||
|
FOREST_LOG_LEVEL=forest=trace
|
||||||
|
@ -6,7 +6,7 @@ use kdl::KdlDocument;
|
|||||||
use rusty_s3::{Bucket, Credentials, S3Action};
|
use rusty_s3::{Bucket, Credentials, S3Action};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
model::{Context, Plan, Project},
|
model::{Context, ForestFile, Plan},
|
||||||
plan_reconciler::PlanReconciler,
|
plan_reconciler::PlanReconciler,
|
||||||
state::SharedState,
|
state::SharedState,
|
||||||
};
|
};
|
||||||
@ -80,84 +80,92 @@ pub async fn execute() -> anyhow::Result<()> {
|
|||||||
let project_file = tokio::fs::read_to_string(&project_file_path).await?;
|
let project_file = tokio::fs::read_to_string(&project_file_path).await?;
|
||||||
let project_doc: KdlDocument = project_file.parse()?;
|
let project_doc: KdlDocument = project_file.parse()?;
|
||||||
|
|
||||||
let project: Project = project_doc.try_into()?;
|
let project: ForestFile = project_doc.try_into()?;
|
||||||
tracing::trace!("found a project name: {}", project.name);
|
|
||||||
|
|
||||||
let plan = if let Some(plan_file_path) = PlanReconciler::new()
|
match project {
|
||||||
.reconcile(&project, &project_path)
|
ForestFile::Workspace(workspace) => {
|
||||||
.await?
|
tracing::trace!("running as workspace")
|
||||||
{
|
|
||||||
let plan_file = tokio::fs::read_to_string(&plan_file_path).await?;
|
|
||||||
let plan_doc: KdlDocument = plan_file.parse()?;
|
|
||||||
|
|
||||||
let plan: Plan = plan_doc.try_into()?;
|
|
||||||
tracing::trace!("found a plan name: {}", project.name);
|
|
||||||
|
|
||||||
Some(plan)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
};
|
|
||||||
|
|
||||||
let context = Context { project, plan };
|
|
||||||
|
|
||||||
let matches = if matches.subcommand_matches("run").is_some() {
|
|
||||||
tracing::debug!("run is called, building extra commands, rerunning the parser");
|
|
||||||
let root = get_root(false);
|
|
||||||
|
|
||||||
let root = run::Run::augment_command(root, &context);
|
|
||||||
|
|
||||||
root.get_matches()
|
|
||||||
} else {
|
|
||||||
matches
|
|
||||||
};
|
|
||||||
|
|
||||||
match matches
|
|
||||||
.subcommand()
|
|
||||||
.expect("forest requires a command to be passed")
|
|
||||||
{
|
|
||||||
("run", args) => {
|
|
||||||
run::Run::execute(args, &project_path, &context).await?;
|
|
||||||
}
|
}
|
||||||
_ => match Commands::from_arg_matches(&matches).unwrap() {
|
ForestFile::Project(project) => {
|
||||||
Commands::Init {} => {
|
tracing::trace!("found a project name: {}", project.name);
|
||||||
tracing::info!("initializing project");
|
|
||||||
tracing::trace!("found context: {:?}", context);
|
let plan = if let Some(plan_file_path) = PlanReconciler::new()
|
||||||
}
|
.reconcile(&project, &project_path)
|
||||||
Commands::Info {} => {
|
.await?
|
||||||
let output = serde_json::to_string_pretty(&context)?;
|
{
|
||||||
println!("{}", output.to_colored_json_auto().unwrap_or(output));
|
let plan_file = tokio::fs::read_to_string(&plan_file_path).await?;
|
||||||
}
|
let plan_doc: KdlDocument = plan_file.parse()?;
|
||||||
Commands::Template(template) => {
|
|
||||||
template.execute(&project_path, &context).await?;
|
let plan: Plan = plan_doc.try_into()?;
|
||||||
}
|
tracing::trace!("found a plan name: {}", project.name);
|
||||||
Commands::Serve {
|
|
||||||
s3_endpoint,
|
Some(plan)
|
||||||
s3_bucket,
|
} else {
|
||||||
s3_region,
|
None
|
||||||
s3_user,
|
};
|
||||||
s3_password,
|
|
||||||
..
|
let context = Context { project, plan };
|
||||||
} => {
|
|
||||||
tracing::info!("Starting server");
|
let matches = if matches.subcommand_matches("run").is_some() {
|
||||||
let creds = Credentials::new(s3_user, s3_password);
|
tracing::debug!("run is called, building extra commands, rerunning the parser");
|
||||||
let bucket = Bucket::new(
|
let root = get_root(false);
|
||||||
url::Url::parse(&s3_endpoint)?,
|
|
||||||
rusty_s3::UrlStyle::Path,
|
let root = run::Run::augment_command(root, &context);
|
||||||
s3_bucket,
|
|
||||||
s3_region,
|
root.get_matches()
|
||||||
)?;
|
} else {
|
||||||
let put_object = bucket.put_object(Some(&creds), "some-object");
|
matches
|
||||||
let _url = put_object.sign(std::time::Duration::from_secs(30));
|
};
|
||||||
let _state = SharedState::new().await?;
|
|
||||||
}
|
match matches
|
||||||
Commands::Clean {} => {
|
.subcommand()
|
||||||
let forest_path = project_path.join(".forest");
|
.expect("forest requires a command to be passed")
|
||||||
if forest_path.exists() {
|
{
|
||||||
tokio::fs::remove_dir_all(forest_path).await?;
|
("run", args) => {
|
||||||
tracing::info!("removed .forest");
|
run::Run::execute(args, &project_path, &context).await?;
|
||||||
}
|
}
|
||||||
|
_ => match Commands::from_arg_matches(&matches).unwrap() {
|
||||||
|
Commands::Init {} => {
|
||||||
|
tracing::info!("initializing project");
|
||||||
|
tracing::trace!("found context: {:?}", context);
|
||||||
|
}
|
||||||
|
Commands::Info {} => {
|
||||||
|
let output = serde_json::to_string_pretty(&context)?;
|
||||||
|
println!("{}", output.to_colored_json_auto().unwrap_or(output));
|
||||||
|
}
|
||||||
|
Commands::Template(template) => {
|
||||||
|
template.execute(&project_path, &context).await?;
|
||||||
|
}
|
||||||
|
Commands::Serve {
|
||||||
|
s3_endpoint,
|
||||||
|
s3_bucket,
|
||||||
|
s3_region,
|
||||||
|
s3_user,
|
||||||
|
s3_password,
|
||||||
|
..
|
||||||
|
} => {
|
||||||
|
tracing::info!("Starting server");
|
||||||
|
let creds = Credentials::new(s3_user, s3_password);
|
||||||
|
let bucket = Bucket::new(
|
||||||
|
url::Url::parse(&s3_endpoint)?,
|
||||||
|
rusty_s3::UrlStyle::Path,
|
||||||
|
s3_bucket,
|
||||||
|
s3_region,
|
||||||
|
)?;
|
||||||
|
let put_object = bucket.put_object(Some(&creds), "some-object");
|
||||||
|
let _url = put_object.sign(std::time::Duration::from_secs(30));
|
||||||
|
let _state = SharedState::new().await?;
|
||||||
|
}
|
||||||
|
Commands::Clean {} => {
|
||||||
|
let forest_path = project_path.join(".forest");
|
||||||
|
if forest_path.exists() {
|
||||||
|
tokio::fs::remove_dir_all(forest_path).await?;
|
||||||
|
tracing::info!("removed .forest");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
use std::{collections::BTreeMap, path::Path};
|
use std::path::Path;
|
||||||
|
|
||||||
use crate::{model::Context, script::ScriptExecutor};
|
use crate::{model::Context, script::ScriptExecutor};
|
||||||
|
|
||||||
|
@ -372,3 +372,40 @@ impl TryFrom<KdlDocument> for Project {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Serialize)]
|
||||||
|
pub struct Workspace {}
|
||||||
|
|
||||||
|
impl TryFrom<KdlDocument> for Workspace {
|
||||||
|
type Error = anyhow::Error;
|
||||||
|
|
||||||
|
fn try_from(value: KdlDocument) -> Result<Self, Self::Error> {
|
||||||
|
Ok(Self {})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Serialize)]
|
||||||
|
pub enum ForestFile {
|
||||||
|
Workspace(Workspace),
|
||||||
|
Project(Project),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TryFrom<KdlDocument> for ForestFile {
|
||||||
|
type Error = anyhow::Error;
|
||||||
|
|
||||||
|
fn try_from(value: KdlDocument) -> Result<Self, Self::Error> {
|
||||||
|
if value.get("workspace").is_some() && value.get("project").is_some() {
|
||||||
|
anyhow::bail!("a forest.kdl file cannot contain both a workspace and project")
|
||||||
|
}
|
||||||
|
|
||||||
|
if value.get("project").is_some() {
|
||||||
|
return Ok(Self::Project(value.try_into()?));
|
||||||
|
}
|
||||||
|
|
||||||
|
if value.get("workspace").is_some() {
|
||||||
|
return Ok(Self::Workspace(value.try_into()?));
|
||||||
|
}
|
||||||
|
|
||||||
|
anyhow::bail!("a forest.kdl file must be either a project, workspace or plan")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -2,7 +2,7 @@ use std::path::{Path, PathBuf};
|
|||||||
|
|
||||||
use anyhow::Context;
|
use anyhow::Context;
|
||||||
|
|
||||||
use crate::model::Project;
|
use crate::model::{ForestFile, Project};
|
||||||
|
|
||||||
pub mod git;
|
pub mod git;
|
||||||
pub mod local;
|
pub mod local;
|
||||||
|
9
examples/workspace/forest.kdl
Normal file
9
examples/workspace/forest.kdl
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
workspace {
|
||||||
|
members {
|
||||||
|
member "./projects/a"
|
||||||
|
member "./projects/b"
|
||||||
|
member "./plan/a"
|
||||||
|
member "./plan/b"
|
||||||
|
member "./components/*"
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user