dry4rust/
command_dispatcher.rs1use std::path::Path;
7
8use crate::analyzer::LanguageAnalyzer;
9use crate::cli::analysis_output::AnalysisOutput;
10use crate::cli::baseline_command::BaselineCommand;
11use crate::cli::check_command::CheckCommand;
12use crate::cli::checking::check_thresholds::CheckThresholds;
13use crate::cli::cleanup_command::CleanupCommand;
14use crate::cli::cli_error::CliError;
15use crate::cli::cli_error::CliResult;
16use crate::cli::cli_overrides::CliOverrides;
17use crate::cli::command::Command;
18use crate::cli::command_outcome::CommandOutcome;
19use crate::cli::ignore_command::IgnoreCommand;
20use crate::cli::ignored_command::IgnoredCommand;
21use crate::cli::output_format::OutputFormat;
22use crate::cli::report_command::ReportCommand;
23use crate::cli::stats_command::StatsCommand;
24use crate::output::reporter::Reporter;
25
26pub struct CommandDispatcher<'a> {
33 analyzer: &'a dyn LanguageAnalyzer,
34 root: &'a Path,
35 format: OutputFormat,
36 overrides: CliOverrides,
37}
38
39impl<'a> CommandDispatcher<'a> {
40 #[must_use]
41 pub const fn new(
42 analyzer: &'a dyn LanguageAnalyzer,
43 root: &'a Path,
44 format: OutputFormat,
45 overrides: CliOverrides,
46 ) -> Self {
47 Self {
48 analyzer,
49 root,
50 format,
51 overrides,
52 }
53 }
54
55 pub fn dispatch(&self, command: &Command) -> CliResult<CommandOutcome> {
63 match command {
64 Command::Ignore {
65 fingerprint,
66 reason,
67 } => IgnoreCommand::new(self.root, fingerprint, reason.as_deref()).run(),
68 Command::Ignored => IgnoredCommand::new(self.root).run(),
69 _ => self.dispatch_analysed(command),
70 }
71 }
72
73 fn dispatch_analysed(&self, command: &Command) -> CliResult<CommandOutcome> {
74 let output = if matches!(command, Command::Baseline { .. }) {
75 AnalysisOutput::produce_ignoring_baseline(
76 self.analyzer,
77 self.root,
78 self.format,
79 &self.overrides,
80 )?
81 } else {
82 AnalysisOutput::produce(self.analyzer, self.root, self.format, &self.overrides)?
83 };
84 Self::report_warnings(&output);
85 self.render(command, &output)
86 }
87
88 fn report_warnings(output: &AnalysisOutput) {
89 for warning in &output.result.warnings {
90 eprintln!("Warning: {warning}");
91 }
92 }
93
94 fn render(&self, command: &Command, output: &AnalysisOutput) -> CliResult<CommandOutcome> {
95 let reporter: &dyn Reporter = &*output.reporter;
96 match command {
97 Command::Stats => StatsCommand::new(&output.result, reporter).run(),
98 Command::Report => ReportCommand::new(&output.result, reporter).run(),
99 Command::Check {
100 max_exact,
101 max_near,
102 max_exact_percent,
103 max_near_percent,
104 } => {
105 let thresholds = CheckThresholds::new(
106 *max_exact,
107 *max_near,
108 *max_exact_percent,
109 *max_near_percent,
110 )
111 .map_err(|e| CliError::InvalidConfig(e.to_string()))?;
112 CheckCommand::new(&output.config, &output.result, reporter, &thresholds).run()
113 }
114 Command::Cleanup { dry_run } => {
115 CleanupCommand::new(self.root, &output.result, *dry_run).run()
116 }
117 Command::Baseline { dry_run } => {
118 BaselineCommand::new(self.root, &output.config, &output.result, *dry_run).run()
119 }
120 Command::Ignore { .. } | Command::Ignored => unreachable!(),
121 }
122 }
123}