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 #[arg(long, global = true)]
31 pub clear_update_cache: bool,
32}
33
34#[derive(Subcommand)]
35pub enum Commands {
36 Analyze {
38 #[arg(value_name = "PROJECT_PATH")]
40 path: PathBuf,
41
42 #[arg(short, long)]
44 json: bool,
45
46 #[arg(short, long, conflicts_with = "display")]
48 detailed: bool,
49
50 #[arg(long, value_enum, default_value = "matrix")]
52 display: Option<DisplayFormat>,
53
54 #[arg(long, value_delimiter = ',')]
56 only: Option<Vec<String>>,
57 },
58
59 Generate {
61 #[arg(value_name = "PROJECT_PATH")]
63 path: PathBuf,
64
65 #[arg(short, long, value_name = "OUTPUT_DIR")]
67 output: Option<PathBuf>,
68
69 #[arg(long)]
71 dockerfile: bool,
72
73 #[arg(long)]
75 compose: bool,
76
77 #[arg(long)]
79 terraform: bool,
80
81 #[arg(long, conflicts_with_all = ["dockerfile", "compose", "terraform"])]
83 all: bool,
84
85 #[arg(long)]
87 dry_run: bool,
88
89 #[arg(long)]
91 force: bool,
92 },
93
94 Validate {
96 #[arg(value_name = "PATH")]
98 path: PathBuf,
99
100 #[arg(long, value_delimiter = ',')]
102 types: Option<Vec<String>>,
103
104 #[arg(long)]
106 fix: bool,
107 },
108
109 Support {
111 #[arg(long)]
113 languages: bool,
114
115 #[arg(long)]
117 frameworks: bool,
118
119 #[arg(short, long)]
121 detailed: bool,
122 },
123
124 Dependencies {
126 #[arg(value_name = "PROJECT_PATH")]
128 path: PathBuf,
129
130 #[arg(long)]
132 licenses: bool,
133
134 #[arg(long)]
136 vulnerabilities: bool,
137
138 #[arg(long, conflicts_with = "dev_only")]
140 prod_only: bool,
141
142 #[arg(long, conflicts_with = "prod_only")]
144 dev_only: bool,
145
146 #[arg(long, value_enum, default_value = "table")]
148 format: OutputFormat,
149 },
150
151 Vulnerabilities {
153 #[arg(default_value = ".")]
155 path: PathBuf,
156
157 #[arg(long, value_enum)]
159 severity: Option<SeverityThreshold>,
160
161 #[arg(long, value_enum, default_value = "table")]
163 format: OutputFormat,
164
165 #[arg(long)]
167 output: Option<PathBuf>,
168 },
169
170 Security {
172 #[arg(value_name = "PROJECT_PATH", default_value = ".")]
174 path: PathBuf,
175
176 #[arg(long, value_enum, default_value = "thorough")]
178 mode: SecurityScanMode,
179
180 #[arg(long)]
182 include_low: bool,
183
184 #[arg(long)]
186 no_secrets: bool,
187
188 #[arg(long)]
190 no_code_patterns: bool,
191
192 #[arg(long, hide = true)]
194 no_infrastructure: bool,
195
196 #[arg(long, hide = true)]
198 no_compliance: bool,
199
200 #[arg(long, value_delimiter = ',', hide = true)]
202 frameworks: Vec<String>,
203
204 #[arg(long, value_enum, default_value = "table")]
206 format: OutputFormat,
207
208 #[arg(long)]
210 output: Option<PathBuf>,
211
212 #[arg(long)]
214 fail_on_findings: bool,
215 },
216
217 Tools {
219 #[command(subcommand)]
220 command: ToolsCommand,
221 },
222}
223
224#[derive(Subcommand)]
225pub enum ToolsCommand {
226 Status {
228 #[arg(long, value_enum, default_value = "table")]
230 format: OutputFormat,
231
232 #[arg(long, value_delimiter = ',')]
234 languages: Option<Vec<String>>,
235 },
236
237 Install {
239 #[arg(long, value_delimiter = ',')]
241 languages: Option<Vec<String>>,
242
243 #[arg(long)]
245 include_owasp: bool,
246
247 #[arg(long)]
249 dry_run: bool,
250
251 #[arg(short, long)]
253 yes: bool,
254 },
255
256 Verify {
258 #[arg(long, value_delimiter = ',')]
260 languages: Option<Vec<String>>,
261
262 #[arg(short, long)]
264 verbose: bool,
265 },
266
267 Guide {
269 #[arg(long, value_delimiter = ',')]
271 languages: Option<Vec<String>>,
272
273 #[arg(long)]
275 platform: Option<String>,
276 },
277}
278
279#[derive(Debug, Clone, Copy, PartialEq, Eq, ValueEnum)]
280pub enum OutputFormat {
281 Table,
282 Json,
283}
284
285#[derive(Debug, Clone, Copy, PartialEq, Eq, ValueEnum)]
286pub enum DisplayFormat {
287 Matrix,
289 Detailed,
291 Summary,
293}
294
295#[derive(Debug, Clone, Copy, PartialEq, Eq, ValueEnum)]
296pub enum SeverityThreshold {
297 Low,
298 Medium,
299 High,
300 Critical,
301}
302
303#[derive(Debug, Clone, Copy, PartialEq, Eq, ValueEnum)]
304pub enum SecurityScanMode {
305 Lightning,
307 Fast,
309 Balanced,
311 Thorough,
313 Paranoid,
315}
316
317impl Cli {
318 pub fn init_logging(&self) {
320 if self.quiet {
321 return;
322 }
323
324 let level = match self.verbose {
325 0 => log::LevelFilter::Warn,
326 1 => log::LevelFilter::Info,
327 2 => log::LevelFilter::Debug,
328 _ => log::LevelFilter::Trace,
329 };
330
331 env_logger::Builder::from_default_env()
332 .filter_level(level)
333 .init();
334 }
335}