summaryrefslogtreecommitdiffstats
path: root/editor/export/editor_export_platform.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'editor/export/editor_export_platform.cpp')
-rw-r--r--editor/export/editor_export_platform.cpp233
1 files changed, 233 insertions, 0 deletions
diff --git a/editor/export/editor_export_platform.cpp b/editor/export/editor_export_platform.cpp
index ef6c835b38..6478f99fb1 100644
--- a/editor/export/editor_export_platform.cpp
+++ b/editor/export/editor_export_platform.cpp
@@ -1322,6 +1322,121 @@ Error EditorExportPlatform::_add_shared_object(void *p_userdata, const SharedObj
return OK;
}
+void EditorExportPlatform::zip_folder_recursive(zipFile &p_zip, const String &p_root_path, const String &p_folder, const String &p_pkg_name) {
+ String dir = p_folder.is_empty() ? p_root_path : p_root_path.path_join(p_folder);
+
+ Ref<DirAccess> da = DirAccess::open(dir);
+ da->list_dir_begin();
+ String f = da->get_next();
+ while (!f.is_empty()) {
+ if (f == "." || f == "..") {
+ f = da->get_next();
+ continue;
+ }
+ if (da->is_link(f)) {
+ OS::DateTime dt = OS::get_singleton()->get_datetime();
+
+ zip_fileinfo zipfi;
+ zipfi.tmz_date.tm_year = dt.year;
+ zipfi.tmz_date.tm_mon = dt.month - 1; // Note: "tm" month range - 0..11, Godot month range - 1..12, https://www.cplusplus.com/reference/ctime/tm/
+ zipfi.tmz_date.tm_mday = dt.day;
+ zipfi.tmz_date.tm_hour = dt.hour;
+ zipfi.tmz_date.tm_min = dt.minute;
+ zipfi.tmz_date.tm_sec = dt.second;
+ zipfi.dosDate = 0;
+ // 0120000: symbolic link type
+ // 0000755: permissions rwxr-xr-x
+ // 0000644: permissions rw-r--r--
+ uint32_t _mode = 0120644;
+ zipfi.external_fa = (_mode << 16L) | !(_mode & 0200);
+ zipfi.internal_fa = 0;
+
+ zipOpenNewFileInZip4(p_zip,
+ p_folder.path_join(f).utf8().get_data(),
+ &zipfi,
+ nullptr,
+ 0,
+ nullptr,
+ 0,
+ nullptr,
+ Z_DEFLATED,
+ Z_DEFAULT_COMPRESSION,
+ 0,
+ -MAX_WBITS,
+ DEF_MEM_LEVEL,
+ Z_DEFAULT_STRATEGY,
+ nullptr,
+ 0,
+ 0x0314, // "version made by", 0x03 - Unix, 0x14 - ZIP specification version 2.0, required to store Unix file permissions
+ 0);
+
+ String target = da->read_link(f);
+ zipWriteInFileInZip(p_zip, target.utf8().get_data(), target.utf8().size());
+ zipCloseFileInZip(p_zip);
+ } else if (da->current_is_dir()) {
+ zip_folder_recursive(p_zip, p_root_path, p_folder.path_join(f), p_pkg_name);
+ } else {
+ bool _is_executable = is_executable(dir.path_join(f));
+
+ OS::DateTime dt = OS::get_singleton()->get_datetime();
+
+ zip_fileinfo zipfi;
+ zipfi.tmz_date.tm_year = dt.year;
+ zipfi.tmz_date.tm_mon = dt.month - 1; // Note: "tm" month range - 0..11, Godot month range - 1..12, https://www.cplusplus.com/reference/ctime/tm/
+ zipfi.tmz_date.tm_mday = dt.day;
+ zipfi.tmz_date.tm_hour = dt.hour;
+ zipfi.tmz_date.tm_min = dt.minute;
+ zipfi.tmz_date.tm_sec = dt.second;
+ zipfi.dosDate = 0;
+ // 0100000: regular file type
+ // 0000755: permissions rwxr-xr-x
+ // 0000644: permissions rw-r--r--
+ uint32_t _mode = (_is_executable ? 0100755 : 0100644);
+ zipfi.external_fa = (_mode << 16L) | !(_mode & 0200);
+ zipfi.internal_fa = 0;
+
+ zipOpenNewFileInZip4(p_zip,
+ p_folder.path_join(f).utf8().get_data(),
+ &zipfi,
+ nullptr,
+ 0,
+ nullptr,
+ 0,
+ nullptr,
+ Z_DEFLATED,
+ Z_DEFAULT_COMPRESSION,
+ 0,
+ -MAX_WBITS,
+ DEF_MEM_LEVEL,
+ Z_DEFAULT_STRATEGY,
+ nullptr,
+ 0,
+ 0x0314, // "version made by", 0x03 - Unix, 0x14 - ZIP specification version 2.0, required to store Unix file permissions
+ 0);
+
+ Ref<FileAccess> fa = FileAccess::open(dir.path_join(f), FileAccess::READ);
+ if (fa.is_null()) {
+ add_message(EXPORT_MESSAGE_ERROR, TTR("ZIP Creation"), vformat(TTR("Could not open file to read from path \"%s\"."), dir.path_join(f)));
+ return;
+ }
+ const int bufsize = 16384;
+ uint8_t buf[bufsize];
+
+ while (true) {
+ uint64_t got = fa->get_buffer(buf, bufsize);
+ if (got == 0) {
+ break;
+ }
+ zipWriteInFileInZip(p_zip, buf, got);
+ }
+
+ zipCloseFileInZip(p_zip);
+ }
+ f = da->get_next();
+ }
+ da->list_dir_end();
+}
+
Error EditorExportPlatform::save_pack(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, Vector<SharedObject> *p_so_files, bool p_embed, int64_t *r_embedded_start, int64_t *r_embedded_size) {
EditorProgress ep("savepack", TTR("Packing"), 102, true);
@@ -1642,5 +1757,123 @@ bool EditorExportPlatform::can_export(const Ref<EditorExportPreset> &p_preset, S
return valid;
}
+Error EditorExportPlatform::ssh_run_on_remote(const String &p_host, const String &p_port, const Vector<String> &p_ssh_args, const String &p_cmd_args, String *r_out, int p_port_fwd) const {
+ String ssh_path = EditorSettings::get_singleton()->get("export/ssh/ssh");
+ if (ssh_path.is_empty()) {
+ ssh_path = "ssh";
+ }
+
+ List<String> args;
+ args.push_back("-p");
+ args.push_back(p_port);
+ for (const String &E : p_ssh_args) {
+ args.push_back(E);
+ }
+ if (p_port_fwd > 0) {
+ args.push_back("-R");
+ args.push_back(vformat("%d:localhost:%d", p_port_fwd, p_port_fwd));
+ }
+ args.push_back(p_host);
+ args.push_back(p_cmd_args);
+
+ String out;
+ int exit_code = -1;
+
+ if (OS::get_singleton()->is_stdout_verbose()) {
+ OS::get_singleton()->print("Executing: %s", ssh_path.utf8().get_data());
+ for (const String &arg : args) {
+ OS::get_singleton()->print(" %s", arg.utf8().get_data());
+ }
+ OS::get_singleton()->print("\n");
+ }
+
+ Error err = OS::get_singleton()->execute(ssh_path, args, &out, &exit_code, true);
+ if (out.is_empty()) {
+ print_verbose(vformat("Exit code: %d", exit_code));
+ } else {
+ print_verbose(vformat("Exit code: %d, Output: %s", exit_code, out.replace("\r\n", "\n")));
+ }
+ if (r_out) {
+ *r_out = out.replace("\r\n", "\n").get_slice("\n", 0);
+ }
+ if (err != OK) {
+ return err;
+ } else if (exit_code != 0) {
+ if (!out.is_empty()) {
+ print_line(out);
+ }
+ return FAILED;
+ }
+ return OK;
+}
+
+Error EditorExportPlatform::ssh_run_on_remote_no_wait(const String &p_host, const String &p_port, const Vector<String> &p_ssh_args, const String &p_cmd_args, OS::ProcessID *r_pid, int p_port_fwd) const {
+ String ssh_path = EditorSettings::get_singleton()->get("export/ssh/ssh");
+ if (ssh_path.is_empty()) {
+ ssh_path = "ssh";
+ }
+
+ List<String> args;
+ args.push_back("-p");
+ args.push_back(p_port);
+ for (const String &E : p_ssh_args) {
+ args.push_back(E);
+ }
+ if (p_port_fwd > 0) {
+ args.push_back("-R");
+ args.push_back(vformat("%d:localhost:%d", p_port_fwd, p_port_fwd));
+ }
+ args.push_back(p_host);
+ args.push_back(p_cmd_args);
+
+ if (OS::get_singleton()->is_stdout_verbose()) {
+ OS::get_singleton()->print("Executing: %s", ssh_path.utf8().get_data());
+ for (const String &arg : args) {
+ OS::get_singleton()->print(" %s", arg.utf8().get_data());
+ }
+ OS::get_singleton()->print("\n");
+ }
+
+ return OS::get_singleton()->create_process(ssh_path, args, r_pid);
+}
+
+Error EditorExportPlatform::ssh_push_to_remote(const String &p_host, const String &p_port, const Vector<String> &p_scp_args, const String &p_src_file, const String &p_dst_file) const {
+ String scp_path = EditorSettings::get_singleton()->get("export/ssh/scp");
+ if (scp_path.is_empty()) {
+ scp_path = "scp";
+ }
+
+ List<String> args;
+ args.push_back("-P");
+ args.push_back(p_port);
+ for (const String &E : p_scp_args) {
+ args.push_back(E);
+ }
+ args.push_back(p_src_file);
+ args.push_back(vformat("%s:%s", p_host, p_dst_file));
+
+ String out;
+ int exit_code = -1;
+
+ if (OS::get_singleton()->is_stdout_verbose()) {
+ OS::get_singleton()->print("Executing: %s", scp_path.utf8().get_data());
+ for (const String &arg : args) {
+ OS::get_singleton()->print(" %s", arg.utf8().get_data());
+ }
+ OS::get_singleton()->print("\n");
+ }
+
+ Error err = OS::get_singleton()->execute(scp_path, args, &out, &exit_code, true);
+ if (err != OK) {
+ return err;
+ } else if (exit_code != 0) {
+ if (!out.is_empty()) {
+ print_line(out);
+ }
+ return FAILED;
+ }
+ return OK;
+}
+
EditorExportPlatform::EditorExportPlatform() {
}