Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for BRIEFCASE_DEBUG. #43

Merged
merged 1 commit into from
Jun 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions cookiecutter.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
"bundle_identifier": "{{ cookiecutter.bundle }}.{{ cookiecutter.app_name|replace('_', '-') }}",
"url": "https://example.com",
"description": "Short description of app",
"console_app": false,
"flatpak_runtime": "org.freedesktop.Platform",
"flatpak_runtime_version": "21.08",
"flatpak_sdk": "org.freedesktop.Sdk",
Expand Down
53 changes: 34 additions & 19 deletions {{ cookiecutter.format }}/src/bootstrap/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,11 @@
#include <stdio.h>
#include <Python.h>

// A global indicator of the debug level
char *debug_mode;

void debug_log(const char *format, ...);

int main(int argc, char *argv[]) {
int ret = 0;
PyStatus status;
Expand All @@ -25,6 +30,9 @@ int main(int argc, char *argv[]) {
PyObject *exc_traceback;
PyObject *systemExit_code;

// Set the global debug state based on the runtime environment
debug_mode = getenv("BRIEFCASE_DEBUG");

// Generate an isolated Python configuration.
PyPreConfig_InitIsolatedConfig(&preconfig);
PyConfig_InitIsolatedConfig(&config);
Expand All @@ -41,7 +49,7 @@ int main(int argc, char *argv[]) {
// Isolated apps need to set the full PYTHONPATH manually.
config.module_search_paths_set = 1;

printf("Pre-initializing Python runtime...\n");
debug_log("Pre-initializing Python runtime...\n");
status = Py_PreInitialize(&preconfig);
if (PyStatus_Exception(status)) {
// crash_dialog("Unable to pre-initialize Python interpreter: %s", status.err_msg, nil]);
Expand All @@ -51,7 +59,7 @@ int main(int argc, char *argv[]) {

// Set the home for the Python interpreter
python_home = "/app";
printf("PYTHONHOME: %s\n", python_home);
debug_log("PYTHONHOME: %s\n", python_home);
wtmp_str = Py_DecodeLocale(python_home, NULL);
status = PyConfig_SetString(&config, &config.home, wtmp_str);
if (PyStatus_Exception(status)) {
Expand All @@ -62,6 +70,7 @@ int main(int argc, char *argv[]) {
PyMem_RawFree(wtmp_str);

// Set the executable to match the known path of the app binary in the flatpak.
debug_log("config.executable: /app/bin/{{ cookiecutter.app_name }}\n");
status = PyConfig_SetBytesString(&config, &config.executable, "/app/bin/{{ cookiecutter.app_name }}");
if (PyStatus_Exception(status)) {
// crash_dialog("Unable to set executable name: %s", status.err_msg);
Expand All @@ -77,6 +86,7 @@ int main(int argc, char *argv[]) {
if (app_module_name == NULL) {
app_module_name = "{{ cookiecutter.module_name }}";
}
debug_log("config.run_module: %s\n", app_module_name);
status = PyConfig_SetBytesString(&config, &config.run_module, app_module_name);
if (PyStatus_Exception(status)) {
// crash_dialog("Unable to set app module name: %s", status.err_msg);
Expand All @@ -93,10 +103,10 @@ int main(int argc, char *argv[]) {
}

// Set the full module path. This includes the stdlib, site-packages, and app code.
printf("PYTHONPATH:\n");
debug_log("PYTHONPATH:\n");
// // The .zip form of the stdlib
path = "/app/lib/python{{ ''.join(cookiecutter.python_version.split('.')[:2]) }}.zip";
printf("- %s\n", path);
debug_log("- %s\n", path);
wtmp_str = Py_DecodeLocale(path, NULL);
status = PyWideStringList_Append(&config.module_search_paths, wtmp_str);
if (PyStatus_Exception(status)) {
Expand All @@ -108,7 +118,7 @@ int main(int argc, char *argv[]) {

// The unpacked form of the stdlib
path = "/app/lib/python{{ '.'.join(cookiecutter.python_version.split('.')[:2]) }}";
printf("- %s\n", path);
debug_log("- %s\n", path);
wtmp_str = Py_DecodeLocale(path, NULL);
status = PyWideStringList_Append(&config.module_search_paths, wtmp_str);
if (PyStatus_Exception(status)) {
Expand All @@ -120,7 +130,7 @@ int main(int argc, char *argv[]) {

// Add the stdlib binary modules path
path = "/app/lib/python{{ '.'.join(cookiecutter.python_version.split('.')[:2]) }}/lib-dynload";
printf("- %s\n", path);
debug_log("- %s\n", path);
wtmp_str = Py_DecodeLocale(path, NULL);
status = PyWideStringList_Append(&config.module_search_paths, wtmp_str);
if (PyStatus_Exception(status)) {
Expand All @@ -132,7 +142,7 @@ int main(int argc, char *argv[]) {

// Add the app_packages path
path = "/app/briefcase/app_packages";
printf("- %s\n", path);
debug_log("- %s\n", path);
wtmp_str = Py_DecodeLocale(path, NULL);
status = PyWideStringList_Append(&config.module_search_paths, wtmp_str);
if (PyStatus_Exception(status)) {
Expand All @@ -144,7 +154,7 @@ int main(int argc, char *argv[]) {

// Add the app path
path = "/app/briefcase/app";
printf("- %s\n", path);
debug_log("- %s\n", path);
wtmp_str = Py_DecodeLocale(path, NULL);
status = PyWideStringList_Append(&config.module_search_paths, wtmp_str);
if (PyStatus_Exception(status)) {
Expand All @@ -154,15 +164,15 @@ int main(int argc, char *argv[]) {
}
PyMem_RawFree(wtmp_str);

printf("Configure argc/argv...\n");
debug_log("Configure argc/argv...\n");
status = PyConfig_SetBytesArgv(&config, argc, argv);
if (PyStatus_Exception(status)) {
// crash_dialog("Unable to configured argc/argv: %s", status.err_msg);
PyConfig_Clear(&config);
Py_ExitStatusException(status);
}

printf("Initializing Python runtime...\n");
debug_log("Initializing Python runtime...\n");
status = Py_InitializeFromConfig(&config);
if (PyStatus_Exception(status)) {
// crash_dialog("Unable to initialize Python interpreter: %s", status.err_msg);
Expand All @@ -177,7 +187,7 @@ int main(int argc, char *argv[]) {
// pymain_run_module() method); we need to re-implement it
// because we need to be able to inspect the error state of
// the interpreter, not just the return code of the module.
printf("Running app module: %s\n", app_module_name);
debug_log("Running app module: %s\n", app_module_name);
module = PyImport_ImportModule("runpy");
if (module == NULL) {
// crash_dialog(@"Could not import runpy module");
Expand All @@ -204,7 +214,7 @@ int main(int argc, char *argv[]) {

// Print a separator to differentiate Python startup logs from app logs,
// then flush stdout/stderr to ensure all startup logs have been output.
printf("---------------------------------------------------------------------------\n");
debug_log("---------------------------------------------------------------------------\n");
fflush(stdout);
fflush(stderr);

Expand All @@ -224,31 +234,36 @@ int main(int argc, char *argv[]) {
if (PyErr_GivenExceptionMatches(exc_value, PyExc_SystemExit)) {
systemExit_code = PyObject_GetAttrString(exc_value, "code");
if (systemExit_code == NULL) {
printf("Could not determine exit code\n");
debug_log("Could not determine exit code\n");
ret = -10;
}
else {
ret = (int) PyLong_AsLong(systemExit_code);
}
} else {
ret = -6;
}

if (ret != 0) {
printf("Application quit abnormally (Exit code %d)!\n", ret);
printf("---------------------------------------------------------------------------\n");
printf("Application quit abnormally!\n");

// Restore the error state of the interpreter.
PyErr_Restore(exc_type, exc_value, exc_traceback);

// Print exception to stderr.
// In case of SystemExit, this will call exit()
PyErr_Print();

exit(ret);
}
}

Py_Finalize();

return ret;
}

void debug_log(const char *format, ...) {
if (debug_mode) {
va_list args;
va_start(args, format);
vprintf(format, args);
va_end(args);
}
}