1#![forbid(unsafe_code)]
2
3use std::path::PathBuf;
4
5use anyhow::Result;
6use clap::Parser;
7use greentic_flow::compile_ygtc_str;
8use tracing::info;
9
10use crate::config::load_pack_config;
11
12#[derive(Debug, Parser)]
13pub struct LintArgs {
14 #[arg(long = "in", value_name = "DIR")]
16 pub input: PathBuf,
17
18 #[arg(long = "allow-oci-tags", default_value_t = false)]
20 pub allow_oci_tags: bool,
21}
22
23pub fn handle(args: LintArgs, json: bool) -> Result<()> {
24 let pack_dir = normalize(args.input);
25 info!(path = %pack_dir.display(), "linting pack");
26
27 let cfg = load_pack_config(&pack_dir)?;
28 crate::extensions::validate_components_extension(&cfg.extensions, args.allow_oci_tags)?;
29
30 let mut compiled = 0usize;
31 for flow in &cfg.flows {
32 let src = std::fs::read_to_string(&flow.file)?;
33 compile_ygtc_str(&src)?;
34 compiled += 1;
35 }
36
37 if json {
38 println!(
39 "{}",
40 serde_json::to_string_pretty(&serde_json::json!({
41 "status": "ok",
42 "pack_id": cfg.pack_id,
43 "version": cfg.version,
44 "flows": compiled,
45 "components": cfg.components.len(),
46 "dependencies": cfg.dependencies.len(),
47 }))?
48 );
49 } else {
50 println!(
51 "lint ok\n pack: {}@{}\n flows: {}\n components: {}\n dependencies: {}",
52 cfg.pack_id,
53 cfg.version,
54 compiled,
55 cfg.components.len(),
56 cfg.dependencies.len()
57 );
58 }
59
60 Ok(())
61}
62
63fn normalize(path: PathBuf) -> PathBuf {
64 if path.is_absolute() {
65 path
66 } else {
67 std::env::current_dir()
68 .unwrap_or_else(|_| PathBuf::from("."))
69 .join(path)
70 }
71}