CLI: support defining custom commands via C++ & Python API

Add support for add-ons to define commands using the new argument
`-c` or `--command`.

Commands behave as follows:

- Passing in a command enables background mode without the need to pass
  in `--background`.
- All arguments following the command are passed to the command
  (without the need to use the `--` argument).
- Add-ons can define their own commands via
  `bpy.utils.register_cli_command` (see examples in API docs).
- Passing in `--command help` lists all available commands.

Ref !119115
This commit is contained in:
Campbell Barton
2024-03-08 11:07:41 +11:00
parent 5214e6f35d
commit 9372e0dfe0
15 changed files with 776 additions and 1 deletions
+17 -1
View File
@@ -37,6 +37,7 @@
/* Mostly initialization functions. */
#include "BKE_appdir.hh"
#include "BKE_blender.hh"
#include "BKE_blender_cli_command.hh"
#include "BKE_brush.hh"
#include "BKE_cachefile.hh"
#include "BKE_callbacks.hh"
@@ -566,8 +567,23 @@ int main(int argc,
#ifndef WITH_PYTHON_MODULE
if (G.background) {
int exit_code;
if (app_state.command.argv) {
const char *id = app_state.command.argv[0];
if (STREQ(id, "help")) {
BKE_blender_cli_command_print_help();
exit_code = EXIT_SUCCESS;
}
else {
exit_code = BKE_blender_cli_command_exec(
C, id, app_state.command.argc - 1, app_state.command.argv + 1);
}
}
else {
exit_code = G.is_break ? EXIT_FAILURE : EXIT_SUCCESS;
}
/* Using window-manager API in background-mode is a bit odd, but works fine. */
WM_exit(C, G.is_break ? EXIT_FAILURE : EXIT_SUCCESS);
WM_exit(C, exit_code);
}
else {
/* Shows the splash as needed. */
+30
View File
@@ -698,6 +698,8 @@ static void print_help(bArgs *ba, bool all)
PRINT("\n");
BLI_args_print_arg_doc(ba, "-noaudio");
BLI_args_print_arg_doc(ba, "-setaudio");
PRINT("\n");
BLI_args_print_arg_doc(ba, "--command");
PRINT("\n");
@@ -924,6 +926,32 @@ static int arg_handle_background_mode_set(int /*argc*/, const char ** /*argv*/,
return 0;
}
static const char arg_handle_command_set_doc[] =
"<command>\n"
"\tRun a command which consumes all remaining arguments.\n"
"\tUse '-c help' to list all other commands.\n"
"\tPass '--help' after the command to see its help text.\n"
"\n"
"\tThis implies '--background' mode.";
static int arg_handle_command_set(int argc, const char **argv, void * /*data*/)
{
if (argc < 2) {
fprintf(stderr, "%s requires at least one argument\n", argv[0]);
exit(EXIT_FAILURE);
BLI_assert_unreachable();
}
/* See `--background` implementation. */
G.background = true;
BKE_sound_force_device("None");
app_state.command.argc = argc - 1;
app_state.command.argv = argv + 1;
/* Consume remaining arguments. */
return argc - 1;
}
static const char arg_handle_log_level_set_doc[] =
"<level>\n"
"\tSet the logging verbosity level (higher for more details) defaults to 1,\n"
@@ -2374,6 +2402,8 @@ void main_args_setup(bContext *C, bArgs *ba, bool all)
ba, nullptr, "--disable-abort-handler", CB(arg_handle_abort_handler_disable), nullptr);
BLI_args_add(ba, "-b", "--background", CB(arg_handle_background_mode_set), nullptr);
/* Command implies background mode. */
BLI_args_add(ba, "-c", "--command", CB(arg_handle_command_set), nullptr);
BLI_args_add(ba, "-a", nullptr, CB(arg_handle_playback_mode), nullptr);
+6
View File
@@ -52,6 +52,12 @@ struct ApplicationState {
struct {
unsigned char python;
} exit_code_on_error;
/** Storage for commands (see `--command` argument). */
struct {
int argc;
const char **argv;
} command;
};
extern struct ApplicationState app_state; /* creator.c */