Ensure more export errors are reported to users

Also fixes the timing issue when exporting all
presets at the same time, where the error report
would try to appear while the progress dialog
was still visible.
This commit is contained in:
Yuri Sizov 2023-12-06 15:18:35 +01:00
parent 2f73a059ce
commit 773b4d7764
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();
if (msg_count) {
if (msg_count > 0) {
p_log->push_table(2);
p_log->set_table_column_expand(0, false);
p_log->set_table_column_expand(1, true);
@ -131,10 +131,39 @@ bool EditorExportPlatform::fill_log_messages(RichTextLabel *p_log, Error p_err)
p_log->pop();
p_log->pop();
}
p_log->pop();
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();
return has_messages;
}

View File

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

View File

@ -1109,37 +1109,40 @@ void ProjectExportDialog::_export_all_dialog_action(const String &p_str) {
}
void ProjectExportDialog::_export_all(bool p_debug) {
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);
exporting = true;
bool show_dialog = false;
result_dialog_log->clear();
for (int i = 0; i < EditorExport::get_singleton()->get_export_preset_count(); i++) {
Ref<EditorExportPreset> preset = EditorExport::get_singleton()->get_export_preset(i);
if (preset.is_null()) {
exporting = false;
ERR_FAIL_MSG("Failed to start the export: one of the presets is invalid.");
}
Ref<EditorExportPlatform> platform = preset->get_platform();
if (platform.is_null()) {
exporting = false;
ERR_FAIL_MSG("Failed to start the export: one of the presets has no valid platform.");
}
{ // 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");
EditorProgress ep("exportall", TTR("Exporting All") + " " + export_target, EditorExport::get_singleton()->get_export_preset_count(), true);
ep.step(preset->get_name(), i);
result_dialog_log->clear();
for (int i = 0; i < EditorExport::get_singleton()->get_export_preset_count(); i++) {
Ref<EditorExportPreset> preset = EditorExport::get_singleton()->get_export_preset(i);
if (preset.is_null()) {
exporting = false;
ERR_FAIL_MSG("Failed to start the export: one of the presets is invalid.");
}
platform->clear_messages();
Error err = platform->export_project(preset, p_debug, preset->get_export_path(), 0);
if (err == ERR_SKIP) {
exporting = false;
return;
Ref<EditorExportPlatform> platform = preset->get_platform();
if (platform.is_null()) {
exporting = false;
ERR_FAIL_MSG("Failed to start the export: one of the presets has no valid platform.");
}
ep.step(preset->get_name(), i);
platform->clear_messages();
Error err = platform->export_project(preset, p_debug, preset->get_export_path(), 0);
if (err == ERR_SKIP) {
exporting = false;
return;
}
bool has_messages = platform->fill_log_messages(result_dialog_log, err);
show_dialog = show_dialog || has_messages;
}
bool has_messages = platform->fill_log_messages(result_dialog_log, err);
show_dialog = show_dialog || has_messages;
}
if (show_dialog) {
result_dialog->popup_centered_ratio(0.5);
}
@ -1148,7 +1151,6 @@ void ProjectExportDialog::_export_all(bool p_debug) {
}
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("get_export_path", &ProjectExportDialog::get_export_path);
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) {
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;
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);
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);
// 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;
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);
unzClose(pkg);
if (err != OK) {
CLEANUP_AND_RETURN(err);
}
// Let's zip-align (must be done before signing)
static const int ZIP_ALIGNMENT = 4;
@ -3392,6 +3393,7 @@ Error EditorExportPlatformAndroid::export_project_helper(const Ref<EditorExportP
// file will invalidate the signature.
err = sign_apk(p_preset, p_debug, p_path, ep);
if (err != OK) {
// Message is supplied by the subroutine method.
CLEANUP_AND_RETURN(err);
}
}

View File

