1
0
mirror of https://github.com/godotengine/godot.git synced 2025-11-23 15:16:17 +00:00

Merge pull request #85845 from YuriSizov/editor-export-hidden-errors

Ensure more export errors are reported to users
This commit is contained in:
Yuri Sizov
2023-12-08 16:59:04 +01:00
9 changed files with 195 additions and 104 deletions

View File

@@ -93,7 +93,7 @@ bool EditorExportPlatform::fill_log_messages(RichTextLabel *p_log, Error p_err)
} }
p_log->add_newline(); p_log->add_newline();
if (msg_count) { if (msg_count > 0) {
p_log->push_table(2); p_log->push_table(2);
p_log->set_table_column_expand(0, false); p_log->set_table_column_expand(0, false);
p_log->set_table_column_expand(1, true); p_log->set_table_column_expand(1, true);
@@ -133,8 +133,37 @@ bool EditorExportPlatform::fill_log_messages(RichTextLabel *p_log, Error p_err)
} }
p_log->pop(); p_log->pop();
p_log->add_newline(); p_log->add_newline();
} else if (p_err != OK) {
// We failed but don't show any user-facing messages. This is bad and should not
// be allowed, but just in case this happens, let's give the user something at least.
p_log->push_table(2);
p_log->set_table_column_expand(0, false);
p_log->set_table_column_expand(1, true);
{
Color color = p_log->get_theme_color(SNAME("error_color"), EditorStringName(Editor));
Ref<Texture> icon = p_log->get_editor_theme_icon(SNAME("Error"));
p_log->push_cell();
p_log->add_text("\t");
if (icon.is_valid()) {
p_log->add_image(icon);
} }
p_log->pop();
p_log->push_cell();
p_log->push_color(color);
p_log->add_text(vformat("[%s]: %s", TTR("Unknown Error"), vformat(TTR("Export failed with error code %d."), p_err)));
p_log->pop();
p_log->pop();
}
p_log->pop();
p_log->add_newline(); p_log->add_newline();
}
p_log->add_newline();
return has_messages; return has_messages;
} }

View File

@@ -161,6 +161,7 @@ Error EditorExportPlatformPC::prepare_template(const Ref<EditorExportPreset> &p_
} }
if (err != OK) { if (err != OK) {
add_message(EXPORT_MESSAGE_ERROR, TTR("Prepare Template"), TTR("Failed to copy export template.")); add_message(EXPORT_MESSAGE_ERROR, TTR("Prepare Template"), TTR("Failed to copy export template."));
return err;
} }
return err; return err;

View File

