C#: Add option to embed dotnet build outputs into the data file

This commit is contained in:
RedworkDE 2023-04-20 22:25:21 +02:00
parent c83f912bcb
commit 777d959e05
2 changed files with 90 additions and 15 deletions

View file

@ -3,6 +3,8 @@ using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using GodotTools.Build;
using GodotTools.Core;
using GodotTools.Internals;
@ -45,6 +47,17 @@ namespace GodotTools.Export
}
},
{ "default_value", true }
},
new Godot.Collections.Dictionary()
{
{
"option", new Godot.Collections.Dictionary()
{
{ "name", "dotnet/embed_build_outputs" },
{ "type", (int)Variant.Type.Bool }
}
},
{ "default_value", false }
}
};
}
@ -146,6 +159,8 @@ namespace GodotTools.Export
}
}
bool embedBuildResults = (bool)GetOption("dotnet/embed_build_outputs");
foreach (var arch in archs)
{
string ridOS = DetermineRuntimeIdentifierOS(platform);
@ -190,17 +205,44 @@ namespace GodotTools.Export
"Publish succeeded but project assembly not found in the output directory");
}
// Add to the exported project shared object list.
var manifest = new StringBuilder();
// Add to the exported project shared object list or packed resources.
foreach (string file in Directory.GetFiles(publishOutputTempDir, "*", SearchOption.AllDirectories))
{
AddSharedObject(file, tags: null,
Path.Join(projectDataDirName,
Path.GetRelativePath(publishOutputTempDir, Path.GetDirectoryName(file))));
if (embedBuildResults)
{
var filePath = SanitizeSlashes(Path.GetRelativePath(publishOutputTempDir, file));
var fileData = File.ReadAllBytes(file);
var hash = Convert.ToBase64String(SHA512.HashData(fileData));
manifest.Append($"{filePath}\t{hash}\n");
AddFile($"res://.godot/mono/publish/{arch}/{filePath}", fileData, false);
}
else
{
AddSharedObject(file, tags: null,
Path.Join(projectDataDirName,
Path.GetRelativePath(publishOutputTempDir, Path.GetDirectoryName(file))));
}
}
if (embedBuildResults)
{
var fileData = Encoding.Default.GetBytes(manifest.ToString());
AddFile($"res://.godot/mono/publish/{arch}/.dotnet-publish-manifest", fileData, false);
}
}
}
private string SanitizeSlashes(string path)
{
if (Path.DirectorySeparatorChar == '\\')
return path.Replace('\\', '/');
return path;
}
private string DetermineRuntimeIdentifierOS(string platform)
=> OS.DotNetOSPlatformMap[platform];

View file

@ -141,19 +141,52 @@ private:
#else // TOOLS_ENABLED
String arch = Engine::get_singleton()->get_architecture_name();
String appname_safe = path::get_csharp_project_name();
String data_dir_root = exe_dir.path_join("data_" + appname_safe + "_" + arch);
if (!DirAccess::exists(data_dir_root)) {
data_dir_root = exe_dir.path_join("data_Godot_" + arch);
}
String packed_path = "res://.godot/mono/publish/" + arch;
if (DirAccess::exists(packed_path)) {
// The dotnet publish data is packed in the pck/zip.
String data_dir_root = OS::get_singleton()->get_cache_path().path_join("data_" + appname_safe + "_" + arch);
bool has_data = false;
if (!has_data) {
// 1. Try to access the data directly.
String global_packed = ProjectSettings::get_singleton()->globalize_path(packed_path);
if (global_packed.is_absolute_path() && FileAccess::exists(global_packed.path_join(".dotnet-publish-manifest"))) {
data_dir_root = global_packed;
has_data = true;
}
}
if (!has_data) {
// 2. Check if the data was extracted before and is up-to-date.
String packed_manifest = packed_path.path_join(".dotnet-publish-manifest");
String extracted_manifest = data_dir_root.path_join(".dotnet-publish-manifest");
if (FileAccess::exists(packed_manifest) && FileAccess::exists(extracted_manifest)) {
if (FileAccess::get_file_as_bytes(packed_manifest) == FileAccess::get_file_as_bytes(extracted_manifest)) {
has_data = true;
}
}
}
if (!has_data) {
// 3. Extract the data to a temporary location to load from there.
Ref<DirAccess> da = DirAccess::create_for_path(packed_path);
ERR_FAIL_NULL(da);
ERR_FAIL_COND(da->copy_dir(packed_path, data_dir_root) != OK);
}
api_assemblies_dir = data_dir_root;
} else {
// The dotnet publish data is in a directory next to the executable.
String data_dir_root = exe_dir.path_join("data_" + appname_safe + "_" + arch);
if (!DirAccess::exists(data_dir_root)) {
data_dir_root = exe_dir.path_join("data_Godot_" + arch);
}
#ifdef MACOS_ENABLED
if (!DirAccess::exists(data_dir_root)) {
data_dir_root = res_dir.path_join("data_" + appname_safe + "_" + arch);
}
if (!DirAccess::exists(data_dir_root)) {
data_dir_root = res_dir.path_join("data_Godot_" + arch);
}
if (!DirAccess::exists(data_dir_root)) {
data_dir_root = res_dir.path_join("data_" + appname_safe + "_" + arch);
}
if (!DirAccess::exists(data_dir_root)) {
data_dir_root = res_dir.path_join("data_Godot_" + arch);
}
#endif
api_assemblies_dir = data_dir_root;
api_assemblies_dir = data_dir_root;
}
#endif
}