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
36#[derive(Subcommand)]
37pub enum Commands {
38 Analyze {
40 #[arg(value_name = "PROJECT_PATH")]
42 path: PathBuf,
43
44 #[arg(short, long)]
46 json: bool,
47
48 #[arg(short, long, conflicts_with = "display")]
50 detailed: bool,
51
52 #[arg(long, value_enum, default_value = "matrix")]
54 display: Option<DisplayFormat>,
55
56 #[arg(long, value_delimiter = ',')]
58 only: Option<Vec<String>>,
59
60 #[arg(long, value_enum, default_value = "auto")]
62 color_scheme: Option<ColorScheme>,
63 },
64
65 Generate {
67 #[arg(value_name = "PROJECT_PATH")]
69 path: PathBuf,
70
71 #[arg(short, long, value_name = "OUTPUT_DIR")]
73 output: Option<PathBuf>,
74
75 #[arg(long)]
77 dockerfile: bool,
78
79 #[arg(long)]
81 compose: bool,
82
83 #[arg(long)]
85 terraform: bool,
86
87 #[arg(long, conflicts_with_all = ["dockerfile", "compose", "terraform"])]
89 all: bool,
90
91 #[arg(long)]
93 dry_run: bool,
94
95 #[arg(long)]
97 force: bool,
98 },
99
100 Validate {
102 #[arg(value_name = "PATH")]
104 path: PathBuf,
105
106 #[arg(long, value_delimiter = ',')]
108 types: Option<Vec<String>>,
109
110 #[arg(long)]
112 fix: bool,
113 },
114
115 Support {
117 #[arg(long)]
119 languages: bool,
120
121 #[arg(long)]
123 frameworks: bool,
124
125 #[arg(short, long)]
127 detailed: bool,
128 },
129
130 Dependencies {
132 #[arg(value_name = "PROJECT_PATH")]
134 path: PathBuf,
135
136 #[arg(long)]
138 licenses: bool,
139
140 #[arg(long)]
142 vulnerabilities: bool,
143
144 #[arg(long, conflicts_with = "dev_only")]
146 prod_only: bool,
147
148 #[arg(long, conflicts_with = "prod_only")]
150 dev_only: bool,
151
152 #[arg(long, value_enum, default_value = "table")]
154 format: OutputFormat,
155 },
156
157 Vulnerabilities {
159 #[arg(default_value = ".")]
161 path: PathBuf,
162
163 #[arg(long, value_enum)]
165 severity: Option<SeverityThreshold>,
166
167 #[arg(long, value_enum, default_value = "table")]
169 format: OutputFormat,
170
171 #[arg(long)]
173 output: Option<PathBuf>,
174 },
175
176 Security {
178 #[arg(value_name = "PROJECT_PATH", default_value = ".")]
180 path: PathBuf,
181
182 #[arg(long, value_enum, default_value = "thorough")]
184 mode: SecurityScanMode,
185
186 #[arg(long)]
188 include_low: bool,
189
190 #[arg(long)]
192 no_secrets: bool,
193
194 #[arg(long)]
196 no_code_patterns: bool,
197
198 #[arg(long, hide = true)]
200 no_infrastructure: bool,
201
202 #[arg(long, hide = true)]
204 no_compliance: bool,
205
206 #[arg(long, value_delimiter = ',', hide = true)]
208 frameworks: Vec<String>,
209
210 #[arg(long, value_enum, default_value = "table")]
212 format: OutputFormat,
213
214 #[arg(long)]
216 output: Option<PathBuf>,
217
218 #[arg(long)]
220 fail_on_findings: bool,
221 },
222
223 Tools {
225 #[command(subcommand)]
226 command: ToolsCommand,
227 },
228}
229
230#[derive(Subcommand)]
231pub enum ToolsCommand {
232 Status {
234 #[arg(long, value_enum, default_value = "table")]
236 format: OutputFormat,
237
238 #[arg(long, value_delimiter = ',')]
240 languages: Option<Vec<String>>,
241 },
242
243 Install {
245 #[arg(long, value_delimiter = ',')]
247 languages: Option<Vec<String>>,
248
249 #[arg(long)]
251 include_owasp: bool,
252
253 #[arg(long)]
255 dry_run: bool,
256
257 #[arg(short, long)]
259 yes: bool,
260 },
261
262 Verify {
264 #[arg(long, value_delimiter = ',')]
266 languages: Option<Vec<String>>,
267
268 #[arg(short, long)]
270 verbose: bool,
271 },
272
273 Guide {
275 #[arg(long, value_delimiter = ',')]
277 languages: Option<Vec<String>>,
278
279 #[arg(long)]
281 platform: Option<String>,
282 },
283}
284
285#[derive(Debug, Clone, Copy, PartialEq, Eq, ValueEnum)]
286pub enum OutputFormat {
287 Table,
288 Json,
289}
290
291#[derive(Debug, Clone, Copy, PartialEq, Eq, ValueEnum)]
292pub enum DisplayFormat {
293 Matrix,
295 Detailed,
297 Summary,
299}
300
301#[derive(Clone, Copy, Debug, ValueEnum)]
302pub enum ColorScheme {
303 Auto,
305 Dark,
307 Light,
309}
310
311#[derive(Debug, Clone, Copy, PartialEq, Eq, ValueEnum)]
312pub enum SeverityThreshold {
313 Low,
314 Medium,
315 High,
316 Critical,
317}
318
319#[derive(Debug, Clone, Copy, PartialEq, Eq, ValueEnum)]
320pub enum SecurityScanMode {
321 Lightning,
323 Fast,
325 Balanced,
327 Thorough,
329 Paranoid,
331}
332
333impl Cli {
334 pub fn init_logging(&self) {
336 if self.quiet {
337 return;
338 }
339
340 let level = match self.verbose {
341 0 => log::LevelFilter::Warn,
342 1 => log::LevelFilter::Info,
343 2 => log::LevelFilter::Debug,
344 _ => log::LevelFilter::Trace,
345 };
346
347 env_logger::Builder::from_default_env()
348 .filter_level(level)
349 .init();
350 }
351}