1use anyhow::Result;
2use clap::CommandFactory;
3use clap::{error::ErrorKind::ArgumentConflict, Parser};
4use env_logger::Env;
5use log::Level;
6
7use crate::audit;
8use crate::basic_measure::measure;
9use crate::config::bump_epoch;
10use crate::config_cmd;
11use crate::git::git_interop::check_git_version;
12use crate::git::git_interop::{list_commits_with_measurements, prune, pull, push};
13use crate::import::{handle_import, ImportOptions};
14use crate::measurement_storage::{add_to_commit as add, remove_measurements_from_commits};
15use crate::reporting::report;
16use crate::reset;
17use crate::size;
18use crate::stats::ReductionFunc;
19use crate::status;
20use git_perf_cli_types::{Cli, Commands};
21
22pub fn handle_calls() -> Result<()> {
23 let cli = Cli::parse();
24 let logger_level = match cli.verbose {
25 0 => Level::Warn,
26 1 => Level::Info,
27 2 => Level::Debug,
28 _ => Level::Trace,
29 };
30 env_logger::Builder::from_env(Env::default().default_filter_or(logger_level.as_str())).init();
31
32 check_git_version()?;
33
34 match cli.command {
35 Commands::Measure {
36 repetitions,
37 measurement,
38 commit,
39 command,
40 } => {
41 let commit = commit.as_deref().unwrap_or("HEAD");
42 measure(
43 commit,
44 &measurement.name,
45 repetitions,
46 &command,
47 &measurement.key_value,
48 )
49 }
50 Commands::Add {
51 value,
52 measurement,
53 commit,
54 } => {
55 let commit = commit.as_deref().unwrap_or("HEAD");
56 add(commit, &measurement.name, value, &measurement.key_value)
57 }
58 Commands::Import {
59 format,
60 file,
61 commit,
62 prefix,
63 metadata,
64 filter,
65 dry_run,
66 verbose,
67 } => {
68 let commit = commit.as_deref().unwrap_or("HEAD").to_string();
69 handle_import(ImportOptions {
70 commit,
71 format,
72 file,
73 prefix,
74 metadata,
75 filter,
76 dry_run,
77 verbose,
78 })
79 }
80 Commands::Push { remote } => push(None, remote.as_deref()),
81 Commands::Pull {} => pull(None),
82 Commands::Report {
83 commit,
84 output,
85 separate_by,
86 report_history,
87 measurement,
88 key_value,
89 aggregate_by,
90 filter,
91 template,
92 custom_css,
93 title,
94 show_epochs,
95 show_changes,
96 } => {
97 let commit = commit.as_deref().unwrap_or("HEAD");
98
99 let combined_patterns =
101 crate::filter::combine_measurements_and_filters(&measurement, &filter);
102
103 let template_config = crate::reporting::ReportTemplateConfig {
104 template_path: template,
105 custom_css_path: custom_css,
106 title,
107 };
108
109 report(
110 commit,
111 output,
112 separate_by,
113 report_history.max_count,
114 &key_value,
115 aggregate_by.map(ReductionFunc::from),
116 &combined_patterns,
117 template_config,
118 show_epochs,
119 show_changes,
120 )
121 }
122 Commands::Audit {
123 commit,
124 measurement,
125 report_history,
126 selectors,
127 separate_by,
128 min_measurements,
129 aggregate_by,
130 sigma,
131 dispersion_method,
132 filter,
133 no_change_point_warning,
134 } => {
135 let commit = commit.as_deref().unwrap_or("HEAD");
136 if measurement.is_empty() && filter.is_empty() {
139 Cli::command()
140 .error(
141 clap::error::ErrorKind::MissingRequiredArgument,
142 "At least one of --measurement or --filter must be provided",
143 )
144 .exit()
145 }
146
147 if let Some(min_count) = min_measurements {
149 if report_history.max_count < min_count.into() {
150 Cli::command().error(ArgumentConflict, format!("The minimal number of measurements ({}) cannot be more than the maximum number of measurements ({})", min_count, report_history.max_count)).exit()
151 }
152 }
153
154 let combined_patterns =
156 crate::filter::combine_measurements_and_filters(&measurement, &filter);
157
158 audit::audit_multiple(
159 commit,
160 report_history.max_count,
161 min_measurements,
162 &selectors,
163 aggregate_by.map(ReductionFunc::from),
164 sigma,
165 dispersion_method.map(crate::stats::DispersionMethod::from),
166 &combined_patterns,
167 &separate_by,
168 no_change_point_warning,
169 )
170 }
171 Commands::BumpEpoch { measurements } => {
172 for measurement in measurements {
173 bump_epoch(&measurement)?;
174 }
175 Ok(())
176 }
177 Commands::Prune {} => prune(),
178 Commands::Status { detailed } => status::show_status(detailed),
179 Commands::Reset { dry_run, force } => reset::reset_measurements(dry_run, force),
180 Commands::Remove {
181 older_than,
182 no_prune,
183 dry_run,
184 } => remove_measurements_from_commits(older_than, !no_prune, dry_run),
185 Commands::ListCommits {} => {
186 let commits = list_commits_with_measurements()?;
187 for commit in commits {
188 println!("{}", commit);
189 }
190 Ok(())
191 }
192 Commands::Size {
193 detailed,
194 format,
195 disk_size,
196 include_objects,
197 } => size::calculate_measurement_size(detailed, format, disk_size, include_objects),
198 Commands::Config {
199 list,
200 detailed,
201 format,
202 validate,
203 measurement,
204 } => {
205 if list {
206 config_cmd::list_config(detailed, format, validate, measurement)
207 } else {
208 anyhow::bail!("config command requires --list flag (try: git perf config --list)");
211 }
212 }
213 }
214}