greentic_component/
cli.rs

1use anyhow::{Error, Result, bail};
2use clap::{Parser, Subcommand};
3
4use crate::cmd::{
5    self, build::BuildArgs, doctor::DoctorArgs, flow::FlowCommand, hash::HashArgs,
6    inspect::InspectArgs, new::NewArgs, store::StoreCommand, templates::TemplatesArgs,
7};
8use crate::scaffold::engine::ScaffoldEngine;
9
10#[derive(Parser, Debug)]
11#[command(
12    name = "greentic-component",
13    about = "Toolkit for Greentic component developers",
14    version,
15    propagate_version = true,
16    arg_required_else_help = true,
17    disable_version_flag = true
18)]
19pub struct Cli {
20    #[command(subcommand)]
21    command: Commands,
22}
23
24#[derive(Subcommand, Debug)]
25enum Commands {
26    /// Scaffold a new Greentic component project
27    New(NewArgs),
28    /// List available component templates
29    Templates(TemplatesArgs),
30    /// Run component doctor checks
31    Doctor(DoctorArgs),
32    /// Inspect manifests and describe payloads
33    Inspect(InspectArgs),
34    /// Recompute manifest hashes
35    Hash(HashArgs),
36    /// Build component wasm + update config flows
37    Build(BuildArgs),
38    /// Flow utilities (config flow regeneration)
39    #[command(subcommand)]
40    Flow(FlowCommand),
41    /// Interact with the component store
42    #[command(subcommand)]
43    Store(StoreCommand),
44}
45
46pub fn main() -> Result<()> {
47    let cli = Cli::parse();
48    let engine = ScaffoldEngine::new();
49    match cli.command {
50        Commands::New(args) => cmd::new::run(args, &engine),
51        Commands::Templates(args) => cmd::templates::run(args, &engine),
52        Commands::Doctor(args) => cmd::doctor::run(args).map_err(Error::new),
53        Commands::Inspect(args) => {
54            let result = cmd::inspect::run(&args)?;
55            cmd::inspect::emit_warnings(&result.warnings);
56            if args.strict && !result.warnings.is_empty() {
57                bail!(
58                    "component-inspect: {} warning(s) treated as errors (--strict)",
59                    result.warnings.len()
60                );
61            }
62            Ok(())
63        }
64        Commands::Hash(args) => cmd::hash::run(args),
65        Commands::Build(args) => cmd::build::run(args),
66        Commands::Flow(flow_cmd) => cmd::flow::run(flow_cmd),
67        Commands::Store(store_cmd) => cmd::store::run(store_cmd),
68    }
69}
70
71#[cfg(test)]
72mod tests {
73    use super::*;
74
75    #[test]
76    fn parses_new_subcommand() {
77        let cli = Cli::try_parse_from(["greentic-component", "new", "--name", "demo", "--json"])
78            .expect("expected CLI to parse");
79        match cli.command {
80            Commands::New(args) => {
81                assert_eq!(args.name, "demo");
82                assert!(args.json);
83                assert!(!args.no_check);
84                assert!(!args.no_git);
85            }
86            _ => panic!("expected new args"),
87        }
88    }
89}