Refactor: generalize deferred command line argument execution
Making arguments call into Python was impractical because Python is only initialized for ARG_PASS_FINAL. Replace "--command" specific logic with a general method of arguments requesting to be executed once all sub-systems have been initialized. Without this, the `main()` function needs hard coded logic to support any time an argument needs to use Python internally.
This commit is contained in:
@@ -37,7 +37,6 @@
|
||||
/* 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"
|
||||
@@ -122,6 +121,7 @@ ApplicationState app_state = []() {
|
||||
app_state.signal.use_crash_handler = true;
|
||||
app_state.signal.use_abort_handler = true;
|
||||
app_state.exit_code_on_error.python = 0;
|
||||
app_state.main_arg_deferred = nullptr;
|
||||
return app_state;
|
||||
}();
|
||||
|
||||
@@ -566,16 +566,9 @@ 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);
|
||||
}
|
||||
if (app_state.main_arg_deferred != nullptr) {
|
||||
exit_code = main_arg_handle_deferred();
|
||||
MEM_freeN(app_state.main_arg_deferred);
|
||||
}
|
||||
else {
|
||||
exit_code = G.is_break ? EXIT_FAILURE : EXIT_SUCCESS;
|
||||
@@ -584,6 +577,9 @@ int main(int argc,
|
||||
WM_exit(C, exit_code);
|
||||
}
|
||||
else {
|
||||
/* Not supported, although it could be made to work if needed. */
|
||||
BLI_assert(app_state.main_arg_deferred == nullptr);
|
||||
|
||||
/* Shows the splash as needed. */
|
||||
WM_init_splash_on_startup(C);
|
||||
|
||||
|
||||
@@ -35,6 +35,7 @@
|
||||
# endif
|
||||
|
||||
# include "BKE_appdir.hh"
|
||||
# include "BKE_blender_cli_command.hh"
|
||||
# include "BKE_blender_version.h"
|
||||
# include "BKE_blendfile.hh"
|
||||
# include "BKE_context.hh"
|
||||
@@ -420,6 +421,57 @@ fail:
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Deferred Argument Handling
|
||||
*
|
||||
* Support executing an argument running instead of #WM_main which is deferred.
|
||||
* Needed for arguments which are handled early but require sub-systems
|
||||
* (Python in particular) * to be initialized.
|
||||
* \{ */
|
||||
|
||||
struct BA_ArgCallback_Deferred {
|
||||
BA_ArgCallback func;
|
||||
int argc;
|
||||
const char **argv;
|
||||
void *data;
|
||||
/** Return-code. */
|
||||
int exit_code;
|
||||
};
|
||||
|
||||
static bool main_arg_deferred_is_set()
|
||||
{
|
||||
return app_state.main_arg_deferred != nullptr;
|
||||
}
|
||||
|
||||
static void main_arg_deferred_setup(BA_ArgCallback func, int argc, const char **argv, void *data)
|
||||
{
|
||||
BLI_assert(app_state.main_arg_deferred == nullptr);
|
||||
BA_ArgCallback_Deferred *d = static_cast<BA_ArgCallback_Deferred *>(
|
||||
MEM_callocN(sizeof(*d), __func__));
|
||||
d->func = func;
|
||||
d->argc = argc;
|
||||
d->argv = argv;
|
||||
d->data = data;
|
||||
d->exit_code = 0;
|
||||
app_state.main_arg_deferred = d;
|
||||
}
|
||||
|
||||
static void main_arg_deferred_exit_code_set(int exit_code)
|
||||
{
|
||||
BA_ArgCallback_Deferred *d = app_state.main_arg_deferred;
|
||||
BLI_assert(d != nullptr);
|
||||
d->exit_code = exit_code;
|
||||
}
|
||||
|
||||
int main_arg_handle_deferred()
|
||||
{
|
||||
BA_ArgCallback_Deferred *d = app_state.main_arg_deferred;
|
||||
d->func(d->argc, d->argv, d->data);
|
||||
return d->exit_code;
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Utilities Python Context Macro (#BPY_CTX_SETUP)
|
||||
* \{ */
|
||||
@@ -940,21 +992,34 @@ static const char arg_handle_command_set_doc[] =
|
||||
"\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*/)
|
||||
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();
|
||||
if (!main_arg_deferred_is_set()) {
|
||||
if (argc < 2) {
|
||||
fprintf(stderr, "%s requires at least one argument\n", argv[0]);
|
||||
exit(EXIT_FAILURE);
|
||||
BLI_assert_unreachable();
|
||||
}
|
||||
/* Application "info" messages get in the way of command line output, suppress them. */
|
||||
G.quiet = true;
|
||||
|
||||
background_mode_set();
|
||||
|
||||
main_arg_deferred_setup(arg_handle_command_set, argc, argv, data);
|
||||
}
|
||||
else {
|
||||
bContext *C = static_cast<bContext *>(data);
|
||||
const char *id = argv[1];
|
||||
int exit_code;
|
||||
if (STREQ(id, "help")) {
|
||||
BKE_blender_cli_command_print_help();
|
||||
exit_code = EXIT_SUCCESS;
|
||||
}
|
||||
else {
|
||||
exit_code = BKE_blender_cli_command_exec(C, id, argc - 2, argv + 2);
|
||||
}
|
||||
main_arg_deferred_exit_code_set(exit_code);
|
||||
}
|
||||
|
||||
/* Application "info" messages get in the way of command line output, suppress them. */
|
||||
G.quiet = true;
|
||||
|
||||
background_mode_set();
|
||||
|
||||
app_state.command.argc = argc - 1;
|
||||
app_state.command.argv = argv + 1;
|
||||
|
||||
/* Consume remaining arguments. */
|
||||
return argc - 1;
|
||||
@@ -2409,8 +2474,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);
|
||||
/* Command implies background mode (defers execution). */
|
||||
BLI_args_add(ba, "-c", "--command", CB(arg_handle_command_set), C);
|
||||
|
||||
BLI_args_add(ba, "-a", nullptr, CB(arg_handle_playback_mode), nullptr);
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
* Functionality for main() initialization.
|
||||
*/
|
||||
|
||||
struct BA_ArgCallback_Deferred;
|
||||
struct bArgs;
|
||||
struct bContext;
|
||||
|
||||
@@ -33,6 +34,12 @@ void main_args_setup(struct bContext *C, struct bArgs *ba, bool all);
|
||||
*/
|
||||
int main_args_handle_load_file(int argc, const char **argv, void *data);
|
||||
|
||||
/**
|
||||
* Handle an argument which requested deferred evaluation.
|
||||
* Needed when arguments which evaluate early need Python to be initialized for example.
|
||||
*/
|
||||
int main_arg_handle_deferred();
|
||||
|
||||
/* `creator_signals.cc` */
|
||||
|
||||
void main_signal_setup(void);
|
||||
@@ -53,12 +60,10 @@ struct ApplicationState {
|
||||
unsigned char python;
|
||||
} exit_code_on_error;
|
||||
|
||||
/** Storage for commands (see `--command` argument). */
|
||||
struct {
|
||||
int argc;
|
||||
const char **argv;
|
||||
} command;
|
||||
/** Store the argument state for later handling. */
|
||||
struct BA_ArgCallback_Deferred *main_arg_deferred;
|
||||
};
|
||||
|
||||
extern struct ApplicationState app_state; /* `creator.cc` */
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user