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 report_history.since.as_deref(),
115 report_history.until.as_deref(),
116 &key_value,
117 aggregate_by.map(ReductionFunc::from),
118 &combined_patterns,
119 template_config,
120 show_epochs,
121 show_changes,
122 )
123 }
124 Commands::Audit {
125 commit,
126 measurement,
127 report_history,
128 selectors,
129 separate_by,
130 min_measurements,
131 aggregate_by,
132 sigma,
133 dispersion_method,
134 filter,
135 no_change_point_warning,
136 } => {
137 let commit = commit.as_deref().unwrap_or("HEAD");
138 if measurement.is_empty() && filter.is_empty() {
141 Cli::command()
142 .error(
143 clap::error::ErrorKind::MissingRequiredArgument,
144 "At least one of --measurement or --filter must be provided",
145 )
146 .exit()
147 }
148
149 if let Some(min_count) = min_measurements {
151 if report_history.max_count < min_count.into() {
152 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()
153 }
154 }
155
156 let combined_patterns =
158 crate::filter::combine_measurements_and_filters(&measurement, &filter);
159
160 audit::audit_multiple(
161 commit,
162 report_history.max_count,
163 report_history.since.as_deref(),
164 report_history.until.as_deref(),
165 min_measurements,
166 &selectors,
167 aggregate_by.map(ReductionFunc::from),
168 sigma,
169 dispersion_method.map(crate::stats::DispersionMethod::from),
170 &combined_patterns,
171 &separate_by,
172 no_change_point_warning,
173 )
174 }
175 Commands::BumpEpoch { measurements } => {
176 for measurement in measurements {
177 bump_epoch(&measurement)?;
178 }
179 Ok(())
180 }
181 Commands::Prune {} => prune(),
182 Commands::Status { detailed } => status::show_status(detailed),
183 Commands::Reset { dry_run, force } => reset::reset_measurements(dry_run, force),
184 Commands::Remove {
185 older_than,
186 no_prune,
187 dry_run,
188 } => remove_measurements_from_commits(older_than, !no_prune, dry_run),
189 Commands::ListCommits {} => {
190 let commits = list_commits_with_measurements()?;
191 for commit in commits {
192 println!("{}", commit);
193 }
194 Ok(())
195 }
196 Commands::Size {
197 detailed,
198 format,
199 disk_size,
200 include_objects,
201 } => size::calculate_measurement_size(detailed, format, disk_size, include_objects),
202 Commands::Config {
203 list,
204 detailed,
205 format,
206 validate,
207 measurement,
208 } => {
209 if list {
210 config_cmd::list_config(detailed, format, validate, measurement)
211 } else {
212 anyhow::bail!("config command requires --list flag (try: git perf config --list)");
215 }
216 }
217 }
218}