1use clap::{Parser, Subcommand, ValueEnum};
2use std::path::PathBuf;
3
4#[derive(Parser)]
5#[command(name = "sync-ctl")]
6#[command(version = env!("CARGO_PKG_VERSION"))]
7#[command(about = "Generate Infrastructure as Code from your codebase")]
8#[command(long_about = "A powerful CLI tool that analyzes your codebase and automatically generates optimized Infrastructure as Code configurations including Dockerfiles, Docker Compose files, and Terraform configurations.")]
9pub struct Cli {
10 #[command(subcommand)]
11 pub command: Commands,
12
13 #[arg(short, long, global = true, value_name = "FILE")]
15 pub config: Option<PathBuf>,
16
17 #[arg(short, long, global = true, action = clap::ArgAction::Count)]
19 pub verbose: u8,
20
21 #[arg(short, long, global = true)]
23 pub quiet: bool,
24
25 #[arg(long, global = true)]
27 pub json: bool,
28}
29
30#[derive(Subcommand)]
31pub enum Commands {
32 Analyze {
34 #[arg(value_name = "PROJECT_PATH")]
36 path: PathBuf,
37
38 #[arg(short, long)]
40 json: bool,
41
42 #[arg(short, long)]
44 detailed: bool,
45
46 #[arg(long, value_delimiter = ',')]
48 only: Option<Vec<String>>,
49 },
50
51 Generate {
53 #[arg(value_name = "PROJECT_PATH")]
55 path: PathBuf,
56
57 #[arg(short, long, value_name = "OUTPUT_DIR")]
59 output: Option<PathBuf>,
60
61 #[arg(long)]
63 dockerfile: bool,
64
65 #[arg(long)]
67 compose: bool,
68
69 #[arg(long)]
71 terraform: bool,
72
73 #[arg(long, conflicts_with_all = ["dockerfile", "compose", "terraform"])]
75 all: bool,
76
77 #[arg(long)]
79 dry_run: bool,
80
81 #[arg(long)]
83 force: bool,
84 },
85
86 Validate {
88 #[arg(value_name = "PATH")]
90 path: PathBuf,
91
92 #[arg(long, value_delimiter = ',')]
94 types: Option<Vec<String>>,
95
96 #[arg(long)]
98 fix: bool,
99 },
100
101 Support {
103 #[arg(long)]
105 languages: bool,
106
107 #[arg(long)]
109 frameworks: bool,
110
111 #[arg(short, long)]
113 detailed: bool,
114 },
115
116 Dependencies {
118 #[arg(value_name = "PROJECT_PATH")]
120 path: PathBuf,
121
122 #[arg(long)]
124 licenses: bool,
125
126 #[arg(long)]
128 vulnerabilities: bool,
129
130 #[arg(long, conflicts_with = "dev_only")]
132 prod_only: bool,
133
134 #[arg(long, conflicts_with = "prod_only")]
136 dev_only: bool,
137
138 #[arg(long, value_enum, default_value = "table")]
140 format: OutputFormat,
141 },
142
143 Vulnerabilities {
145 #[arg(default_value = ".")]
147 path: PathBuf,
148
149 #[arg(long, value_enum)]
151 severity: Option<SeverityThreshold>,
152
153 #[arg(long, value_enum, default_value = "table")]
155 format: OutputFormat,
156
157 #[arg(long)]
159 output: Option<PathBuf>,
160 },
161
162 Security {
164 #[arg(value_name = "PROJECT_PATH", default_value = ".")]
166 path: PathBuf,
167
168 #[arg(long)]
170 include_low: bool,
171
172 #[arg(long)]
174 no_secrets: bool,
175
176 #[arg(long)]
178 no_code_patterns: bool,
179
180 #[arg(long, hide = true)]
182 no_infrastructure: bool,
183
184 #[arg(long, hide = true)]
186 no_compliance: bool,
187
188 #[arg(long, value_delimiter = ',', hide = true)]
190 frameworks: Vec<String>,
191
192 #[arg(long, value_enum, default_value = "table")]
194 format: OutputFormat,
195
196 #[arg(long)]
198 output: Option<PathBuf>,
199
200 #[arg(long)]
202 fail_on_findings: bool,
203 },
204}
205
206#[derive(Debug, Clone, Copy, PartialEq, Eq, ValueEnum)]
207pub enum OutputFormat {
208 Table,
209 Json,
210}
211
212#[derive(Debug, Clone, Copy, PartialEq, Eq, ValueEnum)]
213pub enum SeverityThreshold {
214 Low,
215 Medium,
216 High,
217 Critical,
218}
219
220impl Cli {
221 pub fn init_logging(&self) {
223 if self.quiet {
224 return;
225 }
226
227 let level = match self.verbose {
228 0 => log::LevelFilter::Warn,
229 1 => log::LevelFilter::Info,
230 2 => log::LevelFilter::Debug,
231 _ => log::LevelFilter::Trace,
232 };
233
234 env_logger::Builder::from_default_env()
235 .filter_level(level)
236 .init();
237 }
238}