raz_core/
cargo_options.rs

1//! Cargo command options catalog
2//!
3//! This module provides a comprehensive catalog of cargo command options
4//! to enable intelligent override parsing and validation.
5
6use once_cell::sync::Lazy;
7use std::collections::{HashMap, HashSet};
8
9/// Type of cargo option
10#[derive(Debug, Clone, PartialEq)]
11pub enum OptionType {
12    /// Boolean flag (no value)
13    Flag,
14    /// Single value option
15    Single,
16    /// Multiple values (comma-separated)
17    Multiple,
18    /// Can be used multiple times
19    Repeatable,
20}
21
22/// Cargo option metadata
23#[derive(Debug, Clone)]
24pub struct OptionMetadata {
25    /// Option type
26    pub option_type: OptionType,
27    /// Short description
28    pub description: &'static str,
29    /// Conflicts with these options
30    pub conflicts_with: Vec<&'static str>,
31}
32
33/// Catalog of all cargo options
34pub struct CargoOptions {
35    /// Common options for all cargo commands
36    pub common: HashMap<&'static str, OptionMetadata>,
37    /// cargo run specific options
38    pub run: HashMap<&'static str, OptionMetadata>,
39    /// cargo test specific options
40    pub test: HashMap<&'static str, OptionMetadata>,
41    /// cargo build specific options
42    pub build: HashMap<&'static str, OptionMetadata>,
43    /// cargo check specific options
44    pub check: HashMap<&'static str, OptionMetadata>,
45    /// cargo bench specific options
46    pub bench: HashMap<&'static str, OptionMetadata>,
47}
48
49/// Static instance of cargo options catalog
50pub static CARGO_OPTIONS: Lazy<CargoOptions> = Lazy::new(|| {
51    let mut options = CargoOptions {
52        common: HashMap::new(),
53        run: HashMap::new(),
54        test: HashMap::new(),
55        build: HashMap::new(),
56        check: HashMap::new(),
57        bench: HashMap::new(),
58    };
59
60    // Common options for all cargo commands
61    options.common.insert(
62        "--package",
63        OptionMetadata {
64            option_type: OptionType::Single,
65            description: "Package to run",
66            conflicts_with: vec!["--workspace"],
67        },
68    );
69
70    options.common.insert(
71        "-p",
72        OptionMetadata {
73            option_type: OptionType::Single,
74            description: "Alias for --package",
75            conflicts_with: vec!["--workspace"],
76        },
77    );
78
79    options.common.insert(
80        "--workspace",
81        OptionMetadata {
82            option_type: OptionType::Flag,
83            description: "Run for all workspace members",
84            conflicts_with: vec!["--package", "-p"],
85        },
86    );
87
88    options.common.insert(
89        "--exclude",
90        OptionMetadata {
91            option_type: OptionType::Multiple,
92            description: "Exclude packages from the operation",
93            conflicts_with: vec![],
94        },
95    );
96
97    options.common.insert(
98        "--features",
99        OptionMetadata {
100            option_type: OptionType::Multiple,
101            description: "Space or comma separated list of features to activate",
102            conflicts_with: vec!["--all-features"],
103        },
104    );
105
106    options.common.insert(
107        "--all-features",
108        OptionMetadata {
109            option_type: OptionType::Flag,
110            description: "Activate all available features",
111            conflicts_with: vec!["--features", "--no-default-features"],
112        },
113    );
114
115    options.common.insert(
116        "--no-default-features",
117        OptionMetadata {
118            option_type: OptionType::Flag,
119            description: "Do not activate the default feature",
120            conflicts_with: vec![],
121        },
122    );
123
124    options.common.insert(
125        "--release",
126        OptionMetadata {
127            option_type: OptionType::Flag,
128            description: "Build in release mode",
129            conflicts_with: vec!["--debug"],
130        },
131    );
132
133    options.common.insert(
134        "--debug",
135        OptionMetadata {
136            option_type: OptionType::Flag,
137            description: "Build in debug mode (default)",
138            conflicts_with: vec!["--release"],
139        },
140    );
141
142    options.common.insert(
143        "--profile",
144        OptionMetadata {
145            option_type: OptionType::Single,
146            description: "Build with the specified profile",
147            conflicts_with: vec![],
148        },
149    );
150
151    options.common.insert(
152        "--target",
153        OptionMetadata {
154            option_type: OptionType::Single,
155            description: "Build for the target triple",
156            conflicts_with: vec![],
157        },
158    );
159
160    options.common.insert(
161        "--target-dir",
162        OptionMetadata {
163            option_type: OptionType::Single,
164            description: "Directory for all generated artifacts",
165            conflicts_with: vec![],
166        },
167    );
168
169    options.common.insert(
170        "--verbose",
171        OptionMetadata {
172            option_type: OptionType::Flag,
173            description: "Use verbose output",
174            conflicts_with: vec!["--quiet"],
175        },
176    );
177
178    options.common.insert(
179        "-v",
180        OptionMetadata {
181            option_type: OptionType::Flag,
182            description: "Alias for --verbose",
183            conflicts_with: vec!["--quiet", "-q"],
184        },
185    );
186
187    options.common.insert(
188        "--quiet",
189        OptionMetadata {
190            option_type: OptionType::Flag,
191            description: "No output printed to stdout",
192            conflicts_with: vec!["--verbose", "-v"],
193        },
194    );
195
196    options.common.insert(
197        "-q",
198        OptionMetadata {
199            option_type: OptionType::Flag,
200            description: "Alias for --quiet",
201            conflicts_with: vec!["--verbose", "-v"],
202        },
203    );
204
205    options.common.insert(
206        "--color",
207        OptionMetadata {
208            option_type: OptionType::Single,
209            description: "Coloring: auto, always, never",
210            conflicts_with: vec![],
211        },
212    );
213
214    options.common.insert(
215        "--message-format",
216        OptionMetadata {
217            option_type: OptionType::Single,
218            description: "Error format",
219            conflicts_with: vec![],
220        },
221    );
222
223    options.common.insert(
224        "--manifest-path",
225        OptionMetadata {
226            option_type: OptionType::Single,
227            description: "Path to Cargo.toml",
228            conflicts_with: vec![],
229        },
230    );
231
232    options.common.insert(
233        "--frozen",
234        OptionMetadata {
235            option_type: OptionType::Flag,
236            description: "Require Cargo.lock and cache are up to date",
237            conflicts_with: vec!["--locked"],
238        },
239    );
240
241    options.common.insert(
242        "--locked",
243        OptionMetadata {
244            option_type: OptionType::Flag,
245            description: "Require Cargo.lock is up to date",
246            conflicts_with: vec!["--frozen"],
247        },
248    );
249
250    options.common.insert(
251        "--offline",
252        OptionMetadata {
253            option_type: OptionType::Flag,
254            description: "Run without accessing the network",
255            conflicts_with: vec![],
256        },
257    );
258
259    options.common.insert(
260        "-Z",
261        OptionMetadata {
262            option_type: OptionType::Repeatable,
263            description: "Unstable (nightly-only) flags to Cargo",
264            conflicts_with: vec![],
265        },
266    );
267
268    // cargo run specific options
269    options.run.insert(
270        "--bin",
271        OptionMetadata {
272            option_type: OptionType::Single,
273            description: "Name of the bin target to run",
274            conflicts_with: vec!["--example"],
275        },
276    );
277
278    options.run.insert(
279        "--example",
280        OptionMetadata {
281            option_type: OptionType::Single,
282            description: "Name of the example target to run",
283            conflicts_with: vec!["--bin"],
284        },
285    );
286
287    // Framework-specific options (for Dioxus, etc.)
288    // Framework-specific options for Dioxus serve
289    options.run.insert(
290        "--platform",
291        OptionMetadata {
292            option_type: OptionType::Single,
293            description: "Target platform (web, desktop, mobile)",
294            conflicts_with: vec![],
295        },
296    );
297
298    options.run.insert(
299        "--device",
300        OptionMetadata {
301            option_type: OptionType::Single,
302            description: "Build for device (true) or simulator (false)",
303            conflicts_with: vec![],
304        },
305    );
306
307    options.run.insert(
308        "--hot-reload",
309        OptionMetadata {
310            option_type: OptionType::Flag,
311            description: "Enable hot reloading",
312            conflicts_with: vec![],
313        },
314    );
315
316    options.run.insert(
317        "--open",
318        OptionMetadata {
319            option_type: OptionType::Flag,
320            description: "Open the browser on startup",
321            conflicts_with: vec![],
322        },
323    );
324
325    options.run.insert(
326        "--port",
327        OptionMetadata {
328            option_type: OptionType::Single,
329            description: "Port to serve on",
330            conflicts_with: vec![],
331        },
332    );
333
334    options.run.insert(
335        "--host",
336        OptionMetadata {
337            option_type: OptionType::Single,
338            description: "Host to serve on",
339            conflicts_with: vec![],
340        },
341    );
342
343    // cargo test specific options
344    options.test.insert(
345        "--lib",
346        OptionMetadata {
347            option_type: OptionType::Flag,
348            description: "Test only this package's library",
349            conflicts_with: vec!["--bin", "--bins"],
350        },
351    );
352
353    options.test.insert(
354        "--bin",
355        OptionMetadata {
356            option_type: OptionType::Single,
357            description: "Test only the specified binary",
358            conflicts_with: vec!["--lib", "--bins"],
359        },
360    );
361
362    options.test.insert(
363        "--bins",
364        OptionMetadata {
365            option_type: OptionType::Flag,
366            description: "Test all binaries",
367            conflicts_with: vec!["--lib", "--bin"],
368        },
369    );
370
371    options.test.insert(
372        "--example",
373        OptionMetadata {
374            option_type: OptionType::Single,
375            description: "Test only the specified example",
376            conflicts_with: vec!["--examples"],
377        },
378    );
379
380    options.test.insert(
381        "--examples",
382        OptionMetadata {
383            option_type: OptionType::Flag,
384            description: "Test all examples",
385            conflicts_with: vec!["--example"],
386        },
387    );
388
389    options.test.insert(
390        "--test",
391        OptionMetadata {
392            option_type: OptionType::Single,
393            description: "Test only the specified test target",
394            conflicts_with: vec!["--tests"],
395        },
396    );
397
398    options.test.insert(
399        "--tests",
400        OptionMetadata {
401            option_type: OptionType::Flag,
402            description: "Test all tests",
403            conflicts_with: vec!["--test"],
404        },
405    );
406
407    options.test.insert(
408        "--bench",
409        OptionMetadata {
410            option_type: OptionType::Single,
411            description: "Test only the specified bench target",
412            conflicts_with: vec!["--benches"],
413        },
414    );
415
416    options.test.insert(
417        "--benches",
418        OptionMetadata {
419            option_type: OptionType::Flag,
420            description: "Test all benches",
421            conflicts_with: vec!["--bench"],
422        },
423    );
424
425    options.test.insert(
426        "--all-targets",
427        OptionMetadata {
428            option_type: OptionType::Flag,
429            description: "Test all targets",
430            conflicts_with: vec![],
431        },
432    );
433
434    options.test.insert(
435        "--doc",
436        OptionMetadata {
437            option_type: OptionType::Flag,
438            description: "Test only this library's documentation",
439            conflicts_with: vec![],
440        },
441    );
442
443    options.test.insert(
444        "--no-run",
445        OptionMetadata {
446            option_type: OptionType::Flag,
447            description: "Compile, but don't run tests",
448            conflicts_with: vec![],
449        },
450    );
451
452    options.test.insert(
453        "--no-fail-fast",
454        OptionMetadata {
455            option_type: OptionType::Flag,
456            description: "Run all tests regardless of failure",
457            conflicts_with: vec![],
458        },
459    );
460
461    options.test.insert(
462        "-j",
463        OptionMetadata {
464            option_type: OptionType::Single,
465            description: "Number of parallel jobs",
466            conflicts_with: vec![],
467        },
468    );
469
470    options.test.insert(
471        "--jobs",
472        OptionMetadata {
473            option_type: OptionType::Single,
474            description: "Number of parallel jobs",
475            conflicts_with: vec![],
476        },
477    );
478
479    // Framework-specific options (for Dioxus, etc.)
480    options.test.insert(
481        "--platform",
482        OptionMetadata {
483            option_type: OptionType::Single,
484            description: "Target platform (web, desktop, mobile)",
485            conflicts_with: vec![],
486        },
487    );
488
489    // cargo build specific options
490    options.build.insert(
491        "--lib",
492        OptionMetadata {
493            option_type: OptionType::Flag,
494            description: "Build only this package's library",
495            conflicts_with: vec!["--bin", "--bins"],
496        },
497    );
498
499    options.build.insert(
500        "--bin",
501        OptionMetadata {
502            option_type: OptionType::Single,
503            description: "Build only the specified binary",
504            conflicts_with: vec!["--lib", "--bins"],
505        },
506    );
507
508    options.build.insert(
509        "--bins",
510        OptionMetadata {
511            option_type: OptionType::Flag,
512            description: "Build all binaries",
513            conflicts_with: vec!["--lib", "--bin"],
514        },
515    );
516
517    options.build.insert(
518        "--example",
519        OptionMetadata {
520            option_type: OptionType::Single,
521            description: "Build only the specified example",
522            conflicts_with: vec!["--examples"],
523        },
524    );
525
526    options.build.insert(
527        "--examples",
528        OptionMetadata {
529            option_type: OptionType::Flag,
530            description: "Build all examples",
531            conflicts_with: vec!["--example"],
532        },
533    );
534
535    options.build.insert(
536        "--test",
537        OptionMetadata {
538            option_type: OptionType::Single,
539            description: "Build only the specified test target",
540            conflicts_with: vec!["--tests"],
541        },
542    );
543
544    options.build.insert(
545        "--tests",
546        OptionMetadata {
547            option_type: OptionType::Flag,
548            description: "Build all tests",
549            conflicts_with: vec!["--test"],
550        },
551    );
552
553    options.build.insert(
554        "--bench",
555        OptionMetadata {
556            option_type: OptionType::Single,
557            description: "Build only the specified bench target",
558            conflicts_with: vec!["--benches"],
559        },
560    );
561
562    options.build.insert(
563        "--benches",
564        OptionMetadata {
565            option_type: OptionType::Flag,
566            description: "Build all benches",
567            conflicts_with: vec!["--bench"],
568        },
569    );
570
571    options.build.insert(
572        "--all-targets",
573        OptionMetadata {
574            option_type: OptionType::Flag,
575            description: "Build all targets",
576            conflicts_with: vec![],
577        },
578    );
579
580    // cargo check specific options (shares most with build)
581    options.check.insert(
582        "--lib",
583        OptionMetadata {
584            option_type: OptionType::Flag,
585            description: "Check only this package's library",
586            conflicts_with: vec!["--bin", "--bins"],
587        },
588    );
589
590    options.check.insert(
591        "--bin",
592        OptionMetadata {
593            option_type: OptionType::Single,
594            description: "Check only the specified binary",
595            conflicts_with: vec!["--lib", "--bins"],
596        },
597    );
598
599    options.check.insert(
600        "--bins",
601        OptionMetadata {
602            option_type: OptionType::Flag,
603            description: "Check all binaries",
604            conflicts_with: vec!["--lib", "--bin"],
605        },
606    );
607
608    options.check.insert(
609        "--example",
610        OptionMetadata {
611            option_type: OptionType::Single,
612            description: "Check only the specified example",
613            conflicts_with: vec!["--examples"],
614        },
615    );
616
617    options.check.insert(
618        "--examples",
619        OptionMetadata {
620            option_type: OptionType::Flag,
621            description: "Check all examples",
622            conflicts_with: vec!["--example"],
623        },
624    );
625
626    options.check.insert(
627        "--test",
628        OptionMetadata {
629            option_type: OptionType::Single,
630            description: "Check only the specified test target",
631            conflicts_with: vec!["--tests"],
632        },
633    );
634
635    options.check.insert(
636        "--tests",
637        OptionMetadata {
638            option_type: OptionType::Flag,
639            description: "Check all tests",
640            conflicts_with: vec!["--test"],
641        },
642    );
643
644    options.check.insert(
645        "--bench",
646        OptionMetadata {
647            option_type: OptionType::Single,
648            description: "Check only the specified bench target",
649            conflicts_with: vec!["--benches"],
650        },
651    );
652
653    options.check.insert(
654        "--benches",
655        OptionMetadata {
656            option_type: OptionType::Flag,
657            description: "Check all benches",
658            conflicts_with: vec!["--bench"],
659        },
660    );
661
662    options.check.insert(
663        "--all-targets",
664        OptionMetadata {
665            option_type: OptionType::Flag,
666            description: "Check all targets",
667            conflicts_with: vec![],
668        },
669    );
670
671    // cargo bench specific options
672    options.bench.insert(
673        "--lib",
674        OptionMetadata {
675            option_type: OptionType::Flag,
676            description: "Benchmark only this package's library",
677            conflicts_with: vec!["--bin", "--bins"],
678        },
679    );
680
681    options.bench.insert(
682        "--bin",
683        OptionMetadata {
684            option_type: OptionType::Single,
685            description: "Benchmark only the specified binary",
686            conflicts_with: vec!["--lib", "--bins"],
687        },
688    );
689
690    options.bench.insert(
691        "--bins",
692        OptionMetadata {
693            option_type: OptionType::Flag,
694            description: "Benchmark all binaries",
695            conflicts_with: vec!["--lib", "--bin"],
696        },
697    );
698
699    options.bench.insert(
700        "--example",
701        OptionMetadata {
702            option_type: OptionType::Single,
703            description: "Benchmark only the specified example",
704            conflicts_with: vec!["--examples"],
705        },
706    );
707
708    options.bench.insert(
709        "--examples",
710        OptionMetadata {
711            option_type: OptionType::Flag,
712            description: "Benchmark all examples",
713            conflicts_with: vec!["--example"],
714        },
715    );
716
717    options.bench.insert(
718        "--test",
719        OptionMetadata {
720            option_type: OptionType::Single,
721            description: "Benchmark only the specified test target",
722            conflicts_with: vec!["--tests"],
723        },
724    );
725
726    options.bench.insert(
727        "--tests",
728        OptionMetadata {
729            option_type: OptionType::Flag,
730            description: "Benchmark all tests",
731            conflicts_with: vec!["--test"],
732        },
733    );
734
735    options.bench.insert(
736        "--bench",
737        OptionMetadata {
738            option_type: OptionType::Single,
739            description: "Benchmark only the specified bench target",
740            conflicts_with: vec!["--benches"],
741        },
742    );
743
744    options.bench.insert(
745        "--benches",
746        OptionMetadata {
747            option_type: OptionType::Flag,
748            description: "Benchmark all benches",
749            conflicts_with: vec!["--bench"],
750        },
751    );
752
753    options.bench.insert(
754        "--all-targets",
755        OptionMetadata {
756            option_type: OptionType::Flag,
757            description: "Benchmark all targets",
758            conflicts_with: vec![],
759        },
760    );
761
762    options.bench.insert(
763        "--no-run",
764        OptionMetadata {
765            option_type: OptionType::Flag,
766            description: "Compile, but don't run benchmarks",
767            conflicts_with: vec![],
768        },
769    );
770
771    options
772});
773
774impl CargoOptions {
775    /// Get option metadata for a specific command
776    pub fn get_option(&self, command: &str, option: &str) -> Option<&OptionMetadata> {
777        // Check common options first
778        if let Some(metadata) = self.common.get(option) {
779            return Some(metadata);
780        }
781
782        // Check command-specific options
783        match command {
784            "run" => self.run.get(option),
785            "test" => self.test.get(option),
786            "build" => self.build.get(option),
787            "check" => self.check.get(option),
788            "bench" => self.bench.get(option),
789            _ => None,
790        }
791    }
792
793    /// Check if an option is valid for a command
794    pub fn is_valid_option(&self, command: &str, option: &str) -> bool {
795        // First validate that the command is known
796        match command {
797            "run" | "test" | "build" | "check" | "bench" => {
798                self.get_option(command, option).is_some()
799            }
800            _ => false, // Unknown command
801        }
802    }
803
804    /// Get all valid options for a command
805    pub fn get_all_options(&self, command: &str) -> HashSet<&'static str> {
806        let mut options: HashSet<&'static str> = self.common.keys().copied().collect();
807
808        match command {
809            "run" => options.extend(self.run.keys().copied()),
810            "test" => options.extend(self.test.keys().copied()),
811            "build" => options.extend(self.build.keys().copied()),
812            "check" => options.extend(self.check.keys().copied()),
813            "bench" => options.extend(self.bench.keys().copied()),
814            _ => {}
815        }
816
817        options
818    }
819
820    /// Check for option conflicts
821    pub fn check_conflicts<'a>(
822        &self,
823        command: &str,
824        options: &[&'a str],
825    ) -> Vec<(&'a str, &'a str)> {
826        let mut conflicts = Vec::new();
827
828        for (i, &opt1) in options.iter().enumerate() {
829            if let Some(metadata) = self.get_option(command, opt1) {
830                for &opt2 in &options[i + 1..] {
831                    if metadata.conflicts_with.contains(&opt2) {
832                        conflicts.push((opt1, opt2));
833                    }
834                }
835            }
836        }
837
838        conflicts
839    }
840}
841
842#[cfg(test)]
843mod tests {
844    use super::*;
845
846    #[test]
847    fn test_common_options() {
848        let options = &CARGO_OPTIONS;
849        assert!(options.is_valid_option("run", "--features"));
850        assert!(options.is_valid_option("test", "--release"));
851        assert!(options.is_valid_option("bench", "--package"));
852    }
853
854    #[test]
855    fn test_command_specific_options() {
856        let options = &CARGO_OPTIONS;
857        assert!(options.is_valid_option("run", "--bin"));
858        assert!(options.is_valid_option("test", "--doc"));
859        assert!(options.is_valid_option("bench", "--benches"));
860
861        // Cross-command validation
862        assert!(!options.is_valid_option("run", "--doc")); // doc is test-specific
863        assert!(!options.is_valid_option("run", "--no-run")); // no-run is test/bench-specific
864    }
865
866    #[test]
867    fn test_option_conflicts() {
868        let options = &CARGO_OPTIONS;
869        let conflicts = options.check_conflicts("test", &["--lib", "--bin", "--bins"]);
870        assert!(!conflicts.is_empty());
871        assert!(conflicts.contains(&("--lib", "--bin")));
872        assert!(conflicts.contains(&("--lib", "--bins")));
873        assert!(conflicts.contains(&("--bin", "--bins")));
874    }
875}