@@ -1109,12 +1109,13 @@ void ProjectExportDialog::_export_all_dialog_action(const String &p_str) {
} }
void ProjectExportDialog::_export_all(bool p_debug) { void ProjectExportDialog::_export_all(bool p_debug) {
exporting = true;
bool show_dialog = false;
{ // Scope for the editor progress, we must free it before showing the dialog at the end.
String export_target = p_debug ? TTR("Debug") : TTR("Release"); String export_target = p_debug ? TTR("Debug") : TTR("Release");
EditorProgress ep("exportall", TTR("Exporting All") + " " + export_target, EditorExport::get_singleton()->get_export_preset_count(), true); EditorProgress ep("exportall", TTR("Exporting All") + " " + export_target, EditorExport::get_singleton()->get_export_preset_count(), true);
exporting = true;
bool show_dialog = false;
result_dialog_log->clear(); result_dialog_log->clear();
for (int i = 0; i < EditorExport::get_singleton()->get_export_preset_count(); i++) { for (int i = 0; i < EditorExport::get_singleton()->get_export_preset_count(); i++) {
Ref<EditorExportPreset> preset = EditorExport::get_singleton()->get_export_preset(i); Ref<EditorExportPreset> preset = EditorExport::get_singleton()->get_export_preset(i);
@@ -1140,6 +1141,8 @@ void ProjectExportDialog::_export_all(bool p_debug) {
bool has_messages = platform->fill_log_messages(result_dialog_log, err); bool has_messages = platform->fill_log_messages(result_dialog_log, err);
show_dialog = show_dialog || has_messages; show_dialog = show_dialog || has_messages;
} }
}
if (show_dialog) { if (show_dialog) {
result_dialog->popup_centered_ratio(0.5); result_dialog->popup_centered_ratio(0.5);
} }
@@ -1148,7 +1151,6 @@ void ProjectExportDialog::_export_all(bool p_debug) {
} }
void ProjectExportDialog::_bind_methods() { void ProjectExportDialog::_bind_methods() {
ClassDB::bind_method("_export_all", &ProjectExportDialog::_export_all);
ClassDB::bind_method("set_export_path", &ProjectExportDialog::set_export_path); ClassDB::bind_method("set_export_path", &ProjectExportDialog::set_export_path);
ClassDB::bind_method("get_export_path", &ProjectExportDialog::get_export_path); ClassDB::bind_method("get_export_path", &ProjectExportDialog::get_export_path);
ClassDB::bind_method("get_current_preset", &ProjectExportDialog::get_current_preset); ClassDB::bind_method("get_current_preset", &ProjectExportDialog::get_current_preset);

View File

@@ -2782,6 +2782,12 @@ Error EditorExportPlatformAndroid::export_project(const Ref<EditorExportPreset>
Error EditorExportPlatformAndroid::export_project_helper(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int export_format, bool should_sign, int p_flags) { Error EditorExportPlatformAndroid::export_project_helper(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int export_format, bool should_sign, int p_flags) {
ExportNotifier notifier(*this, p_preset, p_debug, p_path, p_flags); ExportNotifier notifier(*this, p_preset, p_debug, p_path, p_flags);
const String base_dir = p_path.get_base_dir();
if (!DirAccess::exists(base_dir)) {
add_message(EXPORT_MESSAGE_ERROR, TTR("Export"), vformat(TTR("Target folder does not exist or is inaccessible: \"%s\""), base_dir));
return ERR_FILE_BAD_PATH;
}
String src_apk; String src_apk;
Error err; Error err;
@@ -2856,7 +2862,10 @@ Error EditorExportPlatformAndroid::export_project_helper(const Ref<EditorExportP
} }
const String assets_directory = get_assets_directory(p_preset, export_format); const String assets_directory = get_assets_directory(p_preset, export_format);
String sdk_path = EDITOR_GET("export/android/android_sdk_path"); String sdk_path = EDITOR_GET("export/android/android_sdk_path");
ERR_FAIL_COND_V_MSG(sdk_path.is_empty(), ERR_UNCONFIGURED, "Android SDK path must be configured in Editor Settings at 'export/android/android_sdk_path'."); if (sdk_path.is_empty()) {
add_message(EXPORT_MESSAGE_ERROR, TTR("Export"), TTR("Android SDK path must be configured in Editor Settings at 'export/android/android_sdk_path'."));
return ERR_UNCONFIGURED;
}
print_verbose("Android sdk path: " + sdk_path); print_verbose("Android sdk path: " + sdk_path);
// TODO: should we use "package/name" or "application/config/name"? // TODO: should we use "package/name" or "application/config/name"?
@@ -3106,10 +3115,6 @@ Error EditorExportPlatformAndroid::export_project_helper(const Ref<EditorExportP
} }
} }
if (!DirAccess::exists(p_path.get_base_dir())) {
return ERR_FILE_BAD_PATH;
}
Ref<FileAccess> io_fa; Ref<FileAccess> io_fa;
zlib_filefunc_def io = zipio_create_io(&io_fa); zlib_filefunc_def io = zipio_create_io(&io_fa);
@@ -3302,10 +3307,6 @@ Error EditorExportPlatformAndroid::export_project_helper(const Ref<EditorExportP
zipClose(unaligned_apk, nullptr); zipClose(unaligned_apk, nullptr);
unzClose(pkg); unzClose(pkg);
if (err != OK) {
CLEANUP_AND_RETURN(err);
}
// Let's zip-align (must be done before signing) // Let's zip-align (must be done before signing)
static const int ZIP_ALIGNMENT = 4; static const int ZIP_ALIGNMENT = 4;
@@ -3392,6 +3393,7 @@ Error EditorExportPlatformAndroid::export_project_helper(const Ref<EditorExportP
// file will invalidate the signature. // file will invalidate the signature.
err = sign_apk(p_preset, p_debug, p_path, ep); err = sign_apk(p_preset, p_debug, p_path, ep);
if (err != OK) { if (err != OK) {
// Message is supplied by the subroutine method.
CLEANUP_AND_RETURN(err); CLEANUP_AND_RETURN(err);
} }
} }

View File

@@ -620,7 +620,10 @@ Error EditorExportPlatformIOS::_export_icons(const Ref<EditorExportPreset> &p_pr
String sizes; String sizes;
Ref<DirAccess> da = DirAccess::open(p_iconset_dir); Ref<DirAccess> da = DirAccess::open(p_iconset_dir);
ERR_FAIL_COND_V_MSG(da.is_null(), ERR_CANT_OPEN, "Cannot open directory '" + p_iconset_dir + "'."); if (da.is_null()) {
add_message(EXPORT_MESSAGE_ERROR, TTR("Export Icons"), vformat(TTR("Could not open a directory at path \"%s\"."), p_iconset_dir));
return ERR_CANT_OPEN;
}
Color boot_bg_color = GLOBAL_GET("application/boot_splash/bg_color"); Color boot_bg_color = GLOBAL_GET("application/boot_splash/bg_color");
@@ -692,12 +695,20 @@ Error EditorExportPlatformIOS::_export_icons(const Ref<EditorExportPreset> &p_pr
json_description += "]}"; json_description += "]}";
Ref<FileAccess> json_file = FileAccess::open(p_iconset_dir + "Contents.json", FileAccess::WRITE); Ref<FileAccess> json_file = FileAccess::open(p_iconset_dir + "Contents.json", FileAccess::WRITE);
ERR_FAIL_COND_V(json_file.is_null(), ERR_CANT_CREATE); if (json_file.is_null()) {
add_message(EXPORT_MESSAGE_ERROR, TTR("Export Icons"), vformat(TTR("Could not write to a file at path \"%s\"."), p_iconset_dir + "Contents.json"));
return ERR_CANT_CREATE;
}
CharString json_utf8 = json_description.utf8(); CharString json_utf8 = json_description.utf8();
json_file->store_buffer((const uint8_t *)json_utf8.get_data(), json_utf8.length()); json_file->store_buffer((const uint8_t *)json_utf8.get_data(), json_utf8.length());
Ref<FileAccess> sizes_file = FileAccess::open(p_iconset_dir + "sizes", FileAccess::WRITE); Ref<FileAccess> sizes_file = FileAccess::open(p_iconset_dir + "sizes", FileAccess::WRITE);
ERR_FAIL_COND_V(sizes_file.is_null(), ERR_CANT_CREATE); if (sizes_file.is_null()) {
add_message(EXPORT_MESSAGE_ERROR, TTR("Export Icons"), vformat(TTR("Could not write to a file at path \"%s\"."), p_iconset_dir + "sizes"));
return ERR_CANT_CREATE;
}
CharString sizes_utf8 = sizes.utf8(); CharString sizes_utf8 = sizes.utf8();
sizes_file->store_buffer((const uint8_t *)sizes_utf8.get_data(), sizes_utf8.length()); sizes_file->store_buffer((const uint8_t *)sizes_utf8.get_data(), sizes_utf8.length());
@@ -1219,10 +1230,10 @@ Error EditorExportPlatformIOS::_export_additional_assets(const String &p_out_dir
String asset = p_assets[f_idx]; String asset = p_assets[f_idx];
if (asset.begins_with("res://")) { if (asset.begins_with("res://")) {
Error err = _copy_asset(p_out_dir, asset, nullptr, p_is_framework, p_should_embed, r_exported_assets); Error err = _copy_asset(p_out_dir, asset, nullptr, p_is_framework, p_should_embed, r_exported_assets);
ERR_FAIL_COND_V(err, err); ERR_FAIL_COND_V(err != OK, err);
} else if (ProjectSettings::get_singleton()->localize_path(asset).begins_with("res://")) { } else if (ProjectSettings::get_singleton()->localize_path(asset).begins_with("res://")) {
Error err = _copy_asset(p_out_dir, ProjectSettings::get_singleton()->localize_path(asset), nullptr, p_is_framework, p_should_embed, r_exported_assets); Error err = _copy_asset(p_out_dir, ProjectSettings::get_singleton()->localize_path(asset), nullptr, p_is_framework, p_should_embed, r_exported_assets);
ERR_FAIL_COND_V(err, err); ERR_FAIL_COND_V(err != OK, err);
} else { } else {
// either SDK-builtin or already a part of the export template // either SDK-builtin or already a part of the export template
IOSExportAsset exported_asset = { asset, p_is_framework, p_should_embed }; IOSExportAsset exported_asset = { asset, p_is_framework, p_should_embed };
@@ -1306,8 +1317,7 @@ Error EditorExportPlatformIOS::_export_ios_plugins(const Ref<EditorExportPreset>
// We shouldn't embed .xcframework that contains static libraries. // We shouldn't embed .xcframework that contains static libraries.
// Static libraries are not embedded anyway. // Static libraries are not embedded anyway.
err = _copy_asset(dest_dir, plugin_main_binary, &plugin_binary_result_file, true, false, r_exported_assets); err = _copy_asset(dest_dir, plugin_main_binary, &plugin_binary_result_file, true, false, r_exported_assets);
ERR_FAIL_COND_V(err != OK, err);
ERR_FAIL_COND_V(err, err);
// Adding dependencies. // Adding dependencies.
// Use separate container for names to check for duplicates. // Use separate container for names to check for duplicates.
@@ -1432,15 +1442,15 @@ Error EditorExportPlatformIOS::_export_ios_plugins(const Ref<EditorExportPreset>
{ {
// Export linked plugin dependency // Export linked plugin dependency
err = _export_additional_assets(dest_dir, plugin_linked_dependencies, true, false, r_exported_assets); err = _export_additional_assets(dest_dir, plugin_linked_dependencies, true, false, r_exported_assets);
ERR_FAIL_COND_V(err, err); ERR_FAIL_COND_V(err != OK, err);
// Export embedded plugin dependency // Export embedded plugin dependency
err = _export_additional_assets(dest_dir, plugin_embedded_dependencies, true, true, r_exported_assets); err = _export_additional_assets(dest_dir, plugin_embedded_dependencies, true, true, r_exported_assets);
ERR_FAIL_COND_V(err, err); ERR_FAIL_COND_V(err != OK, err);
// Export plugin files // Export plugin files
err = _export_additional_assets(dest_dir, plugin_files, false, false, r_exported_assets); err = _export_additional_assets(dest_dir, plugin_files, false, false, r_exported_assets);
ERR_FAIL_COND_V(err, err); ERR_FAIL_COND_V(err != OK, err);
} }
// Update CPP // Update CPP
@@ -1496,9 +1506,14 @@ Error EditorExportPlatformIOS::export_project(const Ref<EditorExportPreset> &p_p
Error EditorExportPlatformIOS::_export_project_helper(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags, bool p_simulator, bool p_skip_ipa) { Error EditorExportPlatformIOS::_export_project_helper(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags, bool p_simulator, bool p_skip_ipa) {
ExportNotifier notifier(*this, p_preset, p_debug, p_path, p_flags); ExportNotifier notifier(*this, p_preset, p_debug, p_path, p_flags);
String src_pkg_name; const String dest_dir = p_path.get_base_dir() + "/";
String dest_dir = p_path.get_base_dir() + "/"; const String binary_name = p_path.get_file().get_basename();
String binary_name = p_path.get_file().get_basename(); const String binary_dir = dest_dir + binary_name;
if (!DirAccess::exists(dest_dir)) {
add_message(EXPORT_MESSAGE_ERROR, TTR("Export"), vformat(TTR("Target folder does not exist or is inaccessible: \"%s\""), dest_dir));
return ERR_FILE_BAD_PATH;
}
bool export_project_only = p_preset->get("application/export_project_only"); bool export_project_only = p_preset->get("application/export_project_only");
@@ -1507,6 +1522,7 @@ Error EditorExportPlatformIOS::_export_project_helper(const Ref<EditorExportPres
String team_id = p_preset->get("application/app_store_team_id"); String team_id = p_preset->get("application/app_store_team_id");
ERR_FAIL_COND_V_MSG(team_id.length() == 0, ERR_CANT_OPEN, "App Store Team ID not specified - cannot configure the project."); ERR_FAIL_COND_V_MSG(team_id.length() == 0, ERR_CANT_OPEN, "App Store Team ID not specified - cannot configure the project.");
String src_pkg_name;
if (p_debug) { if (p_debug) {
src_pkg_name = p_preset->get("custom_template/debug"); src_pkg_name = p_preset->get("custom_template/debug");
} else { } else {
@@ -1522,10 +1538,6 @@ Error EditorExportPlatformIOS::_export_project_helper(const Ref<EditorExportPres
} }
} }
if (!DirAccess::exists(dest_dir)) {
return ERR_FILE_BAD_PATH;
}
{ {
Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
if (da.is_valid()) { if (da.is_valid()) {
@@ -1533,18 +1545,19 @@ Error EditorExportPlatformIOS::_export_project_helper(const Ref<EditorExportPres
// remove leftovers from last export so they don't interfere // remove leftovers from last export so they don't interfere
// in case some files are no longer needed // in case some files are no longer needed
if (da->change_dir(dest_dir + binary_name + ".xcodeproj") == OK) { if (da->change_dir(binary_dir + ".xcodeproj") == OK) {
da->erase_contents_recursive(); da->erase_contents_recursive();
} }
if (da->change_dir(dest_dir + binary_name) == OK) { if (da->change_dir(binary_dir) == OK) {
da->erase_contents_recursive(); da->erase_contents_recursive();
} }
da->change_dir(current_dir); da->change_dir(current_dir);
if (!da->dir_exists(dest_dir + binary_name)) { if (!da->dir_exists(binary_dir)) {
Error err = da->make_dir(dest_dir + binary_name); Error err = da->make_dir(binary_dir);
if (err) { if (err != OK) {
add_message(EXPORT_MESSAGE_ERROR, TTR("Export"), vformat(TTR("Failed to create the directory: \"%s\""), binary_dir));
return err; return err;
} }
} }
@@ -1554,10 +1567,11 @@ Error EditorExportPlatformIOS::_export_project_helper(const Ref<EditorExportPres
if (ep.step("Making .pck", 0)) { if (ep.step("Making .pck", 0)) {
return ERR_SKIP; return ERR_SKIP;
} }
String pack_path = dest_dir + binary_name + ".pck"; String pack_path = binary_dir + ".pck";
Vector<SharedObject> libraries; Vector<SharedObject> libraries;
Error err = save_pack(p_preset, p_debug, pack_path, &libraries); Error err = save_pack(p_preset, p_debug, pack_path, &libraries);
if (err) { if (err) {
// Message is supplied by the subroutine method.
return err; return err;
} }
@@ -1606,7 +1620,10 @@ Error EditorExportPlatformIOS::_export_project_helper(const Ref<EditorExportPres
Vector<IOSExportAsset> assets; Vector<IOSExportAsset> assets;
Ref<DirAccess> tmp_app_path = DirAccess::create_for_path(dest_dir); Ref<DirAccess> tmp_app_path = DirAccess::create_for_path(dest_dir);
ERR_FAIL_COND_V(tmp_app_path.is_null(), ERR_CANT_CREATE); if (tmp_app_path.is_null()) {
add_message(EXPORT_MESSAGE_ERROR, TTR("Prepare Templates"), vformat(TTR("Could not create and open the directory: \"%s\""), dest_dir));
return ERR_CANT_CREATE;
}
print_line("Unzipping..."); print_line("Unzipping...");
Ref<FileAccess> io_fa; Ref<FileAccess> io_fa;
@@ -1617,8 +1634,14 @@ Error EditorExportPlatformIOS::_export_project_helper(const Ref<EditorExportPres
return ERR_CANT_OPEN; return ERR_CANT_OPEN;
} }
err = _export_ios_plugins(p_preset, config_data, dest_dir + binary_name, assets, p_debug); err = _export_ios_plugins(p_preset, config_data, binary_dir, assets, p_debug);
ERR_FAIL_COND_V(err, err); if (err != OK) {
// TODO: Improve error reporting by using `add_message` throughout all methods called via `_export_ios_plugins`.
// For now a generic top level message would be fine, but we're ought to use proper reporting here instead of
// just fail macros and non-descriptive error return values.
add_message(EXPORT_MESSAGE_ERROR, TTR("iOS Plugins"), vformat(TTR("Failed to export iOS plugins with code %d. Please check the output log."), err));
return err;
}
//export rest of the files //export rest of the files
int ret = unzGoToFirstFile(src_pkg_zip); int ret = unzGoToFirstFile(src_pkg_zip);
@@ -1683,8 +1706,8 @@ Error EditorExportPlatformIOS::_export_project_helper(const Ref<EditorExportPres
print_line("Creating " + dir_name); print_line("Creating " + dir_name);
Error dir_err = tmp_app_path->make_dir_recursive(dir_name); Error dir_err = tmp_app_path->make_dir_recursive(dir_name);
if (dir_err) { if (dir_err) {
ERR_PRINT("Can't create '" + dir_name + "'.");
unzClose(src_pkg_zip); unzClose(src_pkg_zip);
add_message(EXPORT_MESSAGE_ERROR, TTR("Export"), vformat(TTR("Could not create a directory at path \"%s\"."), dir_name));
return ERR_CANT_CREATE; return ERR_CANT_CREATE;
} }
} }
@@ -1693,8 +1716,8 @@ Error EditorExportPlatformIOS::_export_project_helper(const Ref<EditorExportPres
{ {
Ref<FileAccess> f = FileAccess::open(file, FileAccess::WRITE); Ref<FileAccess> f = FileAccess::open(file, FileAccess::WRITE);
if (f.is_null()) { if (f.is_null()) {
ERR_PRINT("Can't write '" + file + "'.");
unzClose(src_pkg_zip); unzClose(src_pkg_zip);
add_message(EXPORT_MESSAGE_ERROR, TTR("Export"), vformat(TTR("Could not write to a file at path \"%s\"."), file));
return ERR_CANT_CREATE; return ERR_CANT_CREATE;
}; };
f->store_buffer(data.ptr(), data.size()); f->store_buffer(data.ptr(), data.size());
@@ -1715,7 +1738,7 @@ Error EditorExportPlatformIOS::_export_project_helper(const Ref<EditorExportPres
unzClose(src_pkg_zip); unzClose(src_pkg_zip);
if (!found_library) { if (!found_library) {
ERR_PRINT("Requested template library '" + library_to_use + "' not found. It might be missing from your template archive."); add_message(EXPORT_MESSAGE_ERROR, TTR("Export"), vformat(TTR("Requested template library '%s' not found. It might be missing from your template archive."), library_to_use));
return ERR_FILE_NOT_FOUND; return ERR_FILE_NOT_FOUND;
} }
@@ -1727,7 +1750,7 @@ Error EditorExportPlatformIOS::_export_project_helper(const Ref<EditorExportPres
Vector<String> translations = GLOBAL_GET("internationalization/locale/translations"); Vector<String> translations = GLOBAL_GET("internationalization/locale/translations");
if (translations.size() > 0) { if (translations.size() > 0) {
{ {
String fname = dest_dir + binary_name + "/en.lproj"; String fname = binary_dir + "/en.lproj";
tmp_app_path->make_dir_recursive(fname); tmp_app_path->make_dir_recursive(fname);
Ref<FileAccess> f = FileAccess::open(fname + "/InfoPlist.strings", FileAccess::WRITE); Ref<FileAccess> f = FileAccess::open(fname + "/InfoPlist.strings", FileAccess::WRITE);
f->store_line("/* Localized versions of Info.plist keys */"); f->store_line("/* Localized versions of Info.plist keys */");
@@ -1747,7 +1770,7 @@ Error EditorExportPlatformIOS::_export_project_helper(const Ref<EditorExportPres
} }
for (const String &lang : languages) { for (const String &lang : languages) {
String fname = dest_dir + binary_name + "/" + lang + ".lproj"; String fname = binary_dir + "/" + lang + ".lproj";
tmp_app_path->make_dir_recursive(fname); tmp_app_path->make_dir_recursive(fname);
Ref<FileAccess> f = FileAccess::open(fname + "/InfoPlist.strings", FileAccess::WRITE); Ref<FileAccess> f = FileAccess::open(fname + "/InfoPlist.strings", FileAccess::WRITE);
f->store_line("/* Localized versions of Info.plist keys */"); f->store_line("/* Localized versions of Info.plist keys */");
@@ -1776,34 +1799,37 @@ Error EditorExportPlatformIOS::_export_project_helper(const Ref<EditorExportPres
String dest_lib_file_path = dest_dir + static_lib_path.get_file(); String dest_lib_file_path = dest_dir + static_lib_path.get_file();
Error lib_copy_err = tmp_app_path->copy(static_lib_path, dest_lib_file_path); Error lib_copy_err = tmp_app_path->copy(static_lib_path, dest_lib_file_path);
if (lib_copy_err != OK) { if (lib_copy_err != OK) {
ERR_PRINT("Can't copy '" + static_lib_path + "'."); add_message(EXPORT_MESSAGE_ERROR, TTR("Export"), vformat(TTR("Could not copy a file at path \"%s\" to \"%s\"."), static_lib_path, dest_lib_file_path));
return lib_copy_err; return lib_copy_err;
} }
} }
} }
String iconset_dir = dest_dir + binary_name + "/Images.xcassets/AppIcon.appiconset/"; String iconset_dir = binary_dir + "/Images.xcassets/AppIcon.appiconset/";
err = OK; err = OK;
if (!tmp_app_path->dir_exists(iconset_dir)) { if (!tmp_app_path->dir_exists(iconset_dir)) {
err = tmp_app_path->make_dir_recursive(iconset_dir); err = tmp_app_path->make_dir_recursive(iconset_dir);
} }
if (err) { if (err != OK) {
add_message(EXPORT_MESSAGE_ERROR, TTR("Export"), vformat(TTR("Could not create a directory at path \"%s\"."), iconset_dir));
return err; return err;
} }
err = _export_icons(p_preset, iconset_dir); err = _export_icons(p_preset, iconset_dir);
if (err) { if (err != OK) {
// Message is supplied by the subroutine method.
return err; return err;
} }
{ {
bool use_storyboard = p_preset->get("storyboard/use_launch_screen_storyboard"); bool use_storyboard = p_preset->get("storyboard/use_launch_screen_storyboard");
String launch_image_path = dest_dir + binary_name + "/Images.xcassets/LaunchImage.launchimage/"; String launch_image_path = binary_dir + "/Images.xcassets/LaunchImage.launchimage/";
String splash_image_path = dest_dir + binary_name + "/Images.xcassets/SplashImage.imageset/"; String splash_image_path = binary_dir + "/Images.xcassets/SplashImage.imageset/";
Ref<DirAccess> launch_screen_da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); Ref<DirAccess> launch_screen_da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
if (launch_screen_da.is_null()) { if (launch_screen_da.is_null()) {
add_message(EXPORT_MESSAGE_ERROR, TTR("Export"), TTR("Could not access the filesystem."));
return ERR_CANT_CREATE; return ERR_CANT_CREATE;
} }
@@ -1816,10 +1842,11 @@ Error EditorExportPlatformIOS::_export_project_helper(const Ref<EditorExportPres
} }
err = _export_loading_screen_file(p_preset, splash_image_path); err = _export_loading_screen_file(p_preset, splash_image_path);
add_message(EXPORT_MESSAGE_ERROR, TTR("Export"), vformat(TTR("Failed to create a file at path \"%s\" with code %d."), splash_image_path, err));
} else { } else {
print_line("Using Launch Images"); print_line("Using Launch Images");
const String launch_screen_path = dest_dir + binary_name + "/Launch Screen.storyboard"; const String launch_screen_path = binary_dir + "/Launch Screen.storyboard";
launch_screen_da->remove(launch_screen_path); launch_screen_da->remove(launch_screen_path);
@@ -1829,21 +1856,22 @@ Error EditorExportPlatformIOS::_export_project_helper(const Ref<EditorExportPres
} }
err = _export_loading_screen_images(p_preset, launch_image_path); err = _export_loading_screen_images(p_preset, launch_image_path);
add_message(EXPORT_MESSAGE_ERROR, TTR("Export"), vformat(TTR("Failed to create a file at path \"%s\" with code %d."), launch_image_path, err));
} }
} }
if (err) { if (err != OK) {
return err; return err;
} }
print_line("Exporting additional assets"); print_line("Exporting additional assets");
_export_additional_assets(dest_dir + binary_name, libraries, assets); _export_additional_assets(binary_dir, libraries, assets);
_add_assets_to_project(p_preset, project_file_data, assets); _add_assets_to_project(p_preset, project_file_data, assets);
String project_file_name = dest_dir + binary_name + ".xcodeproj/project.pbxproj"; String project_file_name = binary_dir + ".xcodeproj/project.pbxproj";
{ {
Ref<FileAccess> f = FileAccess::open(project_file_name, FileAccess::WRITE); Ref<FileAccess> f = FileAccess::open(project_file_name, FileAccess::WRITE);
if (f.is_null()) { if (f.is_null()) {
ERR_PRINT("Can't write '" + project_file_name + "'."); add_message(EXPORT_MESSAGE_ERROR, TTR("Export"), vformat(TTR("Could not write to a file at path \"%s\"."), project_file_name));
return ERR_CANT_CREATE; return ERR_CANT_CREATE;
}; };
f->store_buffer(project_file_data.ptr(), project_file_data.size()); f->store_buffer(project_file_data.ptr(), project_file_data.size());
@@ -1854,7 +1882,7 @@ Error EditorExportPlatformIOS::_export_project_helper(const Ref<EditorExportPres
if (ep.step("Code-signing dylibs", 2)) { if (ep.step("Code-signing dylibs", 2)) {
return ERR_SKIP; return ERR_SKIP;
} }
Ref<DirAccess> dylibs_dir = DirAccess::open(dest_dir + binary_name + "/dylibs"); Ref<DirAccess> dylibs_dir = DirAccess::open(binary_dir + "/dylibs");
ERR_FAIL_COND_V(dylibs_dir.is_null(), ERR_CANT_OPEN); ERR_FAIL_COND_V(dylibs_dir.is_null(), ERR_CANT_OPEN);
CodesignData codesign_data(p_preset, p_debug); CodesignData codesign_data(p_preset, p_debug);
err = _walk_dir_recursive(dylibs_dir, _codesign, &codesign_data); err = _walk_dir_recursive(dylibs_dir, _codesign, &codesign_data);
@@ -1871,10 +1899,11 @@ Error EditorExportPlatformIOS::_export_project_helper(const Ref<EditorExportPres
if (ep.step("Making .xcarchive", 3)) { if (ep.step("Making .xcarchive", 3)) {
return ERR_SKIP; return ERR_SKIP;
} }
String archive_path = p_path.get_basename() + ".xcarchive"; String archive_path = p_path.get_basename() + ".xcarchive";
List<String> archive_args; List<String> archive_args;
archive_args.push_back("-project"); archive_args.push_back("-project");
archive_args.push_back(dest_dir + binary_name + ".xcodeproj"); archive_args.push_back(binary_dir + ".xcodeproj");
archive_args.push_back("-scheme"); archive_args.push_back("-scheme");
archive_args.push_back(binary_name); archive_args.push_back(binary_name);
archive_args.push_back("-sdk"); archive_args.push_back("-sdk");
@@ -1895,9 +1924,14 @@ Error EditorExportPlatformIOS::_export_project_helper(const Ref<EditorExportPres
archive_args.push_back("-allowProvisioningUpdates"); archive_args.push_back("-allowProvisioningUpdates");
archive_args.push_back("-archivePath"); archive_args.push_back("-archivePath");
archive_args.push_back(archive_path); archive_args.push_back(archive_path);
String archive_str; String archive_str;
err = OS::get_singleton()->execute("xcodebuild", archive_args, &archive_str, nullptr, true); err = OS::get_singleton()->execute("xcodebuild", archive_args, &archive_str, nullptr, true);
ERR_FAIL_COND_V(err, err); if (err != OK) {
add_message(EXPORT_MESSAGE_ERROR, TTR("Xcode Build"), vformat(TTR("Failed to run xcodebuild with code %d"), err));
return err;
}
print_line("xcodebuild (.xcarchive):\n" + archive_str); print_line("xcodebuild (.xcarchive):\n" + archive_str);
if (!archive_str.contains("** ARCHIVE SUCCEEDED **")) { if (!archive_str.contains("** ARCHIVE SUCCEEDED **")) {
add_message(EXPORT_MESSAGE_ERROR, TTR("Xcode Build"), TTR("Xcode project build failed, see editor log for details.")); add_message(EXPORT_MESSAGE_ERROR, TTR("Xcode Build"), TTR("Xcode project build failed, see editor log for details."));
@@ -1908,18 +1942,24 @@ Error EditorExportPlatformIOS::_export_project_helper(const Ref<EditorExportPres
if (ep.step("Making .ipa", 4)) { if (ep.step("Making .ipa", 4)) {
return ERR_SKIP; return ERR_SKIP;
} }
List<String> export_args; List<String> export_args;
export_args.push_back("-exportArchive"); export_args.push_back("-exportArchive");
export_args.push_back("-archivePath"); export_args.push_back("-archivePath");
export_args.push_back(archive_path); export_args.push_back(archive_path);
export_args.push_back("-exportOptionsPlist"); export_args.push_back("-exportOptionsPlist");
export_args.push_back(dest_dir + binary_name + "/export_options.plist"); export_args.push_back(binary_dir + "/export_options.plist");
export_args.push_back("-allowProvisioningUpdates"); export_args.push_back("-allowProvisioningUpdates");
export_args.push_back("-exportPath"); export_args.push_back("-exportPath");
export_args.push_back(dest_dir); export_args.push_back(dest_dir);
String export_str; String export_str;
err = OS::get_singleton()->execute("xcodebuild", export_args, &export_str, nullptr, true); err = OS::get_singleton()->execute("xcodebuild", export_args, &export_str, nullptr, true);
ERR_FAIL_COND_V(err, err); if (err != OK) {
add_message(EXPORT_MESSAGE_ERROR, TTR("Xcode Build"), vformat(TTR("Failed to run xcodebuild with code %d"), err));
return err;
}
print_line("xcodebuild (.ipa):\n" + export_str); print_line("xcodebuild (.ipa):\n" + export_str);
if (!export_str.contains("** EXPORT SUCCEEDED **")) { if (!export_str.contains("** EXPORT SUCCEEDED **")) {
add_message(EXPORT_MESSAGE_ERROR, TTR("Xcode Build"), TTR(".ipa export failed, see editor log for details.")); add_message(EXPORT_MESSAGE_ERROR, TTR("Xcode Build"), TTR(".ipa export failed, see editor log for details."));

View File

@@ -79,6 +79,7 @@ Error EditorExportPlatformLinuxBSD::export_project(const Ref<EditorExportPreset>
Ref<DirAccess> tmp_app_dir = DirAccess::create_for_path(tmp_dir_path); Ref<DirAccess> tmp_app_dir = DirAccess::create_for_path(tmp_dir_path);
if (export_as_zip) { if (export_as_zip) {
if (tmp_app_dir.is_null()) { if (tmp_app_dir.is_null()) {
add_message(EXPORT_MESSAGE_ERROR, TTR("Prepare Templates"), vformat(TTR("Could not create and open the directory: \"%s\""), tmp_dir_path));
return ERR_CANT_CREATE; return ERR_CANT_CREATE;
} }
if (DirAccess::exists(tmp_dir_path)) { if (DirAccess::exists(tmp_dir_path)) {
@@ -93,11 +94,11 @@ Error EditorExportPlatformLinuxBSD::export_project(const Ref<EditorExportPreset>
// Export project. // Export project.
Error err = EditorExportPlatformPC::export_project(p_preset, p_debug, path, p_flags); Error err = EditorExportPlatformPC::export_project(p_preset, p_debug, path, p_flags);
if (err != OK) { if (err != OK) {
// Message is supplied by the subroutine method.
return err; return err;
} }
// Save console wrapper. // Save console wrapper.
if (err == OK) {
int con_scr = p_preset->get("debug/export_console_wrapper"); int con_scr = p_preset->get("debug/export_console_wrapper");
if ((con_scr == 1 && p_debug) || (con_scr == 2)) { if ((con_scr == 1 && p_debug) || (con_scr == 2)) {
String scr_path = path.get_basename() + ".sh"; String scr_path = path.get_basename() + ".sh";
@@ -107,7 +108,6 @@ Error EditorExportPlatformLinuxBSD::export_project(const Ref<EditorExportPreset>
add_message(EXPORT_MESSAGE_ERROR, TTR("Debug Console Export"), TTR("Could not create console wrapper.")); add_message(EXPORT_MESSAGE_ERROR, TTR("Debug Console Export"), TTR("Could not create console wrapper."));
} }
} }
}
// ZIP project. // ZIP project.
if (export_as_zip) { if (export_as_zip) {

View File

@@ -1266,10 +1266,16 @@ Error EditorExportPlatformMacOS::_export_debug_script(const Ref<EditorExportPres
Error EditorExportPlatformMacOS::export_project(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags) { Error EditorExportPlatformMacOS::export_project(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags) {
ExportNotifier notifier(*this, p_preset, p_debug, p_path, p_flags); ExportNotifier notifier(*this, p_preset, p_debug, p_path, p_flags);
String src_pkg_name; const String base_dir = p_path.get_base_dir();
if (!DirAccess::exists(base_dir)) {
add_message(EXPORT_MESSAGE_ERROR, TTR("Export"), vformat(TTR("Target folder does not exist or is inaccessible: \"%s\""), base_dir));
return ERR_FILE_BAD_PATH;
}
EditorProgress ep("export", TTR("Exporting for macOS"), 3, true); EditorProgress ep("export", TTR("Exporting for macOS"), 3, true);
String src_pkg_name;
if (p_debug) { if (p_debug) {
src_pkg_name = p_preset->get("custom_template/debug"); src_pkg_name = p_preset->get("custom_template/debug");
} else { } else {
@@ -1280,16 +1286,11 @@ Error EditorExportPlatformMacOS::export_project(const Ref<EditorExportPreset> &p
String err; String err;
src_pkg_name = find_export_template("macos.zip", &err); src_pkg_name = find_export_template("macos.zip", &err);
if (src_pkg_name.is_empty()) { if (src_pkg_name.is_empty()) {
add_message(EXPORT_MESSAGE_ERROR, TTR("Prepare Templates"), TTR("Export template not found.")); add_message(EXPORT_MESSAGE_ERROR, TTR("Prepare Templates"), TTR("Export template not found.") + "\n" + err);
return ERR_FILE_NOT_FOUND; return ERR_FILE_NOT_FOUND;
} }
} }
if (!DirAccess::exists(p_path.get_base_dir())) {
add_message(EXPORT_MESSAGE_ERROR, TTR("Prepare Templates"), TTR("The given export path doesn't exist."));
return ERR_FILE_BAD_PATH;
}
Ref<FileAccess> io_fa; Ref<FileAccess> io_fa;
zlib_filefunc_def io = zipio_create_io(&io_fa); zlib_filefunc_def io = zipio_create_io(&io_fa);

View File

@@ -259,6 +259,7 @@ Error EditorExportPlatformWeb::_build_pwa(const Ref<EditorExportPreset> &p_prese
_replace_strings(replaces, sw); _replace_strings(replaces, sw);
Error err = _write_or_error(sw.ptr(), sw.size(), dir.path_join(name + ".service.worker.js")); Error err = _write_or_error(sw.ptr(), sw.size(), dir.path_join(name + ".service.worker.js"));
if (err != OK) { if (err != OK) {
// Message is supplied by the subroutine method.
return err; return err;
} }
@@ -291,16 +292,19 @@ Error EditorExportPlatformWeb::_build_pwa(const Ref<EditorExportPreset> &p_prese
const String icon144_path = p_preset->get("progressive_web_app/icon_144x144"); const String icon144_path = p_preset->get("progressive_web_app/icon_144x144");
err = _add_manifest_icon(p_path, icon144_path, 144, icons_arr); err = _add_manifest_icon(p_path, icon144_path, 144, icons_arr);
if (err != OK) { if (err != OK) {
// Message is supplied by the subroutine method.
return err; return err;
} }
const String icon180_path = p_preset->get("progressive_web_app/icon_180x180"); const String icon180_path = p_preset->get("progressive_web_app/icon_180x180");
err = _add_manifest_icon(p_path, icon180_path, 180, icons_arr); err = _add_manifest_icon(p_path, icon180_path, 180, icons_arr);
if (err != OK) { if (err != OK) {
// Message is supplied by the subroutine method.
return err; return err;
} }
const String icon512_path = p_preset->get("progressive_web_app/icon_512x512"); const String icon512_path = p_preset->get("progressive_web_app/icon_512x512");
err = _add_manifest_icon(p_path, icon512_path, 512, icons_arr); err = _add_manifest_icon(p_path, icon512_path, 512, icons_arr);
if (err != OK) { if (err != OK) {
// Message is supplied by the subroutine method.
return err; return err;
} }
manifest["icons"] = icons_arr; manifest["icons"] = icons_arr;
@@ -308,6 +312,7 @@ Error EditorExportPlatformWeb::_build_pwa(const Ref<EditorExportPreset> &p_prese
CharString cs = Variant(manifest).to_json_string().utf8(); CharString cs = Variant(manifest).to_json_string().utf8();
err = _write_or_error((const uint8_t *)cs.get_data(), cs.length(), dir.path_join(name + ".manifest.json")); err = _write_or_error((const uint8_t *)cs.get_data(), cs.length(), dir.path_join(name + ".manifest.json"));
if (err != OK) { if (err != OK) {
// Message is supplied by the subroutine method.
return err; return err;
} }
@@ -439,6 +444,11 @@ Error EditorExportPlatformWeb::export_project(const Ref<EditorExportPreset> &p_p
const String base_path = p_path.get_basename(); const String base_path = p_path.get_basename();
const String base_name = p_path.get_file().get_basename(); const String base_name = p_path.get_file().get_basename();
if (!DirAccess::exists(base_dir)) {
add_message(EXPORT_MESSAGE_ERROR, TTR("Export"), vformat(TTR("Target folder does not exist or is inaccessible: \"%s\""), base_dir));
return ERR_FILE_BAD_PATH;
}
// Find the correct template // Find the correct template
String template_path = p_debug ? custom_debug : custom_release; String template_path = p_debug ? custom_debug : custom_release;
template_path = template_path.strip_edges(); template_path = template_path.strip_edges();
@@ -447,10 +457,6 @@ Error EditorExportPlatformWeb::export_project(const Ref<EditorExportPreset> &p_p
template_path = find_export_template(_get_template_name(extensions, p_debug)); template_path = find_export_template(_get_template_name(extensions, p_debug));
} }
if (!DirAccess::exists(base_dir)) {
return ERR_FILE_BAD_PATH;
}
if (!template_path.is_empty() && !FileAccess::exists(template_path)) { if (!template_path.is_empty() && !FileAccess::exists(template_path)) {
add_message(EXPORT_MESSAGE_ERROR, TTR("Prepare Templates"), vformat(TTR("Template file not found: \"%s\"."), template_path)); add_message(EXPORT_MESSAGE_ERROR, TTR("Prepare Templates"), vformat(TTR("Template file not found: \"%s\"."), template_path));
return ERR_FILE_NOT_FOUND; return ERR_FILE_NOT_FOUND;
@@ -480,6 +486,7 @@ Error EditorExportPlatformWeb::export_project(const Ref<EditorExportPreset> &p_p
// Extract templates. // Extract templates.
error = _extract_template(template_path, base_dir, base_name, pwa); error = _extract_template(template_path, base_dir, base_name, pwa);
if (error) { if (error) {
// Message is supplied by the subroutine method.
return error; return error;
} }
@@ -510,6 +517,7 @@ Error EditorExportPlatformWeb::export_project(const Ref<EditorExportPreset> &p_p
_fix_html(html, p_preset, base_name, p_debug, p_flags, shared_objects, file_sizes); _fix_html(html, p_preset, base_name, p_debug, p_flags, shared_objects, file_sizes);
Error err = _write_or_error(html.ptr(), html.size(), p_path); Error err = _write_or_error(html.ptr(), html.size(), p_path);
if (err != OK) { if (err != OK) {
// Message is supplied by the subroutine method.
return err; return err;
} }
html.resize(0); html.resize(0);
@@ -543,6 +551,7 @@ Error EditorExportPlatformWeb::export_project(const Ref<EditorExportPreset> &p_p
if (pwa) { if (pwa) {
err = _build_pwa(p_preset, p_path, shared_objects); err = _build_pwa(p_preset, p_path, shared_objects);
if (err != OK) { if (err != OK) {
// Message is supplied by the subroutine method.
return err; return err;
} }
} }

View File

@@ -226,6 +226,7 @@ Error EditorExportPlatformWindows::export_project(const Ref<EditorExportPreset>
Ref<DirAccess> tmp_app_dir = DirAccess::create_for_path(tmp_dir_path); Ref<DirAccess> tmp_app_dir = DirAccess::create_for_path(tmp_dir_path);
if (export_as_zip) { if (export_as_zip) {
if (tmp_app_dir.is_null()) { if (tmp_app_dir.is_null()) {
add_message(EXPORT_MESSAGE_ERROR, TTR("Prepare Templates"), vformat(TTR("Could not create and open the directory: \"%s\""), tmp_dir_path));
return ERR_CANT_CREATE; return ERR_CANT_CREATE;
} }
if (DirAccess::exists(tmp_dir_path)) { if (DirAccess::exists(tmp_dir_path)) {
@@ -242,8 +243,14 @@ Error EditorExportPlatformWindows::export_project(const Ref<EditorExportPreset>
if (embedded) { if (embedded) {
pck_path = pck_path.get_basename() + ".tmp"; pck_path = pck_path.get_basename() + ".tmp";
} }
Error err = EditorExportPlatformPC::export_project(p_preset, p_debug, pck_path, p_flags); Error err = EditorExportPlatformPC::export_project(p_preset, p_debug, pck_path, p_flags);
if (p_preset->get("codesign/enable") && err == OK) { if (err != OK) {
// Message is supplied by the subroutine method.
return err;
}
if (p_preset->get("codesign/enable")) {
_code_sign(p_preset, pck_path); _code_sign(p_preset, pck_path);
String wrapper_path = p_path.get_basename() + ".console.exe"; String wrapper_path = p_path.get_basename() + ".console.exe";
if (FileAccess::exists(wrapper_path)) { if (FileAccess::exists(wrapper_path)) {
@@ -251,7 +258,7 @@ Error EditorExportPlatformWindows::export_project(const Ref<EditorExportPreset>
} }
} }
if (embedded && err == OK) { if (embedded) {
Ref<DirAccess> tmp_dir = DirAccess::create_for_path(p_path.get_base_dir()); Ref<DirAccess> tmp_dir = DirAccess::create_for_path(p_path.get_base_dir());
err = tmp_dir->rename(pck_path, p_path); err = tmp_dir->rename(pck_path, p_path);
if (err != OK) { if (err != OK) {