feat: with crunch file support
Signed-off-by: kjuulh <contact@kjuulh.io>
This commit is contained in:
15
crates/crunch-cli/Cargo.toml
Normal file
15
crates/crunch-cli/Cargo.toml
Normal file
@@ -0,0 +1,15 @@
|
||||
[package]
|
||||
name = "crunch-cli"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
anyhow.workspace = true
|
||||
tracing.workspace = true
|
||||
tokio.workspace = true
|
||||
thiserror.workspace = true
|
||||
async-trait.workspace = true
|
||||
tracing-subscriber.workspace = true
|
||||
clap.workspace = true
|
78
crates/crunch-cli/src/main.rs
Normal file
78
crates/crunch-cli/src/main.rs
Normal file
@@ -0,0 +1,78 @@
|
||||
use clap::{Args, Parser, Subcommand, ValueEnum};
|
||||
use tracing::Level;
|
||||
|
||||
#[derive(Parser, Clone)]
|
||||
#[command(author, version, about, long_about = None, subcommand_required = true)]
|
||||
struct Cli {
|
||||
#[command(subcommand)]
|
||||
commands: Commands,
|
||||
|
||||
#[command(flatten)]
|
||||
global_args: GlobalArgs,
|
||||
}
|
||||
|
||||
#[derive(Subcommand, Clone)]
|
||||
enum Commands {
|
||||
Generate {},
|
||||
}
|
||||
|
||||
#[derive(Args, Clone)]
|
||||
struct GlobalArgs {
|
||||
#[arg(long, default_value = "none", global = true, help_heading = "Global")]
|
||||
log: LogArg,
|
||||
|
||||
#[arg(
|
||||
long,
|
||||
default_value = ".crunch.toml",
|
||||
global = true,
|
||||
help_heading = "Global"
|
||||
)]
|
||||
crunch_file: String,
|
||||
}
|
||||
|
||||
#[derive(Clone, ValueEnum)]
|
||||
enum LogArg {
|
||||
None,
|
||||
Trace,
|
||||
Debug,
|
||||
Info,
|
||||
Warn,
|
||||
Error,
|
||||
}
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
let cli = Cli::parse();
|
||||
init_logging(&cli.global_args.log);
|
||||
|
||||
match &cli.commands {
|
||||
Commands::Generate {} => {}
|
||||
}
|
||||
}
|
||||
|
||||
fn init_logging(log: &LogArg) {
|
||||
match log {
|
||||
LogArg::None => {}
|
||||
LogArg::Trace => {
|
||||
tracing_subscriber::fmt()
|
||||
.with_max_level(Level::TRACE)
|
||||
.init();
|
||||
}
|
||||
LogArg::Debug => {
|
||||
tracing_subscriber::fmt()
|
||||
.with_max_level(Level::DEBUG)
|
||||
.init();
|
||||
}
|
||||
LogArg::Info => {
|
||||
tracing_subscriber::fmt().with_max_level(Level::INFO).init();
|
||||
}
|
||||
LogArg::Warn => {
|
||||
tracing_subscriber::fmt().with_max_level(Level::WARN).init();
|
||||
}
|
||||
LogArg::Error => {
|
||||
tracing_subscriber::fmt()
|
||||
.with_max_level(Level::ERROR)
|
||||
.init();
|
||||
}
|
||||
}
|
||||
}
|
18
crates/crunch-file/Cargo.toml
Normal file
18
crates/crunch-file/Cargo.toml
Normal file
@@ -0,0 +1,18 @@
|
||||
[package]
|
||||
name = "crunch-file"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
crunch-traits.workspace = true
|
||||
|
||||
anyhow.workspace = true
|
||||
tokio.workspace = true
|
||||
async-trait.workspace = true
|
||||
toml_edit.workspace = true
|
||||
serde.workspace = true
|
||||
|
||||
[dev-dependencies]
|
||||
pretty_assertions.workspace = true
|
223
crates/crunch-file/src/lib.rs
Normal file
223
crates/crunch-file/src/lib.rs
Normal file
@@ -0,0 +1,223 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
use tokio::io::AsyncWriteExt;
|
||||
use toml_edit::{value, Document};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct File {
|
||||
doc: Document,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||
pub struct Config {
|
||||
pub service: Service,
|
||||
pub publish: Option<Vec<Publish>>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||
pub struct Service {
|
||||
pub service: String,
|
||||
pub domain: String,
|
||||
pub codegen: Vec<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||
pub struct Publish {
|
||||
#[serde(alias = "schema-path")]
|
||||
pub schema_path: String,
|
||||
#[serde(alias = "output-path")]
|
||||
pub output_path: String,
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
impl File {
|
||||
pub async fn parse_file(path: &std::path::Path) -> anyhow::Result<File> {
|
||||
let file = tokio::fs::read_to_string(path).await?;
|
||||
|
||||
Self::parse(&file).await
|
||||
}
|
||||
|
||||
pub async fn parse(content: &str) -> anyhow::Result<File> {
|
||||
let config: Document = content.parse::<Document>()?;
|
||||
|
||||
Ok(File { doc: config })
|
||||
}
|
||||
|
||||
pub async fn write_file(&self, path: &std::path::Path) -> anyhow::Result<()> {
|
||||
let content = self.write().await?;
|
||||
let mut file = tokio::fs::File::create(path).await?;
|
||||
|
||||
file.write_all(content.as_bytes()).await?;
|
||||
file.sync_all().await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn write(&self) -> anyhow::Result<String> {
|
||||
let content = self.doc.to_string();
|
||||
|
||||
Ok(content)
|
||||
}
|
||||
|
||||
pub fn add_publish(&mut self, schema_path: &str, output_path: &str) -> &mut Self {
|
||||
let mut publish = toml_edit::Table::new();
|
||||
publish["schema-path"] = value(schema_path);
|
||||
publish["output-path"] = value(output_path);
|
||||
|
||||
if !self.doc.contains_key("publish") {
|
||||
self.doc["publish"] = toml_edit::array()
|
||||
}
|
||||
|
||||
self.doc["publish"]
|
||||
.as_array_of_tables_mut()
|
||||
.expect("publish to be present and be array of tables [[publish]]")
|
||||
.push(publish);
|
||||
|
||||
self
|
||||
}
|
||||
|
||||
pub fn get_config(&self) -> anyhow::Result<Config> {
|
||||
let content = self.doc.to_string();
|
||||
|
||||
let config: Config = toml_edit::de::from_str(&content)?;
|
||||
|
||||
Ok(config)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_can_write() -> anyhow::Result<()> {
|
||||
let raw = r#"[service]
|
||||
service = "my-service"
|
||||
domain = "my-domain"
|
||||
codegen = ["rust"]
|
||||
|
||||
[[publish]]
|
||||
schema-path = "schemas/crunch"
|
||||
output-path = "src/crunch"
|
||||
"#;
|
||||
let output = File::parse(raw).await?.write().await?;
|
||||
|
||||
pretty_assertions::assert_eq!(output, raw);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_can_add_publish() -> anyhow::Result<()> {
|
||||
let raw = r#"[service]
|
||||
service = "my-service"
|
||||
domain = "my-domain"
|
||||
codegen = ["rust"]
|
||||
|
||||
[[publish]]
|
||||
schema-path = "schemas/crunch"
|
||||
output-path = "src/crunch"
|
||||
"#;
|
||||
let expected = r#"[service]
|
||||
service = "my-service"
|
||||
domain = "my-domain"
|
||||
codegen = ["rust"]
|
||||
|
||||
[[publish]]
|
||||
schema-path = "schemas/crunch"
|
||||
output-path = "src/crunch"
|
||||
|
||||
[[publish]]
|
||||
schema-path = "some-schema"
|
||||
output-path = "some-output"
|
||||
"#;
|
||||
let mut config = File::parse(raw).await?;
|
||||
let config = config.add_publish("some-schema", "some-output");
|
||||
let output = config.write().await?;
|
||||
|
||||
pretty_assertions::assert_eq!(output, expected);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_can_add_publish_if_none() -> anyhow::Result<()> {
|
||||
let raw = r#"[service]
|
||||
service = "my-service"
|
||||
domain = "my-domain"
|
||||
codegen = ["rust"]
|
||||
"#;
|
||||
let expected = r#"[service]
|
||||
service = "my-service"
|
||||
domain = "my-domain"
|
||||
codegen = ["rust"]
|
||||
|
||||
[[publish]]
|
||||
schema-path = "some-schema"
|
||||
output-path = "some-output"
|
||||
"#;
|
||||
let mut config = File::parse(raw).await?;
|
||||
let config = config.add_publish("some-schema", "some-output");
|
||||
let output = config.write().await?;
|
||||
|
||||
pretty_assertions::assert_eq!(output, expected);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_can_get_config() -> anyhow::Result<()> {
|
||||
let raw = r#"[service]
|
||||
service = "my-service"
|
||||
domain = "my-domain"
|
||||
codegen = ["rust"]
|
||||
"#;
|
||||
|
||||
let config = File::parse(raw).await?.get_config()?;
|
||||
|
||||
pretty_assertions::assert_eq!(
|
||||
config,
|
||||
Config {
|
||||
service: Service {
|
||||
service: "my-service".into(),
|
||||
domain: "my-domain".into(),
|
||||
codegen: vec!["rust".into()]
|
||||
},
|
||||
publish: None
|
||||
}
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_can_get_config_publish() -> anyhow::Result<()> {
|
||||
let raw = r#"[service]
|
||||
service = "my-service"
|
||||
domain = "my-domain"
|
||||
codegen = ["rust"]
|
||||
|
||||
[[publish]]
|
||||
schema-path = "some-schema"
|
||||
output-path = "some-output"
|
||||
"#;
|
||||
|
||||
let config = File::parse(raw).await?.get_config()?;
|
||||
|
||||
pretty_assertions::assert_eq!(
|
||||
config,
|
||||
Config {
|
||||
service: Service {
|
||||
service: "my-service".into(),
|
||||
domain: "my-domain".into(),
|
||||
codegen: vec!["rust".into()]
|
||||
},
|
||||
publish: Some(vec![Publish {
|
||||
schema_path: "some-schema".into(),
|
||||
output_path: "some-output".into()
|
||||
}])
|
||||
}
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user