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
61 Generate {
63 #[arg(value_name = "PROJECT_PATH")]
65 path: PathBuf,
66
67 #[arg(short, long, value_name = "OUTPUT_DIR")]
69 output: Option<PathBuf>,
70
71 #[arg(long)]
73 dockerfile: bool,
74
75 #[arg(long)]
77 compose: bool,
78
79 #[arg(long)]
81 terraform: bool,
82
83 #[arg(long, conflicts_with_all = ["dockerfile", "compose", "terraform"])]
85 all: bool,
86
87 #[arg(long)]
89 dry_run: bool,
90
91 #[arg(long)]
93 force: bool,
94 },
95
96 Validate {
98 #[arg(value_name = "PATH")]
100 path: PathBuf,
101
102 #[arg(long, value_delimiter = ',')]
104 types: Option<Vec<String>>,
105
106 #[arg(long)]
108 fix: bool,
109 },
110
111 Support {
113 #[arg(long)]
115 languages: bool,
116
117 #[arg(long)]
119 frameworks: bool,
120
121 #[arg(short, long)]
123 detailed: bool,
124 },
125
126 Dependencies {
128 #[arg(value_name = "PROJECT_PATH")]
130 path: PathBuf,
131
132 #[arg(long)]
134 licenses: bool,
135
136 #[arg(long)]
138 vulnerabilities: bool,
139
140 #[arg(long, conflicts_with = "dev_only")]
142 prod_only: bool,
143
144 #[arg(long, conflicts_with = "prod_only")]
146 dev_only: bool,
147
148 #[arg(long, value_enum, default_value = "table")]
150 format: OutputFormat,
151 },
152
153 Vulnerabilities {
155 #[arg(default_value = ".")]
157 path: PathBuf,
158
159 #[arg(long, value_enum)]
161 severity: Option<SeverityThreshold>,
162
163 #[arg(long, value_enum, default_value = "table")]
165 format: OutputFormat,
166
167 #[arg(long)]
169 output: Option<PathBuf>,
170 },
171
172 Security {
174 #[arg(value_name = "PROJECT_PATH", default_value = ".")]
176 path: PathBuf,
177
178 #[arg(long, value_enum, default_value = "thorough")]
180 mode: SecurityScanMode,
181
182 #[arg(long)]
184 include_low: bool,
185
186 #[arg(long)]
188 no_secrets: bool,
189
190 #[arg(long)]
192 no_code_patterns: bool,
193
194 #[arg(long, hide = true)]
196 no_infrastructure: bool,
197
198 #[arg(long, hide = true)]
200 no_compliance: bool,
201
202 #[arg(long, value_delimiter = ',', hide = true)]
204 frameworks: Vec<String>,
205
206 #[arg(long, value_enum, default_value = "table")]
208 format: OutputFormat,
209
210 #[arg(long)]
212 output: Option<PathBuf>,
213
214 #[arg(long)]
216 fail_on_findings: bool,
217 },
218
219 Tools {
221 #[command(subcommand)]
222 command: ToolsCommand,
223 },
224}
225
226#[derive(Subcommand)]
227pub enum ToolsCommand {
228 Status {
230 #[arg(long, value_enum, default_value = "table")]
232 format: OutputFormat,
233
234 #[arg(long, value_delimiter = ',')]
236 languages: Option<Vec<String>>,
237 },
238
239 Install {
241 #[arg(long, value_delimiter = ',')]
243 languages: Option<Vec<String>>,
244
245 #[arg(long)]
247 include_owasp: bool,
248
249 #[arg(long)]
251 dry_run: bool,
252
253 #[arg(short, long)]
255 yes: bool,
256 },
257
258 Verify {
260 #[arg(long, value_delimiter = ',')]
262 languages: Option<Vec<String>>,
263
264 #[arg(short, long)]
266 verbose: bool,
267 },
268
269 Guide {
271 #[arg(long, value_delimiter = ',')]
273 languages: Option<Vec<String>>,
274
275 #[arg(long)]
277 platform: Option<String>,
278 },
279}
280
281#[derive(Debug, Clone, Copy, PartialEq, Eq, ValueEnum)]
282pub enum OutputFormat {
283 Table,
284 Json,
285}
286
287#[derive(Debug, Clone, Copy, PartialEq, Eq, ValueEnum)]
288pub enum DisplayFormat {
289 Matrix,
291 Detailed,
293 Summary,
295}
296
297#[derive(Debug, Clone, Copy, PartialEq, Eq, ValueEnum)]
298pub enum SeverityThreshold {
299 Low,
300 Medium,
301 High,
302 Critical,
303}
304
305#[derive(Debug, Clone, Copy, PartialEq, Eq, ValueEnum)]
306pub enum SecurityScanMode {
307 Lightning,
309 Fast,
311 Balanced,
313 Thorough,
315 Paranoid,
317}
318
319impl Cli {
320 pub fn init_logging(&self) {
322 if self.quiet {
323 return;
324 }
325
326 let level = match self.verbose {
327 0 => log::LevelFilter::Warn,
328 1 => log::LevelFilter::Info,
329 2 => log::LevelFilter::Debug,
330 _ => log::LevelFilter::Trace,
331 };
332
333 env_logger::Builder::from_default_env()
334 .filter_level(level)
335 .init();
336 }
337}