CliRunner: replace start hook by dispatch hook

The `CliRunner` lets a custom binary add processing that should happen
before running a command. This patch replaces that by a hook that can
do processing before and/or after. I thought I would want to use this
for adding telemetry (such as timings) to our custom binary at
Google. I ended up adding that logging outside of `CliRunner::run()`
instead, so it gives a more accurate timing of the whole invocation. I
think this patch is still an improvement, as it's more generic than
the start hook.
This commit is contained in:
Martin von Zweigbergk 2025-04-27 07:41:44 -07:00
parent 517292fd46
commit 4435fae3be

View File

@ -3656,11 +3656,14 @@ pub struct CliRunner {
commit_template_extensions: Vec<Arc<dyn CommitTemplateLanguageExtension>>, commit_template_extensions: Vec<Arc<dyn CommitTemplateLanguageExtension>>,
operation_template_extensions: Vec<Arc<dyn OperationTemplateLanguageExtension>>, operation_template_extensions: Vec<Arc<dyn OperationTemplateLanguageExtension>>,
dispatch_fn: CliDispatchFn, dispatch_fn: CliDispatchFn,
start_hook_fns: Vec<CliDispatchFn>, dispatch_hook_fns: Vec<CliDispatchHookFn>,
process_global_args_fns: Vec<ProcessGlobalArgsFn>, process_global_args_fns: Vec<ProcessGlobalArgsFn>,
} }
type CliDispatchFn = Box<dyn FnOnce(&mut Ui, &CommandHelper) -> Result<(), CommandError>>; pub type CliDispatchFn = Box<dyn FnOnce(&mut Ui, &CommandHelper) -> Result<(), CommandError>>;
type CliDispatchHookFn =
Box<dyn FnOnce(&mut Ui, &CommandHelper, CliDispatchFn) -> Result<(), CommandError>>;
type ProcessGlobalArgsFn = Box<dyn FnOnce(&mut Ui, &ArgMatches) -> Result<(), CommandError>>; type ProcessGlobalArgsFn = Box<dyn FnOnce(&mut Ui, &ArgMatches) -> Result<(), CommandError>>;
@ -3682,7 +3685,7 @@ impl CliRunner {
commit_template_extensions: vec![], commit_template_extensions: vec![],
operation_template_extensions: vec![], operation_template_extensions: vec![],
dispatch_fn: Box::new(crate::commands::run_command), dispatch_fn: Box::new(crate::commands::run_command),
start_hook_fns: vec![], dispatch_hook_fns: vec![],
process_global_args_fns: vec![], process_global_args_fns: vec![],
} }
} }
@ -3779,8 +3782,14 @@ impl CliRunner {
self self
} }
pub fn add_start_hook(mut self, start_hook_fn: CliDispatchFn) -> Self { /// Add a hook that gets called when it's time to run the command. It is
self.start_hook_fns.push(start_hook_fn); /// the hook's responsibility to call the given inner dispatch function to
/// run the command.
pub fn add_dispatch_hook<F>(mut self, dispatch_hook_fn: F) -> Self
where
F: FnOnce(&mut Ui, &CommandHelper, CliDispatchFn) -> Result<(), CommandError> + 'static,
{
self.dispatch_hook_fns.push(Box::new(dispatch_hook_fn));
self self
} }
@ -3940,10 +3949,15 @@ impl CliRunner {
let command_helper = CommandHelper { let command_helper = CommandHelper {
data: Rc::new(command_helper_data), data: Rc::new(command_helper_data),
}; };
for start_hook_fn in self.start_hook_fns { let dispatch_fn = self.dispatch_hook_fns.into_iter().fold(
start_hook_fn(ui, &command_helper)?; self.dispatch_fn,
} |old_dispatch_fn, dispatch_hook_fn| {
(self.dispatch_fn)(ui, &command_helper) Box::new(move |ui: &mut Ui, command_helper: &CommandHelper| {
dispatch_hook_fn(ui, command_helper, old_dispatch_fn)
})
},
);
(dispatch_fn)(ui, &command_helper)
} }
#[must_use] #[must_use]