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, conflicts_with = "display")]
44 detailed: bool,
45
46 #[arg(long, value_enum, default_value = "matrix")]
48 display: Option<DisplayFormat>,
49
50 #[arg(long, value_delimiter = ',')]
52 only: Option<Vec<String>>,
53 },
54
55 Generate {
57 #[arg(value_name = "PROJECT_PATH")]
59 path: PathBuf,
60
61 #[arg(short, long, value_name = "OUTPUT_DIR")]
63 output: Option<PathBuf>,
64
65 #[arg(long)]
67 dockerfile: bool,
68
69 #[arg(long)]
71 compose: bool,
72
73 #[arg(long)]
75 terraform: bool,
76
77 #[arg(long, conflicts_with_all = ["dockerfile", "compose", "terraform"])]
79 all: bool,
80
81 #[arg(long)]
83 dry_run: bool,
84
85 #[arg(long)]
87 force: bool,
88 },
89
90 Validate {
92 #[arg(value_name = "PATH")]
94 path: PathBuf,
95
96 #[arg(long, value_delimiter = ',')]
98 types: Option<Vec<String>>,
99
100 #[arg(long)]
102 fix: bool,
103 },
104
105 Support {
107 #[arg(long)]
109 languages: bool,
110
111 #[arg(long)]
113 frameworks: bool,
114
115 #[arg(short, long)]
117 detailed: bool,
118 },
119
120 Dependencies {
122 #[arg(value_name = "PROJECT_PATH")]
124 path: PathBuf,
125
126 #[arg(long)]
128 licenses: bool,
129
130 #[arg(long)]
132 vulnerabilities: bool,
133
134 #[arg(long, conflicts_with = "dev_only")]
136 prod_only: bool,
137
138 #[arg(long, conflicts_with = "prod_only")]
140 dev_only: bool,
141
142 #[arg(long, value_enum, default_value = "table")]
144 format: OutputFormat,
145 },
146
147 Vulnerabilities {
149 #[arg(default_value = ".")]
151 path: PathBuf,
152
153 #[arg(long, value_enum)]
155 severity: Option<SeverityThreshold>,
156
157 #[arg(long, value_enum, default_value = "table")]
159 format: OutputFormat,
160
161 #[arg(long)]
163 output: Option<PathBuf>,
164 },
165
166 Security {
168 #[arg(value_name = "PROJECT_PATH", default_value = ".")]
170 path: PathBuf,
171
172 #[arg(long)]
174 include_low: bool,
175
176 #[arg(long)]
178 no_secrets: bool,
179
180 #[arg(long)]
182 no_code_patterns: bool,
183
184 #[arg(long, hide = true)]
186 no_infrastructure: bool,
187
188 #[arg(long, hide = true)]
190 no_compliance: bool,
191
192 #[arg(long, value_delimiter = ',', hide = true)]
194 frameworks: Vec<String>,
195
196 #[arg(long, value_enum, default_value = "table")]
198 format: OutputFormat,
199
200 #[arg(long)]
202 output: Option<PathBuf>,
203
204 #[arg(long)]
206 fail_on_findings: bool,
207 },
208
209 Tools {
211 #[command(subcommand)]
212 command: ToolsCommand,
213 },
214}
215
216#[derive(Subcommand)]
217pub enum ToolsCommand {
218 Status {
220 #[arg(long, value_enum, default_value = "table")]
222 format: OutputFormat,
223
224 #[arg(long, value_delimiter = ',')]
226 languages: Option<Vec<String>>,
227 },
228
229 Install {
231 #[arg(long, value_delimiter = ',')]
233 languages: Option<Vec<String>>,
234
235 #[arg(long)]
237 include_owasp: bool,
238
239 #[arg(long)]
241 dry_run: bool,
242
243 #[arg(short, long)]
245 yes: bool,
246 },
247
248 Verify {
250 #[arg(long, value_delimiter = ',')]
252 languages: Option<Vec<String>>,
253
254 #[arg(short, long)]
256 verbose: bool,
257 },
258
259 Guide {
261 #[arg(long, value_delimiter = ',')]
263 languages: Option<Vec<String>>,
264
265 #[arg(long)]
267 platform: Option<String>,
268 },
269}
270
271#[derive(Debug, Clone, Copy, PartialEq, Eq, ValueEnum)]
272pub enum OutputFormat {
273 Table,
274 Json,
275}
276
277#[derive(Debug, Clone, Copy, PartialEq, Eq, ValueEnum)]
278pub enum DisplayFormat {
279 Matrix,
281 Detailed,
283 Summary,
285}
286
287#[derive(Debug, Clone, Copy, PartialEq, Eq, ValueEnum)]
288pub enum SeverityThreshold {
289 Low,
290 Medium,
291 High,
292 Critical,
293}
294
295impl Cli {
296 pub fn init_logging(&self) {
298 if self.quiet {
299 return;
300 }
301
302 let level = match self.verbose {
303 0 => log::LevelFilter::Warn,
304 1 => log::LevelFilter::Info,
305 2 => log::LevelFilter::Debug,
306 _ => log::LevelFilter::Trace,
307 };
308
309 env_logger::Builder::from_default_env()
310 .filter_level(level)
311 .init();
312 }
313}