@ -620,7 +620,10 @@ Error EditorExportPlatformIOS::_export_icons(const Ref<EditorExportPreset> &p_pr
String sizes;
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");
@ -692,12 +695,20 @@ Error EditorExportPlatformIOS::_export_icons(const Ref<EditorExportPreset> &p_pr
json_description += "]}";
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();
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);
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();
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];
if (asset.begins_with("res://")) {
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://")) {
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 {
// either SDK-builtin or already a part of the export template
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.
// Static libraries are not embedded anyway.
err = _copy_asset(dest_dir, plugin_main_binary, &plugin_binary_result_file, true, false, r_exported_assets);
ERR_FAIL_COND_V(err, err);
ERR_FAIL_COND_V(err != OK, err);
// Adding dependencies.
// 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
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
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
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
@ -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) {
ExportNotifier notifier(*this, p_preset, p_debug, p_path, p_flags);
String src_pkg_name;
String dest_dir = p_path.get_base_dir() + "/";
String binary_name = p_path.get_file().get_basename();
const String dest_dir = p_path.get_base_dir() + "/";
const 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");
@ -1507,6 +1522,7 @@ Error EditorExportPlatformIOS::_export_project_helper(const Ref<EditorExportPres
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.");
String src_pkg_name;
if (p_debug) {
src_pkg_name = p_preset->get("custom_template/debug");
} 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);
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
// 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();
}
if (da->change_dir(dest_dir + binary_name) == OK) {
if (da->change_dir(binary_dir) == OK) {
da->erase_contents_recursive();
}
da->change_dir(current_dir);
if (!da->dir_exists(dest_dir + binary_name)) {
Error err = da->make_dir(dest_dir + binary_name);
if (err) {
if (!da->dir_exists(binary_dir)) {
Error err = da->make_dir(binary_dir);
if (err != OK) {
add_message(EXPORT_MESSAGE_ERROR, TTR("Export"), vformat(TTR("Failed to create the directory: \"%s\""), binary_dir));
return err;
}
}
@ -1554,10 +1567,11 @@ Error EditorExportPlatformIOS::_export_project_helper(const Ref<EditorExportPres
if (ep.step("Making .pck", 0)) {
return ERR_SKIP;
}
String pack_path = dest_dir + binary_name + ".pck";
String pack_path = binary_dir + ".pck";
Vector<SharedObject> libraries;
Error err = save_pack(p_preset, p_debug, pack_path, &libraries);
if (err) {
// Message is supplied by the subroutine method.
return err;
}
@ -1606,7 +1620,10 @@ Error EditorExportPlatformIOS::_export_project_helper(const Ref<EditorExportPres
Vector<IOSExportAsset> assets;
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...");
Ref<FileAccess> io_fa;
@ -1617,8 +1634,14 @@ Error EditorExportPlatformIOS::_export_project_helper(const Ref<EditorExportPres
return ERR_CANT_OPEN;
}
err = _export_ios_plugins(p_preset, config_data, dest_dir + binary_name, assets, p_debug);
ERR_FAIL_COND_V(err, err);
err = _export_ios_plugins(p_preset, config_data, binary_dir, assets, p_debug);
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
int ret = unzGoToFirstFile(src_pkg_zip);
@ -1683,8 +1706,8 @@ Error EditorExportPlatformIOS::_export_project_helper(const Ref<EditorExportPres
print_line("Creating " + dir_name);
Error dir_err = tmp_app_path->make_dir_recursive(dir_name);
if (dir_err) {
ERR_PRINT("Can't create '" + dir_name + "'.");
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;
}
}
@ -1693,8 +1716,8 @@ Error EditorExportPlatformIOS::_export_project_helper(const Ref<EditorExportPres
{
Ref<FileAccess> f = FileAccess::open(file, FileAccess::WRITE);
if (f.is_null()) {
ERR_PRINT("Can't write '" + file + "'.");
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;
};
f->store_buffer(data.ptr(), data.size());
@ -1715,7 +1738,7 @@ Error EditorExportPlatformIOS::_export_project_helper(const Ref<EditorExportPres
unzClose(src_pkg_zip);
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;
}
@ -1727,7 +1750,7 @@ Error EditorExportPlatformIOS::_export_project_helper(const Ref<EditorExportPres
Vector<String> translations = GLOBAL_GET("internationalization/locale/translations");
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);
Ref<FileAccess> f = FileAccess::open(fname + "/InfoPlist.strings", FileAccess::WRITE);
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) {
String fname = dest_dir + binary_name + "/" + lang + ".lproj";
String fname = binary_dir + "/" + lang + ".lproj";
tmp_app_path->make_dir_recursive(fname);
Ref<FileAccess> f = FileAccess::open(fname + "/InfoPlist.strings", FileAccess::WRITE);
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();
Error lib_copy_err = tmp_app_path->copy(static_lib_path, dest_lib_file_path);
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;
}
}
}
String iconset_dir = dest_dir + binary_name + "/Images.xcassets/AppIcon.appiconset/";
String iconset_dir = binary_dir + "/Images.xcassets/AppIcon.appiconset/";
err = OK;
if (!tmp_app_path->dir_exists(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;
}
err = _export_icons(p_preset, iconset_dir);
if (err) {
if (err != OK) {
// Message is supplied by the subroutine method.
return err;
}
{
bool use_storyboard = p_preset->get("storyboard/use_launch_screen_storyboard");
String launch_image_path = dest_dir + binary_name + "/Images.xcassets/LaunchImage.launchimage/";
String splash_image_path = dest_dir + binary_name + "/Images.xcassets/SplashImage.imageset/";
String launch_image_path = binary_dir + "/Images.xcassets/LaunchImage.launchimage/";
String splash_image_path = binary_dir + "/Images.xcassets/SplashImage.imageset/";
Ref<DirAccess> launch_screen_da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
if (launch_screen_da.is_null()) {
add_message(EXPORT_MESSAGE_ERROR, TTR("Export"), TTR("Could not access the filesystem."));
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);
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 {
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);
@ -1829,21 +1856,22 @@ Error EditorExportPlatformIOS::_export_project_helper(const Ref<EditorExportPres
}
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;
}
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);
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);
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;
};
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)) {
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);
CodesignData codesign_data(p_preset, p_debug);
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)) {
return ERR_SKIP;
}
String archive_path = p_path.get_basename() + ".xcarchive";
List<String> archive_args;
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(binary_name);
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("-archivePath");
archive_args.push_back(archive_path);
String archive_str;
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);
if (!archive_str.contains("** ARCHIVE SUCCEEDED **")) {
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)) {
return ERR_SKIP;
}
List<String> export_args;
export_args.push_back("-exportArchive");
export_args.push_back("-archivePath");
export_args.push_back(archive_path);
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("-exportPath");
export_args.push_back(dest_dir);
String export_str;
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);
if (!export_str.contains("** EXPORT SUCCEEDED **")) {
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);
if (export_as_zip) {
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;
}
if (DirAccess::exists(tmp_dir_path)) {
@ -93,19 +94,18 @@ Error EditorExportPlatformLinuxBSD::export_project(const Ref<EditorExportPreset>
// Export project.
Error err = EditorExportPlatformPC::export_project(p_preset, p_debug, path, p_flags);
if (err != OK) {
// Message is supplied by the subroutine method.
return err;
}
// Save console wrapper.
if (err == OK) {
int con_scr = p_preset->get("debug/export_console_wrapper");
if ((con_scr == 1 && p_debug) || (con_scr == 2)) {
String scr_path = path.get_basename() + ".sh";
err = _export_debug_script(p_preset, pkg_name, path.get_file(), scr_path);
FileAccess::set_unix_permissions(scr_path, 0755);
if (err != OK) {
add_message(EXPORT_MESSAGE_ERROR, TTR("Debug Console Export"), TTR("Could not create console wrapper."));
}
int con_scr = p_preset->get("debug/export_console_wrapper");
if ((con_scr == 1 && p_debug) || (con_scr == 2)) {
String scr_path = path.get_basename() + ".sh";
err = _export_debug_script(p_preset, pkg_name, path.get_file(), scr_path);
FileAccess::set_unix_permissions(scr_path, 0755);
if (err != OK) {
add_message(EXPORT_MESSAGE_ERROR, TTR("Debug Console Export"), TTR("Could not create console wrapper."));
}
}

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) {
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);
String src_pkg_name;
if (p_debug) {
src_pkg_name = p_preset->get("custom_template/debug");
} else {
@ -1280,16 +1286,11 @@ Error EditorExportPlatformMacOS::export_project(const Ref<EditorExportPreset> &p
String err;
src_pkg_name = find_export_template("macos.zip", &err);
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;
}
}
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;
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);
Error err = _write_or_error(sw.ptr(), sw.size(), dir.path_join(name + ".service.worker.js"));
if (err != OK) {
// Message is supplied by the subroutine method.
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");
err = _add_manifest_icon(p_path, icon144_path, 144, icons_arr);
if (err != OK) {
// Message is supplied by the subroutine method.
return err;
}
const String icon180_path = p_preset->get("progressive_web_app/icon_180x180");
err = _add_manifest_icon(p_path, icon180_path, 180, icons_arr);
if (err != OK) {
// Message is supplied by the subroutine method.
return err;
}
const String icon512_path = p_preset->get("progressive_web_app/icon_512x512");
err = _add_manifest_icon(p_path, icon512_path, 512, icons_arr);
if (err != OK) {
// Message is supplied by the subroutine method.
return err;
}
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();
err = _write_or_error((const uint8_t *)cs.get_data(), cs.length(), dir.path_join(name + ".manifest.json"));
if (err != OK) {
// Message is supplied by the subroutine method.
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_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
String template_path = p_debug ? custom_debug : custom_release;
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));
}
if (!DirAccess::exists(base_dir)) {
return ERR_FILE_BAD_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));
return ERR_FILE_NOT_FOUND;
@ -480,6 +486,7 @@ Error EditorExportPlatformWeb::export_project(const Ref<EditorExportPreset> &p_p
// Extract templates.
error = _extract_template(template_path, base_dir, base_name, pwa);
if (error) {
// Message is supplied by the subroutine method.
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);
Error err = _write_or_error(html.ptr(), html.size(), p_path);
if (err != OK) {
// Message is supplied by the subroutine method.
return err;
}
html.resize(0);
@ -543,6 +551,7 @@ Error EditorExportPlatformWeb::export_project(const Ref<EditorExportPreset> &p_p
if (pwa) {
err = _build_pwa(p_preset, p_path, shared_objects);
if (err != OK) {
// Message is supplied by the subroutine method.
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);
if (export_as_zip) {
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;
}
if (DirAccess::exists(tmp_dir_path)) {
@ -242,8 +243,14 @@ Error EditorExportPlatformWindows::export_project(const Ref<EditorExportPreset>
if (embedded) {
pck_path = pck_path.get_basename() + ".tmp";
}
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);
String wrapper_path = p_path.get_basename() + ".console.exe";
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());
err = tmp_dir->rename(pck_path, p_path);
if (err != OK) {