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(
9 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"
10)]
11pub struct Cli {
12 #[command(subcommand)]
13 pub command: Commands,
14
15 #[arg(short, long, global = true, value_name = "FILE")]
17 pub config: Option<PathBuf>,
18
19 #[arg(short, long, global = true, action = clap::ArgAction::Count)]
21 pub verbose: u8,
22
23 #[arg(short, long, global = true)]
25 pub quiet: bool,
26
27 #[arg(long, global = true)]
29 pub json: bool,
30
31 #[arg(long, global = true)]
33 pub clear_update_cache: bool,
34
35 #[arg(long, global = true)]
37 pub disable_telemetry: bool,
38}
39
40#[derive(Subcommand)]
41pub enum Commands {
42 Analyze {
44 #[arg(value_name = "PROJECT_PATH")]
46 path: PathBuf,
47
48 #[arg(short, long)]
50 json: bool,
51
52 #[arg(short, long, conflicts_with = "display")]
54 detailed: bool,
55
56 #[arg(long, value_enum, default_value = "matrix")]
58 display: Option<DisplayFormat>,
59
60 #[arg(long, value_delimiter = ',')]
62 only: Option<Vec<String>>,
63
64 #[arg(long, value_enum, default_value = "auto")]
66 color_scheme: Option<ColorScheme>,
67 },
68
69 Generate {
71 #[arg(value_name = "PROJECT_PATH")]
73 path: PathBuf,
74
75 #[arg(short, long, value_name = "OUTPUT_DIR")]
77 output: Option<PathBuf>,
78
79 #[arg(long)]
81 dockerfile: bool,
82
83 #[arg(long)]
85 compose: bool,
86
87 #[arg(long)]
89 terraform: bool,
90
91 #[arg(long, conflicts_with_all = ["dockerfile", "compose", "terraform"])]
93 all: bool,
94
95 #[arg(long)]
97 dry_run: bool,
98
99 #[arg(long)]
101 force: bool,
102 },
103
104 Validate {
106 #[arg(value_name = "PATH")]
108 path: PathBuf,
109
110 #[arg(long, value_delimiter = ',')]
112 types: Option<Vec<String>>,
113
114 #[arg(long)]
116 fix: bool,
117 },
118
119 Support {
121 #[arg(long)]
123 languages: bool,
124
125 #[arg(long)]
127 frameworks: bool,
128
129 #[arg(short, long)]
131 detailed: bool,
132 },
133
134 Dependencies {
136 #[arg(value_name = "PROJECT_PATH")]
138 path: PathBuf,
139
140 #[arg(long)]
142 licenses: bool,
143
144 #[arg(long)]
146 vulnerabilities: bool,
147
148 #[arg(long, conflicts_with = "dev_only")]
150 prod_only: bool,
151
152 #[arg(long, conflicts_with = "prod_only")]
154 dev_only: bool,
155
156 #[arg(long, value_enum, default_value = "table")]
158 format: OutputFormat,
159 },
160
161 Vulnerabilities {
163 #[arg(default_value = ".")]
165 path: PathBuf,
166
167 #[arg(long, value_enum)]
169 severity: Option<SeverityThreshold>,
170
171 #[arg(long, value_enum, default_value = "table")]
173 format: OutputFormat,
174
175 #[arg(long)]
177 output: Option<PathBuf>,
178 },
179
180 Security {
182 #[arg(value_name = "PROJECT_PATH", default_value = ".")]
184 path: PathBuf,
185
186 #[arg(long, value_enum, default_value = "thorough")]
188 mode: SecurityScanMode,
189
190 #[arg(long)]
192 include_low: bool,
193
194 #[arg(long)]
196 no_secrets: bool,
197
198 #[arg(long)]
200 no_code_patterns: bool,
201
202 #[arg(long, hide = true)]
204 no_infrastructure: bool,
205
206 #[arg(long, hide = true)]
208 no_compliance: bool,
209
210 #[arg(long, value_delimiter = ',', hide = true)]
212 frameworks: Vec<String>,
213
214 #[arg(long, value_enum, default_value = "table")]
216 format: OutputFormat,
217
218 #[arg(long)]
220 output: Option<PathBuf>,
221
222 #[arg(long)]
224 fail_on_findings: bool,
225 },
226
227 Tools {
229 #[command(subcommand)]
230 command: ToolsCommand,
231 },
232
233 Chat {
235 #[arg(value_name = "PROJECT_PATH", default_value = ".")]
237 path: PathBuf,
238
239 #[arg(long, value_enum)]
241 provider: Option<ChatProvider>,
242
243 #[arg(long)]
245 model: Option<String>,
246
247 #[arg(long)]
249 query: Option<String>,
250
251 #[arg(long)]
253 setup: bool,
254 },
255}
256
257#[derive(Subcommand)]
258pub enum ToolsCommand {
259 Status {
261 #[arg(long, value_enum, default_value = "table")]
263 format: OutputFormat,
264
265 #[arg(long, value_delimiter = ',')]
267 languages: Option<Vec<String>>,
268 },
269
270 Install {
272 #[arg(long, value_delimiter = ',')]
274 languages: Option<Vec<String>>,
275
276 #[arg(long)]
278 include_owasp: bool,
279
280 #[arg(long)]
282 dry_run: bool,
283
284 #[arg(short, long)]
286 yes: bool,
287 },
288
289 Verify {
291 #[arg(long, value_delimiter = ',')]
293 languages: Option<Vec<String>>,
294
295 #[arg(short, long)]
297 detailed: bool,
298 },
299
300 Guide {
302 #[arg(long, value_delimiter = ',')]
304 languages: Option<Vec<String>>,
305
306 #[arg(long)]
308 platform: Option<String>,
309 },
310}
311
312#[derive(Debug, Clone, Copy, PartialEq, Eq, ValueEnum)]
313pub enum OutputFormat {
314 Table,
315 Json,
316}
317
318#[derive(Debug, Clone, Copy, PartialEq, Eq, ValueEnum)]
319pub enum DisplayFormat {
320 Matrix,
322 Detailed,
324 Summary,
326}
327
328#[derive(Clone, Copy, Debug, ValueEnum)]
329pub enum ColorScheme {
330 Auto,
332 Dark,
334 Light,
336}
337
338#[derive(Debug, Clone, Copy, PartialEq, Eq, ValueEnum)]
339pub enum SeverityThreshold {
340 Low,
341 Medium,
342 High,
343 Critical,
344}
345
346#[derive(Debug, Clone, Copy, PartialEq, Eq, ValueEnum)]
347pub enum SecurityScanMode {
348 Lightning,
350 Fast,
352 Balanced,
354 Thorough,
356 Paranoid,
358}
359
360#[derive(Debug, Clone, Copy, PartialEq, Eq, ValueEnum, Default)]
361pub enum ChatProvider {
362 #[default]
364 Openai,
365 Anthropic,
367 Ollama,
369}
370
371impl Cli {
372 pub fn init_logging(&self) {
374 if self.quiet {
375 return;
376 }
377
378 let level = match self.verbose {
379 0 => log::LevelFilter::Warn,
380 1 => log::LevelFilter::Info,
381 2 => log::LevelFilter::Debug,
382 _ => log::LevelFilter::Trace,
383 };
384
385 env_logger::Builder::from_default_env()
386 .filter_level(level)
387 .init();
388 }
389}